Skip to content

Commit 54db013

Browse files
nextlevelshitMichael Czechowski
authored andcommitted
feat(onboarding): replay button in settings (#179)
Co-authored-by: Michael Czechowski <mail@dailysh.it> Co-committed-by: Michael Czechowski <mail@dailysh.it>
1 parent 907b002 commit 54db013

2 files changed

Lines changed: 32 additions & 9 deletions

File tree

src/app.js

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -245,25 +245,33 @@ function wireOnboarding() {
245245
if (e.target === dialog) close("backdrop");
246246
});
247247

248+
// Expose a replay handle for the settings "Replay" button.
249+
function replay() {
250+
stepIdx = 0;
251+
render();
252+
try {
253+
dialog.showModal();
254+
track("onboarding_open");
255+
} catch (_) {}
256+
}
257+
248258
// Show only on first visit: no onboarded flag AND no recorded progress.
249259
let onboarded = false;
250260
try { onboarded = localStorage.getItem("codeCrispies.onboarded") === "1"; } catch (_) {}
251261
const hasProgress = Object.keys(lessonEngine.userProgress || {}).some(
252262
(k) => (lessonEngine.userProgress[k]?.completed?.length || 0) > 0
253263
);
254264
if (!onboarded && !hasProgress) {
255-
stepIdx = 0;
256-
render();
257265
// Defer to next frame so the page paints first
258-
requestAnimationFrame(() => {
259-
try {
260-
dialog.showModal();
261-
track("onboarding_open");
262-
} catch (_) {}
263-
});
266+
requestAnimationFrame(replay);
264267
}
268+
return { replay };
265269
}
266270

271+
// Module-scoped handle so the "Replay" settings button can re-open the
272+
// tour without rewiring listeners (which would double-bind).
273+
let _onboardingHandle = null;
274+
267275
// Track CodeMirror views for cleanup
268276
let sectionCodeViews = [];
269277

@@ -3461,7 +3469,18 @@ function init() {
34613469

34623470
// Onboarding tour — shown once on first visit when user has no progress.
34633471
// 5 steps; localStorage flag prevents re-showing after Skip / completion.
3464-
wireOnboarding();
3472+
_onboardingHandle = wireOnboarding();
3473+
3474+
// Replay onboarding from settings — clears flag + re-shows tour
3475+
// without rewiring listeners (the wireOnboarding handle is reused).
3476+
document.getElementById("reset-onboarding-btn")?.addEventListener("click", () => {
3477+
try { localStorage.removeItem("codeCrispies.onboarded"); } catch (_) {}
3478+
closeSidebar(); // dismiss the settings drawer
3479+
requestAnimationFrame(() => {
3480+
_onboardingHandle?.replay();
3481+
track("onboarding_replay");
3482+
});
3483+
});
34653484

34663485
// Click on editor content to focus CodeMirror
34673486
elements.editorContent?.addEventListener("click", () => {

src/index.html

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -619,6 +619,10 @@ <h4 data-i18n="settings">Settings</h4>
619619
</span>
620620
<input type="range" id="editor-font-size" min="11" max="20" step="1" value="14" class="settings-range" aria-label="Editor font size in pixels" />
621621
</label>
622+
<div class="settings-row">
623+
<span class="settings-label">Show intro tour again</span>
624+
<button id="reset-onboarding-btn" class="btn btn-sm btn-ghost" type="button">Replay</button>
625+
</div>
622626
<div class="settings-row">
623627
<span class="settings-label" data-i18n="resetAllProgress">Reset All Progress</span>
624628
<button id="reset-btn" class="btn btn-sm btn-ghost" data-i18n="reset">Reset</button>

0 commit comments

Comments
 (0)