Add live search to the Help Book's table of contents

A search box above the Contents list filters TOC entries by each
linked section's full text content (not just the link title), so
e.g. searching "european" surfaces "Slash Commands" via its command
history date-format note. Pure vanilla JS/CSS, no dependencies --
the page is a static file opened directly in the default browser.

Tested interactively in Safari Technology Preview: filtering,
no-results state, reset, and click-through navigation all verified
working, in both the matched and empty-query cases.
This commit is contained in:
2026-07-22 15:21:30 +02:00
parent e9aceca4e7
commit 854fd02fad
2 changed files with 63 additions and 1 deletions
@@ -20,7 +20,11 @@
<nav class="toc"> <nav class="toc">
<h2>Contents</h2> <h2>Contents</h2>
<ul> <div class="toc-search">
<input type="search" id="tocSearch" placeholder="Search help topics…" aria-label="Search help topics">
</div>
<p id="tocNoResults" class="toc-no-results" hidden>No topics match your search.</p>
<ul id="tocList">
<li><a href="#getting-started">Getting Started</a></li> <li><a href="#getting-started">Getting Started</a></li>
<li><a href="#providers">AI Providers &amp; API Keys</a></li> <li><a href="#providers">AI Providers &amp; API Keys</a></li>
<li><a href="#models">Selecting Models</a></li> <li><a href="#models">Selecting Models</a></li>
@@ -1812,5 +1816,37 @@ Whenever the user asks you to translate something, translate it to Norwegian Bok
<p>© 2026 oAI - Rune Olsen. For support or feedback, visit <a href="https://gitlab.pm/rune/oai-swift">gitlab.pm</a> or <a href="mailto:support@fubar.pm?subject=oAI Support&body=What can I help you with?">Contact Us</a>.</p> <p>© 2026 oAI - Rune Olsen. For support or feedback, visit <a href="https://gitlab.pm/rune/oai-swift">gitlab.pm</a> or <a href="mailto:support@fubar.pm?subject=oAI Support&body=What can I help you with?">Contact Us</a>.</p>
</footer> </footer>
</div> </div>
<script>
(function () {
var searchInput = document.getElementById('tocSearch');
var tocList = document.getElementById('tocList');
var noResults = document.getElementById('tocNoResults');
if (!searchInput || !tocList) return;
var entries = Array.prototype.map.call(tocList.querySelectorAll('li'), function (li) {
var link = li.querySelector('a');
var id = link ? link.getAttribute('href').slice(1) : null;
var section = id ? document.getElementById(id) : null;
return {
li: li,
text: (section ? section.textContent : li.textContent).toLowerCase()
};
});
searchInput.addEventListener('input', function () {
var query = searchInput.value.trim().toLowerCase();
var visibleCount = 0;
entries.forEach(function (entry) {
var matches = query === '' || entry.text.indexOf(query) !== -1;
entry.li.hidden = !matches;
if (matches) visibleCount++;
});
noResults.hidden = visibleCount > 0;
});
})();
</script>
</body> </body>
</html> </html>
@@ -101,6 +101,32 @@ nav.toc h2 {
margin-bottom: 16px; margin-bottom: 16px;
} }
.toc-search {
margin-bottom: 16px;
}
.toc-search input[type="search"] {
width: 100%;
font-family: inherit;
font-size: 15px;
padding: 10px 14px;
color: var(--text-primary);
background: var(--background);
border: 1px solid var(--border);
border-radius: 8px;
outline: none;
}
.toc-search input[type="search"]:focus {
border-color: var(--primary-color);
}
.toc-no-results {
font-size: 14px;
color: var(--text-secondary);
margin-bottom: 0;
}
nav.toc ul { nav.toc ul {
list-style: none; list-style: none;
} }