From 89171dc86191bcae1cb319f82e9c11752699c4e7 Mon Sep 17 00:00:00 2001 From: yoma Date: Wed, 8 Jul 2026 02:47:55 +0800 Subject: [PATCH] Extract standalone mobile editor parts --- .../MobileStandaloneEditorParts.tsx | 184 +++++++++++++++++ apps/web/src/lib/mobile-editor-standalone.ts | 28 +++ apps/web/src/mobile-edit.tsx | 186 ++++-------------- 3 files changed, 247 insertions(+), 151 deletions(-) create mode 100644 apps/web/src/components/MobileStandaloneEditorParts.tsx diff --git a/apps/web/src/components/MobileStandaloneEditorParts.tsx b/apps/web/src/components/MobileStandaloneEditorParts.tsx new file mode 100644 index 00000000..c80deb59 --- /dev/null +++ b/apps/web/src/components/MobileStandaloneEditorParts.tsx @@ -0,0 +1,184 @@ +import { Bold, Check, ChevronDown, ImagePlus, List, Minus, Quote } from "lucide-react"; +import type { NotebookMoveOption } from "@/lib/app-helpers"; +import type { MobileEditorSaveState } from "@/lib/mobile-editor-standalone"; + +export const MobileEditorHeader = ({ + saveLabel, + statusClassName, + saveState, + onLeave, +}: { + saveLabel: string; + statusClassName: string; + saveState: MobileEditorSaveState; + onLeave: () => void; +}) => ( +
+ +
+ {saveLabel} + +
+
+); + +export const MobileEditorToolbar = ({ + disabled, + boldActive, + bulletListActive, + blockquoteActive, + onPickImage, + onToggleBold, + onToggleBulletList, + onToggleBlockquote, + onSetHorizontalRule, +}: { + disabled: boolean; + boldActive: boolean; + bulletListActive: boolean; + blockquoteActive: boolean; + onPickImage: () => void; + onToggleBold: () => void; + onToggleBulletList: () => void; + onToggleBlockquote: () => void; + onSetHorizontalRule: () => void; +}) => ( +
+ + + + + +
+); + +export const MobileEditorNotebookButton = ({ + label, + disabled, + onOpen, +}: { + label: string; + disabled: boolean; + onOpen: () => void; +}) => ( + +); + +export const MobileEditorNotebookSheet = ({ + options, + selectedNotebookId, + updating, + onClose, + onSelect, +}: { + options: NotebookMoveOption[]; + selectedNotebookId?: string; + updating: boolean; + onClose: () => void; + onSelect: (notebookId: string) => void; +}) => ( +
+
event.stopPropagation()} + > +
+
+); + +export const MobileEditorFallback = ({ markdown }: { markdown: string }) => ( +
+ 查看当前正文 Markdown 备份 +
{markdown}
+
+); diff --git a/apps/web/src/lib/mobile-editor-standalone.ts b/apps/web/src/lib/mobile-editor-standalone.ts index 5e83b603..c69b22b4 100644 --- a/apps/web/src/lib/mobile-editor-standalone.ts +++ b/apps/web/src/lib/mobile-editor-standalone.ts @@ -33,6 +33,34 @@ export type MobileEditorSaveState = | "local-draft" | "leaving"; +export const getMobileEditorSaveLabel = (saveState: MobileEditorSaveState) => + saveState === "loading" + ? "加载中" + : saveState === "saving" + ? "保存中" + : saveState === "compressing" + ? "压缩中" + : saveState === "uploading" + ? "上传中" + : saveState === "dirty" + ? "未保存" + : saveState === "saved" + ? "已保存" + : saveState === "local-draft" + ? "本地草稿" + : saveState === "leaving" + ? "返回中" + : saveState === "error" + ? "保存失败" + : "已保存"; + +export const getMobileEditorStatusClassName = (saveState: MobileEditorSaveState) => + saveState === "error" + ? "error" + : saveState === "dirty" || saveState === "saving" || saveState === "compressing" || saveState === "uploading" || saveState === "leaving" + ? "active" + : ""; + export const getMobileEditorParams = () => new URLSearchParams(window.location.hash ? window.location.hash.slice(1) : window.location.search); diff --git a/apps/web/src/mobile-edit.tsx b/apps/web/src/mobile-edit.tsx index 52b8a083..23fda3d5 100644 --- a/apps/web/src/mobile-edit.tsx +++ b/apps/web/src/mobile-edit.tsx @@ -4,8 +4,14 @@ import { EditorContent, useEditor } from "@tiptap/react"; import StarterKit from "@tiptap/starter-kit"; import Image from "@tiptap/extension-image"; import Placeholder from "@tiptap/extension-placeholder"; -import { Bold, Check, ChevronDown, ImagePlus, List, Minus, Quote } from "lucide-react"; import { docToMarkdown, emptyDoc, type MemoDetail, type Notebook, type TiptapDoc } from "@edgeever/shared"; +import { + MobileEditorFallback, + MobileEditorHeader, + MobileEditorNotebookButton, + MobileEditorNotebookSheet, + MobileEditorToolbar, +} from "@/components/MobileStandaloneEditorParts"; import { getNotebookMoveOptions } from "@/lib/app-helpers"; import { compressImageForUpload } from "@/lib/image-compression"; import { @@ -15,6 +21,8 @@ import { MOBILE_EDITOR_LEAVE_SAVE_TIMEOUT_MS, getMobileEditorDraftKey, getMobileEditorParams, + getMobileEditorSaveLabel, + getMobileEditorStatusClassName, normalizeMobileEditorDoc, parseMobileEditorTags, requestMobileEditorJson, @@ -532,33 +540,8 @@ const MobileTiptapEditorApp = () => { }; }, [leavePage, persistLocalDraft, saveNow]); - const saveLabel = - saveState === "loading" - ? "加载中" - : saveState === "saving" - ? "保存中" - : saveState === "compressing" - ? "压缩中" - : saveState === "uploading" - ? "上传中" - : saveState === "dirty" - ? "未保存" - : saveState === "saved" - ? "已保存" - : saveState === "local-draft" - ? "本地草稿" - : saveState === "leaving" - ? "返回中" - : saveState === "error" - ? "保存失败" - : "已保存"; - - const statusClassName = - saveState === "error" - ? "error" - : saveState === "dirty" || saveState === "saving" || saveState === "compressing" || saveState === "uploading" || saveState === "leaving" - ? "active" - : ""; + const saveLabel = getMobileEditorSaveLabel(saveState); + const statusClassName = getMobileEditorStatusClassName(saveState); const editorActionDisabled = !memo || !editor || saveState === "loading" || saveState === "compressing" || saveState === "uploading" || saveState === "leaving"; const currentNotebookLabel = @@ -577,17 +560,7 @@ const MobileTiptapEditorApp = () => { return (
-
- -
- {saveLabel} - -
-
+ void leavePage()} />
{error &&
{error}
} @@ -601,16 +574,11 @@ const MobileTiptapEditorApp = () => { onChange={(event) => handleTitleChange(event.target.value)} />
- + onOpen={() => setNotebookSheetOpen(true)} + /> { />
-
- - - - - -
+ imageInputRef.current?.click()} + onToggleBold={() => runEditorCommand(() => editor?.chain().focus().toggleBold().run() ?? false)} + onToggleBulletList={() => runEditorCommand(() => editor?.chain().focus().toggleBulletList().run() ?? false)} + onToggleBlockquote={() => runEditorCommand(() => editor?.chain().focus().toggleBlockquote().run() ?? false)} + onSetHorizontalRule={() => runEditorCommand(() => editor?.chain().focus().setHorizontalRule().run() ?? false)} + /> { /> {notebookSheetOpen && ( -
setNotebookSheetOpen(false)}> -
event.stopPropagation()} - > -
-
+ setNotebookSheetOpen(false)} + onSelect={(notebookId) => void handleNotebookChange(notebookId)} + /> )}
- {saveState === "error" && fallbackMarkdown && ( -
- 查看当前正文 Markdown 备份 -
{fallbackMarkdown}
-
- )} + {saveState === "error" && fallbackMarkdown && }
);