Skip to content

feat: Add theme switching and group client settings#72

Merged
imxade merged 2 commits into
AOSSIE-Org:mainfrom
alishair7071:feat/theme-switching-client-settings
Feb 17, 2026
Merged

feat: Add theme switching and group client settings#72
imxade merged 2 commits into
AOSSIE-Org:mainfrom
alishair7071:feat/theme-switching-client-settings

Conversation

@alishair7071
Copy link
Copy Markdown
Contributor

@alishair7071 alishair7071 commented Feb 12, 2026

Summary

Added theme switching functionality and grouped all client-side settings in a dedicated section below the Save Config button.

Fixes #70

Changes

  • Added theme selector dropdown (Dark/Light themes)
  • Grouped Mouse Sensitivity, Invert Scroll, and Theme under "Client Settings" heading
  • Theme persists to localStorage and applies immediately on change
  • ThemeInit component loads saved theme on app startup

Testing

  • Change theme in settings - UI updates instantly
  • Refresh page - theme persists
  • Client settings are clearly separated from server settings
Rein.Theme.Switching.mp4

Summary by CodeRabbit

  • New Features

    • Added theme selector to settings with Light and Dark options.
    • User theme preference now persists across sessions and is applied automatically on app load.
  • Style

    • Updated default interface styling to use a light/dynamic baseline and ensure theme-aware UI appearance.

 Add theme selector Dark/Light in settings page
 Group Mouse Sensitivity, Invert Scroll, and Theme under 'Client Settings' section
 Persist theme to localStorage (rein-theme)
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Feb 12, 2026

📝 Walkthrough

Walkthrough

Adds client-side theme support: a ThemeInit component applies persisted theme at app startup and the Settings page gains a "Client Settings" block with a theme selector that persists and applies the chosen theme via localStorage and document data-theme.

Changes

Cohort / File(s) Summary
Theme initialization
src/routes/__root.tsx
Added ThemeInit component that reads theme from localStorage (using APP_CONFIG.THEME_STORAGE_KEY), validates against THEMES, and sets document.documentElement.dataset.theme. Switched body CSS classes from dark baseline to dynamic/light baseline and invoked ThemeInit in the Root document body.
Settings UI & client state
src/routes/settings.tsx
Added client-side theme state initialized from localStorage, effect to persist theme and update document.documentElement.dataset.theme, and a "Client Settings" section with a theme <select> alongside sensitivity/invert controls. Minor UI grouping and formatting changes.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant SettingsPage as Settings Page
    participant RootInit as ThemeInit (Root)
    participant State as React State
    participant Storage as localStorage
    participant DOM as document.documentElement

    Note over RootInit,Storage: App startup
    RootInit->>Storage: read APP_CONFIG.THEME_STORAGE_KEY
    Storage-->>RootInit: storedTheme
    RootInit->>DOM: set data-theme (validated or default)

    User->>SettingsPage: choose theme from dropdown
    SettingsPage->>State: setTheme(selected)
    State->>Storage: write APP_CONFIG.THEME_STORAGE_KEY
    State->>DOM: set data-theme to selected
    DOM->>DOM: apply theme styles
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

🐰 A rabbit nudges the theme to play,
Light or dark, it hops your way.
Settings gathered, snug and neat,
Choice saved softly, tidy and sweet.
The warren glows in chosen light—huzzah! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main changes: adding theme switching functionality and grouping client settings together.
Linked Issues check ✅ Passed All requirements from issue #70 are met: theme switching with persistence is implemented, and client settings are grouped under a 'Client Settings' heading.
Out of Scope Changes check ✅ Passed All changes are directly aligned with issue #70 requirements; no unrelated modifications were introduced beyond theme switching and client settings grouping.

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

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Tip

Issue Planner is now in beta. Read the docs and try it out! Share your feedback on Discord.


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: 1

🤖 Fix all issues with AI agents
In `@src/routes/settings.tsx`:
- Around line 234-238: The helper label currently rendering the invertScroll
helper text should be changed to a non-form label element (e.g., a <span> or
<p>) so it isn't treated as a form label, and the Theme label must be associated
with its control by adding htmlFor on the label and a matching id on the
<select> element (update the Theme label and the corresponding <select> in the
settings component, referencing the invertScroll helper text and the theme
<select> control by their existing JSX locations/names) — replace the decorative
<label> for invertScroll with a <span> or <p>, and add id="theme" (or another
unique id) to the <select> and htmlFor="theme" to the Theme <label>.
🧹 Nitpick comments (2)
src/routes/__root.tsx (1)

28-36: Theme may flash (FOUC) on page load.

useEffect runs after the first paint, so users may briefly see the default/unstyled theme before data-theme is applied. For a seamless experience, consider moving the theme initialization to a synchronous inline <script> in the <head> (before any body content renders) that reads localStorage and sets data-theme on <html>.

That said, this is a minor UX polish item and fine to defer.

src/routes/settings.tsx (1)

