Skip to content

feat: light/dark theme system, ShortcutField i18n, dark-mode styling#8

Open
khatrihemang07 wants to merge 27 commits into
game1024:masterfrom
khatrihemang07:master
Open

feat: light/dark theme system, ShortcutField i18n, dark-mode styling#8
khatrihemang07 wants to merge 27 commits into
game1024:masterfrom
khatrihemang07:master

Conversation

@khatrihemang07
Copy link
Copy Markdown

Summary

This PR adds a complete light/dark theme system, i18n coverage for the ShortcutField component, dark-mode styling throughout the app, and theme support for the motion-board sub-page. 19 files changed, 312 additions, 68 deletions across 6 commits.


Theme System

Problem

The app previously used a single hardcoded MUI theme. All backgrounds were white (#ffffff, #eeeeee), borders were gray (#e0e0e0), and text colors were hardcoded (#666). There was no way to switch to dark mode or follow the system preference.

Solution

src/theme.ts — Split the single theme into lightTheme and darkTheme, each with a proper mode palette:

export const lightTheme = createTheme({
  palette: { mode: 'light', success: successPalette }
});

export const darkTheme = createTheme({
  palette: { mode: 'dark', success: successPalette }
});

src/main.tsx — New ThemedApp wrapper component that:

  1. Reads the persisted theme preference from getSettings()
  2. Falls back to prefers-color-scheme media query for auto mode
  3. Listens for system theme changes (matchMedia.addEventListener)
  4. Listens for cross-window theme-updated Tauri events
  5. Shows the main window only after theme is resolved (works with visible: false in tauri.conf.json)

src/pages/motion-board/main.tsx — Same ThemedApp wrapper for the motion-board page, which renders in its own webview and was not getting theme context from the main window.

Theme Switch in Settings

src/components/Settings.tsx — New dropdown in the General settings tab:

Value Label Behavior
light Light Always light
dark Dark Always dark
auto Auto Follows system preference

Selecting a theme calls updateSettings({ theme }), which emits a theme-updated Tauri event broadcast to all windows.

src/store/settings.tsupdateSettings now emits theme-updated when the theme field changes.

Prevent Theme Flash on Startup

src-tauri/tauri.conf.json — Main window now starts with "visible": false. The window is only shown after getSettings() resolves in ThemedApp, ensuring the user never sees the wrong theme.


i18n — ShortcutField

Problem

The ShortcutField component had hardcoded Chinese strings:

  • 不支持使用 Win 键作为快捷键 — Win key warning
  • 按下快捷键 — placeholder text
  • 未设置 — empty state

This was broken for non-Chinese users since react-i18next is used everywhere else.

Solution

src/components/ShortcutField.tsx — Added useTranslation() and replaced all hardcoded strings with t() calls:

notify(t('shortcut.winKeyNotSupported'), 'warning');
// ...
<KeyComboTag combo={t('shortcut.pressShortcut')} />
// ...
<KeyComboTag combo={t('shortcut.notSet')} />

8 locale files — Added shortcut translation keys to de-DE, en-US, es-ES, fr-FR, ja-JP, ko-KR, zh-CN, zh-TW:

"shortcut": {
  "winKeyNotSupported": "Win key is not supported as a shortcut key",
  "metaKeyNotSupported": "Meta key is not supported as a shortcut key",
  "pressShortcut": "Press shortcut",
  "notSet": "Not set"
}

src/pages/motion-board/App.tsx — Draw mode snackbar message now uses i18n (i18n.t('drawing.messages.enterDrawMode')) instead of hardcoded Chinese. Added initLocale() on mount so the motion-board page respects the user's language preference.


Dark Mode Styling

ShortcutField (src/components/ShortcutField.tsx)

Before (hardcoded) After (theme-aware)
border: '1px solid #e0e0e0' border: 1px solid ${theme.palette.divider}
backgroundColor: '#f5f5f5' (disabled) theme.palette.action.disabledBackground
backgroundColor: '#e3f2fd' (recording) isDark ? 'rgba(144,202,249,0.16)' : '#e3f2fd'
backgroundColor: '#fff' (default) theme.palette.background.paper
color: '#666' (text) color: 'text.secondary'
backgroundColor: 'rgba(0,0,0,0.04)' (hover) backgroundColor: 'action.hover'

Settings Page (src/components/Settings.tsx)

  • All section cards changed from backgroundColor: '#ffffff' to backgroundColor: 'background.paper'

Tab Panel (src/App.tsx)

  • Background changed from '#eeeeee' to theme.palette.background.default

Snackbar Alerts

  • SnackbarContext.tsx: <Alert variant="filled"> for better dark-mode visibility
  • motion-board/App.tsx: Same variant="filled" applied

Cleanup

  • en-US.json — Removed duplicate primaryColorUpdated / secondaryColorUpdated keys
  • zh-CN.json — Same duplicate removal
  • de-DE.json, es-ES.json, zh-TW.json — Fixed broken JSON formatting (commas/newlines mangled from previous edits)

Testing

  • Theme dropdown in Settings cycles between Light/Dark/Auto
  • Dark mode renders all MUI components correctly
  • System theme change (macOS Appearance toggle) updates in Auto mode
  • Motion-board page follows the same theme as the main window
  • ShortcutField placeholder/warning text displays in the user's language
  • No theme flash on app startup
  • All 8 locales load shortcut keys without errors

khatrihemang07 and others added 27 commits May 31, 2026 00:17
Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
Use theme-aware colors instead of hardcoded hex values for background,
border, text, and hover states.

Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
…ckbar styling

- ShortcutField now uses react-i18next for all display text
- Added shortcut translation keys to all locale files
- Motion-board page gets its own ThemeProvider with system theme support
- Snackbar alerts use filled variant throughout

Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
…board

- Main window starts hidden to prevent flash of wrong theme
- Window shown once theme setting is resolved from store
- Motion-board initializes locale on mount

Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
Window starts with visible: false so theme can be resolved
before the user sees anything.

Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
… in other language READMEs; modify Tauri configuration for window title; adjust App component for conditional rendering; update visitor badge paths and GitHub links to new repository.
Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
…e off

The useEffect cleanup was async fire-and-forget (unlistenPromise.then(...)),
leaving stale key-press/key-release Tauri listeners alive during re-render.
When echo was toggled off, the new effect cleared the keyboard panel, but a
stale listener could fire in the gap and repopulate it. Timing differed per
WebView window, causing one monitor to clear while the other hung onto stale
key state.

Replaced promise-based cleanup with synchronous listener tracking via a
mutable array and cancellation flag.

Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
…p updates

Replaced ad-hoc signing ("-") with a persistent "Penio Dev" self-signed
certificate. macOS TCC now keys Accessibility/Input Monitoring grants to
the cert identity instead of the binary hash, so permissions survive DMG
updates without requiring the user to remove and re-grant them.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
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