diff --git a/apps/desktop/e2e/white-theme.spec.ts b/apps/desktop/e2e/white-theme.spec.ts new file mode 100644 index 0000000..4a67bee --- /dev/null +++ b/apps/desktop/e2e/white-theme.spec.ts @@ -0,0 +1,28 @@ +import { expect, test } from "@playwright/test"; + +test("white canvas, sidebar and panels survive system dark mode", async ({ page }, testInfo) => { + await page.emulateMedia({ colorScheme: "dark" }); + for (const view of ["today", "chats", "teams", "automations", "apps", "providers", "tokens", "settings"]) { + await page.goto(`/?state=active&view=${view}`); + const surfaces = await page.evaluate(() => ["canvas", "sidebar", "surface", "surface-strong"].map((token) => + getComputedStyle(document.documentElement).getPropertyValue(`--${token}`).trim())); + expect(surfaces).toEqual(["#ffffff", "#ffffff", "#ffffff", "#ffffff"]); + for (const selector of ["html", "body", ".app-shell", ".sidebar", ".topbar"]) { + await expect(page.locator(selector)).toHaveCSS("background-color", "rgb(255, 255, 255)"); + } + if (view === "tokens") await expect(page.locator(".token-query")).toHaveCSS("background-color", "rgb(255, 255, 255)"); + expect(await page.evaluate(() => document.documentElement.scrollWidth > document.documentElement.clientWidth)).toBe(false); + } + await page.goto("/?state=active&view=today"); + await page.screenshot({ path: testInfo.outputPath("desktop-white-today.png"), fullPage: true }); +}); + +test("sign-in and access-gated pages use the same white background", async ({ page }, testInfo) => { + for (const state of ["signed_out", "inactive", "unknown"]) { + await page.goto(`/?state=${state}`); + const selectors = state === "signed_out" ? [".access-layout", ".access-story", ".access-panel"] : [".locked-layout"]; + for (const selector of selectors) await expect(page.locator(selector)).toHaveCSS("background-color", "rgb(255, 255, 255)"); + } + await page.goto("/?state=signed_out"); + await page.screenshot({ path: testInfo.outputPath("desktop-white-login.png"), fullPage: true }); +}); diff --git a/apps/desktop/src-tauri/tauri.conf.json b/apps/desktop/src-tauri/tauri.conf.json index a67c0a3..b71baaf 100644 --- a/apps/desktop/src-tauri/tauri.conf.json +++ b/apps/desktop/src-tauri/tauri.conf.json @@ -14,6 +14,8 @@ { "label": "main", "title": "Simplicio", + "theme": "Light", + "backgroundColor": "#ffffff", "width": 1280, "height": 820, "minWidth": 860, diff --git a/apps/desktop/src/design_system.test.ts b/apps/desktop/src/design_system.test.ts index baabf12..fd3a03c 100644 --- a/apps/desktop/src/design_system.test.ts +++ b/apps/desktop/src/design_system.test.ts @@ -1,8 +1,17 @@ import { describe, expect, it } from "vitest"; +import rawConfig from "../src-tauri/tauri.conf.json?raw"; import { copy, locale, t } from "./i18n"; import { designTokens } from "./design_tokens"; describe("desktop design system", () => { + it("keeps white surfaces consistent in shared tokens and the native window", () => { + const config = JSON.parse(rawConfig); + expect(designTokens.color.canvas).toBe("#ffffff"); + expect(designTokens.color.surface).toBe("#ffffff"); + expect(config.app.windows[0].backgroundColor).toBe("#ffffff"); + expect(config.app.windows[0].theme).toBe("Light"); + }); + it("keeps the initial locale and UI copy separate from Runtime data", () => { expect(locale).toBe("pt-BR"); expect(t("nav.settings")).toBe("Configurações"); diff --git a/apps/desktop/src/design_tokens.ts b/apps/desktop/src/design_tokens.ts index ee52656..f82d565 100644 --- a/apps/desktop/src/design_tokens.ts +++ b/apps/desktop/src/design_tokens.ts @@ -2,8 +2,8 @@ export const designTokens = { color: { ink: "#25261f", muted: "#777567", - canvas: "#f3edda", - surface: "#faf7ea", + canvas: "#ffffff", + surface: "#ffffff", green: "#54a879", greenDark: "#2f704e", warning: "#bb7b34", diff --git a/apps/desktop/src/styles.css b/apps/desktop/src/styles.css index 333787d..bf68b83 100644 --- a/apps/desktop/src/styles.css +++ b/apps/desktop/src/styles.css @@ -1,7 +1,7 @@ :root { font-family: Inter, ui-sans-serif, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; color: #25261f; - background: #f3edda; + background: #ffffff; font-synthesis: none; text-rendering: optimizeLegibility; --ink: #25261f; @@ -13,13 +13,13 @@ --green-pale: #eef5e9; --yellow: #e7c66a; --yellow-soft: #f6e9bd; - --canvas: #f3edda; - --sidebar: #ece4cc; - --surface: #faf7ea; - --surface-strong: #fffdf6; - --surface-muted: #f0ead7; - --line: #d8d0b9; - --line-soft: rgba(117, 108, 79, 0.14); + --canvas: #ffffff; + --sidebar: #ffffff; + --surface: #ffffff; + --surface-strong: #ffffff; + --surface-muted: #f5f6f7; + --line: #dfe3e6; + --line-soft: rgba(37, 38, 31, 0.12); --warning: #bb7b34; --danger: #bd665d; --mono: "SFMono-Regular", "IBM Plex Mono", Consolas, monospace; @@ -163,11 +163,11 @@ p { margin-top: 0; } .button-secondary { color: #4f5148; border-color: var(--line); - background: rgba(255, 253, 246, 0.68); + background: var(--surface); } .button-secondary:hover { - border-color: #bdb49b; + border-color: #b9c1c7; background: var(--surface-strong); } @@ -255,7 +255,7 @@ p { margin-top: 0; } .nav-item:hover { color: #41433b; - background: rgba(255, 253, 246, 0.48); + background: var(--surface-muted); } .nav-item.active { @@ -281,9 +281,9 @@ p { margin-top: 0; } .sidebar-runtime { margin-top: auto; padding: 11px; - border: 1px solid #d3cab1; + border: 1px solid var(--line); border-radius: 10px; - background: rgba(255, 253, 246, 0.52); + background: var(--surface); } .runtime-row { @@ -338,7 +338,7 @@ p { margin-top: 0; } grid-template-columns: 1fr auto 1fr; align-items: center; gap: 16px; - background: rgba(250, 247, 234, 0.82); + background: var(--surface); backdrop-filter: blur(14px); } @@ -814,7 +814,7 @@ p { margin-top: 0; } display: flex; align-items: center; gap: 18px; - background: rgba(250, 247, 234, 0.72); + background: var(--surface); } .provider-summary > div { @@ -854,7 +854,7 @@ p { margin-top: 0; } border: 1px solid var(--line); border-radius: 9px; display: inline-flex; - background: rgba(236, 228, 204, 0.56); + background: var(--surface-muted); } .segmented-control button { @@ -1007,13 +1007,13 @@ p { margin-top: 0; } min-width: 0; margin-top: 10px; padding: 13px 15px; - border: 1px solid #d3cbb3; + border: 1px solid var(--line); border-radius: 11px; display: grid; grid-template-columns: auto minmax(0, 1fr) auto; align-items: center; gap: 13px; - background: #eee7d1; + background: var(--surface-muted); } .principle-icon { @@ -1149,7 +1149,7 @@ p { margin-top: 0; } border-radius: 20px 0 0 20px; display: flex; flex-direction: column; - background: var(--yellow-soft); + background: var(--surface); } .access-story > .brand { margin-bottom: 40px; } @@ -1183,7 +1183,7 @@ p { margin-top: 0; } display: inline-flex; align-items: center; gap: 6px; - background: rgba(255, 253, 246, 0.42); + background: var(--surface-muted); } .access-proof-grid article > span { color: var(--green-dark); font-size: 10px; } diff --git a/docs/desktop/DESIGN.md b/docs/desktop/DESIGN.md index ff405bb..f75753e 100644 --- a/docs/desktop/DESIGN.md +++ b/docs/desktop/DESIGN.md @@ -1,10 +1,16 @@ # Desktop design system and accessibility baseline -The Desktop uses a small, light-native visual system: butter canvas, ivory +The Desktop uses a small, light-native visual system: white canvas, sidebar and surfaces, near-black text, soft green for healthy/action states, and amber only for attention. CSS custom properties in `src/styles.css` are the source of truth for color, spacing, radius, focus, motion, and target-size tokens. +The native window also starts with a white background and the light theme, so +startup, login and workspace surfaces remain consistent when the operating +system prefers dark mode. Neutral secondary surfaces use a light gray; color +accents communicate status and actions rather than tinting the application +background. Browser theme tests do not certify an installed platform package. + The initial locale is `pt-BR`. `src/i18n.ts` contains UI copy keys only; Runtime strings and provider IDs remain data and are never used as translation keys.