Skip to content

Commit 4378548

Browse files
Add developers route with code viewer
1 parent ca373ae commit 4378548

File tree

4 files changed

+118
-0
lines changed

4 files changed

+118
-0
lines changed

js/components/code-viewer.js

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
// File: js/components/code-viewer.js
2+
// Component for displaying code snippets in multiple languages with a selector
3+
4+
export default (hostComponent) => {
5+
const pres = Array.from(hostComponent.querySelectorAll('pre[data-lang]'));
6+
if (pres.length === 0) return;
7+
8+
const selector = document.createElement('select');
9+
pres.forEach((pre, index) => {
10+
const { lang } = pre.dataset;
11+
const code = pre.querySelector('code');
12+
if (code) {
13+
code.classList.add(`language-${lang}`);
14+
}
15+
const option = document.createElement('option');
16+
option.value = lang;
17+
option.textContent = lang;
18+
selector.appendChild(option);
19+
pre.style.display = index === 0 ? '' : 'none';
20+
});
21+
22+
selector.addEventListener('change', (event) => {
23+
const lang = event.target.value;
24+
pres.forEach((pre) => {
25+
pre.style.display = pre.dataset.lang === lang ? '' : 'none';
26+
});
27+
});
28+
29+
hostComponent.insertBefore(selector, hostComponent.firstChild);
30+
31+
const ensureHighlight = () =>
32+
new Promise((resolve) => {
33+
if (window.hljs) {
34+
resolve();
35+
return;
36+
}
37+
const link = document.createElement('link');
38+
link.rel = 'stylesheet';
39+
link.href =
40+
'https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/default.min.css';
41+
document.head.appendChild(link);
42+
const script = document.createElement('script');
43+
script.src =
44+
'https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js';
45+
script.onload = resolve;
46+
document.head.appendChild(script);
47+
});
48+
49+
ensureHighlight().then(() => {
50+
pres.forEach((pre) => {
51+
const code = pre.querySelector('code');
52+
if (code && window.hljs?.highlightElement) {
53+
window.hljs.highlightElement(code);
54+
}
55+
});
56+
});
57+
};
58+

js/components/code-viewer.test.js

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import { describe, it, expect, beforeEach, vi } from 'vitest';
2+
import codeViewer from './code-viewer.js';
3+
4+
beforeEach(() => {
5+
// Mock hljs to avoid loading external scripts during tests
6+
vi.stubGlobal('hljs', {
7+
highlightElement: vi.fn(),
8+
});
9+
});
10+
11+
describe('code-viewer component', () => {
12+
it('renders selector and shows only first snippet', () => {
13+
const host = document.createElement('div');
14+
host.innerHTML = `
15+
<pre data-lang="js"><code>console.log('hi')</code></pre>
16+
<pre data-lang="python"><code>print('hi')</code></pre>
17+
`;
18+
codeViewer(host);
19+
const select = host.querySelector('select');
20+
expect(select).toBeTruthy();
21+
const pres = host.querySelectorAll('pre[data-lang]');
22+
expect(pres[0].style.display).toBe('');
23+
expect(pres[1].style.display).toBe('none');
24+
});
25+
26+
it('switches visible snippet on selector change', () => {
27+
const host = document.createElement('div');
28+
host.innerHTML = `
29+
<pre data-lang="js"><code>console.log('hi')</code></pre>
30+
<pre data-lang="python"><code>print('hi')</code></pre>
31+
`;
32+
codeViewer(host);
33+
const select = host.querySelector('select');
34+
select.value = 'python';
35+
select.dispatchEvent(new Event('change'));
36+
const jsPre = host.querySelector('pre[data-lang="js"]');
37+
const pyPre = host.querySelector('pre[data-lang="python"]');
38+
expect(jsPre.style.display).toBe('none');
39+
expect(pyPre.style.display).toBe('');
40+
});
41+
});
42+

js/components/nav.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,10 @@ export default (hostComponent) => {
194194
<span class="icon">🧮</span>
195195
<span class="text">Web GPU tutorial</span>
196196
</a>
197+
<a href="/developers" title="Developer code examples">
198+
<span class="icon">💻</span>
199+
<span class="text">Developers</span>
200+
</a>
197201
<!-- <a href="/web-gpu" title="Web GPU Scene (wip)">
198202
<span class="icon">🧮</span>
199203
<span class="text">Web GPU</span>

js/routes/developers.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// File: js/routes/developers.js
2+
3+
export default (hostComponent) => {
4+
hostComponent.innerHTML = `
5+
<h1>Developers</h1>
6+
<p>Select a language to view the hello world snippet.</p>
7+
<div data-component="code-viewer">
8+
<pre data-lang="js"><code>console.log('Hello, world!');</code></pre>
9+
<pre data-lang="python"><code>print('Hello, world!')</code></pre>
10+
<pre data-lang="ruby"><code>puts 'Hello, world!'</code></pre>
11+
</div>
12+
`;
13+
};
14+

0 commit comments

Comments
 (0)