Files
DSA-Site/lesson-loader.js
pauljd 2b66e1042e
pauljd/davidson-ci: Davidson CI / quality (push) Failing after 34s
pauljd/davidson-ci: Davidson CI / ai-review (push) Failing after 29s
Initial DSA site
2026-09-12 11:50:43 +01:00

78 lines
2.9 KiB
JavaScript

// Loads a lesson's markdown (DSA/*.md) into the right-hand content pane
// when a sidebar link with [data-lesson] is clicked, renders it with
// marked.js, syntax-highlights code blocks with highlight.js, and adds a
// copy button to each code block.
(() => {
"use strict";
const COPY_ICON = `<svg viewBox="0 0 16 16"><path d="M4 2a2 2 0 0 0-2 2v9a2 2 0 0 0 2 2h1a.5.5 0 0 0 0-1H4a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h6a1 1 0 0 1 1 1v1a.5.5 0 0 0 1 0V4a2 2 0 0 0-2-2H4z"/><path d="M7 6a2 2 0 0 0-2 2v6a2 2 0 0 0 2 2h5a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2H7zm-1 2a1 1 0 0 1 1-1h5a1 1 0 0 1 1 1v6a1 1 0 0 1-1 1H7a1 1 0 0 1-1-1V8z"/></svg>`;
const CHECK_ICON = `<svg viewBox="0 0 16 16"><path d="M13.854 3.646a.5.5 0 0 1 0 .708l-7 7a.5.5 0 0 1-.708 0l-3.5-3.5a.5.5 0 1 1 .708-.708L6.5 10.293l6.646-6.647a.5.5 0 0 1 .708 0z"/></svg>`;
const addCopyButtons = (container) => {
container.querySelectorAll("pre code").forEach((codeEl) => {
const pre = codeEl.parentElement;
const wrapper = document.createElement("div");
wrapper.className = "code-block";
pre.replaceWith(wrapper);
wrapper.appendChild(pre);
const button = document.createElement("button");
button.type = "button";
button.className = "code-copy-btn";
button.setAttribute("aria-label", "Copy code");
button.innerHTML = COPY_ICON;
button.addEventListener("click", async () => {
try {
await navigator.clipboard.writeText(codeEl.textContent);
button.innerHTML = CHECK_ICON;
button.classList.add("copied");
setTimeout(() => {
button.innerHTML = COPY_ICON;
button.classList.remove("copied");
}, 1500);
} catch (err) {
console.error("Copy failed", err);
}
});
wrapper.appendChild(button);
});
};
const loadLesson = async (url, pane) => {
pane.innerHTML = `<p class="lesson-placeholder">Loading…</p>`;
try {
const response = await fetch(url);
if (!response.ok) throw new Error(`${response.status} ${response.statusText}`);
const markdown = await response.text();
pane.innerHTML = marked.parse(markdown);
pane.querySelectorAll("pre code").forEach((block) => {
hljs.highlightElement(block);
});
addCopyButtons(pane);
} catch (err) {
pane.innerHTML = `<p class="lesson-placeholder">Couldn't load this lesson (${err.message}).</p>`;
}
};
window.addEventListener("DOMContentLoaded", () => {
const pane = document.getElementById("lesson-pane");
if (!pane) return;
document.querySelectorAll("[data-lesson]").forEach((link) => {
link.addEventListener("click", (event) => {
event.preventDefault();
document
.querySelectorAll("[data-lesson].active")
.forEach((el) => el.classList.remove("active"));
link.classList.add("active");
loadLesson(link.dataset.lesson, pane);
});
});
});
})();