Skip to content

feat: add light mode theme support#258

Merged
webadderall merged 3 commits intomainfrom
feat/light-mode
Apr 18, 2026
Merged

feat: add light mode theme support#258
webadderall merged 3 commits intomainfrom
feat/light-mode

Conversation

@webadderall
Copy link
Copy Markdown
Collaborator

@webadderall webadderall commented Apr 18, 2026

Summary

Adds a complete light mode theme to Recordly with system preference detection and manual toggle support.

Changes

Infrastructure

  • tailwind.config.cjs: Extended with theme color tokens (foreground, surface, border, muted, etc.)
  • src/index.css: CSS custom properties defining light and dark palettes via [data-theme] attribute
  • src/main.tsx / src/App.tsx: ThemeContext provider with prefers-color-scheme detection

UI Components (32 files)

  • Replaced hardcoded dark colors (text-white, bg-zinc-900, border-white/10, etc.) with theme-aware equivalents (text-foreground, bg-surface, border-border)
  • Updated all editor panels: SettingsPanel, ExportSettingsMenu, PlaybackControls, AnnotationSettingsPanel, etc.
  • Updated all dialogs: ProjectBrowserDialog, ShortcutsConfigDialog, AddCustomFontDialog, TutorialHelp, etc.
  • Updated timeline: TimelineEditor, Row, Subrow, Track, Item, ItemGlass.module.css, Timeline.module.css
  • Updated UI primitives: accordion, switch, slider, sonner

What's NOT changed

  • Export pipeline and video processing (no functional changes)
  • Electron main process / IPC layer

Summary by CodeRabbit

  • New Features

    • Added an app-wide theme provider and an Appearance setting with Light / Dark / System theme selector.
  • Style

    • Unified UI styling to theme tokens for consistent light/dark visuals.
    • Updated dialogs, panels, sliders, timeline, playback/controls, and editor surfaces to respect the selected theme for more cohesive appearance.

Add a complete light mode theme with a ThemeContext and CSS custom properties
for all UI surfaces. Replaces hardcoded dark colors with theme-aware
equivalents across 32 files including:

- Tailwind config extended with theme color tokens
- CSS custom properties for light/dark palettes in index.css
- ThemeContext provider in App.tsx with system preference detection
- All editor panels, dialogs, timeline, and settings updated to use
  theme-aware classes (text-foreground, bg-surface, border-border, etc.)
- Timeline glass effects and module CSS updated for both modes
- UI primitives (accordion, switch, slider, sonner) themed
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 18, 2026

Warning

.coderabbit.yaml has a parsing error

The CodeRabbit configuration file in this repository has a parsing error and default settings were used instead. Please fix the error(s) in the configuration file. You can initialize chat with CodeRabbit to get help with the configuration file.

💥 Parsing errors (1)
Validation error: Invalid regex pattern for base branch. Received: "*" at "reviews.auto_review.base_branches[0]"
⚙️ Configuration instructions
  • Please see the configuration documentation for more information.
  • You can also validate your configuration using the online YAML validator.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json
📝 Walkthrough

Walkthrough

Adds a ThemeProvider with persistent theme preference and system sync, introduces editor CSS variables and Tailwind editor color tokens, wires the provider into app bootstrap, and replaces many hardcoded color utilities across UI/editor components; also removes explicit Sonner/Toaster theme props and uses CSS var for thumbnail canvas fallback.

Changes

