feat(site): add interactive learning portal - #333
Conversation
📝 WalkthroughWalkthroughThe static course site now builds local lesson assets, persists reading progress and preferences, loads materials locally, adds lesson completion controls, and provides an interactive homepage course map with progress-aware navigation. ChangesCourse site experience
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant Browser
participant AppJS
participant AIFSProgress
participant LessonPage
Browser->>AppJS: load interactive course homepage
AppJS->>AIFSProgress: read completion state
AIFSProgress-->>AppJS: return progress data
AppJS-->>Browser: render course map and learning command
Browser->>LessonPage: open or resume lesson
LessonPage->>AIFSProgress: save scroll position or completion
AIFSProgress-->>AppJS: notify progress change
AppJS-->>Browser: refresh navigation state
Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (3 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (2)
site/lesson.html (1)
3309-3316: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick winGuard the clipboard call and handle rejection.
navigator.clipboardis undefined in non-secure contexts (e.g. serving over plain HTTP to a non-localhost host), sonavigator.clipboard.writeText(...)throws aTypeErrorand the click does nothing with no feedback. The promise also has no.catch, so a denied permission produces an unhandled rejection.♻️ Suggested guard
- button.addEventListener('click', function () { - navigator.clipboard.writeText(button.getAttribute('data-command')).then(function () { - button.textContent = 'Copied!'; - setTimeout(function () { button.textContent = 'Copy command'; }, 1500); - }); - }); + button.addEventListener('click', function () { + if (!navigator.clipboard) return; + navigator.clipboard.writeText(button.getAttribute('data-command')).then(function () { + button.textContent = 'Copied!'; + setTimeout(function () { button.textContent = 'Copy command'; }, 1500); + }).catch(function () {}); + });🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@site/lesson.html` around lines 3309 - 3316, Update the .code-card-copy click handler to verify navigator.clipboard and its writeText method exist before calling them, and handle rejected clipboard promises with user feedback. Preserve the existing “Copied!” success behavior, while providing a fallback message when the clipboard API is unavailable or the write fails.site/app.js (1)
276-307: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick winAvoid
getComputedStyleon every animation frame.
draw()runs eachrequestAnimationFrametick, and Line 280 callsgetComputedStyle(document.documentElement)per frame, forcing a style recalculation ~60×/sec for a value (--blueprint) that rarely changes. Read the stroke color once outside the loop (recompute only on theme change) to cut sustained main-thread cost.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@site/app.js` around lines 276 - 307, Move the --blueprint color lookup out of the per-frame draw() function and cache the resolved stroke color for reuse during animation. Update the cache only when the theme changes, while preserving the existing fallback color and ctx.strokeStyle behavior in draw().
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@site/app.js`:
- Around line 209-211: Replace the corrupted · separator with the correct
middle dot in the user-facing strings at site/app.js lines 209-211 and 240, and
site/lesson.html line 3224, including the Continue/Start phase labels, resume
text, node title, and Included with this lesson text.
---
Nitpick comments:
In `@site/app.js`:
- Around line 276-307: Move the --blueprint color lookup out of the per-frame
draw() function and cache the resolved stroke color for reuse during animation.
Update the cache only when the theme changes, while preserving the existing
fallback color and ctx.strokeStyle behavior in draw().
In `@site/lesson.html`:
- Around line 3309-3316: Update the .code-card-copy click handler to verify
navigator.clipboard and its writeText method exist before calling them, and
handle rejected clipboard promises with user feedback. Preserve the existing
“Copied!” success behavior, while providing a fallback message when the
clipboard API is unavailable or the write fails.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: e8136dad-4064-4d70-b00c-20110a20d1d9
📒 Files selected for processing (10)
.gitignoresite/README.mdsite/about.htmlsite/app.jssite/build.jssite/index.htmlsite/lesson.htmlsite/progress.jssite/style.csssite/tests/progress.test.js
| if (kicker) kicker.textContent = recent ? 'Continue · Phase ' + String(target.phase.id).padStart(2, '0') : 'Start · Phase ' + String(target.phase.id).padStart(2, '0'); | ||
| if (title) title.textContent = target.lesson.name; | ||
| if (meta) meta.textContent = completed + ' of ' + lessons.length + ' lessons completed' + (readingPct > 1 ? ' · resume at ' + readingPct + '%' : '') + '. Progress stays saved on this device.'; |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Fix mojibake separator in user-facing strings. The middle-dot separator was saved as corrupted UTF-8 (· instead of ·, U+00B7) and will render as garbled text in the UI. Replace each · with · (or the \u00B7 escape / · where markup allows).
site/app.js#L209-L211: correct'Continue · Phase ','Start · Phase ', and' · resume at 'to use·.site/app.js#L240-L240: correct the'Phase ' + ... + ' · ' + ...node title to use·.site/lesson.html#L3224-L3224: correct'Included with this lesson · 'to use·.
📍 Affects 2 files
site/app.js#L209-L211(this comment)site/app.js#L240-L240site/lesson.html#L3224-L3224
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@site/app.js` around lines 209 - 211, Replace the corrupted · separator with
the correct middle dot in the user-facing strings at site/app.js lines 209-211
and 240, and site/lesson.html line 3224, including the Continue/Start phase
labels, resume text, node title, and Included with this lesson text.
What this PR does
Kind of change
Checklist
LESSON_TEMPLATE.mdstructure[Name](phases/...)), not bare textdocs/en.mdclaimsPhase / lesson
Notes for reviewer