From 3417d2ee4998a6ec7502fca49018f0b88208e870 Mon Sep 17 00:00:00 2001 From: cfngc4594 Date: Wed, 7 May 2025 13:42:08 +0800 Subject: [PATCH] refactor(editor): consolidate editor toolbar actions into unified structure - Moved all editor action buttons (copy, format, undo, redo, reset) from `src/components/features/playground/workspace/editor/components/` to new location `src/features/problems/code/components/toolbar/actions/` - Introduced shared `TooltipButton` component to reduce duplication - Created centralized `useProblemEditorActions` hook for common editor operations - Updated imports and exports through new index file - Maintained all existing functionality while improving code organization --- .../editor/components/copy-button.tsx | 75 ------------------- .../editor/components/format-button.tsx | 41 ---------- .../editor/components/redo-button.tsx | 41 ---------- .../editor/components/reset-button.tsx | 57 -------------- .../editor/components/undo-button.tsx | 41 ---------- .../toolbar/actions/copy-button.tsx | 56 ++++++++++++++ .../toolbar/actions/format-button.tsx | 24 ++++++ .../toolbar/actions/redo-button.tsx | 24 ++++++ .../toolbar/actions/reset-button.tsx | 43 +++++++++++ .../toolbar/actions/undo-button.tsx | 24 ++++++ .../problems/code/components/toolbar/index.ts | 5 ++ .../code/hooks/use-problem-editor-actions.ts | 55 ++++++++++++++ 12 files changed, 231 insertions(+), 255 deletions(-) delete mode 100644 src/components/features/playground/workspace/editor/components/copy-button.tsx delete mode 100644 src/components/features/playground/workspace/editor/components/format-button.tsx delete mode 100644 src/components/features/playground/workspace/editor/components/redo-button.tsx delete mode 100644 src/components/features/playground/workspace/editor/components/reset-button.tsx delete mode 100644 src/components/features/playground/workspace/editor/components/undo-button.tsx create mode 100644 src/features/problems/code/components/toolbar/actions/copy-button.tsx create mode 100644 src/features/problems/code/components/toolbar/actions/format-button.tsx create mode 100644 src/features/problems/code/components/toolbar/actions/redo-button.tsx create mode 100644 src/features/problems/code/components/toolbar/actions/reset-button.tsx create mode 100644 src/features/problems/code/components/toolbar/actions/undo-button.tsx create mode 100644 src/features/problems/code/components/toolbar/index.ts create mode 100644 src/features/problems/code/hooks/use-problem-editor-actions.ts diff --git a/src/components/features/playground/workspace/editor/components/copy-button.tsx b/src/components/features/playground/workspace/editor/components/copy-button.tsx deleted file mode 100644 index b229c86..0000000 --- a/src/components/features/playground/workspace/editor/components/copy-button.tsx +++ /dev/null @@ -1,75 +0,0 @@ -"use client"; - -import { - Tooltip, - TooltipContent, - TooltipProvider, - TooltipTrigger, -} from "@/components/ui/tooltip"; -import { cn } from "@/lib/utils"; -import { useState } from "react"; -import { Check, Copy } from "lucide-react"; -import { useTranslations } from "next-intl"; -import { Button } from "@/components/ui/button"; -import { useProblem } from "@/hooks/use-problem"; - -export function CopyButton() { - const { editor } = useProblem(); - const [copied, setCopied] = useState(false); - const t = useTranslations("WorkspaceEditorHeader.CopyButton"); - - const handleCopy = async () => { - try { - await navigator.clipboard.writeText(editor?.getValue() || ""); - setCopied(true); - setTimeout(() => setCopied(false), 1500); - } catch (err) { - console.error("Failed to copy text: ", err); - } - }; - - return ( - - - - - - - {t("TooltipContent")} - - - - ); -} diff --git a/src/components/features/playground/workspace/editor/components/format-button.tsx b/src/components/features/playground/workspace/editor/components/format-button.tsx deleted file mode 100644 index ab934b6..0000000 --- a/src/components/features/playground/workspace/editor/components/format-button.tsx +++ /dev/null @@ -1,41 +0,0 @@ -"use client"; - -import { - Tooltip, - TooltipContent, - TooltipProvider, - TooltipTrigger, -} from "@/components/ui/tooltip"; -import { Paintbrush } from "lucide-react"; -import { useTranslations } from "next-intl"; -import { Button } from "@/components/ui/button"; -import { useProblem } from "@/hooks/use-problem"; - -export function FormatButton() { - const { editor } = useProblem(); - const t = useTranslations("WorkspaceEditorHeader.FormatButton"); - - return ( - - - - - - - {t("TooltipContent")} - - - - ); -} diff --git a/src/components/features/playground/workspace/editor/components/redo-button.tsx b/src/components/features/playground/workspace/editor/components/redo-button.tsx deleted file mode 100644 index 92bcd63..0000000 --- a/src/components/features/playground/workspace/editor/components/redo-button.tsx +++ /dev/null @@ -1,41 +0,0 @@ -"use client"; - -import { - Tooltip, - TooltipContent, - TooltipProvider, - TooltipTrigger, -} from "@/components/ui/tooltip"; -import { Redo2 } from "lucide-react"; -import { useTranslations } from "next-intl"; -import { Button } from "@/components/ui/button"; -import { useProblem } from "@/hooks/use-problem"; - -export function RedoButton() { - const { editor } = useProblem(); - const t = useTranslations("WorkspaceEditorHeader.RedoButton"); - - return ( - - - - - - - {t("TooltipContent")} - - - - ); -} diff --git a/src/components/features/playground/workspace/editor/components/reset-button.tsx b/src/components/features/playground/workspace/editor/components/reset-button.tsx deleted file mode 100644 index 4f4b5d8..0000000 --- a/src/components/features/playground/workspace/editor/components/reset-button.tsx +++ /dev/null @@ -1,57 +0,0 @@ -"use client"; - -import { - Tooltip, - TooltipContent, - TooltipProvider, - TooltipTrigger, -} from "@/components/ui/tooltip"; -import { RotateCcw } from "lucide-react"; -import { useTranslations } from "next-intl"; -import { Button } from "@/components/ui/button"; -import { useProblem } from "@/hooks/use-problem"; - -export function ResetButton() { - const { editor, currentTemplate } = useProblem(); - const t = useTranslations("WorkspaceEditorHeader.ResetButton"); - - const handleReset = () => { - if (editor) { - const model = editor.getModel(); - if (model) { - const fullRange = model.getFullModelRange(); - editor.pushUndoStop(); - editor.executeEdits("reset-code", [ - { - range: fullRange, - text: currentTemplate, - forceMoveMarkers: true, - }, - ]); - editor.pushUndoStop(); - } - } - }; - - return ( - - - - - - - {t("TooltipContent")} - - - - ); -} diff --git a/src/components/features/playground/workspace/editor/components/undo-button.tsx b/src/components/features/playground/workspace/editor/components/undo-button.tsx deleted file mode 100644 index d7ec502..0000000 --- a/src/components/features/playground/workspace/editor/components/undo-button.tsx +++ /dev/null @@ -1,41 +0,0 @@ -"use client"; - -import { - Tooltip, - TooltipContent, - TooltipProvider, - TooltipTrigger, -} from "@/components/ui/tooltip"; -import { Undo2 } from "lucide-react"; -import { useTranslations } from "next-intl"; -import { Button } from "@/components/ui/button"; -import { useProblem } from "@/hooks/use-problem"; - -export function UndoButton() { - const { editor } = useProblem(); - const t = useTranslations("WorkspaceEditorHeader.UndoButton"); - - return ( - - - - - - - {t("TooltipContent")} - - - - ); -} diff --git a/src/features/problems/code/components/toolbar/actions/copy-button.tsx b/src/features/problems/code/components/toolbar/actions/copy-button.tsx new file mode 100644 index 0000000..3c97762 --- /dev/null +++ b/src/features/problems/code/components/toolbar/actions/copy-button.tsx @@ -0,0 +1,56 @@ +"use client"; + +import { cn } from "@/lib/utils"; +import { useState } from "react"; +import { Check, Copy } from "lucide-react"; +import { useTranslations } from "next-intl"; +import { TooltipButton } from "@/components/tooltip-button"; +import { useProblemEditorActions } from "@/features/problems/code/hooks/use-problem-editor-actions"; + +const CopyButton = () => { + const t = useTranslations("WorkspaceEditorHeader.CopyButton"); + const [copied, setCopied] = useState(false); + const { canExecute, handleCopy } = useProblemEditorActions(); + + const handleClick = async () => { + const success = await handleCopy(); + if (success) { + setCopied(true); + setTimeout(() => setCopied(false), 1500); + } + }; + + return ( + +
+
+
+
+
+ ); +}; + +export { CopyButton }; diff --git a/src/features/problems/code/components/toolbar/actions/format-button.tsx b/src/features/problems/code/components/toolbar/actions/format-button.tsx new file mode 100644 index 0000000..8add6e3 --- /dev/null +++ b/src/features/problems/code/components/toolbar/actions/format-button.tsx @@ -0,0 +1,24 @@ +"use client"; + +import { Paintbrush } from "lucide-react"; +import { useTranslations } from "next-intl"; +import { TooltipButton } from "@/components/tooltip-button"; +import { useProblemEditorActions } from "@/features/problems/code/hooks/use-problem-editor-actions"; + +const FormatButton = () => { + const t = useTranslations("WorkspaceEditorHeader.FormatButton"); + const { canExecute, handleFormat } = useProblemEditorActions(); + + return ( + + + ); +}; + +export { FormatButton }; diff --git a/src/features/problems/code/components/toolbar/actions/redo-button.tsx b/src/features/problems/code/components/toolbar/actions/redo-button.tsx new file mode 100644 index 0000000..af6411d --- /dev/null +++ b/src/features/problems/code/components/toolbar/actions/redo-button.tsx @@ -0,0 +1,24 @@ +"use client"; + +import { Redo2 } from "lucide-react"; +import { useTranslations } from "next-intl"; +import { TooltipButton } from "@/components/tooltip-button"; +import { useProblemEditorActions } from "@/features/problems/code/hooks/use-problem-editor-actions"; + +const RedoButton = () => { + const t = useTranslations("WorkspaceEditorHeader.RedoButton"); + const { canExecute, handleRedo } = useProblemEditorActions(); + + return ( + + + ); +}; + +export { RedoButton }; diff --git a/src/features/problems/code/components/toolbar/actions/reset-button.tsx b/src/features/problems/code/components/toolbar/actions/reset-button.tsx new file mode 100644 index 0000000..7f5ed2a --- /dev/null +++ b/src/features/problems/code/components/toolbar/actions/reset-button.tsx @@ -0,0 +1,43 @@ +"use client"; + +import { useMemo } from "react"; +import { RotateCcw } from "lucide-react"; +import { useTranslations } from "next-intl"; +import type { Template } from "@/generated/client"; +import { TooltipButton } from "@/components/tooltip-button"; +import { useProblemEditorStore } from "@/stores/problem-editor-store"; +import { useProblemEditorActions } from "@/features/problems/code/hooks/use-problem-editor-actions"; + +interface ResetButtonProps { + templates: Template[]; +} + +const ResetButton = ({ templates }: ResetButtonProps) => { + const t = useTranslations("WorkspaceEditorHeader.ResetButton"); + const { language } = useProblemEditorStore(); + const { canExecute, handleReset } = useProblemEditorActions(); + + const currentTemplate = useMemo(() => { + return ( + templates.find((template) => template.language === language)?.template ?? + "" + ); + }, [language, templates]); + + const handleClick = () => { + handleReset(currentTemplate); + }; + + return ( + + + ); +}; + +export { ResetButton }; diff --git a/src/features/problems/code/components/toolbar/actions/undo-button.tsx b/src/features/problems/code/components/toolbar/actions/undo-button.tsx new file mode 100644 index 0000000..d10a579 --- /dev/null +++ b/src/features/problems/code/components/toolbar/actions/undo-button.tsx @@ -0,0 +1,24 @@ +"use client"; + +import { Undo2 } from "lucide-react"; +import { useTranslations } from "next-intl"; +import { TooltipButton } from "@/components/tooltip-button"; +import { useProblemEditorActions } from "@/features/problems/code/hooks/use-problem-editor-actions"; + +const UndoButton = () => { + const t = useTranslations("WorkspaceEditorHeader.UndoButton"); + const { canExecute, handleUndo } = useProblemEditorActions(); + + return ( + + + ); +}; + +export { UndoButton }; diff --git a/src/features/problems/code/components/toolbar/index.ts b/src/features/problems/code/components/toolbar/index.ts new file mode 100644 index 0000000..4ce7274 --- /dev/null +++ b/src/features/problems/code/components/toolbar/index.ts @@ -0,0 +1,5 @@ +export * from "./actions/copy-button"; +export * from "./actions/format-button"; +export * from "./actions/redo-button"; +export * from "./actions/reset-button"; +export * from "./actions/undo-button"; diff --git a/src/features/problems/code/hooks/use-problem-editor-actions.ts b/src/features/problems/code/hooks/use-problem-editor-actions.ts new file mode 100644 index 0000000..b17cd33 --- /dev/null +++ b/src/features/problems/code/hooks/use-problem-editor-actions.ts @@ -0,0 +1,55 @@ +import { useCallback } from "react"; +import { useProblemEditorStore } from "@/stores/problem-editor-store"; + +export const useProblemEditorActions = () => { + const { editor } = useProblemEditorStore(); + + const handleCopy = useCallback(async () => { + try { + await navigator.clipboard.writeText(editor?.getValue() || ""); + return true; + } catch (error) { + console.error("Failed to copy text: ", error); + return false; + } + }, [editor]); + + const handleFormat = useCallback(() => { + editor?.trigger("format", "editor.action.formatDocument", null); + }, [editor]); + + const handleUndo = useCallback(() => { + editor?.trigger("undo", "undo", null); + }, [editor]); + + const handleRedo = useCallback(() => { + editor?.trigger("redo", "redo", null); + }, [editor]); + + const handleReset = useCallback((template: string) => { + if (!editor) return; + + const model = editor.getModel(); + if (!model) return; + + const fullRange = model.getFullModelRange(); + editor.pushUndoStop(); + editor.executeEdits("reset-code", [ + { + range: fullRange, + text: template, + forceMoveMarkers: true, + }, + ]); + editor.pushUndoStop(); + }, [editor]); + + return { + handleCopy, + handleFormat, + handleUndo, + handleRedo, + handleReset, + canExecute: !!editor, + }; +};