Skip to content

Commit e48a373

Browse files
author
yashrajbharticybtekk
committed
Feat: Searchbar
1 parent b28ddf7 commit e48a373

File tree

3 files changed

+200
-105
lines changed

3 files changed

+200
-105
lines changed

index.html

Lines changed: 72 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1,76 +1,81 @@
11
<!DOCTYPE html>
22
<html>
3-
<head>
4-
<meta charset="utf-8">
5-
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
6-
<title>WebGPU Samples</title>
7-
<meta
8-
name="description"
9-
content="The WebGPU Samples are a set of samples demonstrating the use of the WebGPU API."
10-
/>
11-
<meta
12-
name="viewport"
13-
content="width=device-width, initial-scale=1, shrink-to-fit=no"
14-
/>
153

16-
<link
17-
href="https://fonts.googleapis.com/css?family=Inconsolata&display=swap"
18-
rel="stylesheet"
19-
/>
20-
<link
21-
rel="icon"
22-
type="image/x-icon"
23-
href="favicon.ico"
24-
/>
4+
<head>
5+
<meta charset="utf-8">
6+
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
7+
<title>WebGPU Samples</title>
8+
<meta name="description" content="The WebGPU Samples are a set of samples demonstrating the use of the WebGPU API." />
9+
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
2510

26-
<link href="css/styles.css" rel="stylesheet">
11+
<link href="https://fonts.googleapis.com/css?family=Inconsolata&display=swap" rel="stylesheet" />
12+
<link rel="icon" type="image/x-icon" href="favicon.ico" />
2713

28-
</head>
29-
<script defer type="module" src="main.js"></script>
30-
<body>
31-
<div class="wrapper">
32-
<nav class="panel container">
33-
<h1>
34-
<a href="./">WebGPU Samples</a>
35-
</h1>
36-
<input type="checkbox" id="menuToggle">
37-
<label class="expand" for="menuToggle"></label>
38-
<div class="panelContents">
39-
<a href="https://github.com/webgpu/webgpu-samples">
40-
Github
41-
</a>
14+
<link href="css/styles.css" rel="stylesheet">
15+
16+
</head>
17+
<script defer type="module" src="main.js"></script>
18+
19+
<body>
20+
<div class="wrapper">
21+
<nav class="panel container">
22+
<h1>
23+
<a href="./">WebGPU Samples</a>
24+
</h1>
25+
<input type="checkbox" id="menuToggle">
26+
<label class="expand" for="menuToggle"></label>
27+
<div class="panelContents">
28+
<search>
4229
<hr>
43-
<div id="samplelist"></div>
44-
</div>
45-
</nav>
30+
<label>
31+
<svg width="24px" height="24px" viewBox="0 0 1024 1024" class="icon" version="1.1"
32+
xmlns="http://www.w3.org/2000/svg">
33+
<title>Search</title>
34+
<path
35+
d="M448 768A320 320 0 1 0 448 128a320 320 0 0 0 0 640z m297.344-76.992l214.592 214.592-54.336 54.336-214.592-214.592a384 384 0 1 1 54.336-54.336z"
36+
fill="currentColor" />
37+
</svg>
38+
<input type="search" name="search">
39+
</label>
40+
<hr>
41+
</search>
42+
43+
<a href="https://github.com/webgpu/webgpu-samples">
44+
Github
45+
</a>
46+
<hr>
47+
<div id="samplelist"></div>
48+
</div>
49+
</nav>
4650

