FE: Add dark mode view to storybook#43469
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #43469 +/- ##
=======================================
Coverage 66.90% 66.90%
=======================================
Files 2599 2599
Lines 208184 208184
Branches 9334 9334
=======================================
Hits 139276 139276
Misses 56250 56250
Partials 12658 12658
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Claude Code Review
This repository is configured for manual code reviews. Comment @claude review to trigger a review and subscribe this PR to future pushes, or @claude review once for a one-time review.
Tip: disable this comment in your organization's Code Review settings.
Review Summary by QodoAdd dark mode toggle to Storybook with global theme support
WalkthroughsDescription• Add dark/light mode toggle to Storybook with global theme support • Implement theme decorator applying dark mode styles dynamically • Remove redundant background parameters from story files • Fix dropdown button icon color inheritance for dark mode Diagramflowchart LR
A["Storybook Preview Config"] -->|"Add globalTypes"| B["Theme Toggle UI"]
A -->|"Add withTheme Decorator"| C["Apply Dark Mode Styles"]
C -->|"Toggle dark-mode class"| D["Body Element"]
C -->|"Set background/color"| D
E["Story Files"] -->|"Remove backgrounds"| F["Use Global Decorator"]
G["DropdownButton Styles"] -->|"Add currentColor"| H["Icon Adapts to Dark Mode"]
File Changes1. .storybook/preview.js
|
Code Review by Qodo
|
| variant: { | ||
| options: [ | ||
| "default", | ||
| "success", | ||
| "alert", | ||
| "pill", | ||
| "text-link", | ||
| "link", | ||
| "text-icon", |
There was a problem hiding this comment.
1. Invalid variant in story 🐞 Bug ≡ Correctness
DropdownButton Storybook controls include variant "link", but the underlying Button component does not support it (it supports "text-link"), so selecting it will produce an unstyled button--link class. This makes the Storybook story misleading and can hide regressions for the real supported variants.
Agent Prompt
### Issue description
`DropdownButton.stories.tsx` exposes a `variant` control value `"link"`, but the actual Button variants support `"text-link"` (not `"link"`). Selecting `"link"` yields a `button--link` class with no corresponding styles.
### Issue Context
`DropdownButton.jsx` forwards `variant` directly to `<Button variant={variant}>`, so Storybook controls must match Button’s real variant API.
### Fix Focus Areas
- frontend/components/buttons/DropdownButton/DropdownButton.stories.tsx[31-43]
- frontend/components/buttons/Button/Button.tsx[7-21]
- frontend/components/buttons/Button/_styles.scss[220-255]
### Suggested fix
Replace `"link"` with `"text-link"` in the `argTypes.variant.options` list (and any other story args/controls that reference `"link"`).
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
There was a problem hiding this comment.
variant="link" not supported (Qodo + Copilot)
- Already resolved — you merged Fleet UI: Improve internal links/buttons #43470 which adds the link variant. No action needed.
WalkthroughAdded Storybook-wide theming: a Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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 |
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
frontend/components/buttons/DropdownButton/DropdownButton.stories.tsx (1)
31-43:⚠️ Potential issue | 🟡 Minor
linkis not a supported button variant.Line 36 no longer matches
frontend/components/buttons/Button/Button.tsx:8-21, which still exposes"text-link"rather than"link". With this option inargTypes, Storybook can generate avariantvalue thatDropdownButton/Buttondoesn’t understand.Suggested fix
options: [ "default", "alert", "pill", - "link", + "text-link", "text-icon", "icon", "inverse",🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@frontend/components/buttons/DropdownButton/DropdownButton.stories.tsx` around lines 31 - 43, The Storybook argTypes for DropdownButton lists an unsupported variant "link"; update the variant options in DropdownButton.stories.tsx to match the actual Button variants (replace "link" with "text-link") so the generated variant values align with the Button implementation (see Button.tsx's exposed variants).
🧹 Nitpick comments (1)
.storybook/preview.js (1)
18-25: Prefer class-driven styling over hard-coded hex values.The
dark-modeclass already gives Storybook the same theming hook as the app. The inline colors ondocument.bodyand.docs-storyadd a second source of truth that can drift the next time the production theme changes. I’d keep the JS limited to toggling the class and move any Storybook-only backdrop tweaks into CSS keyed offbody.dark-mode.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.storybook/preview.js around lines 18 - 25, The applyTheme function is applying inline hex colors (document.body.style.backgroundColor, document.body.style.color, and per-element .docs-story backgroundColor) which duplicates the theme; remove those inline style assignments and keep only document.body.classList.toggle("dark-mode", isDark) and the document.querySelectorAll(".docs-story").forEach call should no longer set styles in JS; instead add Storybook-only CSS rules (e.g., in .storybook/preview.css or a global decorator) that target body.dark-mode and body.dark-mode .docs-story to define background and text colors so the dark theme is driven by classes not hard-coded hex values.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@frontend/components/buttons/DropdownButton/_styles.scss`:
- Around line 75-76: The selector .dropdown-button .icon doesn't match the caret
because DropdownButton.jsx renders <Icon /> directly inside <Button> (see the
JSX around the caret rendering), so change the selector to target the actual SVG
markup (e.g. target the svg/path produced by <Icon /> such as .dropdown-button
svg path or .dropdown-button > svg path) and fix the keyword casing to lowercase
(use currentcolor) so Stylelint passes and the dark-mode stroke override applies
to the chevron.
---
Outside diff comments:
In `@frontend/components/buttons/DropdownButton/DropdownButton.stories.tsx`:
- Around line 31-43: The Storybook argTypes for DropdownButton lists an
unsupported variant "link"; update the variant options in
DropdownButton.stories.tsx to match the actual Button variants (replace "link"
with "text-link") so the generated variant values align with the Button
implementation (see Button.tsx's exposed variants).
---
Nitpick comments:
In @.storybook/preview.js:
- Around line 18-25: The applyTheme function is applying inline hex colors
(document.body.style.backgroundColor, document.body.style.color, and per-element
.docs-story backgroundColor) which duplicates the theme; remove those inline
style assignments and keep only document.body.classList.toggle("dark-mode",
isDark) and the document.querySelectorAll(".docs-story").forEach call should no
longer set styles in JS; instead add Storybook-only CSS rules (e.g., in
.storybook/preview.css or a global decorator) that target body.dark-mode and
body.dark-mode .docs-story to define background and text colors so the dark
theme is driven by classes not hard-coded hex values.
🪄 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: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 09b0516d-c2b2-4623-8420-b5d788427430
📒 Files selected for processing (6)
.storybook/preview.jsfrontend/components/LiveQuery/TargetChipSelector/TargetChipSelector.stories.tsxfrontend/components/TabNav/TabNav.stories.tsxfrontend/components/TeamsDropdown/TeamsDropdown.stories.tsxfrontend/components/buttons/DropdownButton/DropdownButton.stories.tsxfrontend/components/buttons/DropdownButton/_styles.scss
💤 Files with no reviewable changes (2)
- frontend/components/LiveQuery/TargetChipSelector/TargetChipSelector.stories.tsx
- frontend/components/TabNav/TabNav.stories.tsx
| .dropdown-button .icon svg path { | ||
| stroke: currentColor; |
There was a problem hiding this comment.
Target the actual chevron markup here.
frontend/components/buttons/DropdownButton/DropdownButton.jsx:101-109 renders <Icon /> directly inside <Button>, so Line 75’s .icon selector never matches the caret. That means the new dark-mode override won’t affect the icon, and Line 76 also still fails Stylelint because the keyword casing is wrong.
Suggested fix
-.dropdown-button .icon svg path {
- stroke: currentColor;
+.dropdown-button svg path {
+ stroke: currentcolor;
}📝 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.
| .dropdown-button .icon svg path { | |
| stroke: currentColor; | |
| .dropdown-button svg path { | |
| stroke: currentcolor; |
🧰 Tools
🪛 Stylelint (17.6.0)
[error] 76-76: Expected "currentColor" to be "currentcolor" (value-keyword-case)
(value-keyword-case)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@frontend/components/buttons/DropdownButton/_styles.scss` around lines 75 -
76, The selector .dropdown-button .icon doesn't match the caret because
DropdownButton.jsx renders <Icon /> directly inside <Button> (see the JSX around
the caret rendering), so change the selector to target the actual SVG markup
(e.g. target the svg/path produced by <Icon /> such as .dropdown-button svg path
or .dropdown-button > svg path) and fix the keyword casing to lowercase (use
currentcolor) so Stylelint passes and the dark-mode stroke override applies to
the chevron.
There was a problem hiding this comment.
Pull request overview
Adds a global dark/light mode toggle to Storybook so components can be previewed under the same body.dark-mode theming approach used by the app.
Changes:
- Adds a Storybook toolbar control (
globalTypes.theme) and a global decorator to togglebody.dark-mode. - Removes per-story background overrides from several stories to rely on the global theme toggle.
- Tweaks
DropdownButtonchevron styling to better adapt in dark mode.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
.storybook/preview.js |
Introduces the global theme toolbar toggle and applies the dark-mode class via a decorator. |
frontend/components/buttons/DropdownButton/_styles.scss |
Overrides dropdown chevron stroke to follow text color for dark mode compatibility. |
frontend/components/buttons/DropdownButton/DropdownButton.stories.tsx |
Updates story controls/options and removes Storybook background parameters. |
frontend/components/TeamsDropdown/TeamsDropdown.stories.tsx |
Adds a decorator wrapper to ensure adequate height for rendering. |
frontend/components/TabNav/TabNav.stories.tsx |
Removes per-story background parameters in favor of global theming. |
frontend/components/LiveQuery/TargetChipSelector/TargetChipSelector.stories.tsx |
Removes per-story background parameters in favor of global theming. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| const withTheme = (Story, context) => { | ||
| const isDark = context.globals.theme === "dark"; | ||
|
|
||
| useEffect(() => { | ||
| applyTheme(isDark); | ||
| }, [isDark]); |
There was a problem hiding this comment.
withTheme calls useEffect, but the function name is lowercase. With plugin:react-hooks/recommended enabled, this violates react-hooks/rules-of-hooks (hooks must be called from a React component or custom hook). Rename the decorator to an uppercase component name (e.g., WithTheme) or move the effect into a properly named custom hook, so lint/build doesn’t fail.
| document.body.style.backgroundColor = isDark ? "#181a1f" : ""; | ||
| document.body.style.color = isDark ? "#e2e4ea" : ""; | ||
|
|
||
| document.querySelectorAll(".docs-story").forEach((el) => { | ||
| el.style.backgroundColor = isDark ? "#181a1f" : ""; | ||
| }); |
There was a problem hiding this comment.
applyTheme hard-codes background/text colors via inline styles. Since the app’s theming is already driven by CSS custom properties that switch on body.dark-mode, these inline overrides can drift from production colors and can accidentally override token-based styling. Prefer toggling only the dark-mode class and handling any Storybook-specific docs/canvas background tweaks in CSS (e.g., a Storybook-only stylesheet using the same tokens).
| document.body.style.backgroundColor = isDark ? "#181a1f" : ""; | |
| document.body.style.color = isDark ? "#e2e4ea" : ""; | |
| document.querySelectorAll(".docs-story").forEach((el) => { | |
| el.style.backgroundColor = isDark ? "#181a1f" : ""; | |
| }); |
There was a problem hiding this comment.
Replaced with variables, thanks!
4284fb0 to
14f1fcd
Compare
|
There was a problem hiding this comment.
Claude Code Review
This repository is configured for manual code reviews. Comment @claude review to trigger a review and subscribe this PR to future pushes, or @claude review once for a one-time review.
Tip: disable this comment in your organization's Code Review settings.
There was a problem hiding this comment.
♻️ Duplicate comments (1)
frontend/components/buttons/DropdownButton/_styles.scss (1)
75-76:⚠️ Potential issue | 🟡 MinorFix CSS keyword casing.
Upon re-examination of the Icon component structure (which wraps the SVG in a
divwith classicon), the selector.dropdown-button .icon svg pathappears correct and should match the chevron markup. However, the CSS keyword casing needs correction.🎨 Proposed fix
-.dropdown-button .icon svg path { - stroke: currentColor; +.dropdown-button .icon svg path { + stroke: currentcolor; }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@frontend/components/buttons/DropdownButton/_styles.scss` around lines 75 - 76, The CSS uses the wrong casing for the color keyword in the selector .dropdown-button .icon svg path; update the declaration so the stroke uses the correct CSS keyword casing (currentColor) instead of the lowercase variant to ensure the SVG chevron inherits the icon color.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Duplicate comments:
In `@frontend/components/buttons/DropdownButton/_styles.scss`:
- Around line 75-76: The CSS uses the wrong casing for the color keyword in the
selector .dropdown-button .icon svg path; update the declaration so the stroke
uses the correct CSS keyword casing (currentColor) instead of the lowercase
variant to ensure the SVG chevron inherits the icon color.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 8a8e1e2d-63ac-4970-a0bb-22f376c3b026
📒 Files selected for processing (6)
.storybook/preview.jsfrontend/components/LiveQuery/TargetChipSelector/TargetChipSelector.stories.tsxfrontend/components/TabNav/TabNav.stories.tsxfrontend/components/TeamsDropdown/TeamsDropdown.stories.tsxfrontend/components/buttons/DropdownButton/DropdownButton.stories.tsxfrontend/components/buttons/DropdownButton/_styles.scss
💤 Files with no reviewable changes (3)
- frontend/components/LiveQuery/TargetChipSelector/TargetChipSelector.stories.tsx
- frontend/components/TabNav/TabNav.stories.tsx
- frontend/components/buttons/DropdownButton/DropdownButton.stories.tsx
✅ Files skipped from review due to trivial changes (2)
- frontend/components/TeamsDropdown/TeamsDropdown.stories.tsx
- .storybook/preview.js
Issue
Closes #43468
Description
Screenrecording
Screen.Recording.2026-04-13.at.12.49.13.PM.mov
Testing
Summary by CodeRabbit
New Features
Bug Fixes
Chores