feat: add warm sand theme colors and light / dark mode toggle #302

Merged
talksik merged 2 commits from visual-flair into main 2026-06-21 17:56:59 +00:00
talksik commented 2026-06-21 17:27:32 +00:00 (Migrated from github.com)

Summary by CodeRabbit

  • New Features

    • Added theme selection: choose between Light, Dark, or System preference modes.
    • Added Appearance settings section to customize theme preference.
  • Style

    • Refreshed visual styling across the UI with improved consistency and dark/light mode support.
    • Updated component colors and contrast for better readability in both themes.
<!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added theme selection: choose between Light, Dark, or System preference modes. * Added Appearance settings section to customize theme preference. * **Style** * Refreshed visual styling across the UI with improved consistency and dark/light mode support. * Updated component colors and contrast for better readability in both themes. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
coderabbitai[bot] commented 2026-06-21 17:27:39 +00:00 (Migrated from github.com)

Review Change Stack

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Free

Run ID: c0f4c7ff-1991-4259-9161-11768e635159

📥 Commits

Reviewing files that changed from the base of the PR and between 3d80ac2993 and fdaa5ca255.

📒 Files selected for processing (43)
  • js/desktop/index.html
  • js/desktop/src/components/composing-indicator.tsx
  • js/desktop/src/components/confirm-destructive-overlay.tsx
  • js/desktop/src/components/key-hint.tsx
  • js/desktop/src/components/keybindings-overlay.tsx
  • js/desktop/src/components/link-preview-card.tsx
  • js/desktop/src/components/screen-source-picker.tsx
  • js/desktop/src/components/ui/dialog.tsx
  • js/desktop/src/components/ui/slider.tsx
  • js/desktop/src/components/ui/sonner.tsx
  • js/desktop/src/components/window-controls.tsx
  • js/desktop/src/features/attachments/attachment-lightbox.tsx
  • js/desktop/src/features/compose/attachment-strip.tsx
  • js/desktop/src/features/compose/compose-overlay.tsx
  • js/desktop/src/features/compose/configure-container-step.tsx
  • js/desktop/src/features/compose/markdown-editor.css
  • js/desktop/src/features/compose/recording-overlay.tsx
  • js/desktop/src/features/compose/task-compose-step.tsx
  • js/desktop/src/features/compose/text-editor.tsx
  • js/desktop/src/features/particles/container-view.tsx
  • js/desktop/src/features/particles/deleted-particle-view.tsx
  • js/desktop/src/features/particles/media-particle-view.tsx
  • js/desktop/src/features/particles/particle-attachments.tsx
  • js/desktop/src/features/particles/particle-children-list.tsx
  • js/desktop/src/features/particles/particle-preview.tsx
  • js/desktop/src/features/particles/particle-view-resolver.tsx
  • js/desktop/src/features/particles/playback-page-indicator.tsx
  • js/desktop/src/features/particles/reaction-bar.tsx
  • js/desktop/src/features/particles/rename-stream-overlay.tsx
  • js/desktop/src/features/particles/stream-bottom-bar.tsx
  • js/desktop/src/features/particles/stream-list-sidebar.tsx
  • js/desktop/src/features/particles/stream-members-overlay.tsx
  • js/desktop/src/features/particles/stream-top-bar.tsx
  • js/desktop/src/features/particles/stream-view.tsx
  • js/desktop/src/features/particles/task-particle-view.tsx
  • js/desktop/src/features/particles/text-particle-view.tsx
  • js/desktop/src/features/particles/text-reaction-input.tsx
  • js/desktop/src/features/settings-page.tsx
  • js/desktop/src/renderer.tsx
  • js/desktop/src/stores/theme-store.ts
  • js/desktop/src/styles/globals.css
  • js/desktop/src/web/index.html
  • js/desktop/src/web/renderer.tsx

📝 Walkthrough

Walkthrough

Introduces a Zustand-based theme store (light/dark/system) with localStorage persistence and OS preference sync via matchMedia. Adds pre-render inline scripts to both HTML entry points to avoid flash-of-wrong-theme. Replaces the hardcoded dark Tailwind palette with a new Warm Sand/Amber CSS token set and migrates all hardcoded bg-black/text-white classes to design-system tokens across ~40 files. Adds an Appearance settings section with a theme toggle.

Changes

Light/Dark/System Theme Switcher

