Skip to content

✨(frontend) add dark / light / system colour-mode switcher#2519

Open
MashdorDev wants to merge 4 commits into
suitenumerique:mainfrom
MashdorDev:feat/theme-color-mode
Open

✨(frontend) add dark / light / system colour-mode switcher#2519
MashdorDev wants to merge 4 commits into
suitenumerique:mainfrom
MashdorDev:feat/theme-color-mode

Conversation

@MashdorDev

Copy link
Copy Markdown

Purpose

Docs already ships a dark Cunningham token set, but there is no way for a user to select it and no following of the OS colour scheme. This adds an in-app dark / light / system colour-mode switcher, which is one of the recurring asks around theming.

Proposal

  • Add a themeMode (light / dark / system) to the theme store, persisted to localStorage
  • In system mode, resolve and follow the OS prefers-color-scheme live
  • Pre-hydration inline script in _document sets the theme class on <html> so the correct scheme paints on first frame (no flash), with suppressHydrationWarning
  • A user's explicit mode preference takes precedence over the plain light/dark FRONTEND_THEME backend default (non-default brand themes like dsfr still apply)
  • A ThemeSwitch control in the left-panel footer (app) and the home header (landing page)
  • Unit tests for the theme-mode store logic

The store maps the mode onto the existing Cunningham themes (light -> default, dark -> dark), so no new tokens are introduced.

External contributions

Thank you for your contribution! 🎉

General requirements

CI requirements

  • I made sure that all existing tests are passing
  • I have signed off my commits with git commit --signoff (DCO compliance)
  • I have signed my commits with my SSH or GPG key (git commit -S)
  • My commit messages follow the required format: <gitmoji>(type) title description
  • I have added a changelog entry under ## [Unreleased] section (if noticeable change)

AI requirements

  • I used AI assistance to produce part or all of this contribution
  • I have read, reviewed, understood and can explain the code I am submitting
  • I can jump in a call or a chat to explain my work to a maintainer

Adds a user-facing colour-mode preference on top of the existing Cunningham
dark token set:

- useCunninghamTheme: themeMode state (light/dark/system) + setThemeMode,
  persisted to localStorage; system resolves via prefers-color-scheme.
- ThemeProvider: applies the stored mode on mount and follows live OS
  changes while in system mode.
- _document: pre-hydration inline script sets the theme class on <html>
  to avoid a flash of the wrong theme; suppressHydrationWarning on <html>.
- ConfigProvider: user mode preference takes precedence over the plain
  light/dark FRONTEND_THEME default (brand themes still apply).
- ThemeSwitch component in the left-panel footer and the home header.
- Unit tests for the theme-mode store logic.

Signed-off-by: MashdorDev <dorzairi@ymail.com>
@coderabbitai

coderabbitai Bot commented Jul 10, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 93d5e5af-a6c0-459f-ba92-2afdf65a5fd1

📥 Commits

Reviewing files that changed from the base of the PR and between 77dc653 and 99b9fd5.

📒 Files selected for processing (2)
  • src/frontend/apps/impress/src/components/dropdown-menu/DropdownMenu.tsx
  • src/frontend/apps/impress/src/features/docs/doc-editor/styles.tsx

Walkthrough

