Skip to content

Per-list themes, localization, Follow System Theme fix and other fixes - #190

Open
fildunsky wants to merge 21 commits into
davidsmorais:masterfrom
fildunsky:feat/list-themes-i18n-fixes
Open

fildunsky wants to merge 21 commits into
davidsmorais:masterfrom
fildunsky:feat/list-themes-i18n-fixes

Conversation

@fildunsky

@fildunsky fildunsky commented Sep 6, 2026 •

Copy link
Copy Markdown

A batch of fixes and features from daily use of Kuro on Ubuntu GNOME (Wayland/XWayland, HiDPI). Each commit is self-contained and can be reviewed (or dropped) on its own.

Fixes

  • Follow System Theme (Auto Night Mode) actually follows the OS. It compared the truthiness of <html data-theme>, which To-Do always sets, so the app stayed dark after the system switched to light. Now follows prefers-color-scheme, themes the loading screen too, and flips To-Do's own dark-mode switch so the choice persists.
  • Menu/shortcut commands work again against the current To-Do DOM: Complete/Rename/Delete To-Do, Add to My Day, Set Reminder/Due Date/Repeat (lazy detail pane), Tasks, Toggle Sidebar, Sign out, Ctrl+1..9, next/previous list. window.open() links go to the system browser via setWindowOpenHandler.
  • Layout glitches: the sidebar comes back after narrowing and widening the window (it used to stay trapped behind the hamburger); the header search icon is pinned above the list title instead of floating right on wide windows; the list header no longer jumps between My Day and other lists; To-Do's settings pane closes on a click outside.
  • Delete-list button readable in the light theme; notification toasts have a background again.
  • Nix packaging: electron_22 no longer exists in nixpkgs; hicolor icons are rendered at the right sizes; meta.mainProgram.

