From 1794d0dc51261a36fa4758702c4df8a9ba05d6d6 Mon Sep 17 00:00:00 2001 From: boojack Date: Sun, 5 Jul 2026 20:43:02 +0800 Subject: [PATCH] chore(editor): flatten insert menu MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Insert menu: replace the nested "More" submenu with a flat dropdown — insert actions plus inline Focus Mode and Formatting-toolbar toggles. - Formatting toolbar: remove the link button and its window.prompt flow; the link command stays in the shared catalog for future surfaces. --- .../MemoEditor/Toolbar/FormattingToolbar.tsx | 48 ++----- .../MemoEditor/Toolbar/InsertMenu.tsx | 119 ++++-------------- web/tests/formatting-toolbar.test.tsx | 19 --- 3 files changed, 30 insertions(+), 156 deletions(-) diff --git a/web/src/components/MemoEditor/Toolbar/FormattingToolbar.tsx b/web/src/components/MemoEditor/Toolbar/FormattingToolbar.tsx index 24974621..e3146b6b 100644 --- a/web/src/components/MemoEditor/Toolbar/FormattingToolbar.tsx +++ b/web/src/components/MemoEditor/Toolbar/FormattingToolbar.tsx @@ -1,18 +1,11 @@ import { Heading1Icon, Heading2Icon, Heading3Icon, type LucideIcon, Minimize2Icon, MoreHorizontalIcon, PilcrowIcon } from "lucide-react"; import { type ComponentPropsWithoutRef, forwardRef, type MouseEventHandler, type RefObject, useRef } from "react"; import { Button } from "@/components/ui/button"; -import { - DropdownMenu, - DropdownMenuContent, - DropdownMenuItem, - DropdownMenuSeparator, - DropdownMenuTrigger, -} from "@/components/ui/dropdown-menu"; +import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@/components/ui/dropdown-menu"; import { cn } from "@/lib/utils"; import { useTranslate } from "@/utils/i18n"; import { EDITOR_COMMANDS, - EDITOR_COMMANDS_BY_ID, type EditorCommand, type EditorCommandId, isCommandActive, @@ -60,12 +53,12 @@ const SEGMENT_ACTIVE = "bg-accent text-accent-foreground"; const preventFocusSteal: MouseEventHandler = (event) => event.preventDefault(); /** - * Formatting toolbar: a lean inline row of the heading picker plus mark/list/link + * Formatting toolbar: a lean inline row of the heading picker plus mark/list * controls, every one derived from the shared command catalog * (formatting/commands.ts), so adding a verb there surfaces it here automatically. * Groups are separated by thin vertical dividers. Responsive: below - * COMPACT_TOOLBAR_WIDTH the list and link controls fold into a "more" menu while - * marks stay inline. In focus mode an exit button is pushed to the far edge. + * COMPACT_TOOLBAR_WIDTH the list controls fold into a "more" menu while marks stay + * inline. In focus mode an exit button is pushed to the far edge. */ export function FormattingToolbar({ controllerRef, onExit, className }: FormattingToolbarProps) { const t = useTranslate(); @@ -83,28 +76,12 @@ export function FormattingToolbar({ controllerRef, onExit, className }: Formatti controllerRef.current?.focus(); }; - const handleLink = () => { - const formatting = controllerRef.current?.formatting; - if (!formatting) { - return; - } - if (formatting.getActiveFormats().link) { - formatting.run("link"); - } else { - // window.prompt blurs the editor, so refocus below regardless of outcome. - const url = window.prompt(t("editor.format.link-prompt")); - if (url) formatting.run("link", { url }); - } - controllerRef.current?.focus(); - }; - - // Map a catalog command to a toolbar button. `link` keeps its bespoke - // prompt-then-apply flow; everything else just runs its command. + // Map a catalog command to a toolbar button. const toButton = (command: EditorCommand): ToolbarButton => ({ Icon: command.icon, label: t(command.labelKey), active: isCommandActive(active, command.id), - onClick: command.id === "link" ? handleLink : () => run(command.id), + onClick: () => run(command.id), }); // Pilcrow for paragraph, else the matching Hn glyph. Deeper levels (H4–H6) @@ -112,7 +89,6 @@ export function FormattingToolbar({ controllerRef, onExit, className }: Formatti const HeadingGlyph = active.headingLevel === null ? PilcrowIcon : HEADING_LEVEL_ICONS[active.headingLevel]; const markButtons = MARK_COMMANDS.map(toButton); const listButtons = LIST_COMMANDS.map(toButton); - const linkButton = toButton(EDITOR_COMMANDS_BY_ID.link); return (
))} - - {linkButton.label} ) : ( - <> - {listButtons.map((button) => ( - - ))} - - - + listButtons.map((button) => ) )} {onExit && ( @@ -179,7 +147,7 @@ export function FormattingToolbar({ controllerRef, onExit, className }: Formatti ); } -// Thin vertical rule between command groups (heading · marks · lists · link). +// Thin vertical rule between command groups (heading · marks · lists). function Divider() { return