A single-page 28-chapter manual generated from manual.json covers the 11 workspaces, all React editors, OPFS save/reopen, explicit local downloads, import/export routes, preferences/keymap and the capability matrix. It reuses verified course screenshots and adds 14 fresh Chromium captures for shell, storage, area, camera, preferences, IO and troubleshooting chapters. Manual-driven fixes: Save As now states OPFS-only, GLTF import is restored, quick toolbar honors its preference, startup workspace is applied, Properties tabs jump to sections, Outliner fallback search filters, and the editor-header ⋮ opens the area menu. Help and the tutorial landing link the new manual; the PDF remains as an archive. Co-Authored-By: Claude Code <noreply@anthropic.com>
39 lines
1.9 KiB
JavaScript
39 lines
1.9 KiB
JavaScript
(() => {
|
|
const sidebar = document.querySelector('.manual-sidebar');
|
|
const toggle = document.querySelector('.manual-menu-toggle');
|
|
const search = document.querySelector('.manual-search input');
|
|
const status = document.querySelector('.manual-search-status');
|
|
const links = Array.from(document.querySelectorAll('.manual-nav a[data-nav-id]'));
|
|
const articles = Array.from(document.querySelectorAll('.manual-chapter'));
|
|
const apply = () => {
|
|
const query = (search?.value || '').trim().toLowerCase();
|
|
let matches = 0;
|
|
for (const link of links) {
|
|
const article = document.querySelector('#' + CSS.escape(link.dataset.navId));
|
|
const text = (article?.dataset.search || link.textContent || '').toLowerCase();
|
|
const hit = !query || text.includes(query) || (link.textContent || '').toLowerCase().includes(query);
|
|
link.hidden = !hit;
|
|
if (hit) matches += 1;
|
|
}
|
|
for (const article of articles) {
|
|
const text = (article.dataset.search || '').toLowerCase();
|
|
article.hidden = Boolean(query) && !text.includes(query);
|
|
}
|
|
if (status) status.textContent = query ? matches + ' 个匹配' : '';
|
|
};
|
|
search?.addEventListener('input', apply);
|
|
toggle?.addEventListener('click', () => sidebar?.classList.toggle('open'));
|
|
window.addEventListener('keydown', (event) => {
|
|
if (event.key === '/' && document.activeElement !== search) { event.preventDefault(); search?.focus(); }
|
|
if (event.key === 'Escape' && search) { search.value = ''; apply(); search.blur(); }
|
|
});
|
|
const observer = 'IntersectionObserver' in window ? new IntersectionObserver((entries) => {
|
|
for (const entry of entries) {
|
|
if (!entry.isIntersecting) continue;
|
|
const id = entry.target.id;
|
|
for (const link of links) link.classList.toggle('active', link.dataset.navId === id);
|
|
}
|
|
}, { rootMargin: '-30% 0px -60% 0px' }) : null;
|
|
for (const article of articles) observer?.observe(article);
|
|
})();
|