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 -->
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'.
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.
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 -->
[](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 -->
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Summary by CodeRabbit
New Features
Style
ℹ️ 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
3d80ac2993andfdaa5ca255.📒 Files selected for processing (43)
js/desktop/index.htmljs/desktop/src/components/composing-indicator.tsxjs/desktop/src/components/confirm-destructive-overlay.tsxjs/desktop/src/components/key-hint.tsxjs/desktop/src/components/keybindings-overlay.tsxjs/desktop/src/components/link-preview-card.tsxjs/desktop/src/components/screen-source-picker.tsxjs/desktop/src/components/ui/dialog.tsxjs/desktop/src/components/ui/slider.tsxjs/desktop/src/components/ui/sonner.tsxjs/desktop/src/components/window-controls.tsxjs/desktop/src/features/attachments/attachment-lightbox.tsxjs/desktop/src/features/compose/attachment-strip.tsxjs/desktop/src/features/compose/compose-overlay.tsxjs/desktop/src/features/compose/configure-container-step.tsxjs/desktop/src/features/compose/markdown-editor.cssjs/desktop/src/features/compose/recording-overlay.tsxjs/desktop/src/features/compose/task-compose-step.tsxjs/desktop/src/features/compose/text-editor.tsxjs/desktop/src/features/particles/container-view.tsxjs/desktop/src/features/particles/deleted-particle-view.tsxjs/desktop/src/features/particles/media-particle-view.tsxjs/desktop/src/features/particles/particle-attachments.tsxjs/desktop/src/features/particles/particle-children-list.tsxjs/desktop/src/features/particles/particle-preview.tsxjs/desktop/src/features/particles/particle-view-resolver.tsxjs/desktop/src/features/particles/playback-page-indicator.tsxjs/desktop/src/features/particles/reaction-bar.tsxjs/desktop/src/features/particles/rename-stream-overlay.tsxjs/desktop/src/features/particles/stream-bottom-bar.tsxjs/desktop/src/features/particles/stream-list-sidebar.tsxjs/desktop/src/features/particles/stream-members-overlay.tsxjs/desktop/src/features/particles/stream-top-bar.tsxjs/desktop/src/features/particles/stream-view.tsxjs/desktop/src/features/particles/task-particle-view.tsxjs/desktop/src/features/particles/text-particle-view.tsxjs/desktop/src/features/particles/text-reaction-input.tsxjs/desktop/src/features/settings-page.tsxjs/desktop/src/renderer.tsxjs/desktop/src/stores/theme-store.tsjs/desktop/src/styles/globals.cssjs/desktop/src/web/index.htmljs/desktop/src/web/renderer.tsx📝 Walkthrough
Walkthrough
Introduces a Zustand-based theme store (
light/dark/system) with localStorage persistence and OS preference sync viamatchMedia. 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 hardcodedbg-black/text-whiteclasses to design-system tokens across ~40 files. Adds an Appearance settings section with a theme toggle.Changes
Light/Dark/System Theme Switcher
js/desktop/src/styles/globals.css:root/.darkpalette with a Warm Sand/Amber token set, adds--scrimand four scrollbar CSS variables, and refactors scrollbar styling to reference those variables.js/desktop/src/stores/theme-store.ts,js/desktop/src/renderer.tsx,js/desktop/src/web/renderer.tsxThemeModetype anduseThemeStorewithloadMode(), dark-class DOM toggling, amatchMediachange listener for system mode, andsetMode()persisting to localStorage. Both renderer entry points import the store for module-level initialization.js/desktop/index.html,js/desktop/src/web/index.html<html class="dark">with an inline head script that reads the stored theme, evaluates system preference, toggles thedarkclass before first paint, and falls back to dark on error.js/desktop/src/features/settings-page.tsxThemeSettingwith aToggleGroupwired touseThemeStore/setModefor system/light/dark selection, inserts an "Appearance"SettingsGroupabove Notifications, and updates the avatar overlay to the scrim token.js/desktop/src/components/ui/sonner.tsxToasterreadsisDarkfromuseThemeStoreand passes a dynamic'dark'/'light'value to Sonner instead of the previous hardcoded'dark'.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.tsxbg-card,bg-scrim,bg-popover,border-border,text-muted-foreground,bg-background, etc.).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.tsxjs/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.tsxbg-black/text-white/opacity classes withbg-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
Comment
@coderabbitai helpto get the list of available commands and usage tips.