Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -383,7 +383,6 @@ Open Notebook is MIT licensed. See the [LICENSE](LICENSE) file for details.
[license-url]: https://github.com/lfnovo/open-notebook/blob/master/LICENSE.txt
[linkedin-shield]: https://img.shields.io/badge/-LinkedIn-black.svg?style=for-the-badge&logo=linkedin&colorB=555
[linkedin-url]: https://linkedin.com/in/lfnovo
[product-screenshot]: images/screenshot.png
[Next.js]: https://img.shields.io/badge/Next.js-000000?style=for-the-badge&logo=next.js&logoColor=white
[Next-url]: https://nextjs.org/
[React]: https://img.shields.io/badge/React-61DAFB?style=for-the-badge&logo=react&logoColor=black
Expand Down
33 changes: 33 additions & 0 deletions docs/7-DEVELOPMENT/decisions/ADR-008-design-token-system.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# ADR-008: Visual identity is a token contract in globals.css, reviewed through /dev/design

- **Status**: Accepted
- **Date**: 2026-07
- **Related**: Discussion #1202 (community co-design), #1218 (foundation), #1220 (screen reskin), [frontend rules](../../7-DEVELOPMENT/frontend.md)

## Context

The 2026 redesign ("Quiet Green", co-designed with the community in Discussion #1202) replaced the stock shadcn theme with a product-specific visual identity. Before it, colors were scattered across components as raw Tailwind palette classes (`text-red-600`, `bg-amber-50`), each with hand-written `dark:` twins — visually inconsistent, semantically meaningless, and expensive to change. The redesign also pre-designed Stage-2 UX (citations, per-source context states, content-type identity) that needs colors with *meaning*, not decoration.

## Decision

**All visual identity lives as a layered custom-property token system in `frontend/src/app/globals.css`. Components consume semantic tokens only — raw palette classes are banned. `/dev/design` is the living reference.**

- **Layers**: raw palette (fern, sage, gold, teal, plum, mauve, slate, violet, clay) → semantic slots (surfaces, ink ramp, hairlines, action, danger, warn) → product vocabularies: content-type hues (`--type-*`), evidence/citation classes (`--cite-*`), context states (`--ctx-*`). The product vocabularies are canonized now even where nothing consumes them yet, so Stage-2 features and community PRs share one contract.
- **The laws** (enforced in review): fern acts · teal speaks (the AI/system voice) · red destroys, and only destroys · warn is clay, never an action hue · color never washes a reading surface · hairlines separate, popovers own the only real shadow · geometry is squared (4–6px) · mono is for data, not prose.
- **Dark mode** overrides only the raw layers on `.dark`; every alias re-resolves via `var()`. This works **only** because the `dark` class sits on the document root (`theme-store` behavior). CSS custom properties resolve where they are *declared*, so a nested `.dark` wrapper inherits already-resolved light values — never theme a subtree.
- **Values are hex**, kept 1:1 with the validated design spec (a pixel-diff re-application test against the design mockups reached 0.000% visible difference). Converting to oklch would reintroduce drift for zero benefit.
- **`/dev/design`** (dev-only route, 404 in production) renders every token and primitive in both themes. It is the acceptance reference for visual PRs and the regression detector: screen-level PRs must leave it byte-identical.

## Alternatives considered

- **Keep per-component palette classes** — rejected: the status quo that produced the inconsistency; every rebrand becomes a 38-file sweep (we did exactly one and never want another).
- **A theming library / CSS-in-JS tokens** — rejected: Tailwind v4 `@theme` already bridges custom properties to utilities; adding a runtime dependency contradicts the lean posture.
- **Full design-system tooling (Storybook, Figma library, published npm package)** — rejected as over-engineering for a single-app project; `/dev/design` gives the same review value at near-zero maintenance cost.
- **oklch values (shadcn convention)** — rejected: fidelity to the pixel-diff-validated spec wins over convention; the file documents this so nobody "fixes" it later.

## Consequences

- Contributors must use token utilities (`text-destructive`, `bg-warn-tint`, `text-type-video`…) — see the styling rule in [frontend/AGENTS.md](../../../frontend/AGENTS.md). A PR reintroducing `text-red-600` is a review reject.
- `slate` and `violet` are exposed to Tailwind as `slate-hue`/`violet-hue` to avoid colliding with Tailwind's built-in palettes.
- Rebrands and theme tweaks are token edits, verified in `/dev/design`, instead of app-wide sweeps.
- Stage-2 features consume `--cite-*`/`--ctx-*` without new color decisions; the vocabulary already exists.
Binary file modified docs/assets/asset_list.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
63 changes: 5 additions & 58 deletions docs/assets/hero.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions frontend/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ Normative rules for working on the Next.js frontend. Architecture and flow walkt
## Hard rules

- **i18n is mandatory**: every UI string goes through `t('section.key')` and the key must exist in **all locales** under `src/lib/locales/` (currently 14; en-US is the reference). Missing keys fall back to en-US silently — keep locales in sync. Each non-en-US locale ends with `satisfies TranslationShape` (type derived from en-US), so a missing/extra key fails `tsc`; the parity test (`src/lib/locales/index.test.ts`) checks the same at runtime.
- **Styling goes through design tokens** ([ADR-008](../docs/7-DEVELOPMENT/decisions/ADR-008-design-token-system.md)): use semantic utilities (`text-destructive`, `bg-warn-tint`, `text-teal`, `text-type-video`, …) defined in `src/app/globals.css` — never raw Tailwind palette classes (`text-red-600`, `bg-amber-50`) and never hand-written `dark:` color twins (tokens re-resolve per theme). The laws: fern acts, teal is the AI voice, red only destroys, warn is clay, color never washes a reading surface. `/dev/design` (dev-only route) renders every token and primitive in both themes — it's the visual reference, and screen-level PRs must not change it.
- All requests go through `apiClient` (`src/lib/api/client.ts`); never create a second axios instance. Auth token is auto-added from localStorage key `auth-storage`.
- Data fetching uses TanStack Query hooks in `src/lib/hooks/` with `QUERY_KEYS`; mutations invalidate caches and show toasts (sonner). Follow the existing hook shape.
- FormData requests: nested objects/arrays must be `JSON.stringify`-ed before appending; the interceptor strips Content-Type so the browser sets the multipart boundary — don't re-add it.
Expand Down
Loading