Layer / File(s) Summary
Global CSS design tokens and palette
js/desktop/src/styles/globals.css
Replaces the monochrome :root/.dark palette with a Warm Sand/Amber token set, adds --scrim and four scrollbar CSS variables, and refactors scrollbar styling to reference those variables.
Zustand theme store with persistence and OS sync
js/desktop/src/stores/theme-store.ts, js/desktop/src/renderer.tsx, js/desktop/src/web/renderer.tsx
Creates ThemeMode type and useThemeStore with loadMode(), dark-class DOM toggling, a matchMedia change listener for system mode, and setMode() persisting to localStorage. Both renderer entry points import the store for module-level initialization.
Pre-render theme script in HTML entry points
js/desktop/index.html, js/desktop/src/web/index.html
Both HTML files replace the static <html class="dark"> with an inline head script that reads the stored theme, evaluates system preference, toggles the dark class before first paint, and falls back to dark on error.
Appearance settings section and theme picker
js/desktop/src/features/settings-page.tsx
Adds ThemeSetting with a ToggleGroup wired to useThemeStore/setMode for system/light/dark selection, inserts an "Appearance" SettingsGroup above Notifications, and updates the avatar overlay to the scrim token.
Toaster theme wired to store
js/desktop/src/components/ui/sonner.tsx
Toaster reads isDark from useThemeStore and passes a dynamic 'dark'/'light' value to Sonner instead of the previous hardcoded 'dark'.
Shared UI component token migration
js/desktop/src/components/key-hint.tsx, js/desktop/src/components/composing-indicator.tsx, js/desktop/src/components/confirm-destructive-overlay.tsx, js/desktop/src/components/keybindings-overlay.tsx, js/desktop/src/components/link-preview-card.tsx, js/desktop/src/components/screen-source-picker.tsx, js/desktop/src/components/ui/dialog.tsx, js/desktop/src/components/ui/slider.tsx, js/desktop/src/components/window-controls.tsx
All shared UI components replace hardcoded white/black opacity classes with design-system tokens (bg-card, bg-scrim, bg-popover, border-border, text-muted-foreground, bg-background, etc.).
Compose feature token migration
js/desktop/src/features/compose/markdown-editor.css, js/desktop/src/features/compose/text-editor.tsx, js/desktop/src/features/compose/attachment-strip.tsx, js/desktop/src/features/compose/compose-overlay.tsx, js/desktop/src/features/compose/configure-container-step.tsx, js/desktop/src/features/compose/task-compose-step.tsx, js/desktop/src/features/compose/recording-overlay.tsx
All compose-related components and the Milkdown Crepe CSS theme are migrated from hardcoded dark classes to design token–based Tailwind utilities; the Crepe palette switches from fixed RGBA/hex values to CSS variable references.
Particles feature token migration
js/desktop/src/features/particles/stream-view.tsx, js/desktop/src/features/particles/stream-list-sidebar.tsx, js/desktop/src/features/particles/stream-top-bar.tsx, js/desktop/src/features/particles/stream-bottom-bar.tsx, js/desktop/src/features/particles/reaction-bar.tsx, js/desktop/src/features/particles/task-particle-view.tsx, js/desktop/src/features/particles/text-particle-view.tsx, js/desktop/src/features/particles/text-reaction-input.tsx, js/desktop/src/features/particles/stream-members-overlay.tsx, js/desktop/src/features/particles/rename-stream-overlay.tsx, js/desktop/src/features/particles/playback-page-indicator.tsx, js/desktop/src/features/particles/particle-attachments.tsx, js/desktop/src/features/particles/particle-preview.tsx, js/desktop/src/features/particles/particle-children-list.tsx, js/desktop/src/features/particles/particle-view-resolver.tsx, js/desktop/src/features/particles/container-view.tsx, js/desktop/src/features/particles/deleted-particle-view.tsx, js/desktop/src/features/particles/media-particle-view.tsx, js/desktop/src/features/attachments/attachment-lightbox.tsx
All particle-related rendering components replace hardcoded bg-black/text-white/opacity classes with bg-background, bg-card, bg-scrim, bg-muted, text-muted-foreground, border-border, and related design tokens.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

🐇 Hop, hop — the rabbit flips the switch,
No more darkness baked in every niche!
A warm sand palette, amber-lit and bright,
--scrim, --card, --muted dancing right.
localStorage holds the bunny's choice,
System, light, or dark — now you have a voice! 🌙☀️


Note

🎁 Summarized by CodeRabbit Free

Your organization is on the Free plan. CodeRabbit will generate a high-level summary and a walkthrough for each pull request. For a comprehensive line-by-line review, please upgrade your subscription to CodeRabbit Pro by visiting https://app.coderabbit.ai/login.

Comment @coderabbitai help to get the list of available commands and usage tips.

<!-- This is an auto-generated comment: summarize by coderabbit.ai --> <!-- review_stack_entry_start --> [![Review Change Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](https://app.coderabbit.ai/change-stack/flowy-live/llink/pull/302?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack) <!-- review_stack_entry_end --> <details> <summary>ℹ️ Recent review info</summary> <details> <summary>⚙️ Run configuration</summary> **Configuration used**: defaults **Review profile**: CHILL **Plan**: Free **Run ID**: `c0f4c7ff-1991-4259-9161-11768e635159` </details> <details> <summary>📥 Commits</summary> Reviewing files that changed from the base of the PR and between 3d80ac2993ae4463318d0b46528dbc5c9a980d0c and fdaa5ca2551a1d337be6577215f48d9857041fd5. </details> <details> <summary>📒 Files selected for processing (43)</summary> * `js/desktop/index.html` * `js/desktop/src/components/composing-indicator.tsx` * `js/desktop/src/components/confirm-destructive-overlay.tsx` * `js/desktop/src/components/key-hint.tsx` * `js/desktop/src/components/keybindings-overlay.tsx` * `js/desktop/src/components/link-preview-card.tsx` * `js/desktop/src/components/screen-source-picker.tsx` * `js/desktop/src/components/ui/dialog.tsx` * `js/desktop/src/components/ui/slider.tsx` * `js/desktop/src/components/ui/sonner.tsx` * `js/desktop/src/components/window-controls.tsx` * `js/desktop/src/features/attachments/attachment-lightbox.tsx` * `js/desktop/src/features/compose/attachment-strip.tsx` * `js/desktop/src/features/compose/compose-overlay.tsx` * `js/desktop/src/features/compose/configure-container-step.tsx` * `js/desktop/src/features/compose/markdown-editor.css` * `js/desktop/src/features/compose/recording-overlay.tsx` * `js/desktop/src/features/compose/task-compose-step.tsx` * `js/desktop/src/features/compose/text-editor.tsx` * `js/desktop/src/features/particles/container-view.tsx` * `js/desktop/src/features/particles/deleted-particle-view.tsx` * `js/desktop/src/features/particles/media-particle-view.tsx` * `js/desktop/src/features/particles/particle-attachments.tsx` * `js/desktop/src/features/particles/particle-children-list.tsx` * `js/desktop/src/features/particles/particle-preview.tsx` * `js/desktop/src/features/particles/particle-view-resolver.tsx` * `js/desktop/src/features/particles/playback-page-indicator.tsx` * `js/desktop/src/features/particles/reaction-bar.tsx` * `js/desktop/src/features/particles/rename-stream-overlay.tsx` * `js/desktop/src/features/particles/stream-bottom-bar.tsx` * `js/desktop/src/features/particles/stream-list-sidebar.tsx` * `js/desktop/src/features/particles/stream-members-overlay.tsx` * `js/desktop/src/features/particles/stream-top-bar.tsx` * `js/desktop/src/features/particles/stream-view.tsx` * `js/desktop/src/features/particles/task-particle-view.tsx` * `js/desktop/src/features/particles/text-particle-view.tsx` * `js/desktop/src/features/particles/text-reaction-input.tsx` * `js/desktop/src/features/settings-page.tsx` * `js/desktop/src/renderer.tsx` * `js/desktop/src/stores/theme-store.ts` * `js/desktop/src/styles/globals.css` * `js/desktop/src/web/index.html` * `js/desktop/src/web/renderer.tsx` </details> </details> --- <!-- walkthrough_start --> <details> <summary>📝 Walkthrough</summary> ## Walkthrough Introduces a Zustand-based theme store (`light`/`dark`/`system`) with localStorage persistence and OS preference sync via `matchMedia`. Adds pre-render inline scripts to both HTML entry points to avoid flash-of-wrong-theme. Replaces the hardcoded dark Tailwind palette with a new Warm Sand/Amber CSS token set and migrates all hardcoded `bg-black`/`text-white` classes to design-system tokens across ~40 files. Adds an Appearance settings section with a theme toggle. ## Changes **Light/Dark/System Theme Switcher** | Layer / File(s) | Summary | |---|---| | **Global CSS design tokens and palette** <br> `js/desktop/src/styles/globals.css` | Replaces the monochrome `:root`/`.dark` palette with a Warm Sand/Amber token set, adds `--scrim` and four scrollbar CSS variables, and refactors scrollbar styling to reference those variables. | | **Zustand theme store with persistence and OS sync** <br> `js/desktop/src/stores/theme-store.ts`, `js/desktop/src/renderer.tsx`, `js/desktop/src/web/renderer.tsx` | Creates `ThemeMode` type and `useThemeStore` with `loadMode()`, dark-class DOM toggling, a `matchMedia` change listener for system mode, and `setMode()` persisting to localStorage. Both renderer entry points import the store for module-level initialization. | | **Pre-render theme script in HTML entry points** <br> `js/desktop/index.html`, `js/desktop/src/web/index.html` | Both HTML files replace the static `<html class="dark">` with an inline head script that reads the stored theme, evaluates system preference, toggles the `dark` class before first paint, and falls back to dark on error. | | **Appearance settings section and theme picker** <br> `js/desktop/src/features/settings-page.tsx` | Adds `ThemeSetting` with a `ToggleGroup` wired to `useThemeStore`/`setMode` for system/light/dark selection, inserts an "Appearance" `SettingsGroup` above Notifications, and updates the avatar overlay to the scrim token. | | **Toaster theme wired to store** <br> `js/desktop/src/components/ui/sonner.tsx` | `Toaster` reads `isDark` from `useThemeStore` and passes a dynamic `'dark'`/`'light'` value to Sonner instead of the previous hardcoded `'dark'`. | | **Shared UI component token migration** <br> `js/desktop/src/components/key-hint.tsx`, `js/desktop/src/components/composing-indicator.tsx`, `js/desktop/src/components/confirm-destructive-overlay.tsx`, `js/desktop/src/components/keybindings-overlay.tsx`, `js/desktop/src/components/link-preview-card.tsx`, `js/desktop/src/components/screen-source-picker.tsx`, `js/desktop/src/components/ui/dialog.tsx`, `js/desktop/src/components/ui/slider.tsx`, `js/desktop/src/components/window-controls.tsx` | All shared UI components replace hardcoded white/black opacity classes with design-system tokens (`bg-card`, `bg-scrim`, `bg-popover`, `border-border`, `text-muted-foreground`, `bg-background`, etc.). | | **Compose feature token migration** <br> `js/desktop/src/features/compose/markdown-editor.css`, `js/desktop/src/features/compose/text-editor.tsx`, `js/desktop/src/features/compose/attachment-strip.tsx`, `js/desktop/src/features/compose/compose-overlay.tsx`, `js/desktop/src/features/compose/configure-container-step.tsx`, `js/desktop/src/features/compose/task-compose-step.tsx`, `js/desktop/src/features/compose/recording-overlay.tsx` | All compose-related components and the Milkdown Crepe CSS theme are migrated from hardcoded dark classes to design token–based Tailwind utilities; the Crepe palette switches from fixed RGBA/hex values to CSS variable references. | | **Particles feature token migration** <br> `js/desktop/src/features/particles/stream-view.tsx`, `js/desktop/src/features/particles/stream-list-sidebar.tsx`, `js/desktop/src/features/particles/stream-top-bar.tsx`, `js/desktop/src/features/particles/stream-bottom-bar.tsx`, `js/desktop/src/features/particles/reaction-bar.tsx`, `js/desktop/src/features/particles/task-particle-view.tsx`, `js/desktop/src/features/particles/text-particle-view.tsx`, `js/desktop/src/features/particles/text-reaction-input.tsx`, `js/desktop/src/features/particles/stream-members-overlay.tsx`, `js/desktop/src/features/particles/rename-stream-overlay.tsx`, `js/desktop/src/features/particles/playback-page-indicator.tsx`, `js/desktop/src/features/particles/particle-attachments.tsx`, `js/desktop/src/features/particles/particle-preview.tsx`, `js/desktop/src/features/particles/particle-children-list.tsx`, `js/desktop/src/features/particles/particle-view-resolver.tsx`, `js/desktop/src/features/particles/container-view.tsx`, `js/desktop/src/features/particles/deleted-particle-view.tsx`, `js/desktop/src/features/particles/media-particle-view.tsx`, `js/desktop/src/features/attachments/attachment-lightbox.tsx` | All particle-related rendering components replace hardcoded `bg-black`/`text-white`/opacity classes with `bg-background`, `bg-card`, `bg-scrim`, `bg-muted`, `text-muted-foreground`, `border-border`, and related design tokens. | ## Estimated code review effort 🎯 4 (Complex) | ⏱️ ~60 minutes ## Poem > 🐇 Hop, hop — the rabbit flips the switch, > No more darkness baked in every niche! > A warm sand palette, amber-lit and bright, > `--scrim`, `--card`, `--muted` dancing right. > `localStorage` holds the bunny's choice, > System, light, or dark — now you have a voice! 🌙☀️ </details> <!-- walkthrough_end --> <!-- tips_start --> --- > [!NOTE] > <details> > <summary>🎁 Summarized by CodeRabbit Free</summary> > > Your organization is on the Free plan. CodeRabbit will generate a high-level summary and a walkthrough for each pull request. For a comprehensive line-by-line review, please upgrade your subscription to CodeRabbit Pro by visiting <https://app.coderabbit.ai/login>. > > </details> <sub>Comment `@coderabbitai help` to get the list of available commands and usage tips.</sub> <!-- tips_end -->
Sign in to join this conversation.