feat: add light mode theme support#258
Conversation
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
|
Warning
|
| 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
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.tsxand 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 | 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.
Comment @coderabbitai help to get the list of available commands and usage tips.
There was a problem hiding this comment.
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 | 🟠 MajorMake 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-foregroundtokens. 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 | 🟡 MinorTokenize 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 | 🟠 MajorDo not use
text-foregroundon fixed accent backgrounds.These controls use fixed blue/red fills, but
text-foregroundbecomes 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 | 🟠 MajorFix active MP4/GIF toggle contrast in light mode.
The active pill only paints
bg-[#2563EB]/10, sotext-whitebecomes 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 23selector-pseudo-class-no-unknownwarnings on lines 177–278 are noise — consider whitelisting:global/:localin 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:
.glassGreenand.glassCyanshare 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?
Tracknow themes viabg-foreground/10, butRangeandThumbon lines 16–18 keep hardcoded#2563EB. That's consistent with--brand-accentinindex.css, so it's fine — just noting you could swap them forbg-[hsl(var(--primary))]/border-primaryto 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-basedkbdbackground for light mode.
bg-white/5becomes effectively invisible on light dialog surfaces.bg-foreground/5matches 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
📒 Files selected for processing (32)
src/App.tsxsrc/components/ui/accordion.tsxsrc/components/ui/item-content.tsxsrc/components/ui/slider.tsxsrc/components/ui/sonner.tsxsrc/components/ui/switch.tsxsrc/components/video-editor/AddCustomFontDialog.tsxsrc/components/video-editor/AnnotationOverlay.tsxsrc/components/video-editor/AnnotationSettingsPanel.tsxsrc/components/video-editor/ExportSettingsMenu.tsxsrc/components/video-editor/ExtensionManager.tsxsrc/components/video-editor/FormatSelector.tsxsrc/components/video-editor/GifOptionsPanel.tsxsrc/components/video-editor/KeyboardShortcutsHelp.tsxsrc/components/video-editor/PlaybackControls.tsxsrc/components/video-editor/ProjectBrowserDialog.tsxsrc/components/video-editor/SettingsPanel.tsxsrc/components/video-editor/ShortcutsConfigDialog.tsxsrc/components/video-editor/SliderControl.tsxsrc/components/video-editor/TutorialHelp.tsxsrc/components/video-editor/VideoEditor.tsxsrc/components/video-editor/timeline/Item.tsxsrc/components/video-editor/timeline/ItemGlass.module.csssrc/components/video-editor/timeline/Row.tsxsrc/components/video-editor/timeline/Subrow.tsxsrc/components/video-editor/timeline/Timeline.module.csssrc/components/video-editor/timeline/TimelineEditor.tsxsrc/components/video-editor/timeline/TimelineWrapper.tsxsrc/components/video-editor/timeline/Track.tsxsrc/index.csssrc/main.tsxtailwind.config.cjs
💤 Files with no reviewable changes (1)
- src/components/ui/sonner.tsx
- 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)
There was a problem hiding this comment.
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
📒 Files selected for processing (12)
src/components/video-editor/AnnotationSettingsPanel.tsxsrc/components/video-editor/ExportSettingsMenu.tsxsrc/components/video-editor/ExtensionManager.tsxsrc/components/video-editor/FormatSelector.tsxsrc/components/video-editor/KeyboardShortcutsHelp.tsxsrc/components/video-editor/PlaybackControls.tsxsrc/components/video-editor/ProjectBrowserDialog.tsxsrc/components/video-editor/SettingsPanel.tsxsrc/components/video-editor/TutorialHelp.tsxsrc/components/video-editor/timeline/TimelineEditor.tsxsrc/contexts/ThemeContext.tsxsrc/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
| "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]", | ||
| )} |
There was a problem hiding this comment.
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.
| "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.
| <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( |
There was a problem hiding this comment.
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.
| <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.
- Default preference to 'system' so first-run users get OS preference detection - Set data-theme attribute on documentElement alongside .dark class toggle
There was a problem hiding this comment.
🧹 Nitpick comments (1)
src/contexts/ThemeContext.tsx (1)
50-55: Move the DOM write out of the state initializer.Line 53 mutates
document.documentElementwhile 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
📒 Files selected for processing (1)
src/contexts/ThemeContext.tsx
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]attributesrc/main.tsx/src/App.tsx: ThemeContext provider withprefers-color-schemedetectionUI Components (32 files)
text-white,bg-zinc-900,border-white/10, etc.) with theme-aware equivalents (text-foreground,bg-surface,border-border)What's NOT changed
Summary by CodeRabbit
New Features
Style