mirror of
https://github.com/pbakaus/impeccable.git
synced 2026-09-17 08:36:25 +03:00
Copy buttons on code blocks + merge Skills and Tutorials under Docs
Two small-to-medium improvements bundled together.
1. Copy buttons on every rendered code block.
- render-markdown.js: wrap each fenced code block in a .code-block-wrap
container and emit a <button class="code-block-copy" data-copy="...">
alongside it. Button text is set via CSS ::before content so the
'Copy' / 'Copied' label is a single toggle class (.is-copied).
- render-page.js: 12-line inline script at the end of the body wires
a delegated click handler that calls navigator.clipboard.writeText
and flips .is-copied for 1.5s.
- sub-pages.css: button styles matching the dark terminal palette,
hidden until you hover the code block, accent-colored success state.
2. Merge Skills and Tutorials under a single Docs nav item.
- Rename the Skills nav link to 'Docs' in every header (partial +
4 hand-authored pages). Drop the separate Tutorials nav item; it
now lives inside Docs. Anti-patterns stays as its own top-level.
- scripts/build-sub-pages.js: replace renderSkillsSidebar and
renderTutorialsSidebar with a unified renderDocsSidebar that shows
every skill category followed by a Tutorials group. Takes a
current descriptor of shape { kind: 'skill'|'tutorial', id|slug }
so both skill detail and tutorial detail pages can mark the active
row. activeNav on every /skills/* and /tutorials/* page is now
'docs'; the shared site header's data-nav matches.
Verified: /skills/polish and /tutorials/getting-started both render
with the unified Docs sidebar (all 21 skills grouped by category +
both tutorials as a final group). The Docs nav item is aria-current
on both. Copy buttons appear on every fenced code block and toggle
to 'Copied' when clicked.
This commit is contained in:
@@ -56,9 +56,12 @@ export function createRenderer({ knownSkillIds = new Set(), currentSkillId = nul
|
||||
};
|
||||
|
||||
// Fenced code blocks — minimal glass-terminal styling, no syntax highlighter in v1.
|
||||
// Wrapped in a container with a copy button; click handling lives in the
|
||||
// page-level inline script added by render-page.js.
|
||||
renderer.code = ({ text, lang }) => {
|
||||
const langClass = lang ? ` code-block--${escapeAttr(lang)}` : '';
|
||||
return `<pre class="code-block${langClass}"><code>${escapeHtml(text)}</code></pre>\n`;
|
||||
const copyValue = escapeAttr(text);
|
||||
return `<div class="code-block-wrap"><pre class="code-block${langClass}"><code>${escapeHtml(text)}</code></pre><button class="code-block-copy" type="button" data-copy="${copyValue}" aria-label="Copy to clipboard"></button></div>\n`;
|
||||
};
|
||||
|
||||
return renderer;
|
||||
|
||||
@@ -102,6 +102,19 @@ export function renderPage({
|
||||
<main id="main">
|
||||
${bodyHtml}
|
||||
</main>
|
||||
<script>
|
||||
// Copy buttons on rendered code blocks
|
||||
document.addEventListener('click', (e) => {
|
||||
const btn = e.target.closest('[data-copy]');
|
||||
if (!btn) return;
|
||||
const text = btn.getAttribute('data-copy');
|
||||
if (!text) return;
|
||||
navigator.clipboard.writeText(text).then(() => {
|
||||
btn.classList.add('is-copied');
|
||||
setTimeout(() => btn.classList.remove('is-copied'), 1500);
|
||||
}).catch(() => {});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
`;
|
||||
|
||||
Reference in New Issue
Block a user