Skip to content
kandown
104 releases

Changelog

2026-07-27

v0.42.0· Onboarding Tour

Added

  • First-visit onboarding modal is now a real accessible dialog. The 3-step welcome that ships in src/components/OnboardingTour.tsx now exposes role="dialog", aria-modal="true", aria-labelledby, aria-describedby, and a polite live region that announces "Step X of Y" to screen readers on every transition. Focus is trapped inside the panel (Tab / Shift+Tab cycle) and restored to the previously-focused element on close, so the modal never strands the user mid-board. The Close onboarding button is the first thing that receives focus on open, matching how every other centered dialog in the app behaves.

  • Keyboard- and click-driven dismissal paths. Esc, backdrop click and X all dismiss the modal. Back works on steps 2 and 3, and is hidden on step 1 to avoid a useless click target. Settings still re-opens the modal via the existing kandown:showOnboarding window event, with the close-on-anywhere semantics applying to that re-opening too.

  • i18n the onboarding copy. Every visible string now lives under a new onboarding.* namespace in en.json (stepLabel, back, next, getStarted, close, plus three step<N>Title / step<N>Desc pairs, 11 keys total), consumed via useTranslation(). The same 11 keys have been translated to all 47 non-en locales; RTL locales (ar, fa, ur) wrap interpolation variables in U+200F so screen readers and copy-paste keep them readable LTR. A new idempotent injector lives at scripts/translate-onboarding.py for future-maintenance use: adding a new locale is "add the locale file + add its translations dict + rerun the script".

  • Per-project "first time only" gate now actually persists. A new configLoaded: boolean flag on the Zustand store flips to true only after loadConfig() (or openServerProject, which previously bypassed loadConfig entirely) resolves with the persisted kandown.json. The onboarding modal reads that flag instead of acting on the DEFAULT_CONFIG placeholder, so first-time visitors in a project whose kandown.json already has ui.onboardingCompleted: true never see the modal at all (no more flash-and-flicker on reload). A userHasClosedRef guard absorbs the brief window where setOpen(false) and the async updateConfig write race to re-open the modal for a single frame.

Changed

  • OnboardingTour lifecycle. The useEffect that auto-shows the modal now depends on both onboardingCompleted and configLoaded, so the modal cannot commit to opening until it has read the real persisted value. The Close onboarding aria-label is now i18n'd. Step transitions animate via the existing AnimatePresence pattern from Cheatsheet.tsx.

  • Settings → "Show onboarding tour" still re-opens the modal via the kandown:showOnboarding window event. Closing it is a no-op write to the persistent flag when the flag is already true, so re-opening does not toggle the persisted state.