feat(demo): typing splash + intro on every fresh visit; neutral desktop Cloud tabs

- Demo boots at '/' (first visit or a browser refresh) always start with
  the typing splash into the onboarding intro — the per-calendar-day
  gate is gone. In-session SPA navigation never replays it, and
  deep-route refreshes keep the visitor's place.
- Cloud top-level tabs return to the standard mode-switcher style on
  desktop; the orange full-width switcher stays mobile-only.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Dorian
2026-07-15 11:12:49 +01:00
co-authored by Claude Fable 5
parent 6e5a99ef71
commit c13ee58edf
5 changed files with 25 additions and 48 deletions
+6 -32
View File
@@ -1,10 +1,10 @@
/**
* Public-demo helpers.
*
* The demo build (VITE_DEMO=1) replays the intro/onboarding on each visit, but
* only once per calendar day per browser — tracked in localStorage so it
* survives the short-lived backend session. Also exposes the shared demo
* credentials shown on the login screen.
* The demo build (VITE_DEMO=1) replays the typing splash + intro/onboarding on
* EVERY fresh boot of the app at '/' (first visit or browser refresh) — see
* App.vue and RootRedirect.demoRoute. Also exposes the shared demo credentials
* shown on the login screen.
*/
export const IS_DEMO =
@@ -13,36 +13,10 @@ export const IS_DEMO =
/** Memorable shared password for the public demo (must match the mock backend). */
export const DEMO_PASSWORD = 'entertoexit'
const INTRO_DATE_KEY = 'demo_intro_date'
function todayKey(): string {
// Local calendar day, e.g. "2026-06-22".
const d = new Date()
return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`
}
/** True if this browser already watched the intro earlier today. */
export function demoIntroSeenToday(): boolean {
try {
return localStorage.getItem(INTRO_DATE_KEY) === todayKey()
} catch {
return false
}
}
/** Record that the intro has been seen today, so it won't replay until tomorrow. */
export function markDemoIntroSeen(): void {
try {
localStorage.setItem(INTRO_DATE_KEY, todayKey())
} catch {
/* ignore (private mode / storage disabled) */
}
}
/** Forget today's "seen" marker so the intro plays again (e.g. "Replay Intro"). */
/** Forget any legacy per-day gate marker (pre-2026-07 builds stored one). */
export function clearDemoIntroSeen(): void {
try {
localStorage.removeItem(INTRO_DATE_KEY)
localStorage.removeItem('demo_intro_date')
} catch {
/* ignore */
}