47-
<main>
48-
<div id="intro">
49-
<p>
50-
The WebGPU Samples are a set of samples and demos demonstrating the use
51-
of the <a href="//webgpu.dev">WebGPU API</a>. Please see the current
52-
implementation status and how to run WebGPU in your browser at
53-
<a href="//webgpu.io">webgpu.io</a>.
54-
</p>
51+
<main>
52+
<div id="intro">
53+
<p>
54+
The WebGPU Samples are a set of samples and demos demonstrating the use
55+
of the <a href="//webgpu.dev">WebGPU API</a>. Please see the current
56+
implementation status and how to run WebGPU in your browser at
57+
<a href="//webgpu.io">webgpu.io</a>.
58+
</p>
59+
</div>
60+
<div id="sample" style="display: none;">
61+
<div class="sampleInfo">
62+
<h1 id="title"></h1>
63+
<a id="src" target="_blank" rel="noreferrer" href="">View source!</a>
64+
&mdash; <a id="standalone" target="_blank" rel="noreferrer" href="">View as standalone webpage</a>
65+
<p id="description"></p>
5566
</div>
56-
<div id="sample" style="display: none;">
57-
<div class="sampleInfo">
58-
<h1 id="title"></h1>
59-
<a id="src" target="_blank" rel="noreferrer" href="">View source!</a>
60-
&mdash; <a id="standalone" target="_blank" rel="noreferrer" href="">View as standalone webpage</a>
61-
<p id="description"></p>
62-
</div>
63-
<div class="sampleContainer"></div>
67+
<div class="sampleContainer"></div>
68+
</div>
69+
<nav id="code" class="sourceFileNav">
70+
<div class="sourceLR" id="sourceL">&lt;</div>
71+
<div id="sourceTabs" class="sourceFileScrollContainer">
72+
<ul id="codeTabs"></ul>
6473
</div>
65-
<nav id="code" class="sourceFileNav">
66-
<div class="sourceLR" id="sourceL">&lt;</div>
67-
<div id="sourceTabs" class="sourceFileScrollContainer">
68-
<ul id="codeTabs"></ul>
69-
</div>
70-
<div class="sourceLR" id="sourceR">&gt;</div>
71-
</nav>
72-
<div id="sources"></div>
73-
</main>
74-
</div>
75-
</body>
76-
</html>
74+
<div class="sourceLR" id="sourceR">&gt;</div>
75+
</nav>
76+
<div id="sources"></div>
77+
</main>
78+
</div>
79+
</body>
80+
81+
</html>

public/css/MainLayout.css

Lines changed: 45 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,48 @@ main {
6464
overflow: auto;
6565
}
6666

67+
search {
68+
inline-size: 100%;
69+
margin-block-end: 20px;
70+
71+
&>hr {
72+
border-color: var(--tooltip-border);
73+
margin-block: 0;
74+
}
75+
76+
&>label {
77+
display: flex;
78+
justify-content: flex-start;
79+
align-items: center;
80+
gap: 10px;
81+
inline-size: 100%;
82+
block-size: 50px;
83+
84+
&:has(input:focus)>svg {
85+
display: none;
86+
}
87+
88+
&>svg {
89+
margin-inline-start: 10px;
90+
}
91+
92+
&>input {
93+
opacity: 0;
94+
border: none;
95+
block-size: 100%;
96+
flex: 1;
97+
padding-inline: 20px;
98+
background-color: var(--panel-background);
99+
font-size: 1rem;
100+
101+
&:is(:focus) {
102+
opacity: 1;
103+
}
104+
}
105+
}
106+
107+
}
108+
67109
@media only screen and (max-width: 768px) {
68110
.wrapper {
69111
flex-direction: column;
@@ -73,12 +115,12 @@ main {
73115
overflow: visible;
74116
}
75117

76-
#menuToggle ~ .panelContents {
118+
#menuToggle~.panelContents {
77119
max-height: 0;
78120
overflow: hidden;
79121
}
80122

81-
#menuToggle:checked ~ .panelContents {
123+
#menuToggle:checked~.panelContents {
82124
max-height: 2000px;
83125
}
84126

@@ -98,5 +140,4 @@ main {
98140
display: inline-block;
99141
}
100142

101-
}
102-
143+
}

src/main.ts

Lines changed: 83 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -273,47 +273,96 @@ function setSampleIFrameURL(e: PointerEvent, sampleInfo: SampleInfo) {
273273
setSampleIFrame(sampleInfo);
274274
}
275275

