From f36ca9317dad153c89643f8b8abee619df9a3aeb Mon Sep 17 00:00:00 2001 From: amblued Date: Fri, 21 Aug 2026 21:14:28 +0800 Subject: [PATCH] feat(web): add a global memo composer to the sidebar (#6219) --- web/package.json | 6 +- web/src/components/AppSidebar/AppSidebar.tsx | 65 ++++- .../components/AppSidebar/QuickFindDialog.tsx | 12 - web/src/components/MemoEditor/README.md | 37 ++- web/src/components/MemoEditor/index.tsx | 6 + .../components/MemoEditor/types/components.ts | 2 + web/src/contexts/GlobalMemoEditorContext.tsx | 164 +++++++++++ web/src/layouts/RootLayout.tsx | 51 ++-- web/src/locales/en.json | 1 + web/src/locales/zh-Hans.json | 1 + web/src/locales/zh-Hant.json | 1 + web/tests/about-page.test.tsx | 4 +- web/tests/app-sidebar-logo.test.tsx | 59 +++- web/tests/attachment-library-stats.test.ts | 2 +- .../auth-context-initialization.test.tsx | 4 +- .../calendar-cell-empty-clickable.test.tsx | 2 +- web/tests/editor.test.tsx | 11 +- web/tests/filtered-memo-stats.test.ts | 6 +- web/tests/formatting-toolbar.test.tsx | 7 +- web/tests/global-memo-editor.test.tsx | 255 ++++++++++++++++++ web/tests/guards.test.tsx | 2 +- web/tests/inline-image-upload-files.test.ts | 1 - web/tests/managed-attachment.test.ts | 6 +- web/tests/markdown-task-actions.test.ts | 4 +- web/tests/media-loading.test.tsx | 4 +- web/tests/memo-card-height.test.ts | 16 +- web/tests/memo-comments-pagination.test.tsx | 5 +- .../memo-content-lazy-renderers.test.tsx | 4 +- web/tests/memo-share-image.test.ts | 8 +- web/tests/memo-views.test.ts | 4 +- web/tests/near-viewport.test.tsx | 1 + web/tests/placeholder-pool.test.ts | 2 +- web/tests/query-deduplication.test.tsx | 8 +- web/tests/root-layout-global-editor.test.tsx | 80 ++++++ web/tests/router-config.test.tsx | 13 +- web/tests/scroll-restoration.test.tsx | 6 +- web/tests/sidebar-row-grammar.test.tsx | 3 +- web/tests/tag.test.ts | 13 +- web/tests/use-memo-init.test.tsx | 6 +- web/tests/video-poster.test.tsx | 9 +- web/tsconfig.json | 2 +- 41 files changed, 720 insertions(+), 173 deletions(-) create mode 100644 web/src/contexts/GlobalMemoEditorContext.tsx create mode 100644 web/tests/global-memo-editor.test.tsx create mode 100644 web/tests/root-layout-global-editor.test.tsx diff --git a/web/package.json b/web/package.json index 63e7d208..6e9141af 100644 --- a/web/package.json +++ b/web/package.json @@ -9,9 +9,9 @@ "dev": "vite", "build": "vite build", "release": "vite build --mode release --outDir=../server/router/frontend/dist --emptyOutDir", - "lint": "tsc --noEmit --skipLibCheck && biome check src", - "lint:fix": "biome check --write src", - "format": "biome format --write src", + "lint": "tsc --noEmit --skipLibCheck && biome check src tests", + "lint:fix": "biome check --write src tests", + "format": "biome format --write src tests", "test": "vitest run", "test:watch": "vitest", "test:coverage": "vitest run --coverage" diff --git a/web/src/components/AppSidebar/AppSidebar.tsx b/web/src/components/AppSidebar/AppSidebar.tsx index 44517b66..57069f16 100644 --- a/web/src/components/AppSidebar/AppSidebar.tsx +++ b/web/src/components/AppSidebar/AppSidebar.tsx @@ -20,6 +20,7 @@ import { PaperclipIcon, PlusIcon, SearchIcon, + SquarePenIcon, Trash2Icon, UserRoundIcon, } from "lucide-react"; @@ -39,6 +40,7 @@ import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/comp import { memoViewServiceClient } from "@/connect"; import { type AttachmentSection, type InboxFilter, useAppSidebar } from "@/contexts/AppSidebarContext"; import { useAuth } from "@/contexts/AuthContext"; +import { useGlobalMemoEditor } from "@/contexts/GlobalMemoEditorContext"; import { useInstance } from "@/contexts/InstanceContext"; import { stringifyFilters, useMemoFilterContext } from "@/contexts/MemoFilterContext"; import { useAttachmentLibraryStats } from "@/hooks/useAttachmentLibrary"; @@ -72,6 +74,32 @@ import SidebarSection, { import TagsSection from "./TagsSection"; const SIDEBAR_HORIZONTAL_PADDING = "px-3"; +const SIDEBAR_HEADER_ACTION_CLASSES = "size-7 shrink-0 rounded-md text-muted-foreground hover:text-foreground"; + +const NewMemoAction = ({ onClick }: { onClick: () => void }) => { + const t = useTranslate(); + const label = t("editor.new-memo"); + + return ( + + + } + > + + + {label} + + ); +}; const ViewsSection = ({ manageActive = false }: { manageActive?: boolean }) => { const t = useTranslate(); @@ -604,6 +632,7 @@ const AppSidebar = ({ className }: { className?: string }) => { const t = useTranslate(); const currentUser = useCurrentUser(); const { setMobileOpen, setQuickFindOpen } = useAppSidebar(); + const { canOpen: canCompose, openEditor } = useGlobalMemoEditor(); return (