15-30: Consider centralizing localStorage keys in APP_CONFIG.

'rein_invert' (line 18) and 'rein_sensitivity' (line 27) are hardcoded strings, while the theme key uses APP_CONFIG.THEME_STORAGE_KEY. For consistency and easier refactoring, consider moving all localStorage keys into APP_CONFIG.

Comment thread src/routes/settings.tsx Outdated
Comment on lines +234 to +238
<label className="label">
<span className="label-text-alt opacity-50">
{invertScroll ? 'Traditional scrolling enabled' : 'Natural scrolling'}
</span>
</label>
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

Accessibility: labels not associated with their controls.

The static analysis tool correctly flags these two <label> elements. The helper-text label at line 234 and the "Theme" label at line 242 lack htmlFor attributes and don't wrap their associated controls.

For the Theme label, add htmlFor pointing to the <select>, and give the select an id. The helper-text label for Invert Scroll is purely decorative — consider using a <span> or <p> instead of <label>.

Proposed fix
-                    <label className="label">
+                    <span className="label">
                         <span className="label-text-alt opacity-50">
                             {invertScroll ? 'Traditional scrolling enabled' : 'Natural scrolling'}
                         </span>
-                    </label>
+                    </span>
-                    <label className="label">
+                    <label className="label" htmlFor="theme-select">
                         <span className="label-text">Theme</span>
                     </label>
                     <select
                         className="select select-bordered w-full"
+                        id="theme-select"
                         value={theme}
                         onChange={(e) => setTheme(e.target.value)}
                     >

Also applies to: 242-244

🧰 Tools
🪛 Biome (2.3.14)

[error] 234-238: A form label must be associated with an input.

Consider adding a for or htmlFor attribute to the label element or moving the input element to inside the label element.

(lint/a11y/noLabelWithoutControl)

🤖 Prompt for AI Agents
In `@src/routes/settings.tsx` around lines 234 - 238, The helper label currently
rendering the invertScroll helper text should be changed to a non-form label
element (e.g., a <span> or <p>) so it isn't treated as a form label, and the
Theme label must be associated with its control by adding htmlFor on the label
and a matching id on the <select> element (update the Theme label and the
corresponding <select> in the settings component, referencing the invertScroll
helper text and the theme <select> control by their existing JSX
locations/names) — replace the decorative <label> for invertScroll with a <span>
or <p>, and add id="theme" (or another unique id) to the <select> and
htmlFor="theme" to the Theme <label>.

@aniket866
Copy link
Copy Markdown
Contributor

hi @alishair7071 Changes looks good and great work, Please resolve the merge conflicts and apply suggested improvements.

@imxade LGTM

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.

Caution

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

⚠️ Outside diff range comments (1)
src/routes/settings.tsx (1)

138-209: ⚠️ Potential issue | 🟡 Minor

Port setting is visually grouped under "Client Settings" but it's a server setting.

The PR objective is to separate client-only settings from server settings. The "Port" form control (lines 198–209) and the "Save Config" button appear below the "Client Settings" heading, making them look like client settings. Consider moving the Port input and Save Config button above the divider (alongside the Server IP field), or adding a second "Server Settings" heading above the server-related controls.

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

In `@src/routes/settings.tsx` around lines 138 - 209, The Port input
(state/frontendPort, placeholder CONFIG.FRONTEND_PORT) and the "Save Config"
button are currently under the "Client Settings" header; move these
server-related controls out of that block by either relocating the Port input
and the "Save Config" button next to the Server IP control above the divider or
by inserting a new "Server Settings" heading above the Port input and button;
update the JSX so the Port input (value={frontendPort}
onChange={setFrontendPort}) and the button with label "Save Config" are grouped
under the server section to visually separate client vs server settings.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@src/routes/settings.tsx`:
- Around line 138-209: The Port input (state/frontendPort, placeholder
CONFIG.FRONTEND_PORT) and the "Save Config" button are currently under the
"Client Settings" header; move these server-related controls out of that block
by either relocating the Port input and the "Save Config" button next to the
Server IP control above the divider or by inserting a new "Server Settings"
heading above the Port input and button; update the JSX so the Port input
(value={frontendPort} onChange={setFrontendPort}) and the button with label
"Save Config" are grouped under the server section to visually separate client
vs server settings.

---

Duplicate comments:
In `@src/routes/settings.tsx`:
- Around line 185-187: The Theme label in the settings UI is not linked to its
select control; update the label element in src/routes/settings.tsx by adding
htmlFor="theme-select" and add id="theme-select" to the corresponding <select>
element (the Theme label and its select control) so the <label> and <select> are
properly associated for accessibility.

@aniket866
Copy link
Copy Markdown
Contributor

I think make the touch area also white in light mode and dark in dark mode.

@imxade imxade merged commit 91ef0d9 into AOSSIE-Org:main Feb 17, 2026
2 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.

Settings UI: add theme switching and group client settings (sensitivity, invert, theme) in one section

3 participants