diff --git a/design.md b/design.md index 3b206f5775..33c5338b73 100644 --- a/design.md +++ b/design.md @@ -1,6 +1,6 @@ # OmniRoute — Design System & Visual Identity -> **Status:** standardization plan. **Phases 1–3 are implemented in this PR** (grid, primitives, status-color centralization, mono token, and the DataTable token migration). The DataTable migration is **faithful** — dark stays byte-identical (the new `--table-*` dark values equal the old hardcoded rgba); light is fixed (it was buggy always-dark via dead `var()` fallbacks). **⚠️ Wants a visual pass before merge** (light-theme tables + the secondary-text shift `#888`→`--color-text-muted`). **Phase 4 is now largely done too** (C6 focus-ring → accent, C7 Checkbox/Textarea primitives, C9 `cn()`→tailwind-merge); only the selective C8 hex-sweep remains. Note several remaining "hardcoded" hex are _intentional_ (always-dark console terminal, ReactFlow SVG strokes) and must NOT be swept. +> **Status:** standardization plan. **Phases 1–3 are implemented in this PR** (grid, primitives, status-color centralization, mono token, and the DataTable token migration). The DataTable migration is **faithful** — dark stays byte-identical (the new `--table-*` dark values equal the old hardcoded rgba); light is fixed (it was buggy always-dark via dead `var()` fallbacks). **⚠️ Wants a visual pass before merge** (light-theme tables + the secondary-text shift `#888`→`--color-text-muted`). **Phase 4 is now largely done too** (C6 focus-ring → accent, C7 Checkbox/Textarea primitives, C9 `cn()`→tailwind-merge); only the selective C8 hex-sweep remains. Note several remaining "hardcoded" hex are _intentional_ (always-dark console terminal, ReactFlow SVG strokes) and must NOT be swept. **Phase 5 (D4 + D8): the grid now reaches every standalone screen** (login/auth/error/legal/status/onboarding — their opaque `bg-bg` full-screen wrappers were hiding it) **and the dashboard content shell is fluid up to 4K** (`max-w-7xl` → `max-w-[3840px]`) so it follows the viewport on large monitors instead of centering with wide side gutters. > **Date:** 2026-06-16 · **Scope:** unify the OmniRoute dashboard (`src/`) with the marketing site (`_mono_repo/omnirouteSite/`) into **one visual identity** — same graph-paper grid background, same color tokens, standardized components. --- @@ -127,7 +127,7 @@ The grid is global by construction (it covers the panel, `auth`/`login`, error p ### 4.6 Login / auth / error pages -These render directly under `` (no panel chrome) and their wrappers are mostly transparent — the global grid appears behind them automatically. Exception: `login/page.tsx:124,139` uses opaque `bg-bg` wrappers; softening them (D4) is a small Phase 2 follow-up. +These render directly under `` (no panel chrome), so the global grid should appear behind them automatically. **Phase 5 — DONE:** the standalone full-screen wrappers were in fact opaque (`min-h-screen … bg-bg`, where `bg-bg` is the same solid fill as ``), which hid the grid on every non-dashboard screen — not just login. All of them are now transparent so the shared wallpaper shows through: `login`, `forgot-password`, `callback`, `maintenance`, `offline`, `status`, `terms`, `privacy`, `onboarding`, and `ErrorPageScaffold` (covers `400`/`401`). This closes **D4** (extended from login-only to every standalone screen). Guarded by `tests/unit/design-grid-background.test.ts`. ### 4.7 Landing page @@ -187,10 +187,11 @@ Each phase: `npm run lint` + `npm run typecheck:core` + a visual pass. - **D1 — Button primary:** keep red→red or switch to **red→violet `--grad-brand`**? Rec: **red→violet** (Phase 2). - **D2 — Grid line color:** **neutral** (site style) — chosen — vs brand-red. Size **32px** (shrunk ~30% from the original 46px on owner feedback — 46px cells read too large on the dashboard layout). - **D3 — Chrome vibrancy:** sidebar/header **solid** — chosen. -- **D4 — Auth/login grid:** soften `login/page.tsx` wrappers (Phase 2). Rec: yes. +- **D4 — Auth/login grid:** ✅ **DONE (Phase 5)** — opaque `bg-bg` removed from every standalone full-screen wrapper (not just login), so the grid shows on all screens. See §4.6. - **D5 — Landing page:** leave animated splash as-is. Chosen. - **D6 — Radius 14/9 product-wide:** Rec: yes (Phase 2). - **D7 — Phase 1 ships first:** Chosen. +- **D8 — Layout width (Phase 5):** the dashboard content shell was capped at `max-w-7xl` (1280px), centering with wide empty side gutters on large monitors. ✅ **DONE** — raised to a fluid `max-w-[3840px]` (true 4K): content now follows the viewport up to ~4K and only centers beyond it (`DashboardLayout.tsx`). Deliberately-narrow pages stay narrow by design (`ProviderOnboardingWizard` max-w-5xl, `Rtk`/`CavemanContextPageClient` max-w-6xl). --- diff --git a/src/app/(dashboard)/dashboard/onboarding/page.tsx b/src/app/(dashboard)/dashboard/onboarding/page.tsx index 36ace2b1c1..a1cbf3544e 100644 --- a/src/app/(dashboard)/dashboard/onboarding/page.tsx +++ b/src/app/(dashboard)/dashboard/onboarding/page.tsx @@ -224,14 +224,14 @@ export default function OnboardingWizard() { if (loading) { return ( -
+
{tc("loading")}
); } return ( -
+
{/* Progress Indicator */}
diff --git a/src/app/callback/page.tsx b/src/app/callback/page.tsx index ebf3be1384..4a209b51da 100644 --- a/src/app/callback/page.tsx +++ b/src/app/callback/page.tsx @@ -123,7 +123,7 @@ export default function CallbackPage() { }, []); return ( -
+
{status === "processing" && ( <> diff --git a/src/app/forgot-password/page.tsx b/src/app/forgot-password/page.tsx index d821f8fdf3..00d1110b54 100644 --- a/src/app/forgot-password/page.tsx +++ b/src/app/forgot-password/page.tsx @@ -30,7 +30,7 @@ export default function ForgotPasswordPage() { }, [isElectron]); return ( -
+

{t("resetPassword")}

diff --git a/src/app/login/page.tsx b/src/app/login/page.tsx index 0ab5f66353..61d8bba128 100644 --- a/src/app/login/page.tsx +++ b/src/app/login/page.tsx @@ -121,7 +121,7 @@ export default function LoginPage() { if (hasPassword === null || setupComplete === null) { return ( -
+
{nodeWarningBanner}
@@ -136,7 +136,7 @@ export default function LoginPage() { if (!hasPassword && !setupComplete) { return ( -
+
{nodeWarningBanner}
+
{nodeWarningBanner}
+
{nodeWarningBanner && (
{nodeWarningBanner}
)} -
+
+
construction diff --git a/src/app/offline/page.tsx b/src/app/offline/page.tsx index a280f45814..192546c85a 100644 --- a/src/app/offline/page.tsx +++ b/src/app/offline/page.tsx @@ -20,7 +20,7 @@ export default function OfflinePage() { ); return ( -
+
wifi_off diff --git a/src/app/privacy/page.tsx b/src/app/privacy/page.tsx index 6cc0e38cc0..39a806c2d7 100644 --- a/src/app/privacy/page.tsx +++ b/src/app/privacy/page.tsx @@ -15,7 +15,7 @@ export default function PrivacyPage() { const t = useTranslations("legal"); return ( -
+
+
diff --git a/src/app/terms/page.tsx b/src/app/terms/page.tsx index 2b6138a75d..86feae7d83 100644 --- a/src/app/terms/page.tsx +++ b/src/app/terms/page.tsx @@ -15,7 +15,7 @@ export default function TermsPage() { const t = useTranslations("legal"); return ( -
+
diff --git a/src/shared/components/layouts/DashboardLayout.tsx b/src/shared/components/layouts/DashboardLayout.tsx index c671ec55ba..0a0a3fa866 100644 --- a/src/shared/components/layouts/DashboardLayout.tsx +++ b/src/shared/components/layouts/DashboardLayout.tsx @@ -102,7 +102,10 @@ export default function DashboardLayout({ children }) { /> {!isE2EMode && }
-
+ {/* Fluid up to a 4K cap (3840px): content follows the viewport on large + monitors and only centers (side gutters) beyond ~4K, instead of the prior + 1280px cap that left big empty margins on wide screens. */} +
{children} diff --git a/tests/unit/design-grid-background.test.ts b/tests/unit/design-grid-background.test.ts index 01b594664a..4408626651 100644 --- a/tests/unit/design-grid-background.test.ts +++ b/tests/unit/design-grid-background.test.ts @@ -183,3 +183,42 @@ test("form controls focus on the accent ring, not the red primary", () => { } } }); + +// ── Phase 5: the grid reaches every standalone screen + the shell is fluid up to 4K ── + +test("standalone full-screen pages stay transparent so the grid shows through", () => { + // Same contract as the DashboardLayout shell: a full-viewport wrapper must not paint + // an opaque bg-bg over the body::before grid. These are the auth / error / legal / + // status / onboarding screens that render outside the dashboard layout — the ones the + // first grid phase missed. (?![\w-]) keeps bg-bg-alt / bg-bg-main from matching. + const pages = [ + "../../src/app/login/page.tsx", + "../../src/app/forgot-password/page.tsx", + "../../src/app/callback/page.tsx", + "../../src/app/maintenance/page.tsx", + "../../src/app/offline/page.tsx", + "../../src/app/status/page.tsx", + "../../src/app/terms/page.tsx", + "../../src/app/privacy/page.tsx", + "../../src/app/(dashboard)/dashboard/onboarding/page.tsx", + "../../src/shared/components/ErrorPageScaffold.tsx", + ]; + for (const p of pages) { + const src = read(p); + assert.ok( + !/min-h-screen[^"]*\bbg-bg(?![\w-])/.test(src) && + !/\bbg-bg(?![\w-])[^"]*min-h-screen/.test(src), + `${p} must not paint bg-bg on a min-h-screen wrapper (it would hide the grid)` + ); + } +}); + +test("DashboardLayout content shell is fluid up to ~4K before centering", () => { + // The inner content wrapper grows with the viewport up to a 4K cap (3840px) instead + // of the old max-w-7xl (1280px) that left wide side gutters on large monitors. + assert.ok( + dashboardLayout.includes("max-w-[3840px] mx-auto"), + "content wrapper caps at 3840px (4K) and centers only beyond that" + ); + assert.ok(!dashboardLayout.includes("max-w-7xl"), "the old 1280px max-w-7xl cap is gone"); +});