mirror of
https://github.com/got-feedBack/feedBack.git
synced 2026-08-11 03:09:57 +00:00
feat(onboarding): first-run home tour (spotlight coach marks) (#528)
* style(tour): align tour engine + Shepherd bubbles to the v3 fb-* palette The tour/help engine shipped its own indigo/blue dark palette (#181830 / #4080e0) that predates the v3 fee[dB]ack tokens, and the spotlight bubbles themselves used the vendored Shepherd LIGHT default (white card, black text) — both clashed with the navy/sky v3 UI behind them. - Recolor the "?" menu button, popover and first-visit toast to the fb-* tokens (card #1e293b, primary #0ea5e9, border #334155, text #f8fafc/#94a3b8, gold #e8c040 unchanged). - Add a dark .shepherd-* override block (loads after the vendored shepherd.css, which is left pristine for upgrades): dark bubble + arrow, fb-primary Next/Done button, slate secondary button, fb text scale, and bump the modal dim to 0.6 to match the onboarding overlay. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(tour-engine): let client/core tours register into the consolidated menu The tour engine only listed server-discovered plugins (those with a tour.json, populated from /api/plugins) in the "?" menu, and always prompted unseen relevant tours via the toast + button pulse. Generalize register() so a core/client-owned tour can participate: - `name` registers the tour into the menu catalog (_tourPlugins) so it shows in the "?" menu even without a server plugin; never clobbers a real plugin entry. - `autoPrompt:false` opts the tour OUT of the unseen toast + pulse (for tours driven programmatically by their owner), while still listing + running on demand. _unseenRelevant honours it. Both options are additive and default to the prior behaviour. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * chore(v3): add stable tour anchors to home cards + instrument badge Give the first-run home tour stable spotlight targets: #v3-hero on the hero panel and data-tour="continue" on the three continue/pick/browse card variants (dashboard.js), and #v3-instrument-wrap on the topbar instrument selector (badges.js, mirroring the existing #v3-tuner-wrap). The other targets (audio routing, tuner, profile, sidebar nav) already had stable ids. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(onboarding): first-run home tour (spotlight coach marks) After a genuine onboarding completion, dim the home page and spotlight one card at a time with an explanatory bubble + Next, reusing the shared tour engine (Shepherd). 7 stops: Hero/Start Playing → Continue/Pick → Instrument selector → Tuner → Audio Routing → Profile → Sidebar nav. Auto-runs once; replayable forever from the "?" tour menu as "Welcome tour". - New static/v3/onboarding-tour.js: registers the spotlight tour (screens: ['v3-home'], name "Welcome tour", autoPrompt:false) and exposes startFirstRun(), gated on the engine's seen/dismissed state so it never repeats; loaded after tour-engine.js + dashboard.js. - profile.js finish(): trigger startFirstRun() only on a real onboarding completion (!editing) — a later profile edit must not relaunch it. Verified headlessly (native core + Playwright): all 7 anchors resolve, the spotlight advances one bubble at a time in the v3 dark theme, completion marks seen, startFirstRun is once-only, and the "?" menu lists "Welcome tour". Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(capabilities): clear the handler timeout timer once the race settles Codex round-6: _withTimeout raced the handler promise against a bare setTimeout but never cleared it, so a handler that resolves first leaves the timer alive until it fires. Harmless at 250ms, but the new 15s MIDI permission-command overrides (discover/open-source) kept the event loop alive ~15s after every successful call (and the test process hung that long) and could accumulate delayed callbacks across repeated scans. Capture the timer and clearTimeout it in a .finally on the race. (Domain/capabilities tests now finish in ~0.1s, not 15s.) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(midi-input): give the built-in Web-MIDI provider a distinct participant id Codex round-7: the built-in Web-MIDI provider registered with participantId 'core.midi-input' — the same id as the domain owner. unregisterProvider() unregisters the provider's participant, so a provider swap/hot-reload would tear down the domain OWNER too, leaving midi-input with no owner for later commands. Register the provider as 'core.midi-input.web-midi'. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(onboarding): don't start the home tour when launching the diagnostic Codex round-7: on the final onboarding step, "Play it now" calls finish() (which started the home tour) and THEN playSong(target). startFirstRun() navigated to v3-home and scheduled the tour, then playSong switched to the player — so the tour spotlighted hidden home elements / stole focus from the diagnostic. Gate the tour on a launchingSong flag (passed by the "Play it now" path); the Skip path stays on home, so the tour still runs there. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
fb06e288e1
commit
c7fb074111
+24
-1
@@ -127,7 +127,13 @@
|
||||
}
|
||||
|
||||
function _unseenRelevant(screenId) {
|
||||
return _relevantPlugins(screenId).filter(p => !hasSeen(p.id) && !hasDismissed(p.id));
|
||||
// Drives the toast prompt + button "has-unseen" pulse. A tour registered
|
||||
// with autoPrompt:false is excluded — it's started programmatically by
|
||||
// its owner (e.g. the first-run home tour), so nagging via toast/pulse
|
||||
// would double up. It still lists in the menu and runs on demand.
|
||||
return _relevantPlugins(screenId).filter(p =>
|
||||
!hasSeen(p.id) && !hasDismissed(p.id) &&
|
||||
(_registry[p.id] ? _registry[p.id].autoPrompt !== false : true));
|
||||
}
|
||||
|
||||
// ── Menu UI ────────────────────────────────────────────────────────────
|
||||
@@ -615,7 +621,24 @@
|
||||
onStart: opts.onStart || null,
|
||||
onComplete: opts.onComplete || null,
|
||||
screens: Array.isArray(opts.screens) ? opts.screens.slice() : null,
|
||||
// autoPrompt:false opts the tour OUT of the unseen toast + button
|
||||
// pulse (it's driven programmatically by its owner, e.g. the
|
||||
// first-run home tour started from onboarding). It still lists in the
|
||||
// menu and runs via start(). Defaults to the legacy always-prompt.
|
||||
autoPrompt: opts.autoPrompt !== false,
|
||||
};
|
||||
// A `name` registers a CLIENT/CORE-owned tour — one that isn't a
|
||||
// server-discovered plugin with a tour.json — into the consolidated menu
|
||||
// catalog so it appears in the "?" menu. Never clobber a richer entry the
|
||||
// /api/plugins pass already supplied for a real plugin of the same id.
|
||||
if (opts.name && !_tourPlugins[pluginId]) {
|
||||
_tourPlugins[pluginId] = {
|
||||
id: pluginId,
|
||||
name: opts.name,
|
||||
has_screen: true,
|
||||
is_viz: false,
|
||||
};
|
||||
}
|
||||
// If the override changes the relevance for the current screen, refresh.
|
||||
_updateMenuVisibility();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user