Repository navigation
v0.2.0 — Design system overhaul, universal dock, coding agents
A near-total UI overhaul. Same product underneath — every screen looks
different, the desktop chrome is reimagined as a side-rail dock, and a
handful of long-standing dev paper-cuts are gone.
Highlights
🎨 Swappable design system — Saigon + Render
Two distinct visual identities you can flip between at runtime via
Settings → Appearance → Design system:
| Pack | Vibe | Defaults |
|---|---|---|
| Saigon (default) | Atmospheric dark, organic | Inter typography, sage-green accent, 75 px pill buttons, spacious 4 px rhythm |
| Render | Crisp light, vibrant | Tight Inter, vivid purple → sunset accent gradient, sharp 0 px buttons |
Both packs support both light and dark tones. Saigon-dark and
Render-light are the primary designs; the inverse tones are best-effort
tonal mappings.
Mechanism: a single semantic token vocabulary (--ds-bg-canvas,
--ds-radius-button, --ds-text-h1, …) overridden per pack via
[data-ds="saigon"] / [data-ds="render"] selectors. Components
consume only tokens — no hardcoded hex anywhere — so flipping the
active pack restyles the entire app without re-rendering.
🧱 Component primitives
New token-driven primitives in @notebooklm/ui/components/primitives:
Button, Card, Heading, Text, Pill, Input, Textarea,
IconButton, Stack/Inline, Modal, Skeleton, Spinner. Each
consumes only --ds-* tokens via CVA variants — adding a new
primitive doesn't require touching either pack's stylesheet.
🧭 Universal sidebar dock (desktop only)
The desktop app's chrome is now a single floating vertical pill on the
left edge. Icon-only at rest; per-icon labels slide in on hover.
Replaces the per-page top-header pattern across /notebooks,
/notebooks/[id], and /settings/*.
The dock is context-aware — it hides the Library entry when you're
already on /notebooks, and the Settings entry on /settings/*
where the sidebar already shows the current section.
The web app keeps top headers for now.
⚙️ Settings — full redesign
- Left-rail sidebar (lg+) with grouped sections: You / AI
/ Capabilities / Workspace. Mobile gets a horizontal
scrollable strip. - Status dots per section: green when configured, amber if
partially set up, accent when a runtime is actively routing chat,
muted otherwise. Driven by a single shared
useSettingsStatus()hook so both layouts share one set of tRPC
observers. - New: Coding Agents pane at
/settings/coding-agents. Detects
Claude Code, OpenAI Codex, andgh copilotvia
runtimes.detectAvailable, lets you route chat through whichever
is installed (writespreferences.chat = [<agentId>, "ai-sdk"]
viaaiConfig.update). Studio + deep-research keep falling back
to your saved AI provider.
🚀 Onboarding — expanded
- Chat provider step: 5 → 11 curated providers (Free: Google
Gemini, Groq · Paid: OpenAI, Anthropic, Mistral, Cohere, xAI ·
Aggregator: Together AI, OpenRouter · Local: Ollama · Custom:
OpenAI-compatible for LM Studio / vLLM / gateways). 3-column grid
on lg+, tonal badges per category. - Web search step: now exposes all 3 providers
(Tavily, Exa, SearxNG) instead of just Tavily + Exa,
with per-provider input kind (api key vs base URL) and inline test
button. - Test status persists: onboarding now upserts the credential and
immediately re-tests it bycredentialId, so the saved row's
validationStatusis"ok"straight away. No more "Saved ·
untested" in Settings until you manually re-test. - Models updated to the live catalogue: retired
gemini-2.0-flash-expswapped togemini-2.5-flash; Anthropic
default moved toclaude-haiku-4-5-20251001. - New
api_key_and_base_urlauth flow for OpenAI-compatible
providers — renders API key + base URL + freeform model id
together.
🪲 Notable fixes
- React-19 / TanStack-Router page duplication. Switching settings
tabs (or navigating between Notebooks / Notebook / Settings) used
to leave the previous route's tree mounted underneath the new one
— visible as the same page rendered twice top-to-bottom. Cause:
inline arrowcomponent:callbacks on every route changed
identity each render, triggering React 19's stricter unmount
path, which silently bailed when our DOM-mutating ThemeProvider
had touched the document. Fixed by extracting every route's
component into a stable named function (RootShell,
OnboardingShell,NotebooksShell,NotebookShell,
SettingsLayoutShell). ELECTRON_RUN_AS_NODEtrap. Some agent runtimes / CI configs
export this var, which makeselectron .run as plain Node and
silently crashes onapp.isPackaged. New
apps/desktop/scripts/dev-electron.mjswrapper scrubs the var
before spawning Electron —bun run devnow works regardless of
the parent shell.electron-updaterdev-mode crash.
apps/desktop/electron/updater.cjsused to destructure
autoUpdaterat module top, triggering a getter that crashed on
Electron 33 + bun. Moved the require insidesetupAutoUpdater
(only called in production) so the import no longer fires during
dev.- Provider logos disappearing on dark surfaces. Many provider
SVGs (OpenAI, Ollama, Groq) usefill="currentColor"and vanish
on dark backgrounds. Fixed by pinning the logo wrapper to a
forced-white tile regardless of pack/tone. - Pill buttons touching. The
-ml-[1px]"shared border" trick
(a leftover from sharp-cornered Render styling) made the pill
buttons in NotebooksHeader and SettingsNav overlap. Replaced with
gap-2.
🎯 Brand mark + app icon
New app icon — saigon-accent green plate carrying a stack-of-books
glyph in black (the spirit of Material Symbols book_2, which is
what the in-app sidebar / dock / auth chrome / onboarding header all
use). Same composition now reads consistently across:
- Desktop installer + taskbar (
apps/desktop/build/icon.{png,ico,icns}) - Electron
BrowserWindow({ icon })at runtime - Web favicon (
apps/web/src/app/icon.tsx) - Apple Touch Icon (
apps/web/src/app/apple-icon.tsx)
Migration notes
- Two new
localStoragekeys are written:notebooklm-theme(existing,
unchanged) andnotebooklm-ds(new,"saigon" | "render",
default"saigon"). Existing users keep their tone preference and
start on Saigon. - Inter + JetBrains Mono replace Google Sans as the default fonts.
Loaded vianext/fonton web, Google Fonts CDN on desktop. - The token vocabulary is documented inline in
packages/ui/src/styles/tokens.css. New screens should import
from@notebooklm/ui/components/primitivesrather than rolling
their own<button>/<div>chrome. - The legacy Tailwind colour aliases (
bg-background-light,
bg-element-dark, etc.) have been removed from both apps'
@themeblocks. All call sites were migrated as part of the
same release — if you have an out-of-tree fork that still uses
them, swap in the new utilities (bg-canvas,bg-elevated,
border-border-subtle, …).
Commits
7b70ebd feat(brand): redesign app icon — bump 0.2.0
9c66d51 fix(desktop): ELECTRON_RUN_AS_NODE + electron-updater defer
c765aa6 feat(desktop): universal AppDock + named route components
b7250f2 feat(onboarding): 11 chat providers, 3 web-search providers
9b28f72 feat(settings): coding agents pane
57a71aa feat(settings): sidebar nav with grouped sections + status dots
5c922c7 refactor(ui): consume design tokens across every screen
053146d feat(ui): swappable design system foundation
Full diff: v0.1.24...v0.2.0