Fixes from a review pass over the code base

  • Startup: startup.js still used the remote module (gone since Electron 14) on macOS and crashed the preload; an unparsable or extended kuro.json (trailing comma, "$schema") threw at startup; a global shortcut Electron cannot parse threw before the window was shown, leaving the app running invisibly. Menus and the tray template are now built after ready, so "system" language resolves on Windows/macOS too.
  • Header search icon jumped when switching lists (measured with transforms in flight; NaN on lists with an SVG icon).
  • The list theme was dropped while the sidebar was collapsed (To-Do unmounts the active entry the key came from).
  • "Dark Theme" while "Follow System Theme" is on flipped the theme and the pin flipped it straight back.
  • Checkbox items duplicated across menu, tray and settings window got out of sync and needed two clicks; language change relaunched with app.exit() and lost the window state; crashed (removed in Electron 44) replaced by render-process-gone; closing the window with "Hide Tray" on left the app with no way back; Help > Keyboard Shortcuts now lists the configured accelerators; toggle-list-accents / list-theme-panel are customizable on all platforms.
  • Kuro Settings: shortcut validation (modifiers + one key), the Language select always showed "System", a malformed kuro.json broke every read/write in the window, and a few smaller state issues.
  • Theme pane: closed early on a bubbled transitionend, the active ring on scene tiles was clipped by overflow: hidden, and the :where() button reset never applied (injected sheets lose specificity ties with the page's own CSS).

Features

  • Per-list themes ([Feature 🚀]: Color theme for section only #91): seven colours + seven light tints or eight scenes, per list and for My Day. The picker is a pane that slides in from the right like To-Do's own settings pane (palette button next to the gear, View > Change List Theme, Ctrl+Shift+B, tray).
  • Follow List Colors ([Feature 🚀]: Color theme for section only #91): the list view and its sidebar entry follow the colour palette To-Do assigns to the list.
  • Localization: English and Russian for menus, tray and dialogs, with View > Language (system/en/ru). The chosen language is also applied to the To-Do web app itself ("Add a task", dates) via the process locale.
  • Kuro Settings window (native controls, three tabs) replaces "Edit Kuro Settings (JSON)". Hiding the menu bar is no longer a one-way trap.
  • Reopen the last open list on launch ([Feature 🚀]: Set Default Launch List #111), on by default.
  • Update check via the GitHub Releases API, with docs/update.json as fallback (the manifest was stuck at 9.0.0).
  • Config in ~/.config/Kuro/kuro.json (XDG / Electron userData), migrating ~/.kuro.json automatically.
  • Zoom range 50–300%.
  • Readme: snap channel, config location, Wayland notes.
  • Motion. One motion language for everything Kuro adds to To-Do: an eased 350 ms slide for the theme pane, a subtle bounce-in for the task area on a list switch and for the pane content, underline/pill indicators that slide between tabs (theme pane, Kuro Settings), hover/press scaling on swatches, a soft ring flash confirming a choice, colour cross-fade when the theme flips, toasts popping in. Everything is off under prefers-reduced-motion.
  • Kuro Settings follow the desktop accent colour (xdg-desktop-portal org.freedesktop.appearance accent-color, GNOME 47+ / Plasma 6, with GNOME's named accent-color as fallback): checkboxes, selects and the active tab use it via accent-color; the old colours remain the fallback.

Testing

Built with electron-builder (deb) and run daily against a logged-in Microsoft account on Ubuntu GNOME at 200% scaling (Wayland), Electron 44. Search alignment, pane/indicator transitions, flash timing, the list theme surviving a sidebar collapse and the accent colour were verified through CDP against the running app. xo and stylelint report no new findings (the 18 / 17 pre-existing ones are untouched).

Note for reviewers of the theme pane: its DOM is built once and only updated in place. Fluent UI toggles a class on <body> at every mousedown; a pane re-rendered from a mutation observer at that moment loses the button under the cursor before mouseup, so real clicks never become click events (scripted .click() still works, which made it hard to spot).

- default.nix: electron_22 no longer exists in nixpkgs; use pkgs.electron
- release.nix: render properly sized hicolor icons from the 1080px source
  (the desktop item's Icon=kuro was pointing at wrongly sized files) and
  set meta.mainProgram
- docs/update.json: point at the current release (9.1.3)
Most commands driven from the menus/shortcuts clicked selectors that no
longer exist in MS To-Do, so they silently did nothing:

- Complete To-Do, Rename/Delete To-Do, Add to My Day, Set Reminder,
  Add Due Date, Set Repeat: the detail pane is a lazy-loaded chunk, so
  open it and click inside once it is rendered (nav.waitFor/clickWhenReady)
- Tasks (smart list), Toggle Sidebar, Sign out: updated selectors; the
  account menu is rendered lazily, so wait for it instead of a fixed timeout
- Dark Theme goes through mode.dark() so the state stays consistent
- Ctrl+1..9 and next/previous list no longer throw while the sidebar is
  collapsed (To-Do unmounts it) and jump to the right list
- nav.click() no longer throws on a missing element and reports whether
  it clicked
- window.open() links go to the system browser via setWindowOpenHandler
  (the "new-window" event was removed in Electron 22)
The old 70–130% range was too narrow on HiDPI screens.
Auto Night Mode compared the truthiness of <html data-theme>, which To-Do
always sets ("default" for light), so the app stayed dark after the
system switched to light. It also required win.activate() from the
renderer, which does not exist there.

Now the renderer follows prefers-color-scheme: it pins data-theme to the
OS scheme from the first paint (so the loading screen is themed too),
remembers what To-Do wanted and flips To-Do's own dark-mode switch so the
choice persists, and re-syncs on every OS change. The window background
colour follows nativeTheme to avoid a white flash before first paint.
docs/update.json was stuck at 9.0.0, so the update check never noticed
new releases. Ask api.github.com for the latest release first and fall
back to the manifest; version parsing tolerates "v9.1.3" and
pre-release suffixes.
kuro.json now lives next to Electron's own data (~/.config/Kuro on Linux,
following the XDG base directory spec) instead of ~/.kuro.json. An
existing ~/.kuro.json is migrated on first start. The path is resolved
the same way in the main process and in the preload, where electron.app
is not available.
All menu, tray and dialog strings go through src/locale.js (t()), with
English and Russian tables in src/locales. The language comes from
KURO_LANG, the new View > Language setting (system/en/ru; relaunches),
the OS locale, or LANG.

The To-Do web app picks its own language bundle ("Add a task", dates)
from navigator.language, which follows the process locale, so the chosen
language is also applied to LANG/LC_ALL/LANGUAGE, --lang and the
Accept-Language header. "Auto Night Mode" is now called "Follow System
Theme"; "MS ToDo Settings" and "To-Do Settings" are unified.
The last URL was already stored, but never used. Start on it (unless it
is an auth or task-detail URL) when the new View > Reopen Last List
option is on, which is the default. Full navigations are tracked too.
File > Kuro Settings… (and the tray) open a small native window
(BaseWindow + WebContentsView with standard form controls) with three
tabs: General (launch on start, launch minimized, tray, menu bar, exit
confirmation, global shortcuts, update-check period), Appearance
(follow system theme, language, the custom theme colours) and Shortcuts.
The JSON file and its folder can still be opened from there; the
"Edit Kuro Settings (JSON)" menu item is gone.

Hiding the menu bar used to be a trap (the setting was never persisted
and there was no way back); it is now persisted and can be undone from
the settings window, the tray, or Alt.
- Narrowing the window switches To-Do to its overlay layout; widening it
  again left the sidebar hidden behind the hamburger. Restore the sidebar
  when the window grows back (the old CSS that hid .leftColumn below
  620px is gone, it caused the same trap).
- The header search icon floated far to the right on wide windows; pin it
  above the list title icon (transform only, so the O365 header keeps its
  own measurements) and keep the gear above the expanding search box.
- My Day has a date line under its title, other lists do not, so the
  header jumped when switching lists; give every list the same geometry.
- To-Do's settings pane only closed from its own button; close it on a
  click outside as well.
The destructive button override left dark text on red in the light theme
(its custom-theme variables are undefined there); only recolour it under
the custom theme, bold white on red like To-Do's own. Notification toasts
used --bg-primary-transparent, which To-Do never defines.
MS To-Do web marks the current list's colour on #app.theme-<name> and
ships a palette per theme, but Kuro's brand colour overrode it. With
View > Follow List Colors (default on) the list view and the list's own
sidebar entry follow that palette, like the official clients do; nothing
outside the current list is recoloured.
…ais#91)

Like the mobile clients: each list (and My Day) can get a background
theme - seven solid colours and seven light tints, or eight CSS-drawn
scenes. Stored per list in the settings store and applied through <html
data-kuro-background> plus CSS variables; the list header switches to
light or dark text to stay readable.

The picker is a pane that slides in from the right over the To-Do UI,
with the same geometry, header and close button as To-Do's own settings
pane, opened from a palette button next to the gear, View > Change List
Theme (Ctrl+Shift+B) or the tray. It closes on Escape, on a click
outside, and when To-Do's own settings pane opens.

Its DOM is built once and updated in place on purpose: Fluent UI toggles
a class on <body> at every mousedown, which fired the background observer;
a pane re-rendered at that moment loses the button under the cursor
before mouseup, so real clicks never became click events.
@fildunsky
fildunsky force-pushed the feat/list-themes-i18n-fixes branch from a82c06e to 33df543 Compare September 6, 2026 07:52
…tion flash

Bring one motion language to everything Kuro adds to To-Do (borrowed from
zashboard): an iOS-style ease (cubic-bezier(0.32, 0.72, 0, 1)) for movement,
a springy one for indicators, a subtle bounce-in for content that appears
and a soft ring flash confirming a choice. All of it respects
prefers-reduced-motion.

- src/style/motion.css: shared keyframes and eases; the list column's content
  bounces in on a list switch (html.kuro-list-switch set by background.js);
  sidebar entries, tasks and buttons transition their colours; toasts pop in;
  dark/light toggles cross-fade colours for 300 ms (html.kuro-theme-switch set
  by mode.js).
- Theme pane: 350 ms eased slide, content bounce-in, an underline that slides
  between the Color/Scenes tabs, swatch/scene hover and press scaling, the
  active ring springs in, the clicked swatch flashes in its own colour.
  Also fixes the active ring on scene tiles, which overflow: hidden clipped.
- Kuro Settings: a pill slides behind the active tab (spring), panels bounce
  in, the row/select/input that was just saved flashes, hover transitions.
The search icon is aligned to the list title by measuring both with
getBoundingClientRect(), which includes transforms in flight - the list-switch
bounce-in scaled the toolbar for 400 ms, so the first measurement after a
switch landed a few pixels off and a later one corrected it. Measure layout
positions (offsetLeft chain) instead, keep the toolbar out of the list-switch
animation, and let the icon glide to a new anchor with the shared ease.
Checkboxes, selects and the active tab used a hardcoded teal and Chromium's
default blue. Read the desktop accent through the xdg-desktop-portal Settings
interface (org.freedesktop.appearance accent-color; GNOME 47+, KDE Plasma 6),
falling back to GNOME's named accent-color key, and apply it as
`accent-color` for the native form controls and as the window's --accent.
Text on the accent picks black or white by luminance. The old colours remain
the fallback when the desktop publishes none.
…ne handoff

- close() hid the pane on the first bubbled transitionend (a button's hover
  colour finishing mid-slide) and its fallback timer was shorter than the
  slide; only the pane's own transform counts now, fallback 450 ms.
- flash(): clear the previous timer/listener on restart, ignore the active
  ring's animationend (dispatched to the same node), keep the light swatch's
  inset ring while flashing.
- Injected sheets lose specificity ties with To-Do's own button reset, so the
  :where() reset never applied: tabs and the "No background" button size
  themselves explicitly (tabs share the row, indicator follows).
- When To-Do's settings pane is open, wait for it to leave the DOM before
  watching for it, otherwise our pane closed itself at once.
- Reduced motion also covers the palette icon press.
…with Follow System

- background.js: To-Do unmounts the sidebar when collapsed, so the active
  list entry (the key source) disappeared and the background was dropped;
  remember the key per URL. The list-switch bounce only plays between two
  real lists. Themes are cached in memory instead of re-reading the store on
  every class mutation, and <html> attributes are written only on change.
  The observer also watches childList so the restored theme applies as soon
  as To-Do renders.
- mode.js: Dark Theme while Follow System Theme is on flipped the theme and
  the pin flipped it straight back (To-Do's settings pane flashing twice);
  a manual choice now ends Follow System first. The colour cross-fade starts
  when the colours actually flip, not before the settings pane is fetched.
- list-backgrounds.css: the toolbar subline (My Day's date) follows the tone
  colour too. browser.css: --bg-danger fallback restored for platforms whose
  defaults lack it.
- startup.js used `remote` (removed in Electron 14) on macOS and crashed the
  preload; use process.execPath. Autostart for an AppImage now points at the
  image ($APPIMAGE), not the transient mount point.
- config.js: an unparsable or extended kuro.json (trailing comma, "$schema")
  threw at startup; unknown sections/keys are dropped instead.
- index.js: a global shortcut Electron cannot parse threw before the window
  was shown (app running invisibly); guarded. Menus and the tray template
  are built after ready so "system" language resolves on Windows/macOS too.
  "crashed" is gone in Electron 44: log render-process-gone. Closing the
  window with Hide Tray on quits instead of hiding with no way back.
- Checkbox menu items (menu, tray) toggle from the stored value, so copies
  of the same setting no longer need two clicks after getting out of sync.
  Language change relaunches via quit() so the window state is saved.
  Dead focusedWindow.send() removed. Help > Keyboard Shortcuts lists the
  configured accelerators instead of hardcoded Linux ones.
- configs: toggle-list-accents and list-theme-panel are customizable on all
  platforms. updateCheckPeriod default is a string like the menu compares.
- win.js: drop the dead enableRemoteModule option.
- Shortcuts are validated as Electron accelerators (modifiers + one key);
  before, any ASCII passed and a typo made the app start without a window.
- The Language select always showed "System": the stored language was not
  part of the state.
- A malformed kuro.json no longer breaks every read/write in the window.
- Language change relaunches via quit() (window state saved);
  disableAutoUpdateCheck is marked as needing a restart; text colour fields
  keep the exact saved value; a reverted shortcut field drops its error
  state; flash() cleans up its previous timer/listener.
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