refactor(web): unify compact editor chrome
This commit is contained in:
1 parent
d032072c67
commit
766faacbcf
7 files changed
+61
-17
No files matched your search
@@ -256,6 +256,12 @@ describe("diagram editor canvas surface", () => {
|
||||
expect(source).toContain('graph.startBatch("quick-create")');
|
||||
});
|
||||
|
||||
test("keeps the desktop header compact without shrinking mobile controls", () => {
|
||||
expect(source).toContain("MEMO_EDITOR_TOP_ROW_CLASS_NAME");
|
||||
expect(source).toContain("MEMO_EDITOR_TITLE_ROW_CLASS_NAME");
|
||||
expect(toolbarSource).toContain("MEMO_EDITOR_TOOLBAR_PADDING_CLASS_NAME");
|
||||
});
|
||||
|
||||
test("repaints the graph when the application appearance changes", () => {
|
||||
expect(source).toContain("const { resolvedTheme } = useAppearanceTheme();");
|
||||
expect(source).toContain("applyGraphPalette(graph, themeRef.current, document.kind, resolvedTheme);");
|
||||
|
||||
@@ -90,6 +90,10 @@ import { ShareMemoDialog } from "@/components/dialogs/ShareMemoDialog";
|
||||
import { ClipboardCopyNotice } from "@/components/ClipboardCopyNotice";
|
||||
import { DiagramToolbar, DiagramToolbarAddTrigger } from "@/components/DiagramToolbar";
|
||||
import { MemoEditorHeaderActions } from "@/components/MemoEditorHeaderActions";
|
||||
import {
|
||||
MEMO_EDITOR_TITLE_ROW_CLASS_NAME,
|
||||
MEMO_EDITOR_TOP_ROW_CLASS_NAME,
|
||||
} from "@/components/MemoEditorChromeDensity";
|
||||
import { EditorNoteSearchBar } from "@/components/editor/EditorNoteSearchBar";
|
||||
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@/components/ui/collapsible";
|
||||
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger } from "@/components/ui/dropdown-menu";
|
||||
@@ -2180,7 +2184,7 @@ export const DiagramEditorPane = ({
|
||||
<TooltipProvider>
|
||||
<div className="flex h-full min-h-0 flex-col bg-white">
|
||||
<header className="shrink-0 border-b border-slate-200 bg-white">
|
||||
<div className="flex min-h-12 items-center justify-between gap-2 border-b border-slate-100 px-3 py-2 sm:px-5">
|
||||
<div className={MEMO_EDITOR_TOP_ROW_CLASS_NAME}>
|
||||
<div className="flex min-w-0 items-center gap-2 text-sm">
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
@@ -2340,7 +2344,7 @@ export const DiagramEditorPane = ({
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex min-h-14 items-center gap-3 px-4 py-2.5 sm:px-7">
|
||||
<div className={MEMO_EDITOR_TITLE_ROW_CLASS_NAME}>
|
||||
<MemoTitleInput
|
||||
value={title}
|
||||
readOnly={readOnly}
|
||||
|
||||
@@ -17,6 +17,7 @@ import {
|
||||
import { useTranslation } from "react-i18next";
|
||||
import type { DiagramTheme } from "@edgeever/shared";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { MEMO_EDITOR_TOOLBAR_PADDING_CLASS_NAME } from "@/components/MemoEditorChromeDensity";
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
@@ -26,6 +27,7 @@ import {
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip";
|
||||
import { resolveDiagramPalette, type DiagramAppearance } from "@/lib/diagram-theme";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
type DiagramToolbarProps = {
|
||||
appearance: DiagramAppearance;
|
||||
@@ -93,7 +95,7 @@ export const DiagramToolbar = ({
|
||||
}: DiagramToolbarProps) => {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<div className="flex shrink-0 flex-wrap items-center gap-1 border-b border-slate-200 bg-white px-3 py-2" role="toolbar" aria-label={t("diagram.toolbar")}>
|
||||
<div className={cn("flex shrink-0 flex-wrap items-center gap-1 border-b border-slate-200 bg-white", MEMO_EDITOR_TOOLBAR_PADDING_CLASS_NAME)} role="toolbar" aria-label={t("diagram.toolbar")}>
|
||||
{leading ? <>{leading}<ToolbarDivider /></> : null}
|
||||
<Tooltip><TooltipTrigger asChild><Button size="icon" variant="ghost" aria-label={t("diagram.undo")} disabled={!canUndo || readOnly} onClick={onUndo}><Undo2 className="h-4 w-4" /></Button></TooltipTrigger><TooltipContent>{t("diagram.undo")}</TooltipContent></Tooltip>
|
||||
<Tooltip><TooltipTrigger asChild><Button size="icon" variant="ghost" aria-label={t("diagram.redo")} disabled={!canRedo || readOnly} onClick={onRedo}><Redo2 className="h-4 w-4" /></Button></TooltipTrigger><TooltipContent>{t("diagram.redo")}</TooltipContent></Tooltip>
|
||||
|
||||
@@ -41,6 +41,10 @@ import {
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { ClipboardCopyNotice } from "@/components/ClipboardCopyNotice";
|
||||
import { MemoEditorHeaderActions } from "@/components/MemoEditorHeaderActions";
|
||||
import {
|
||||
MEMO_EDITOR_TEXT_TITLE_REGION_CLASS_NAME,
|
||||
MEMO_EDITOR_TOP_ROW_CLASS_NAME,
|
||||
} from "@/components/MemoEditorChromeDensity";
|
||||
import { MemoTitleInput } from "@/components/MemoTitleInput";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import {
|
||||
@@ -3807,7 +3811,7 @@ const RichEditorPane = ({
|
||||
/>
|
||||
)}
|
||||
<header className="shrink-0 border-b border-slate-200 bg-white">
|
||||
<div className="flex min-h-12 items-center justify-between gap-2 border-b border-slate-100 px-3 py-2 sm:px-5">
|
||||
<div className={MEMO_EDITOR_TOP_ROW_CLASS_NAME}>
|
||||
<div className="flex min-w-0 items-center gap-2 text-sm">
|
||||
<Button
|
||||
className="lg:hidden"
|
||||
@@ -4146,18 +4150,20 @@ const RichEditorPane = ({
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="space-y-1.5 px-4 pb-2.5 pt-2.5 sm:space-y-3 sm:px-7 sm:pb-4 sm:pt-4 lg:space-y-0 lg:pb-0.5 lg:pt-1.5">
|
||||
<MemoTitleInput
|
||||
value={title}
|
||||
readOnly={effectiveReadOnly}
|
||||
onValueChange={(nextTitle) => {
|
||||
setTitle(nextTitle);
|
||||
persistCurrentDraft(nextTitle, tagsText, getMobilePlainTextValue());
|
||||
markDirty();
|
||||
}}
|
||||
placeholder={t("common.untitledMemo")}
|
||||
/>
|
||||
<div className="flex flex-wrap items-center gap-1.5 sm:gap-2">
|
||||
<div className={MEMO_EDITOR_TEXT_TITLE_REGION_CLASS_NAME}>
|
||||
<div className="min-w-0 min-[1600px]:flex-1">
|
||||
<MemoTitleInput
|
||||
value={title}
|
||||
readOnly={effectiveReadOnly}
|
||||
onValueChange={(nextTitle) => {
|
||||
setTitle(nextTitle);
|
||||
persistCurrentDraft(nextTitle, tagsText, getMobilePlainTextValue());
|
||||
markDirty();
|
||||
}}
|
||||
placeholder={t("common.untitledMemo")}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-wrap items-center gap-1.5 sm:gap-2 min-[1600px]:shrink-0 min-[1600px]:flex-nowrap">
|
||||
<button
|
||||
className="flex h-7 min-w-0 max-w-full items-center gap-1 rounded-md border border-transparent bg-transparent px-1.5 text-xs font-medium text-slate-600 outline-none transition hover:border-slate-200 hover:bg-slate-50 hover:text-slate-900 focus-visible:border-emerald-300 focus-visible:ring-2 focus-visible:ring-emerald-500/20 disabled:opacity-50 sm:hidden"
|
||||
type="button"
|
||||
|
||||
@@ -22,6 +22,7 @@ import {
|
||||
ChevronUp,
|
||||
} from "lucide-react";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { MEMO_EDITOR_TOOLBAR_PADDING_CLASS_NAME } from "@/components/MemoEditorChromeDensity";
|
||||
import { Select, SelectTrigger, SelectValue, SelectContent, SelectItem } from "@/components/ui/select";
|
||||
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip";
|
||||
import {
|
||||
@@ -288,7 +289,8 @@ export const EditorToolbar = ({
|
||||
<div
|
||||
ref={controlsRef}
|
||||
className={cn(
|
||||
"flex min-w-0 max-w-full flex-wrap items-center gap-1 px-3 py-2 sm:px-5",
|
||||
"flex min-w-0 max-w-full flex-wrap items-center gap-1",
|
||||
MEMO_EDITOR_TOOLBAR_PADDING_CLASS_NAME,
|
||||
hasOverflow && "pr-14 sm:pr-16",
|
||||
!expanded && "max-h-12 overflow-hidden"
|
||||
)}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
export const MEMO_EDITOR_TOP_ROW_CLASS_NAME =
|
||||
"flex min-h-12 items-center justify-between gap-2 border-b border-slate-100 px-3 py-2 sm:min-h-10 sm:px-5 sm:py-1";
|
||||
|
||||
export const MEMO_EDITOR_TITLE_ROW_CLASS_NAME =
|
||||
"flex min-h-12 items-center gap-3 px-4 py-2 sm:min-h-11 sm:px-7 sm:py-1";
|
||||
|
||||
export const MEMO_EDITOR_TOOLBAR_PADDING_CLASS_NAME =
|
||||
"px-3 py-2 sm:px-5 sm:py-1";
|
||||
|
||||
export const MEMO_EDITOR_TEXT_TITLE_REGION_CLASS_NAME =
|
||||
"space-y-1.5 px-4 pb-2.5 pt-2.5 sm:space-y-3 sm:px-7 sm:pb-4 sm:pt-4 lg:space-y-0 lg:py-0 min-[1600px]:flex min-[1600px]:min-h-11 min-[1600px]:items-center min-[1600px]:gap-3 min-[1600px]:py-1";
|
||||
@@ -4,6 +4,9 @@ import { readFileSync } from "node:fs";
|
||||
const actionsSource = readFileSync(new URL("./MemoEditorHeaderActions.tsx", import.meta.url), "utf8");
|
||||
const editorSource = readFileSync(new URL("./EditorPane.tsx", import.meta.url), "utf8");
|
||||
const diagramSource = readFileSync(new URL("./DiagramEditorPane.tsx", import.meta.url), "utf8");
|
||||
const densitySource = readFileSync(new URL("./MemoEditorChromeDensity.ts", import.meta.url), "utf8");
|
||||
const editorToolbarSource = readFileSync(new URL("./EditorToolbar.tsx", import.meta.url), "utf8");
|
||||
const diagramToolbarSource = readFileSync(new URL("./DiagramToolbar.tsx", import.meta.url), "utf8");
|
||||
|
||||
describe("shared memo editor header actions", () => {
|
||||
test("owns every action shared by text and diagram notes", () => {
|
||||
@@ -24,4 +27,14 @@ describe("shared memo editor header actions", () => {
|
||||
expect(diagramSource).not.toContain("textNoteActions=");
|
||||
expect(diagramSource).not.toContain("<WeChatIcon");
|
||||
});
|
||||
|
||||
test("applies one shared compact density standard to both editors", () => {
|
||||
expect(editorSource).toContain("MEMO_EDITOR_TOP_ROW_CLASS_NAME");
|
||||
expect(diagramSource).toContain("MEMO_EDITOR_TOP_ROW_CLASS_NAME");
|
||||
expect(editorToolbarSource).toContain("MEMO_EDITOR_TOOLBAR_PADDING_CLASS_NAME");
|
||||
expect(diagramToolbarSource).toContain("MEMO_EDITOR_TOOLBAR_PADDING_CLASS_NAME");
|
||||
expect(densitySource).toContain("sm:min-h-10 sm:px-5 sm:py-1");
|
||||
expect(densitySource).toContain("min-[1600px]:min-h-11");
|
||||
expect(densitySource).toContain("min-[1600px]:flex");
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user