diff --git a/apps/web/index.html b/apps/web/index.html index d9d9d03d..127caf54 100644 --- a/apps/web/index.html +++ b/apps/web/index.html @@ -6,7 +6,7 @@ name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover, interactive-widget=resizes-content" /> - + diff --git a/apps/web/src/components/MemoCard.tsx b/apps/web/src/components/MemoCard.tsx index 8ac478bb..64228b03 100644 --- a/apps/web/src/components/MemoCard.tsx +++ b/apps/web/src/components/MemoCard.tsx @@ -312,7 +312,7 @@ export const MemoCard = ({ draggable={!isTrashView} onDragStart={handleDragStart} className={cn( - "group relative overflow-hidden border border-slate-100 bg-white transition lg:rounded-none lg:border-x-0 lg:border-t-0 lg:border-slate-200 lg:shadow-none lg:last:border-b-0 dark:lg:border-slate-300/70 transition-all duration-200 select-none", + "edgeever-memo-divider group relative overflow-hidden border border-slate-100 bg-white transition lg:rounded-none lg:border-x-0 lg:border-t-0 lg:border-slate-200 lg:shadow-none lg:last:border-b-0 transition-all duration-200 select-none", listDensity === "compact" ? "rounded-md shadow-none" : "rounded-lg shadow-[0_4px_16px_rgba(15,23,42,0.045)]", !selectionMode && selected ? "edgeever-workspace-selection-desktop" diff --git a/apps/web/src/lib/dark-theme.test.mjs b/apps/web/src/lib/dark-theme.test.mjs index 8b89c127..029a28f7 100644 --- a/apps/web/src/lib/dark-theme.test.mjs +++ b/apps/web/src/lib/dark-theme.test.mjs @@ -40,10 +40,16 @@ describe("dark theme contracts", () => { test("public shares and divided surfaces have explicit dark rules", () => { const css = readFileSync(new URL("../styles/globals.css", import.meta.url), "utf8"); + const memoCard = readFileSync(new URL("../components/MemoCard.tsx", import.meta.url), "utf8"); expect(css).toContain(":root.dark .edgeever-public-share .ProseMirror"); expect(css).toContain("color: #f8fafc;"); expect(css).toContain('[class~="divide-slate-100"]'); expect(css).toContain('[class~="text-emerald-700"]'); + expect(css).toContain("--workspace-memo-divider: #3b4540;"); + expect(css).toContain(":root.dark .edgeever-workspace-memo-list .edgeever-memo-divider"); + expect(memoCard).toContain("edgeever-memo-divider"); + expect(memoCard).not.toContain("dark:lg:border-slate-300"); + expect(memoCard).not.toContain("dark:lg:border-slate-300/70"); }); test("workspace dark surfaces stay neutral and bundled editor themes blend into the canvas", () => { diff --git a/apps/web/src/lib/ui-palette.test.mjs b/apps/web/src/lib/ui-palette.test.mjs index 6bd012d6..f554b000 100644 --- a/apps/web/src/lib/ui-palette.test.mjs +++ b/apps/web/src/lib/ui-palette.test.mjs @@ -14,13 +14,16 @@ describe("application color system", () => { expect(contrastRatio("#11694a", "#f0f8f4")).toBeGreaterThanOrEqual(4.5); }); - test("keeps the light workspace crisp and neutral while preserving text hierarchy", () => { - expect(globals).toContain("--workspace-canvas: #f3f5f7;"); - expect(globals).toContain("--workspace-sidebar: #eff1f4;"); - expect(globals).toContain("--workspace-memo-list: #f6f7f9;"); + test("keeps the light workspace achromatic while preserving text hierarchy", () => { + expect(globals).toContain("--workspace-canvas: #f2f2f2;"); + expect(globals).toContain("--workspace-sidebar: #f2f2f2;"); + expect(globals).toContain("--workspace-memo-list: #f7f7f7;"); expect(globals).toContain("--workspace-editor: #ffffff;"); - expect(contrastRatio("#0f172a", "#ffffff")).toBeGreaterThanOrEqual(4.5); - expect(contrastRatio("#64748b", "#ffffff")).toBeGreaterThanOrEqual(4.5); + expect(globals).toContain("--workspace-selection: #e5e5e5;"); + expect(globals).toContain("--slate-500-rgb: 115 115 115;"); + expect(globals).not.toContain("--slate-500-rgb: 100 116 139;"); + expect(contrastRatio("#222222", "#ffffff")).toBeGreaterThanOrEqual(4.5); + expect(contrastRatio("#737373", "#ffffff")).toBeGreaterThanOrEqual(4.5); }); test("keeps dark workspace surfaces distinct without blue-black color casts", () => { diff --git a/apps/web/src/styles/globals.css b/apps/web/src/styles/globals.css index 15fa49b9..0d2d57a0 100644 --- a/apps/web/src/styles/globals.css +++ b/apps/web/src/styles/globals.css @@ -88,8 +88,8 @@ html[data-edgeever-environment="demo"] body::after { @layer base { :root { - --background: 80 11% 96%; - --foreground: 224 71% 4%; + --background: 0 0% 96%; + --foreground: 0 0% 13%; --brand-green: #16a06e; --brand-green-hover: #12845b; --brand-green-muted: #def1e9; @@ -109,22 +109,23 @@ html[data-edgeever-environment="demo"] body::after { --brand-green-800-rgb: 17 83 60; --brand-green-900-rgb: 15 68 50; --brand-green-950-rgb: 7 37 28; - --workspace-canvas: #f3f5f7; - --workspace-sidebar: #eff1f4; - --workspace-memo-list: #f6f7f9; + --workspace-canvas: #f2f2f2; + --workspace-sidebar: #f2f2f2; + --workspace-memo-list: #f7f7f7; --workspace-editor: #ffffff; - --workspace-divider: #dde1e7; - --workspace-selection: #eef2f6; - --slate-50-rgb: 248 250 252; - --slate-100-rgb: 241 245 249; - --slate-200-rgb: 226 232 240; - --slate-300-rgb: 203 213 225; - --slate-400-rgb: 148 163 184; - --slate-500-rgb: 100 116 139; - --slate-600-rgb: 71 85 105; - --slate-700-rgb: 51 65 85; - --slate-800-rgb: 30 41 59; - --slate-900-rgb: 15 23 42; + --workspace-divider: #dcdcdc; + --workspace-memo-divider: #dedede; + --workspace-selection: #e5e5e5; + --slate-50-rgb: 250 250 250; + --slate-100-rgb: 245 245 245; + --slate-200-rgb: 229 229 229; + --slate-300-rgb: 212 212 212; + --slate-400-rgb: 166 166 166; + --slate-500-rgb: 115 115 115; + --slate-600-rgb: 82 82 82; + --slate-700-rgb: 64 64 64; + --slate-800-rgb: 38 38 38; + --slate-900-rgb: 24 24 24; --dark-surface-rgb: 255 255 255; --editor-body-font-size: 0.9375rem; --editor-body-line-height: 1.6; @@ -135,10 +136,10 @@ html[data-edgeever-environment="demo"] body::after { --editor-content-max-width: 880px; --card: 0 0% 100%; - --card-foreground: 224 71% 4%; + --card-foreground: 0 0% 13%; --popover: 0 0% 100%; - --popover-foreground: 224 71% 4%; + --popover-foreground: 0 0% 13%; --primary: 158 76% 36%; --primary-foreground: 80 11% 96%; @@ -146,8 +147,8 @@ html[data-edgeever-environment="demo"] body::after { --secondary: 158 32% 94%; --secondary-foreground: 158 70% 25%; - --muted: 210 40% 96.1%; - --muted-foreground: 215.4 16.3% 46.9%; + --muted: 0 0% 95%; + --muted-foreground: 0 0% 40%; --accent: 158 32% 94%; --accent-foreground: 158 70% 25%; @@ -155,8 +156,8 @@ html[data-edgeever-environment="demo"] body::after { --destructive: 0 84.2% 60.2%; --destructive-foreground: 210 40% 98%; - --border: 220 13% 91%; - --input: 220 13% 91%; + --border: 0 0% 88%; + --input: 0 0% 88%; --ring: 158 76% 36%; --radius: 0.5rem; @@ -197,6 +198,7 @@ html[data-edgeever-environment="demo"] body::after { --workspace-memo-list: #151a17; --workspace-editor: #191e1b; --workspace-divider: #2a312d; + --workspace-memo-divider: #3b4540; --workspace-selection: #1d3028; --slate-50-rgb: 15 20 17; --slate-100-rgb: 21 28 24; @@ -373,6 +375,14 @@ html[data-edgeever-extension-theme] kbd { background: var(--workspace-selection); } +.edgeever-memo-divider { + border-bottom-color: var(--workspace-memo-divider) !important; +} + +:root.dark .edgeever-workspace-memo-list .edgeever-memo-divider { + border-bottom-color: var(--workspace-memo-divider) !important; +} + html[data-edgeever-extension-theme] .edgeever-workspace-shell { background: var(--edgeever-theme-background, var(--workspace-canvas)); } @@ -395,6 +405,10 @@ html[data-edgeever-extension-theme] .edgeever-workspace-selection { background: var(--edgeever-theme-surface-muted, var(--workspace-selection)); } +html[data-edgeever-extension-theme] .edgeever-memo-divider { + border-bottom-color: var(--edgeever-theme-border, var(--workspace-memo-divider)) !important; +} + @media (min-width: 1024px) { .edgeever-workspace-grid--editor { grid-template-columns: @@ -458,11 +472,6 @@ html[data-edgeever-extension-theme] .edgeever-workspace-selection { --editor-theme-bg: var(--workspace-editor); } -/* Repeated memo rows need less separation than the three workspace panes. */ -:root.dark .edgeever-workspace-memo-list article { - border-color: color-mix(in srgb, var(--workspace-divider) 58%, transparent) !important; -} - :root.dark .ProseMirror { color: hsl(var(--foreground)); }