276+
const searchInput = document.querySelector(
277+
'input[type="search"]'
278+
) as HTMLInputElement;
279+
280+
let debounceTimer: number | undefined;
281+
282+
searchInput.addEventListener('input', () => {
283+
clearTimeout(debounceTimer);
284+
debounceTimer = window.setTimeout(() => {
285+
const q = searchInput.value.trim();
286+
const url = new URL(window.location.href);
287+
288+
if (q) {
289+
url.searchParams.set('q', q);
290+
} else {
291+
url.searchParams.delete('q');
292+
}
293+
294+
// Do NOT touch 'sample' param — we preserve it
295+
history.replaceState(null, '', url.toString());
296+
297+
// Re-render the list
298+
sampleListElem.innerHTML = '';
299+
samplesByKey.clear();
300+
renderSampleList();
301+
}, 200); // debounce delay
302+
});
303+
276304
// Samples are looked up by `?sample=key` so this is a map
277305
// from those keys to each sample.
278306
const samplesByKey = new Map<string, SampleInfo>();
279307

308+
renderSampleList();
309+
280310
// Generate the list of samples
281-
for (const { title, description, samples } of pageCategories) {
282-
for (const [key, sampleInfo] of Object.entries(samples)) {
283-
samplesByKey.set(key, sampleInfo);
284-
}
311+
function renderSampleList() {
312+
const url = new URL(window.location.href);
313+
const q = url.searchParams.get('q')?.toLowerCase().trim() || '';
314+
315+
sampleListElem.innerHTML = '';
316+
samplesByKey.clear();
317+
318+
for (const { title, description, samples } of pageCategories) {
319+
const filteredSamples = Object.entries(samples).filter(([, sample]) => {
320+
if (!q) return true;
321+
const name = sample.name?.toLowerCase() || '';
322+
const tocName = sample.tocName?.toLowerCase() || '';
323+
const titleMatch = title.toLowerCase().includes(q);
324+
return name.includes(q) || tocName.includes(q) || titleMatch;
325+
});
285326

286-
sampleListElem.appendChild(
287-
el('ul', { className: 'exampleList' }, [
288-
el('div', {}, [
289-
el('div', { className: 'sampleCategory' }, [
290-
el('h3', {
291-
style: { 'margin-top': '5px' },
292-
textContent: title,
293-
dataset: { tooltip: description },
294-
}),
295-
]),
296-
...Object.entries(samples).map(([key, sampleInfo]) =>
297-
el('li', {}, [
298-
el('a', {
299-
href: sampleInfo.external
300-
? sampleInfo.external.url
301-
: sampleInfo.filename,
302-
...(!sampleInfo.openInNewTab && {
303-
onClick: (e: PointerEvent) => {
304-
setSampleIFrameURL(e, sampleInfo);
305-
},
306-
}),
307-
textContent: `${sampleInfo.tocName || key}${
308-
sampleInfo.openInNewTab ? ' ↗️' : ''
309-
}`,
310-
...(sampleInfo.openInNewTab && { target: '_blank' }),
327+
// Skip categories with no matches
328+
if (filteredSamples.length === 0) continue;
329+
330+
for (const [key, sampleInfo] of filteredSamples) {
331+
samplesByKey.set(key, sampleInfo);
332+
}
333+
334+
sampleListElem.appendChild(
335+
el('ul', { className: 'exampleList' }, [
336+
el('div', {}, [
337+
el('div', { className: 'sampleCategory' }, [
338+
el('h3', {
339+
style: { 'margin-top': '5px' },
340+
textContent: title,
341+
dataset: { tooltip: description },
311342
}),
312-
])
313-
),
314-
]),
315-
])
316-
);
343+
]),
344+
...filteredSamples.map(([key, sampleInfo]) =>
345+
el('li', {}, [
346+
el('a', {
347+
href: sampleInfo.external
348+
? sampleInfo.external.url
349+
: sampleInfo.filename,
350+
...(!sampleInfo.openInNewTab && {
351+
onClick: (e: PointerEvent) => {
352+
setSampleIFrameURL(e, sampleInfo);
353+
},
354+
}),
355+
textContent: `${sampleInfo.tocName || key}${
356+
sampleInfo.openInNewTab ? ' ↗️' : ''
357+
}`,
358+
...(sampleInfo.openInNewTab && { target: '_blank' }),
359+
}),
360+
])
361+
),
362+
]),
363+
])
364+
);
365+
}
317366
}
318367

319368
sourceLElem.addEventListener('click', () => switchToRelativeTab(-1).click());

0 commit comments

Comments
 (0)