Adds persisted light, dark, and system color-mode state with system preference resolution. Theme providers hydrate stored preferences, synchronize operating-system changes, and preserve configured brand themes. A pre-hydration document script applies the initial theme class. The new translated ThemeSwitch is exported and rendered in the home header and left-panel footer, while editors and related styling respond to the active theme. Tests cover persistence, mode resolution, and invalid stored values.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Suggested reviewers: AntoLC, qbey, sampaccoud

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly matches the main change: adding a light/dark/system colour-mode switcher.
Description check ✅ Passed The description directly describes the theme-mode switcher, persistence, system sync, hydration fix, and related UI changes.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

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 current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/frontend/apps/impress/src/components/ThemeSwitch.tsx`:
- Around line 30-42: Update the ThemeSwitch component’s DropdownMenu usage to
remove selectedValues, allowing the single-choice theme options to use radio
semantics via isSelected. Also remove the redundant inner aria-label while
retaining the DropButton label.

In `@src/frontend/apps/impress/src/core/config/ThemeProvider.tsx`:
- Around line 22-35: Prevent the OS color-scheme listener in ThemeProvider from
overriding brand themes: when onChange checks the store, only call
setThemeMode('system') if themeMode is 'system' and the current theme is the
default theme; alternatively update setTheme to synchronize themeMode when
applying a brand theme. Use useCunninghamTheme, onChange, setThemeMode, and
setTheme as references.
- Around line 2-20: ThemeProvider’s mount reconciliation persists the fallback
“system” value and prevents backend brand themes from being applied. Update the
theme handling around useIsomorphicLayoutEffect and useCunninghamTheme so a
missing stored preference applies “system” only in memory without localStorage
persistence, using an internal non-persisting applyThemeMode path; continue
using the persisting setter when getStoredThemeMode() returns an explicit value.

In `@src/frontend/apps/impress/src/pages/_document.tsx`:
- Around line 11-22: Replace the hardcoded 'doc-theme-mode' in THEME_INIT_SCRIPT
with an interpolation of the shared THEME_MODE_STORAGE_KEY constant imported
from useCunninghamTheme.tsx, ensuring the script and hook remain synchronized if
the storage key 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: ASSERTIVE

Plan: Pro

Run ID: 62d5b6bc-37f0-43ed-8631-3b8edddd06ed

📥 Commits

Reviewing files that changed from the base of the PR and between 57ad4f4 and be17af8.

📒 Files selected for processing (10)
  • CHANGELOG.md
  • src/frontend/apps/impress/src/components/ThemeSwitch.tsx
  • src/frontend/apps/impress/src/components/index.ts
  • src/frontend/apps/impress/src/core/config/ConfigProvider.tsx
  • src/frontend/apps/impress/src/core/config/ThemeProvider.tsx
  • src/frontend/apps/impress/src/cunningham/__tests__/useCunninghamTheme.spec.tsx
  • src/frontend/apps/impress/src/cunningham/useCunninghamTheme.tsx
  • src/frontend/apps/impress/src/features/home/components/HomeHeader.tsx
  • src/frontend/apps/impress/src/features/left-panel/components/LeftPanelFooter.tsx
  • src/frontend/apps/impress/src/pages/_document.tsx

Comment thread src/frontend/apps/impress/src/components/ThemeSwitch.tsx
Comment thread src/frontend/apps/impress/src/core/config/ThemeProvider.tsx Outdated
Comment thread src/frontend/apps/impress/src/core/config/ThemeProvider.tsx Outdated
Comment thread src/frontend/apps/impress/src/pages/_document.tsx
- Drive the BlockNote editor (editable + reader) theme from the resolved
  Cunningham theme so the document canvas is dark in dark mode instead of
  staying light with unreadable text.
- Fade the doc floating bar to the surface background token instead of solid
  white (the white blur band under the header in dark mode).
- ThemeProvider: resolve the default 'system' in memory (new non-persisting
  applyThemeMode) so an unset preference no longer masks a backend brand
  theme, and skip the OS-change listener when a brand theme is active.
- ThemeSwitch: use radio semantics (drop selectedValues), remove the
  redundant inner aria-label.
- _document: reference the shared THEME_MODE_STORAGE_KEY constant.
- Add a test for applyThemeMode not persisting.

Signed-off-by: MashdorDev <dorzairi@ymail.com>
The BlockNote editor used its own Mantine surface (distinct from the app
background) and the loading skeleton was hardcoded to gray-000 (white), so in
dark mode both stood out. Make the editor background transparent so it shares
the page background, and paint the skeleton with the surface token.

Signed-off-by: MashdorDev <dorzairi@ymail.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/frontend/apps/impress/src/features/docs/doc-editor/styles.tsx`:
- Around line 25-33: Reformat the explanatory comment above the `.bn-editor`
rule so the referenced selector `.bn-root.bn-editor` remains intact on one line
or is broken clearly without splitting hyphenated class names.
🪄 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: ASSERTIVE

Plan: Pro

Run ID: fa655852-54b1-44ff-b796-f73188c09476

📥 Commits

Reviewing files that changed from the base of the PR and between 80846f4 and 77dc653.

📒 Files selected for processing (2)
  • src/frontend/apps/impress/src/components/dropdown-menu/DropdownMenu.tsx
  • src/frontend/apps/impress/src/features/docs/doc-editor/styles.tsx

Comment on lines +25 to +33
/* Share the page background instead of BlockNote's own (Mantine) light/dark
surface, so the canvas matches the app in any theme. `.bn -
root.bn -
editor`
outranks BlockNote's own `.bn -
editor` background rule. */
.bn-editor {
height: 100%;
background-color: transparent;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Fix the multi-line comment readability.

The class name reference .bn-root.bn-editor is split across lines 26–30 with hyphens and line breaks (.bn -\nroot.bn -\neditor), making the comment hard to parse. Consider keeping the selector reference on a single line or using a clearer break.

📝 Suggested comment reformatting
-    /* Share the page background instead of BlockNote's own (Mantine) light/dark
-       surface, so the canvas matches the app in any theme. `.bn -
-  root.bn -
-  editor`
-       outranks BlockNote's own `.bn -
-  editor` background rule. */
+    /* Share the page background instead of BlockNote's own (Mantine) light/dark
+       surface, so the canvas matches the app in any theme. `.bn-root.bn-editor`
+       outranks BlockNote's own `.bn-editor` background rule. */
     .bn-editor {
       height: 100%;
       background-color: transparent;
     }
📝 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
/* Share the page background instead of BlockNote's own (Mantine) light/dark
surface, so the canvas matches the app in any theme. `.bn -
root.bn -
editor`
outranks BlockNote's own `.bn -
editor` background rule. */
.bn-editor {
height: 100%;
background-color: transparent;
/* Share the page background instead of BlockNote's own (Mantine) light/dark
surface, so the canvas matches the app in any theme. `.bn-root.bn-editor`
outranks BlockNote's own `.bn-editor` background rule. */
.bn-editor {
height: 100%;
background-color: transparent;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/frontend/apps/impress/src/features/docs/doc-editor/styles.tsx` around
lines 25 - 33, Reformat the explanatory comment above the `.bn-editor` rule so
the referenced selector `.bn-root.bn-editor` remains intact on one line or is
broken clearly without splitting hyphenated class names.

Setting the BlockNote CSS var lost to BlockNote's own
.bn-root[data-color-scheme=dark] rule, so the editor kept Mantine's dark
surface. Set the background directly on .bn-root .bn-editor (which outranks
BlockNote's .bn-editor rule) so the canvas shares the page background in any
theme. Also make the dropdown selected-check use the theme-aware neutral text
colour instead of a fixed gray that was invisible on the dark menu.

Signed-off-by: MashdorDev <dorzairi@ymail.com>
@MashdorDev
MashdorDev force-pushed the feat/theme-color-mode branch from 77dc653 to 99b9fd5 Compare July 10, 2026 23:49
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