Skip to content

Add theme switcher with drop-in theme discovery#295

Open
mageaustralia wants to merge 1 commit intoabhinavxd:mainfrom
mageaustralia:feat/theme-switcher
Open

Add theme switcher with drop-in theme discovery#295
mageaustralia wants to merge 1 commit intoabhinavxd:mainfrom
mageaustralia:feat/theme-switcher

Conversation

@mageaustralia
Copy link
Copy Markdown

Summary

Adds a tiny extensibility module so users and forks can build their own UI themes without modifying any upstream files. Defaults are unchanged — the switcher UI hides itself when only the default theme is registered, and the default theme uses no data-theme attribute, so stock installs see zero visual or DOM change.

Pathway towards modular themes that don't conflict with core

A common pain for downstream users today is that any visual customisation requires patching upstream Vue/SCSS files, which conflict on every release. This PR proposes a contract that breaks that cycle for CSS-based theming:

  • Drop-in directory. Themes live under frontend/apps/main/src/themes/<name>/ and are auto-discovered via Vite glob (import.meta.glob). Adding a theme requires zero edits to upstream files — no rebase pain.
  • Attribute-scoped CSS. Themes target [data-theme="<name>"] selectors, so they never bleed into the default look.
  • Switcher auto-hides. With one theme registered (default), the switcher UI does not render. Forks adding a theme automatically get the dropdown.

A theme is two files:

themes/<name>/
  theme.js       // export default { id: '<name>', label: '<Label>' }
  theme.scss     // [data-theme="<name>"] { --primary: ...; ... }

(See the README in that directory for the full convention.)

Choice persists in localStorage and syncs across tabs via useStorage.

Out of scope: swapping Vue components (custom layouts, replacement message bubbles, etc.) — that's a separate, larger discussion around component override points. This PR covers visual theming via CSS only.

Test plan

  • Stock install: no theme switcher icon in sidebar, <html> has no data-theme attribute, no visual difference vs main
  • Drop a themes/foo/theme.js exporting { id: 'foo', label: 'Foo' } and themes/foo/theme.scss with [data-theme="foo"] { --primary: ... } → switcher appears in the icon rail; picking "Foo" sets data-theme="foo" on <html> and the styles apply
  • Switching back to "Default" removes the attribute
  • Choice persists across reloads (localStorage) and across browser tabs (useStorage)
  • Choosing a theme that no longer exists falls back to default silently

Adds a tiny extensibility module so users and forks can build their own
UI themes without modifying any upstream files. Defaults are unchanged:
the switcher UI hides itself when only the default theme is registered,
and the default theme uses no `data-theme` attribute, so stock installs
see zero visual or DOM change.

Themes live under `frontend/apps/main/src/themes/<name>/` and are
auto-discovered via Vite glob. Adding a theme is two files
(`theme.js` + `theme.scss`) and zero edits to upstream code.

Out of scope: swapping Vue components — this is CSS-only theming.
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