From 6ffbdcd10e24a3afbab972b1a598968229c8d6bd Mon Sep 17 00:00:00 2001 From: tianma-if Date: Fri, 25 Sep 2026 09:26:11 +0800 Subject: [PATCH] fix: pin runtime accent steps and widen site decoration on P3 Amber, rose, and red steps used by the app now follow the runtime RGB palette in both themes. Site gradients and glows stay on celadon hex and switch to wider oklch only on P3 displays. --- .../src/components/magicui/border-beam.tsx | 4 ++-- .../src/components/magicui/magic-card.tsx | 2 +- apps/site/src/styles/brand-gamut.test.mjs | 19 ++++++++++++++++ apps/site/src/styles/brand.css | 22 +++++++++++++++++++ apps/site/src/styles/global.css | 6 ++--- apps/web/src/lib/tailwind-theme.test.mjs | 5 +++++ apps/web/src/lib/ui-palette.test.mjs | 5 +++++ apps/web/src/styles/globals.css | 10 +++++++++ 8 files changed, 67 insertions(+), 6 deletions(-) create mode 100644 apps/site/src/styles/brand-gamut.test.mjs diff --git a/apps/site/src/components/magicui/border-beam.tsx b/apps/site/src/components/magicui/border-beam.tsx index 7586d0d3..2d35e379 100644 --- a/apps/site/src/components/magicui/border-beam.tsx +++ b/apps/site/src/components/magicui/border-beam.tsx @@ -15,8 +15,8 @@ export const BorderBeam = ({ size = 200, duration = 15, borderWidth = 1.5, - colorFrom = "#70c9b7", // edgeever brand - colorTo = "#3fb2a1", // edgeever brand + colorFrom = "var(--edgeever-decor-beam-from)", + colorTo = "var(--edgeever-decor-beam-to)", delay = 0, }: BorderBeamProps) => { return ( diff --git a/apps/site/src/components/magicui/magic-card.tsx b/apps/site/src/components/magicui/magic-card.tsx index 42fe2f25..c24bf6c6 100644 --- a/apps/site/src/components/magicui/magic-card.tsx +++ b/apps/site/src/components/magicui/magic-card.tsx @@ -12,7 +12,7 @@ export function MagicCard({ children, className, gradientSize = 200, - gradientColor = "#3fb2a1", // edgeever brand + gradientColor = "var(--edgeever-decor-beam-to)", gradientOpacity = 0.8, }: MagicCardProps) { const mouseX = useMotionValue(-gradientSize); diff --git a/apps/site/src/styles/brand-gamut.test.mjs b/apps/site/src/styles/brand-gamut.test.mjs new file mode 100644 index 00000000..a216c09c --- /dev/null +++ b/apps/site/src/styles/brand-gamut.test.mjs @@ -0,0 +1,19 @@ +import { describe, expect, test } from "bun:test"; +import { readFileSync } from "node:fs"; + +const brand = readFileSync(new URL("./brand.css", import.meta.url), "utf8"); +const globalCss = readFileSync(new URL("./global.css", import.meta.url), "utf8"); + +describe("site decorative wide gamut", () => { + test("keeps the celadon brand in sRGB and limits oklch to decorative tokens", () => { + expect(brand).toContain("--edgeever-celadon-600: #2b968b;"); + expect(brand).toContain("--edgeever-brand: var(--edgeever-celadon-600);"); + expect(brand).toContain("--edgeever-decor-gradient: linear-gradient(135deg, var(--edgeever-decor-from) 0%, var(--edgeever-decor-to) 100%);"); + expect(brand).toContain("@media (color-gamut: p3)"); + expect(brand).toContain("--edgeever-decor-to: oklch(0.611 0.129 185);"); + expect(brand).not.toContain("--edgeever-brand: oklch("); + expect(globalCss).toContain("background-image: var(--edgeever-decor-gradient);"); + expect(globalCss).toContain("box-shadow: 0 20px 40px -15px var(--edgeever-decor-shadow);"); + expect(globalCss).toContain("box-shadow: 0 0 50px -12px var(--edgeever-decor-glow);"); + }); +}); diff --git a/apps/site/src/styles/brand.css b/apps/site/src/styles/brand.css index 6389b4a9..6cd13b8b 100644 --- a/apps/site/src/styles/brand.css +++ b/apps/site/src/styles/brand.css @@ -24,4 +24,26 @@ --edgeever-brand-logo-mark: var(--edgeever-celadon-700); --edgeever-brand-logo-accent: var(--edgeever-celadon-400); --edgeever-brand-surface: #f8fafc; + + /* Decorative color only. Buttons, links, and the logo keep the hex brand tokens. */ + --edgeever-decor-from: var(--edgeever-celadon-800); + --edgeever-decor-to: var(--edgeever-celadon-600); + --edgeever-decor-gradient: linear-gradient(135deg, var(--edgeever-decor-from) 0%, var(--edgeever-decor-to) 100%); + --edgeever-decor-beam-from: var(--edgeever-celadon-400); + --edgeever-decor-beam-to: var(--edgeever-celadon-500); + --edgeever-decor-glow: rgb(var(--edgeever-brand-rgb) / 0.25); + --edgeever-decor-shadow: rgb(var(--edgeever-brand-rgb) / 0.15); +} + +@media (color-gamut: p3) { + :root { + /* Same lightness and hue as the celadon hex stops, with chroma past sRGB. */ + --edgeever-decor-from: oklch(0.453 0.096 188.1); + --edgeever-decor-to: oklch(0.611 0.129 185); + --edgeever-decor-gradient: linear-gradient(in oklch 135deg, var(--edgeever-decor-from) 0%, var(--edgeever-decor-to) 100%); + --edgeever-decor-beam-from: oklch(0.775 0.169 179.2); + --edgeever-decor-beam-to: oklch(0.695 0.149 181.5); + --edgeever-decor-glow: oklch(0.611 0.129 185 / 0.25); + --edgeever-decor-shadow: oklch(0.611 0.129 185 / 0.15); + } } diff --git a/apps/site/src/styles/global.css b/apps/site/src/styles/global.css index 0588190c..43eefee7 100644 --- a/apps/site/src/styles/global.css +++ b/apps/site/src/styles/global.css @@ -18,7 +18,7 @@ } @utility glow-brand { - box-shadow: 0 0 50px -12px rgb(var(--edgeever-brand-rgb) / 0.25); + box-shadow: 0 0 50px -12px var(--edgeever-decor-glow); } @utility glow-card { @@ -32,7 +32,7 @@ transition: all 0.4s cubic-bezier(0.25, 1, 0.5, 1); &:hover { transform: translateY(-6px); - box-shadow: 0 20px 40px -15px rgb(var(--edgeever-brand-rgb) / 0.15); + box-shadow: 0 20px 40px -15px var(--edgeever-decor-shadow); border-color: var(--color-brand-border); } } @@ -48,7 +48,7 @@ background-clip: text; -webkit-background-clip: text; -webkit-text-fill-color: transparent; - background-image: linear-gradient(135deg, var(--color-brand-text) 0%, var(--color-brand) 100%); + background-image: var(--edgeever-decor-gradient); } @utility animate-slow-spin { diff --git a/apps/web/src/lib/tailwind-theme.test.mjs b/apps/web/src/lib/tailwind-theme.test.mjs index c476eda5..419c1e4c 100644 --- a/apps/web/src/lib/tailwind-theme.test.mjs +++ b/apps/web/src/lib/tailwind-theme.test.mjs @@ -13,7 +13,12 @@ describe("tailwind theme tokens", () => { expect(css).toContain("--color-slate-950: rgb(var(--slate-950-rgb) / 1)"); expect(css).toContain("--color-emerald-500: rgb(var(--brand-green-500-rgb) / 1)"); expect(css).toContain("--color-amber-50: rgb(var(--amber-50-rgb) / 1)"); + expect(css).toContain("--color-amber-300: rgb(var(--amber-300-rgb) / 1)"); + expect(css).toContain("--color-amber-400: rgb(var(--amber-400-rgb) / 1)"); + expect(css).toContain("--color-amber-500: rgb(var(--amber-500-rgb) / 1)"); expect(css).toContain("--color-rose-50: rgb(var(--rose-50-rgb) / 1)"); + expect(css).toContain("--color-rose-400: rgb(var(--rose-400-rgb) / 1)"); + expect(css).toContain("--color-red-100: rgb(var(--rose-100-rgb) / 1)"); expect(css).toContain("--shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05)"); expect(css).toContain("--blur-sm: 4px"); expect(css).toContain(".focus-visible\\:outline-none:focus-visible"); diff --git a/apps/web/src/lib/ui-palette.test.mjs b/apps/web/src/lib/ui-palette.test.mjs index f90d5ef1..77b0c4f1 100644 --- a/apps/web/src/lib/ui-palette.test.mjs +++ b/apps/web/src/lib/ui-palette.test.mjs @@ -26,7 +26,11 @@ describe("application color system", () => { expect(globals).toContain("--slate-500-rgb: 115 115 115;"); expect(globals).toContain("--slate-950-rgb: 10 10 10;"); expect(globals).toContain("--amber-50-rgb: 255 251 235;"); + expect(globals).toContain("--amber-300-rgb: 252 211 77;"); + expect(globals).toContain("--amber-400-rgb: 251 191 36;"); + expect(globals).toContain("--amber-500-rgb: 245 158 11;"); expect(globals).toContain("--rose-50-rgb: 255 241 242;"); + expect(globals).toContain("--rose-400-rgb: 251 113 133;"); expect(globals).not.toContain("--slate-500-rgb: 100 116 139;"); expect(contrastRatio("#222222", "#ffffff")).toBeGreaterThanOrEqual(4.5); expect(contrastRatio("#737373", "#ffffff")).toBeGreaterThanOrEqual(4.5); @@ -37,6 +41,7 @@ describe("application color system", () => { expect(globals).toContain("--workspace-sidebar: #121612;"); expect(globals).toContain("--workspace-memo-list: #151a17;"); expect(globals).toContain("--workspace-editor: #191e1b;"); + expect(globals).toContain("--amber-300-rgb: 180 83 9;"); expect(globals).not.toContain("scrollbar-color: rgba(100, 116, 139, 0.18)"); expect(contrastRatio("#cad4ce", "#191e1b")).toBeGreaterThanOrEqual(4.5); expect(contrastRatio("#9aa9a0", "#191e1b")).toBeGreaterThanOrEqual(4.5); diff --git a/apps/web/src/styles/globals.css b/apps/web/src/styles/globals.css index 7b6d102d..823b773c 100644 --- a/apps/web/src/styles/globals.css +++ b/apps/web/src/styles/globals.css @@ -67,6 +67,9 @@ --color-amber-50: rgb(var(--amber-50-rgb) / 1); --color-amber-100: rgb(var(--amber-100-rgb) / 1); --color-amber-200: rgb(var(--amber-200-rgb) / 1); + --color-amber-300: rgb(var(--amber-300-rgb) / 1); + --color-amber-400: rgb(var(--amber-400-rgb) / 1); + --color-amber-500: rgb(var(--amber-500-rgb) / 1); --color-amber-600: rgb(var(--amber-600-rgb) / 1); --color-amber-700: rgb(var(--amber-700-rgb) / 1); --color-amber-800: rgb(var(--amber-800-rgb) / 1); @@ -75,12 +78,14 @@ --color-rose-50: rgb(var(--rose-50-rgb) / 1); --color-rose-100: rgb(var(--rose-100-rgb) / 1); --color-rose-200: rgb(var(--rose-200-rgb) / 1); + --color-rose-400: rgb(var(--rose-400-rgb) / 1); --color-rose-500: rgb(var(--rose-500-rgb) / 1); --color-rose-600: rgb(var(--rose-600-rgb) / 1); --color-rose-700: rgb(var(--rose-700-rgb) / 1); --color-rose-800: rgb(var(--rose-800-rgb) / 1); --color-rose-950: rgb(var(--rose-950-rgb) / 1); --color-red-50: rgb(var(--rose-50-rgb) / 1); + --color-red-100: rgb(var(--rose-100-rgb) / 1); --color-red-600: rgb(var(--rose-600-rgb) / 1); --color-red-700: rgb(var(--rose-700-rgb) / 1); --color-blue-600: rgb(var(--blue-600-rgb) / 1); @@ -308,6 +313,9 @@ html.dark[data-edgeever-environment="demo"] body::after { --amber-50-rgb: 255 251 235; --amber-100-rgb: 254 243 199; --amber-200-rgb: 253 230 138; + --amber-300-rgb: 252 211 77; + --amber-400-rgb: 251 191 36; + --amber-500-rgb: 245 158 11; --amber-600-rgb: 217 119 6; --amber-700-rgb: 180 83 9; --amber-800-rgb: 146 64 14; @@ -316,6 +324,7 @@ html.dark[data-edgeever-environment="demo"] body::after { --rose-50-rgb: 255 241 242; --rose-100-rgb: 255 228 230; --rose-200-rgb: 254 205 211; + --rose-400-rgb: 251 113 133; --rose-500-rgb: 244 63 94; --rose-600-rgb: 225 29 72; --rose-700-rgb: 190 18 60; @@ -418,6 +427,7 @@ html.dark[data-edgeever-environment="demo"] body::after { --amber-50-rgb: 69 26 3; --amber-100-rgb: 80 30 5; --amber-200-rgb: 146 64 14; + --amber-300-rgb: 180 83 9; --amber-600-rgb: 253 230 138; --amber-700-rgb: 253 230 138; --amber-800-rgb: 252 211 77;