Cohort / File(s) Summary
Theme infra & bootstrap
src/contexts/ThemeContext.tsx, src/main.tsx, src/index.css, tailwind.config.cjs
Added ThemeProvider + useTheme(), persisted recordly.theme, applied/resolved theme to DOM, added editor CSS custom properties and slider vars, and registered Tailwind editor color tokens.
App & Toaster usages
src/App.tsx, src/components/ui/sonner.tsx, src/components/video-editor/VideoEditor.tsx
Removed explicit theme props from Sonner/Toaster, adjusted root/container token classes, and read --editor-bg for thumbnail canvas fallback.
UI primitives
src/components/ui/accordion.tsx, src/components/ui/item-content.tsx, src/components/ui/slider.tsx, src/components/ui/switch.tsx
Replaced hardcoded slate/white classes with theme tokens (foreground, muted-foreground, background, etc.) for borders, text, tracks, thumbs.
Dialogs & shared controls
src/components/video-editor/AddCustomFontDialog.tsx, src/components/video-editor/ShortcutsConfigDialog.tsx, src/components/video-editor/ProjectBrowserDialog.tsx
Swapped dialog/card/input/button classes to use editor/tokenized colors and muted-foreground for helper text instead of hex/slate hardcoding.
Settings & appearance
src/components/video-editor/SettingsPanel.tsx
Wired useTheme() into SettingsPanel, added Appearance (Light/Dark/System) controls, and tokenized many panel styles and controls.
Export/Format & manager components
src/components/video-editor/ExportSettingsMenu.tsx, src/components/video-editor/FormatSelector.tsx, src/components/video-editor/ExtensionManager.tsx
Converted option/button/card styling to theme tokens, adjusted active/inactive/hover color mappings and focus-ring usage.
Playback, sliders & controls
src/components/video-editor/PlaybackControls.tsx, src/components/video-editor/SliderControl.tsx, src/components/video-editor/GifOptionsPanel.tsx
Updated play/pause, seek/volume, and slider visuals to use foreground-based tokens for tracks, thumbs, icons, and helper text.
Annotation & editor panels
src/components/video-editor/AnnotationOverlay.tsx, src/components/video-editor/AnnotationSettingsPanel.tsx
Replaced hardcoded background/text/border classes with editor token classes across annotation UI and empty-state text.
Help, tutorial & dialogs
src/components/video-editor/TutorialHelp.tsx, src/components/video-editor/KeyboardShortcutsHelp.tsx
Tokenized dialog/tooltips, button class constants, and instructional UI colors to bg-editor-dialog, text-foreground, text-muted-foreground, and border-foreground/*.
Timeline & track styling
src/components/video-editor/timeline/... (Item.tsx, ItemGlass.module.css, Row.tsx, Subrow.tsx, Timeline.module.css, TimelineEditor.tsx, TimelineWrapper.tsx, Track.tsx)
Removed inline color overrides and hardcoded backgrounds, updated glass palettes (with light-mode overrides), scrollbar and gridline colors to use HSL/CSS vars and theme tokens, adjusted text tokens for light/dark modes.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant App as App / Main
    participant Theme as ThemeProvider
    participant DOM as document.documentElement
    participant Toaster as Sonner/Toaster
    participant Editor as VideoEditor

    User->>App: load
    App->>Theme: mount ThemeProvider
    Theme->>Theme: read localStorage (recordly.theme)
    Theme->>Theme: resolve preference (light|dark|system)
    Theme->>DOM: set dataset.theme & toggle "dark" class
    Theme->>App: provide theme context
    App->>Toaster: render (no explicit theme prop)
    App->>Editor: render
    Editor->>DOM: read --editor-bg for thumbnail fallback
    Note over Theme,DOM: matchMedia listener registered when pref=system
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • webadderall/Recordly#246: Overlaps on Sonner/Toaster theming, ThemeProvider integration, Tailwind/CSS variable edits, and many identical UI component token substitutions.
  • webadderall/Recordly#249: Modifies SettingsPanel.tsx and settings UI; strongly related to the new Appearance/theme controls.
  • webadderall/Recordly#248: Edits the same timeline files (Item, ItemGlass, Row, TimelineEditor, etc.) with styling and light/dark background changes.

Suggested labels

Checked

🐰
I hopped through tokens, classes, and light,
Swapped hard whites for variables bright.
Theme set, localStorage kept in sight,
Now day and night can gracefully unite. ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 19.05% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the main feature: adding light mode theme support to the application.
Description check ✅ Passed The description provides motivation, changes overview across infrastructure and UI components, and clearly states what was not changed, though some template sections are missing.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/light-mode

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 11

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (4)
src/components/video-editor/PlaybackControls.tsx (1)

44-124: ⚠️ Potential issue | 🟠 Major

Make the playback container theme-aware too.

Line 44 keeps the pill fixed dark, but the child text/icons/thumbs now use light-theme foreground/muted-foreground tokens. In light mode that makes several controls render dark-on-dark. Either keep the whole overlay light-on-dark, or make the container use the same theme surface tokens.

🎨 Proposed fix
-		<div className="flex items-center gap-2 px-1.5 pr-3 py-0.5 rounded-full bg-black/75 backdrop-blur-md border border-foreground/10 transition-colors duration-300 hover:bg-black/80 hover:border-white/20">
+		<div className="flex items-center gap-2 px-1.5 pr-3 py-0.5 rounded-full bg-background/75 backdrop-blur-md border border-foreground/10 transition-colors duration-300 hover:bg-background/80 hover:border-foreground/20">
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/video-editor/PlaybackControls.tsx` around lines 44 - 124, The
outer playback container currently hardcodes a dark background ("bg-black/75")
causing mismatched contrast with child tokens; update the top-level wrapper (the
div with className starting "flex items-center..." in PlaybackControls.tsx) to
use the app's theme surface/background tokens (e.g., bg-surface or bg-background
with appropriate opacity) and matching border tokens instead of hardcoded black
and hover styles so the overlay follows light/dark theming and remains readable
with children using foreground/muted-foreground; keep the same layout classes
and transitions, only swap the color utility classes (including hover:border and
hover:bg variants) to their theme equivalents so it behaves correctly in both
themes.
src/components/video-editor/timeline/TimelineEditor.tsx (1)

2006-2020: ⚠️ Potential issue | 🟡 Minor

Tokenize the custom aspect-ratio inputs.

These inputs still use dark-only border-white/15 bg-black/20, which looks out of place and can lose border contrast in light mode.

Suggested fix
-											className="w-12 h-7 rounded border border-white/15 bg-black/20 px-1.5 text-sm text-foreground focus:outline-none focus:ring-1 focus:ring-[`#2563EB`]"
+											className="w-12 h-7 rounded border border-foreground/10 bg-foreground/5 px-1.5 text-sm text-foreground focus:outline-none focus:ring-1 focus:ring-[`#2563EB`]"
...
-											className="w-12 h-7 rounded border border-white/15 bg-black/20 px-1.5 text-sm text-foreground focus:outline-none focus:ring-1 focus:ring-[`#2563EB`]"
+											className="w-12 h-7 rounded border border-foreground/10 bg-foreground/5 px-1.5 text-sm text-foreground focus:outline-none focus:ring-1 focus:ring-[`#2563EB`]"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/video-editor/timeline/TimelineEditor.tsx` around lines 2006 -
2020, The two custom aspect ratio inputs (the input elements tied to
customAspectWidth and customAspectHeight and using setCustomAspectHeight and
handleCustomAspectRatioKeyDown) use dark-only utility classes ("border-white/15
bg-black/20") which lose contrast in light mode; update their className to
theme-aware tokens (e.g., neutral/semantic tokens or paired light/dark classes
such as border-[light-token] dark:border-white/15 and bg-[light-token]
dark:bg-black/20 or replace with design-system tokens like border-border and
bg-background) so the border and background render with proper contrast in both
light and dark themes while keeping the existing sizing and focus ring styles
intact.
src/components/video-editor/SettingsPanel.tsx (1)

1452-1465: ⚠️ Potential issue | 🟠 Major

Do not use text-foreground on fixed accent backgrounds.

These controls use fixed blue/red fills, but text-foreground becomes dark in light mode. That makes active/hover labels and remove icons low-contrast; keep fixed white text on fixed accent colors.

🎨 Proposed fix
-												? "text-foreground"
+												? "text-white"
 												: "text-muted-foreground hover:text-foreground",
-										className="w-full gap-2 bg-foreground/5 text-foreground border-foreground/10 hover:bg-[`#2563EB`] hover:text-foreground hover:border-[`#2563EB`] transition-all h-7 text-[10px]"
+										className="w-full gap-2 bg-foreground/5 text-foreground border-foreground/10 hover:bg-[`#2563EB`] hover:text-white hover:border-[`#2563EB`] transition-all h-7 text-[10px]"
-														<X className="w-2 h-2 text-foreground" />
+														<X className="w-2 h-2 text-white" />

Apply the same upload-button and remove-icon changes in both image and video sections.

Also applies to: 1497-1497, 1524-1527, 1555-1555, 1584-1587

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/video-editor/SettingsPanel.tsx` around lines 1452 - 1465, The
active/hover labels and remove icons in SettingsPanel are using
"text-foreground" on fixed blue/red accent backgrounds which produces low
contrast in light mode; update the span and related upload-button/remove-icon
class usages (look for the cn(...) conditional around "relative z-10" and the
upload-button/remove-icon elements in both image and video sections) to use a
fixed white text class (e.g. "text-white" or your design system's on-accent
class) instead of "text-foreground" for the isActive and hover states, and make
the same replacement in the other occurrences referenced (lines near the
upload-button/remove-icon in both image and video blocks).
src/components/video-editor/ExportSettingsMenu.tsx (1)

97-105: ⚠️ Potential issue | 🟠 Major

Fix active MP4/GIF toggle contrast in light mode.

The active pill only paints bg-[#2563EB]/10, so text-white becomes nearly invisible on the light theme. Match the selected text to the blue accent for light mode.

🎨 Proposed fix
 									isActive
-										? "border-[`#2563EB`]/50 text-white"
+										? "border-[`#2563EB`]/50 text-[`#2563EB`] dark:text-white"
 										: "border-foreground/10 bg-foreground/5 text-muted-foreground hover:bg-foreground/10 hover:text-foreground",
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/video-editor/ExportSettingsMenu.tsx` around lines 97 - 105,
The active toggle pill in ExportSettingsMenu uses isActive to apply "text-white"
which is unreadable in light mode; update the class for the active branch (the
ternary that currently yields "border-[`#2563EB`]/50 text-white") to set the
selected text color to the blue accent in light mode and keep white in dark mode
(e.g., replace "text-white" with "text-[`#2563EB`] dark:text-white" or
equivalent). Also ensure the motion.span with layoutId
"header-export-format-pill" and its "bg-[`#2563EB`]/10" background remain
unchanged so the pill background and text contrast correctly across themes.
🧹 Nitpick comments (3)
src/components/video-editor/timeline/ItemGlass.module.css (1)

176-280: Light-mode overrides look correct; stylelint warnings are false positives for CSS Modules.

The :global(:root:not(.dark)) pattern is valid CSS Modules syntax and is the right way to reach the document root from a scoped module. Stylelint's 23 selector-pseudo-class-no-unknown warnings on lines 177–278 are noise — consider whitelisting :global/:local in stylelint config so this file stays clean.

Suggested stylelint rule tweak
// .stylelintrc(.json) or equivalent
{
  "rules": {
    "selector-pseudo-class-no-unknown": [true, { "ignorePseudoClasses": ["global", "local"] }]
  }
}

One substantive note: .glassGreen and .glassCyan share identical dark and light palettes (lines 4-5/114-115 and 177-189/247-259). If that's intentional (the two variants should look the same), consider collapsing them to a shared class to avoid drift; if not, the cyan variant likely wants a cyan palette.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/video-editor/timeline/ItemGlass.module.css` around lines 176 -
280, Stylelint is flagging valid CSS Modules pseudo-classes :global/:local;
update the stylelint config rule selector-pseudo-class-no-unknown to ignore
"global" and "local" (so files like ItemGlass.module.css with selectors
:global(:root:not(.dark)) no longer produce noise), and as a separate optional
cleanup decide whether to deduplicate identical palettes by collapsing
.glassGreen and .glassCyan into a shared class (or adjust .glassCyan to use
distinct cyan colors) to prevent future drift; target the selectors .glassGreen,
.glassCyan and the stylelint rule selector-pseudo-class-no-unknown when applying
these changes.
src/components/ui/slider.tsx (1)

15-18: Range/thumb still hardcoded to brand blue — intentional?

Track now themes via bg-foreground/10, but Range and Thumb on lines 16–18 keep hardcoded #2563EB. That's consistent with --brand-accent in index.css, so it's fine — just noting you could swap them for bg-[hsl(var(--primary))] / border-primary to make future accent changes a one-liner.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/ui/slider.tsx` around lines 15 - 18, Slider's Range and Thumb
are using hardcoded `#2563EB` which breaks theming; update the class names on
SliderPrimitive.Range and SliderPrimitive.Thumb to use the theme variables
instead (e.g., replace the hardcoded bg and border values with the project
accent tokens such as bg-[hsl(var(--primary))] for the Range and bg-primary /
border-primary (or equivalent CSS variable/token used in index.css) for the
Thumb) so accent changes are applied globally; ensure the focus and ring
utilities still reference the token (e.g., ring-[color]/50) to preserve
accessibility styles.
src/components/video-editor/KeyboardShortcutsHelp.tsx (1)

48-48: Use a foreground-based kbd background for light mode.

bg-white/5 becomes effectively invisible on light dialog surfaces. bg-foreground/5 matches the tokenized pattern used elsewhere in the PR.

Suggested update
-							<kbd className="px-1 py-0.5 bg-white/5 border border-foreground/10 rounded text-[`#2563EB`] font-mono">
+							<kbd className="px-1 py-0.5 bg-foreground/5 border border-foreground/10 rounded text-[`#2563EB`] font-mono">
...
-							<kbd className="px-1 py-0.5 bg-white/5 border border-foreground/10 rounded text-[`#2563EB`] font-mono">
+							<kbd className="px-1 py-0.5 bg-foreground/5 border border-foreground/10 rounded text-[`#2563EB`] font-mono">
...
-							<kbd className="px-1 py-0.5 bg-white/5 border border-foreground/10 rounded text-[`#2563EB`] font-mono">
+							<kbd className="px-1 py-0.5 bg-foreground/5 border border-foreground/10 rounded text-[`#2563EB`] font-mono">
...
-							<kbd className="px-1 py-0.5 bg-white/5 border border-foreground/10 rounded text-[`#2563EB`] font-mono">
+							<kbd className="px-1 py-0.5 bg-foreground/5 border border-foreground/10 rounded text-[`#2563EB`] font-mono">

Also applies to: 59-59, 67-67, 75-75

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/video-editor/KeyboardShortcutsHelp.tsx` at line 48, Replace
the light-mode-specific background token on the inline <kbd> elements in the
KeyboardShortcutsHelp component: change any className using "bg-white/5" to use
the foreground-based token "bg-foreground/5" instead so the keycaps remain
visible on light dialog surfaces; update all occurrences referenced (the <kbd>
in KeyboardShortcutsHelp.tsx at the noted spots) so they follow the same pattern
used elsewhere in the PR.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/components/video-editor/AnnotationSettingsPanel.tsx`:
- Line 509: The hover state currently sets hover:text-foreground which yields
dark text on the blue background in light mode; in AnnotationSettingsPanel.tsx
update the element with the className string containing "hover:bg-[`#2563EB`]
hover:text-foreground hover:border-[`#2563EB`]" to use white text on hover
(replace hover:text-foreground with hover:text-white) so the blue hover
background always displays white text.

In `@src/components/video-editor/ExtensionManager.tsx`:
- Around line 616-617: The active tab pill's badge uses "bg-foreground/20
text-foreground" which makes the count unreadable on the blue parent; update the
active-branch class so the badge uses a high-contrast text token (for example
replace "text-foreground" with "text-muted-foreground" or your project's
inverted/contrast text token) instead of text-foreground in the expression that
currently yields "bg-foreground/20 text-foreground" in ExtensionManager.tsx so
the badge remains readable on the blue pill.

In `@src/components/video-editor/FormatSelector.tsx`:
- Around line 54-56: The selected option uses a fixed "text-white" which is
unreadable on the very light selected background in light mode; update the class
string in FormatSelector (where the ternary returns the selected classes) to use
a theme-aware color such as "text-blue-600 dark:text-white" (or similar tailwind
dark: utility) instead of plain "text-white" so the label is blue in light mode
and remains white in dark mode.

In `@src/components/video-editor/ProjectBrowserDialog.tsx`:
- Line 203: The placeholder uses a fixed dark gradient but the class
text-muted-foreground changes with theme, which can make the muted text too dark
in light mode; update the two placeholder divs in ProjectBrowserDialog (the JSX
fragment containing the class string with bg-[linear-gradient(...)] and
text-muted-foreground at the locations referenced) to use a fixed light text
color (e.g., text-white or text-neutral-100) instead of text-muted-foreground,
or alternatively make the gradient theme-aware—apply the same change to both
placeholder branches so both use the consistent readable color.

In `@src/components/video-editor/SettingsPanel.tsx`:
- Around line 663-666: The dot preview in SettingsPanel currently uses the
theme-dependent class border-foreground and disappears in dark mode; replace
border-foreground on the span returned in the style === "dot" branch with a
fixed contrasting Tailwind border class (e.g., border-neutral-800 or
border-gray-900) so the 2.5px border remains visible against the white fill in
all themes; update the JSX span (the element returned when style === "dot") to
use the chosen fixed border class instead of border-foreground.
- Line 31: Create the missing ThemeContext module so imports used by
SettingsPanel and main.tsx resolve: implement and export a ThemeProvider
component and a useTheme hook in src/contexts/ThemeContext.tsx (matching the
names imported: ThemeProvider and useTheme) that provide theme state and updater
functions used by SettingsPanel; ensure the provider wraps children and that
useTheme returns the context value (so SettingsPanel and main.tsx can import and
use ThemeProvider/useTheme without build errors).

In `@src/components/video-editor/timeline/TimelineEditor.tsx`:
- Line 404: The tooltip’s text color on the timestamp div in TimelineEditor.tsx
uses text-foreground/90 which can be dark in light mode; replace that token with
a light text token (e.g., text-white or text-white/90) on the absolute timestamp
div (the element with classes starting "absolute -top-6 left-1/2 ...") so the
text remains readable on the bg-black/80 overlay; alternatively, if you need
theme-aware behavior, conditionally apply text-white for light theme and keep
text-foreground/90 for dark theme in the same element (use the surrounding
theme/state to toggle the class).

In `@src/components/video-editor/TutorialHelp.tsx`:
- Line 191: Replace the hardcoded "bg-black/20" on the keyboard shortcut chips
with a theme-aware background token (e.g., "bg-foreground/10" or your design
system's dedicated token) so the <kbd> chips keep consistent contrast in light
and dark modes; update all instances of the <kbd className="rounded border
border-foreground/10 bg-black/20 px-2 py-1 font-mono text-[`#2563EB`]"> pattern
(the four <kbd> elements shown around lines 191, 199, 205, 211) to use the
chosen token and keep the rest of the classes unchanged.
- Line 83: The DialogContent className contains a malformed Tailwind arbitrary
variant (the token `[[&>button:hover]:text-white>button:hover]:text-foreground`)
so the close button hover color never becomes text-foreground; update the
className on the DialogContent elements in TutorialHelp.tsx (the instances that
use max-w-lg and max-w-2xl) to use valid Tailwind selectors such as combining
the base and hover variants separately — e.g. keep "bg-editor-dialog
border-foreground/10 [&>button]:text-muted-foreground" and add a proper hover
rule "[&>button:hover]:text-foreground" (remove the invalid embedded :text-white
part), and apply this same fix to all three DialogContent occurrences.

In `@src/components/video-editor/VideoEditor.tsx`:
- Line 4258: Create a new ThemeContext that exports ThemeProvider and useTheme
to fix the missing module and enable dark-mode toggling: implement a React
context (e.g., ThemeContext) that holds current theme state (light/dark), a
toggleTheme function, and a hook useTheme to consume it; in ThemeProvider
add/remove the "dark" class on document.documentElement when theme changes and
persist the choice to localStorage on set, initializing from localStorage or
system preference on mount; ensure ThemeProvider wraps the app (matching the
imported ThemeProvider in main.tsx) so components like SettingsPanel can call
useTheme to toggle theme and thus activate the Tailwind dark: variants.

In `@src/index.css`:
- Around line 62-64: The root-level timeline color tokens (--editor-timeline,
--editor-row, --editor-subrow) are set to the same dark HSL values as the .dark
block so light mode surfaces remain dark and conflict with theme-aware
foregrounds; update :root to use light-mode HSL values (or pick explicit
foreground pairing) for --editor-timeline/--editor-row/--editor-subrow so
bg-editor-timeline/bg-editor-row/bg-editor-subrow produce readable light-mode
backgrounds, or if the timeline must stay dark keep the dark token values but
change the timeline components (e.g., Subrow.tsx which uses text-foreground/60)
to use a fixed light-on-dark foreground instead of --foreground so contrast
remains correct.

---

Outside diff comments:
In `@src/components/video-editor/ExportSettingsMenu.tsx`:
- Around line 97-105: The active toggle pill in ExportSettingsMenu uses isActive
to apply "text-white" which is unreadable in light mode; update the class for
the active branch (the ternary that currently yields "border-[`#2563EB`]/50
text-white") to set the selected text color to the blue accent in light mode and
keep white in dark mode (e.g., replace "text-white" with "text-[`#2563EB`]
dark:text-white" or equivalent). Also ensure the motion.span with layoutId
"header-export-format-pill" and its "bg-[`#2563EB`]/10" background remain
unchanged so the pill background and text contrast correctly across themes.

In `@src/components/video-editor/PlaybackControls.tsx`:
- Around line 44-124: The outer playback container currently hardcodes a dark
background ("bg-black/75") causing mismatched contrast with child tokens; update
the top-level wrapper (the div with className starting "flex items-center..." in
PlaybackControls.tsx) to use the app's theme surface/background tokens (e.g.,
bg-surface or bg-background with appropriate opacity) and matching border tokens
instead of hardcoded black and hover styles so the overlay follows light/dark
theming and remains readable with children using foreground/muted-foreground;
keep the same layout classes and transitions, only swap the color utility
classes (including hover:border and hover:bg variants) to their theme
equivalents so it behaves correctly in both themes.

In `@src/components/video-editor/SettingsPanel.tsx`:
- Around line 1452-1465: The active/hover labels and remove icons in
SettingsPanel are using "text-foreground" on fixed blue/red accent backgrounds
which produces low contrast in light mode; update the span and related
upload-button/remove-icon class usages (look for the cn(...) conditional around
"relative z-10" and the upload-button/remove-icon elements in both image and
video sections) to use a fixed white text class (e.g. "text-white" or your
design system's on-accent class) instead of "text-foreground" for the isActive
and hover states, and make the same replacement in the other occurrences
referenced (lines near the upload-button/remove-icon in both image and video
blocks).

In `@src/components/video-editor/timeline/TimelineEditor.tsx`:
- Around line 2006-2020: The two custom aspect ratio inputs (the input elements
tied to customAspectWidth and customAspectHeight and using setCustomAspectHeight
and handleCustomAspectRatioKeyDown) use dark-only utility classes
("border-white/15 bg-black/20") which lose contrast in light mode; update their
className to theme-aware tokens (e.g., neutral/semantic tokens or paired
light/dark classes such as border-[light-token] dark:border-white/15 and
bg-[light-token] dark:bg-black/20 or replace with design-system tokens like
border-border and bg-background) so the border and background render with proper
contrast in both light and dark themes while keeping the existing sizing and
focus ring styles intact.

---

Nitpick comments:
In `@src/components/ui/slider.tsx`:
- Around line 15-18: Slider's Range and Thumb are using hardcoded `#2563EB` which
breaks theming; update the class names on SliderPrimitive.Range and
SliderPrimitive.Thumb to use the theme variables instead (e.g., replace the
hardcoded bg and border values with the project accent tokens such as
bg-[hsl(var(--primary))] for the Range and bg-primary / border-primary (or
equivalent CSS variable/token used in index.css) for the Thumb) so accent
changes are applied globally; ensure the focus and ring utilities still
reference the token (e.g., ring-[color]/50) to preserve accessibility styles.

In `@src/components/video-editor/KeyboardShortcutsHelp.tsx`:
- Line 48: Replace the light-mode-specific background token on the inline <kbd>
elements in the KeyboardShortcutsHelp component: change any className using
"bg-white/5" to use the foreground-based token "bg-foreground/5" instead so the
keycaps remain visible on light dialog surfaces; update all occurrences
referenced (the <kbd> in KeyboardShortcutsHelp.tsx at the noted spots) so they
follow the same pattern used elsewhere in the PR.

In `@src/components/video-editor/timeline/ItemGlass.module.css`:
- Around line 176-280: Stylelint is flagging valid CSS Modules pseudo-classes
:global/:local; update the stylelint config rule
selector-pseudo-class-no-unknown to ignore "global" and "local" (so files like
ItemGlass.module.css with selectors :global(:root:not(.dark)) no longer produce
noise), and as a separate optional cleanup decide whether to deduplicate
identical palettes by collapsing .glassGreen and .glassCyan into a shared class
(or adjust .glassCyan to use distinct cyan colors) to prevent future drift;
target the selectors .glassGreen, .glassCyan and the stylelint rule
selector-pseudo-class-no-unknown when applying these changes.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 81b483ab-2b3d-442e-9ab4-bcc0b07e0366

📥 Commits

Reviewing files that changed from the base of the PR and between 12d7608 and aecefd6.

📒 Files selected for processing (32)
  • src/App.tsx
  • src/components/ui/accordion.tsx
  • src/components/ui/item-content.tsx
  • src/components/ui/slider.tsx
  • src/components/ui/sonner.tsx
  • src/components/ui/switch.tsx
  • src/components/video-editor/AddCustomFontDialog.tsx
  • src/components/video-editor/AnnotationOverlay.tsx
  • src/components/video-editor/AnnotationSettingsPanel.tsx
  • src/components/video-editor/ExportSettingsMenu.tsx
  • src/components/video-editor/ExtensionManager.tsx
  • src/components/video-editor/FormatSelector.tsx
  • src/components/video-editor/GifOptionsPanel.tsx
  • src/components/video-editor/KeyboardShortcutsHelp.tsx
  • src/components/video-editor/PlaybackControls.tsx
  • src/components/video-editor/ProjectBrowserDialog.tsx
  • src/components/video-editor/SettingsPanel.tsx
  • src/components/video-editor/ShortcutsConfigDialog.tsx
  • src/components/video-editor/SliderControl.tsx
  • src/components/video-editor/TutorialHelp.tsx
  • src/components/video-editor/VideoEditor.tsx
  • src/components/video-editor/timeline/Item.tsx
  • src/components/video-editor/timeline/ItemGlass.module.css
  • src/components/video-editor/timeline/Row.tsx
  • src/components/video-editor/timeline/Subrow.tsx
  • src/components/video-editor/timeline/Timeline.module.css
  • src/components/video-editor/timeline/TimelineEditor.tsx
  • src/components/video-editor/timeline/TimelineWrapper.tsx
  • src/components/video-editor/timeline/Track.tsx
  • src/index.css
  • src/main.tsx
  • tailwind.config.cjs
💤 Files with no reviewable changes (1)
  • src/components/ui/sonner.tsx

Comment thread src/components/video-editor/AnnotationSettingsPanel.tsx Outdated
Comment thread src/components/video-editor/ExtensionManager.tsx Outdated
Comment thread src/components/video-editor/FormatSelector.tsx
Comment thread src/components/video-editor/ProjectBrowserDialog.tsx Outdated
Comment thread src/components/video-editor/SettingsPanel.tsx
Comment thread src/components/video-editor/timeline/TimelineEditor.tsx Outdated
Comment thread src/components/video-editor/TutorialHelp.tsx Outdated
Comment thread src/components/video-editor/TutorialHelp.tsx Outdated
Comment thread src/components/video-editor/VideoEditor.tsx
Comment thread src/index.css Outdated
- Create missing ThemeContext.tsx (build-breaking)
- Fix text contrast on blue accent backgrounds (use text-white on bg-[#2563EB])
- Fix PlaybackControls border to use border-white/10 (dark overlay)
- Fix ExportSettingsMenu/FormatSelector active state text for light mode
- Fix ProjectBrowserDialog placeholder text on dark gradient
- Fix SettingsPanel dot preview border, accent text, hover text, X button text
- Fix TimelineEditor tooltip text and custom aspect input borders/bg
- Fix TutorialHelp malformed CSS class and kbd backgrounds
- Fix KeyboardShortcutsHelp kbd backgrounds for light mode
- Fix ExtensionManager badge text on blue pill
- Fix AnnotationSettingsPanel upload button hover text
- Fix index.css light mode timeline colors (was identical to dark)
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/components/video-editor/SettingsPanel.tsx`:
- Around line 1826-1830: Replace the hardcoded light-mode overlay class
"bg-white/[0.02]" in the SettingsPanel JSX where the className is built (the
ternary that checks isSelected) with a theme token-based foreground/surface
token; e.g. use "bg-foreground/[0.02]" or the same token used for other controls
like "hover:bg-foreground/[0.05]". Update the string in the ternary that
currently reads 'border-foreground/[0.06] bg-white/[0.02]
hover:bg-foreground/[0.05]' so it uses the consistent token (e.g.
'border-foreground/[0.06] bg-foreground/[0.02] hover:bg-foreground/[0.05]') to
keep light/dark theming consistent.
- Around line 2721-2723: In SettingsPanel (the JSX block containing the div with
className "mt-2 flex items-center justify-between rounded-lg bg-black/10 px-2.5
py-1.5"), replace the hard-coded dark-mode color class "bg-black/10" with the
same theme-aware background utility used by the other rows (i.e., the themed bg
class used elsewhere in SettingsPanel) so the webcam row follows light/dark
theme styling consistently.

In `@src/contexts/ThemeContext.tsx`:
- Around line 40-47: The applyThemeToDOM function currently toggles the "dark"
class but doesn't update the data-theme attribute used by the PR's CSS
variables; update applyThemeToDOM (the function handling ResolvedTheme) to set
document.documentElement.setAttribute("data-theme", theme) (or remove/clear when
appropriate) in addition to adding/removing the "dark" class so token-based
colors follow the resolved theme.
- Around line 19-29: The getStoredPreference function currently falls back to
"dark" for users without a stored preference; change the fallback to "system" so
first-run users get OS preference detection. In the getStoredPreference function
(referencing ThemePreference and THEME_STORAGE_KEY), keep the try/catch and the
stored value checks for "light" | "dark" | "system" but return "system" instead
of "dark" at the end so the default behavior uses system preference.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: d2598692-ec90-411a-aef3-5790e2aff1e6

📥 Commits

Reviewing files that changed from the base of the PR and between aecefd6 and 6536975.

📒 Files selected for processing (12)
  • src/components/video-editor/AnnotationSettingsPanel.tsx
  • src/components/video-editor/ExportSettingsMenu.tsx
  • src/components/video-editor/ExtensionManager.tsx
  • src/components/video-editor/FormatSelector.tsx
  • src/components/video-editor/KeyboardShortcutsHelp.tsx
  • src/components/video-editor/PlaybackControls.tsx
  • src/components/video-editor/ProjectBrowserDialog.tsx
  • src/components/video-editor/SettingsPanel.tsx
  • src/components/video-editor/TutorialHelp.tsx
  • src/components/video-editor/timeline/TimelineEditor.tsx
  • src/contexts/ThemeContext.tsx
  • src/index.css
✅ Files skipped from review due to trivial changes (8)
  • src/components/video-editor/ExtensionManager.tsx
  • src/components/video-editor/FormatSelector.tsx
  • src/components/video-editor/KeyboardShortcutsHelp.tsx
  • src/components/video-editor/timeline/TimelineEditor.tsx
  • src/components/video-editor/PlaybackControls.tsx
  • src/components/video-editor/ProjectBrowserDialog.tsx
  • src/components/video-editor/AnnotationSettingsPanel.tsx
  • src/components/video-editor/ExportSettingsMenu.tsx
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/index.css
  • src/components/video-editor/TutorialHelp.tsx

Comment on lines 1826 to 1830
"flex flex-col items-center gap-1 p-1.5 rounded-lg border transition-all text-center",
isSelected
? "border-[#2563EB]/50 bg-[#2563EB]/10 ring-1 ring-[#2563EB]/30"
: "border-white/[0.06] bg-white/[0.02] hover:bg-white/[0.05]",
: "border-foreground/[0.06] bg-white/[0.02] hover:bg-foreground/[0.05]",
)}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Replace the remaining hardcoded white overlay.

bg-white/[0.02] is effectively invisible in light mode and inconsistent with the theme-token pass. Use a foreground/surface token like the surrounding controls.

🎨 Proposed fix
-												: "border-foreground/[0.06] bg-white/[0.02] hover:bg-foreground/[0.05]",
+												: "border-foreground/[0.06] bg-foreground/[0.03] hover:bg-foreground/[0.05]",
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"flex flex-col items-center gap-1 p-1.5 rounded-lg border transition-all text-center",
isSelected
? "border-[#2563EB]/50 bg-[#2563EB]/10 ring-1 ring-[#2563EB]/30"
: "border-white/[0.06] bg-white/[0.02] hover:bg-white/[0.05]",
: "border-foreground/[0.06] bg-white/[0.02] hover:bg-foreground/[0.05]",
)}
"flex flex-col items-center gap-1 p-1.5 rounded-lg border transition-all text-center",
isSelected
? "border-[`#2563EB`]/50 bg-[`#2563EB`]/10 ring-1 ring-[`#2563EB`]/30"
: "border-foreground/[0.06] bg-foreground/[0.03] hover:bg-foreground/[0.05]",
)}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/video-editor/SettingsPanel.tsx` around lines 1826 - 1830,
Replace the hardcoded light-mode overlay class "bg-white/[0.02]" in the
SettingsPanel JSX where the className is built (the ternary that checks
isSelected) with a theme token-based foreground/surface token; e.g. use
"bg-foreground/[0.02]" or the same token used for other controls like
"hover:bg-foreground/[0.05]". Update the string in the ternary that currently
reads 'border-foreground/[0.06] bg-white/[0.02] hover:bg-foreground/[0.05]' so
it uses the consistent token (e.g. 'border-foreground/[0.06]
bg-foreground/[0.02] hover:bg-foreground/[0.05]') to keep light/dark theming
consistent.

Comment on lines 2721 to 2723
<div className="mt-2 flex items-center justify-between rounded-lg bg-black/10 px-2.5 py-1.5">
<span className="text-[10px] text-slate-400">
<span className="text-[10px] text-muted-foreground">
{tSettings(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Keep this webcam row theme-aware too.

This row still uses bg-black/10, which is a dark-mode-era color and can disappear on dark surfaces. Match the other themed rows.

🎨 Proposed fix
-								<div className="mt-2 flex items-center justify-between rounded-lg bg-black/10 px-2.5 py-1.5">
+								<div className="mt-2 flex items-center justify-between rounded-lg bg-foreground/[0.03] px-2.5 py-1.5">
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<div className="mt-2 flex items-center justify-between rounded-lg bg-black/10 px-2.5 py-1.5">
<span className="text-[10px] text-slate-400">
<span className="text-[10px] text-muted-foreground">
{tSettings(
<div className="mt-2 flex items-center justify-between rounded-lg bg-foreground/[0.03] px-2.5 py-1.5">
<span className="text-[10px] text-muted-foreground">
{tSettings(
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/video-editor/SettingsPanel.tsx` around lines 2721 - 2723, In
SettingsPanel (the JSX block containing the div with className "mt-2 flex
items-center justify-between rounded-lg bg-black/10 px-2.5 py-1.5"), replace the
hard-coded dark-mode color class "bg-black/10" with the same theme-aware
background utility used by the other rows (i.e., the themed bg class used
elsewhere in SettingsPanel) so the webcam row follows light/dark theme styling
consistently.

Comment thread src/contexts/ThemeContext.tsx
Comment thread src/contexts/ThemeContext.tsx
- Default preference to 'system' so first-run users get OS preference detection
- Set data-theme attribute on documentElement alongside .dark class toggle
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
src/contexts/ThemeContext.tsx (1)

50-55: Move the DOM write out of the state initializer.

Line 53 mutates document.documentElement while React is computing initial state. Keep the initializer pure and apply the initial/resolved theme from the existing effect path instead. If avoiding first-paint flash is required, prefer a tiny bootstrap script before React mounts.

♻️ Proposed refactor
 export function ThemeProvider({ children }: { children: React.ReactNode }) {
 	const [preference, setPreferenceState] = useState<ThemePreference>(() => {
 		const stored = getStoredPreference();
-		applyThemeToDOM(resolveTheme(stored));
 		return stored;
 	});

Also applies to: 91-93

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/contexts/ThemeContext.tsx` around lines 50 - 55, The state initializer in
ThemeProvider currently reads getStoredPreference() and calls
applyThemeToDOM(resolveTheme(stored)) which performs a DOM mutation during
React's initial state computation; make the initializer pure by only returning
the stored preference (call getStoredPreference() inside the initializer but do
NOT call applyThemeToDOM or resolveTheme there), then move the DOM mutation into
the existing effect that already uses resolveTheme/applyThemeToDOM (the effect
that currently contains the theme application logic around the same area as the
existing effect referencing resolveTheme/applyThemeToDOM), so the DOM write
happens in an effect after mount; if first-paint flash is a concern, add a
separate small bootstrap script outside React instead of performing DOM writes
in the state initializer.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/contexts/ThemeContext.tsx`:
- Around line 50-55: The state initializer in ThemeProvider currently reads
getStoredPreference() and calls applyThemeToDOM(resolveTheme(stored)) which
performs a DOM mutation during React's initial state computation; make the
initializer pure by only returning the stored preference (call
getStoredPreference() inside the initializer but do NOT call applyThemeToDOM or
resolveTheme there), then move the DOM mutation into the existing effect that
already uses resolveTheme/applyThemeToDOM (the effect that currently contains
the theme application logic around the same area as the existing effect
referencing resolveTheme/applyThemeToDOM), so the DOM write happens in an effect
after mount; if first-paint flash is a concern, add a separate small bootstrap
script outside React instead of performing DOM writes in the state initializer.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: b26dd267-7ab6-444d-85af-24885d137447

📥 Commits

Reviewing files that changed from the base of the PR and between 6536975 and 7ca96f3.

📒 Files selected for processing (1)
  • src/contexts/ThemeContext.tsx

@webadderall webadderall merged commit 944d4f8 into main Apr 18, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant