diff --git a/apps/web/src/components/EditorToolbar.tsx b/apps/web/src/components/EditorToolbar.tsx index 260d4bef..65ee5276 100644 --- a/apps/web/src/components/EditorToolbar.tsx +++ b/apps/web/src/components/EditorToolbar.tsx @@ -61,12 +61,14 @@ const EditorToolbarButton = ({ children, disabled = false, onClick, + shortcutLabel, title, }: { active?: boolean; children: ReactNode; disabled?: boolean; onClick: () => void; + shortcutLabel?: string | null; title: string; }) => ( @@ -88,7 +90,16 @@ const EditorToolbarButton = ({ {children} - {title} + + {shortcutLabel ? ( + <> + {title} + + {shortcutLabel} + + + ) : title} + ); @@ -221,6 +232,8 @@ export const EditorToolbar = ({ : "plaintext"; const activeEditorView = onEditorViewChange ? editorView : markdownMode ? "markdown" : "rich"; const showFormattingTools = activeEditorView === "rich"; + const nextEditorViewMode = EDITOR_VIEW_MODES[activeEditorView === "rich" ? 1 : 0]; + const canCycleEditorView = Boolean(onEditorViewChange || onMarkdownModeChange); useEffect(() => { const controls = controlsRef.current; @@ -328,50 +341,22 @@ export const EditorToolbar = ({ !expanded && MEMO_EDITOR_TOOLBAR_COLLAPSED_CLASS_NAME )} > - {onEditorViewChange ? ( + {canCycleEditorView ? ( <> -
- {EDITOR_VIEW_MODES.map((mode) => ( - onEditorViewChange(mode.value)} - > - - - ))} -
- - - ) : onMarkdownModeChange ? ( - <> - - - - - - {markdownMode ? t("editorToolbar.richText") : t("editorToolbar.markdown")} - {markdownModeShortcutLabel && ( - - {markdownModeShortcutLabel} - - )} - - + { + if (onEditorViewChange) { + onEditorViewChange(nextEditorViewMode.value); + return; + } + onMarkdownModeChange?.(); + }} + > + + ) : null} diff --git a/apps/web/src/components/MemoEditorHeaderActions.test.mjs b/apps/web/src/components/MemoEditorHeaderActions.test.mjs index b4f0a261..bfe434ab 100644 --- a/apps/web/src/components/MemoEditorHeaderActions.test.mjs +++ b/apps/web/src/components/MemoEditorHeaderActions.test.mjs @@ -76,6 +76,13 @@ describe("shared memo editor header actions", () => { expect(densitySource).not.toContain("min-[1600px]:flex"); }); + test("cycles rich text and markdown from one toolbar button", () => { + expect(editorToolbarSource).toContain("const nextEditorViewMode = EDITOR_VIEW_MODES[activeEditorView === \"rich\" ? 1 : 0]"); + expect(editorToolbarSource).toContain("onEditorViewChange(nextEditorViewMode.value)"); + expect(editorToolbarSource).not.toContain("EDITOR_VIEW_MODES.map"); + expect(editorToolbarSource).not.toContain('t("editorToolbar.viewMode")'); + }); + test("aligns the note title, notebook row, and article on one reading gutter", () => { expect(editorSource).toContain("MEMO_EDITOR_READING_GUTTER_CLASS_NAME"); expect(densitySource).toContain('px-[var(--editor-reading-gutter)]'); diff --git a/packages/shared/src/i18n/en-US.ts b/packages/shared/src/i18n/en-US.ts index f9e63a3f..7b8b4451 100644 --- a/packages/shared/src/i18n/en-US.ts +++ b/packages/shared/src/i18n/en-US.ts @@ -2259,7 +2259,6 @@ export const enUS = { deleteTable: "Delete table", markdown: "Switch to Markdown source", richText: "Switch to rich text", - viewMode: "Note view", appearance: "Appearance and style", blockStyle: "Paragraph style", markdownSource: "Markdown source", diff --git a/packages/shared/src/i18n/ja.ts b/packages/shared/src/i18n/ja.ts index c0b1242b..33a7d166 100644 --- a/packages/shared/src/i18n/ja.ts +++ b/packages/shared/src/i18n/ja.ts @@ -2259,7 +2259,6 @@ export const ja = { deleteTable: "表を削除", markdown: "Markdown ソースに切り替え", richText: "リッチテキストに切り替え", - viewMode: "ノートの表示", appearance: "外観とスタイル", blockStyle: "段落スタイル", markdownSource: "Markdown ソース", diff --git a/packages/shared/src/i18n/zh-CN.ts b/packages/shared/src/i18n/zh-CN.ts index d46ea586..2b0854d7 100644 --- a/packages/shared/src/i18n/zh-CN.ts +++ b/packages/shared/src/i18n/zh-CN.ts @@ -2257,7 +2257,6 @@ export const zhCN = { deleteTable: "删除表格", markdown: "切换到 Markdown 源码", richText: "切换到富文本编辑", - viewMode: "笔记视图", appearance: "外观与样式", blockStyle: "段落样式", markdownSource: "Markdown 源码",