From 8c5012ab89e045205b324430419bd401dd5b2494 Mon Sep 17 00:00:00 2001 From: Michael Czechowski Date: Thu, 15 Jan 2026 16:13:31 +0100 Subject: [PATCH] feat: extend references and enhance analytics tracking MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reference pages: - Add Transitions & Animations section (transition-*, animation-*) - Add CSS Variables section (--*, var(), :root) - Add Interactive Elements section (
, , , , , ) Analytics tracking (Umami v2): - Add lesson_nav tracking for next/prev navigation - Add lesson_select tracking for sidebar lesson clicks - Add reset_code tracking for code resets - Add help_open tracking for help dialog - Add sidebar_open tracking for menu opens - Add share_open and share_copy tracking for sharing 🤖 Generated with [Claude Code](https://claude.com/claude-code) --- src/app.js | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 54 insertions(+), 1 deletion(-) diff --git a/src/app.js b/src/app.js index 015f4ac..d8fc76a 100644 --- a/src/app.js +++ b/src/app.js @@ -195,6 +195,7 @@ let currentMode = "css"; let sidebarTrigger = null; function openSidebar() { + track("sidebar_open"); // Store trigger element for focus return sidebarTrigger = document.activeElement; @@ -444,6 +445,7 @@ function selectLesson(moduleId, lessonIndex) { } lessonEngine.setLessonByIndex(lessonIndex); + track("lesson_select", { module: moduleId, lesson: lessonIndex }); // Show lesson UI showLessonUI(); @@ -687,6 +689,7 @@ function nextLesson() { const success = lessonEngine.nextLesson(); if (success) { const newState = lessonEngine.getCurrentState(); + track("lesson_nav", { direction: "next", module: newState.module.id, lesson: newState.lessonIndex }); // Update URL updateHash(newState.module.id, newState.lessonIndex); @@ -702,6 +705,7 @@ function prevLesson() { const success = lessonEngine.previousLesson(); if (success) { const newState = lessonEngine.getCurrentState(); + track("lesson_nav", { direction: "prev", module: newState.module.id, lesson: newState.lessonIndex }); // Update URL updateHash(newState.module.id, newState.lessonIndex); @@ -728,6 +732,7 @@ function resetCode() { // Reset editor to initial code for current lesson lessonEngine.reset(); const engineState = lessonEngine.getCurrentState(); + track("reset_code", { module: engineState.module?.id, lesson: engineState.lessonIndex }); if (codeEditor && engineState.lesson) { codeEditor.setValue(engineState.lesson.initialCode || ""); } @@ -853,6 +858,7 @@ function runCode() { // ================= DIALOGS ================= function showHelp() { + track("help_open"); elements.helpDialog.showModal(); } @@ -915,6 +921,7 @@ function handleResetCodeClick() { // ================= SHARE DIALOG ================= function showShareDialog() { + track("share_open"); const engineState = lessonEngine.getCurrentState(); if (engineState.module && engineState.lesson !== null) { const shareUrl = getShareableUrl(engineState.module.id, engineState.lessonIndex); @@ -929,6 +936,7 @@ function closeShareDialog() { } async function copyShareUrl() { + track("share_copy"); try { await navigator.clipboard.writeText(elements.shareUrlInput.value); elements.copyFeedback.hidden = false; @@ -1370,12 +1378,42 @@ const referenceContent = { box-shadowx y blur spread colorbox-shadow: 0 4px 8px rgba(0,0,0,0.1); text-shadowx y blur colortext-shadow: 1px 1px 2px gray; transformtranslate, rotate, scaletransform: translateY(-2px); - transitionproperty duration easingtransition: all 0.3s ease; cursorpointer, default, text, grabcursor: pointer; +
+

Transitions & Animations

+ + + + + + + + + + + + + +
PropertyValuesExample
transitionproperty duration easingtransition: all 0.3s ease;
transition-propertyall, none, specifictransition-property: opacity;
transition-durationtime (s, ms)transition-duration: 0.3s;
transition-timing-functionease, linear, ease-in-outtransition-timing-function: ease-out;
animationname duration timing delayanimation: fade 1s ease-in;
animation-name@keyframes nameanimation-name: slide;
animation-durationtime (s, ms)animation-duration: 2s;
animation-iteration-countnumber, infiniteanimation-iteration-count: infinite;
animation-fill-modenone, forwards, backwards, bothanimation-fill-mode: forwards;
+
+ +
+

CSS Variables

+ + + + + + + + +
SyntaxDescriptionExample
--nameDefine custom property--primary: steelblue;
var(--name)Use custom propertycolor: var(--primary);
var(--name, fallback)With fallback valuecolor: var(--accent, blue);
:root { }Global scope:root { --gap: 1rem; }
+
+

See also: Flexbox Reference | Grid Reference | Selectors Reference

`, @@ -1737,6 +1775,21 @@ const referenceContent = { +
+

Interactive Elements

+ + + + + + + + + + +
ElementPurposeKey Attributes
<details>Expandable contentopen (default expanded)
<summary>Details toggle labelFirst child of details
<dialog>Modal/popup dialogopen, use showModal()
<progress>Progress barvalue, max
<meter>Scalar measurementvalue, min, max, low, high
<datalist>Input suggestionsid (link via input list attr)
+
+

Learn: HTML Section | Style with: CSS Properties

` };