iter(g14): 演示站目录支持关键字过滤
This commit is contained in:
@@ -49,6 +49,10 @@ body{margin:0;background:var(--page-bg);color:var(--page-text);font:14px/1.7 -ap
|
|||||||
.page{max-width:900px;margin:0;padding:0}
|
.page{max-width:900px;margin:0;padding:0}
|
||||||
.toc{position:sticky;top:24px;align-self:start;max-height:calc(100vh - 48px);overflow:auto;font-size:13px}
|
.toc{position:sticky;top:24px;align-self:start;max-height:calc(100vh - 48px);overflow:auto;font-size:13px}
|
||||||
.toc-title{color:var(--page-muted);font-size:11px;letter-spacing:.08em;margin-bottom:8px}
|
.toc-title{color:var(--page-muted);font-size:11px;letter-spacing:.08em;margin-bottom:8px}
|
||||||
|
.toc-search{width:100%;box-sizing:border-box;margin-bottom:8px;padding:4px 8px;border:1px solid var(--ua-color-border);border-radius:6px;background:var(--ua-color-bg);color:var(--page-text);font-size:12px}
|
||||||
|
.toc-search:focus{outline:none;border-color:var(--ua-color-accent);box-shadow:0 0 0 2px color-mix(in srgb,var(--ua-color-accent) 18%,transparent)}
|
||||||
|
.toc-link[hidden]{display:none}
|
||||||
|
.toc-empty{color:var(--page-muted);font-size:12px;padding:4px 8px;margin:0}
|
||||||
.toc-link{display:block;padding:3px 8px;border-left:2px solid transparent;border-radius:0 4px 4px 0;color:var(--page-muted);text-decoration:none;transition:color .15s,background .15s,border-color .15s}
|
.toc-link{display:block;padding:3px 8px;border-left:2px solid transparent;border-radius:0 4px 4px 0;color:var(--page-muted);text-decoration:none;transition:color .15s,background .15s,border-color .15s}
|
||||||
.toc-link:hover{color:var(--page-text);background:rgba(127,127,127,.08)}
|
.toc-link:hover{color:var(--page-text);background:rgba(127,127,127,.08)}
|
||||||
.toc-link.is-active{color:var(--ua-color-accent);border-left-color:var(--ua-color-accent);background:color-mix(in srgb,var(--ua-color-accent) 10%,transparent)}
|
.toc-link.is-active{color:var(--ua-color-accent);border-left-color:var(--ua-color-accent);background:color-mix(in srgb,var(--ua-color-accent) 10%,transparent)}
|
||||||
|
|||||||
+22
-2
@@ -51,14 +51,34 @@ import {
|
|||||||
} from '@ui-arch/ui';
|
} from '@ui-arch/ui';
|
||||||
import type { RowKey } from '@ui-arch/ui';
|
import type { RowKey } from '@ui-arch/ui';
|
||||||
|
|
||||||
/*** 侧边目录:挂载后从 .sec 反推锚点,IntersectionObserver 高亮视口内区块(清单改动自动跟随) ***/
|
/*** 侧边目录:挂载后从 .sec 反推锚点,IntersectionObserver 高亮视口内区块(清单改动自动跟随);顶部搜索框按标题过滤 ***/
|
||||||
function buildToc(toc: HTMLElement, content: HTMLElement): void {
|
function buildToc(toc: HTMLElement, content: HTMLElement): void {
|
||||||
const secs = Array.from(content.querySelectorAll<HTMLElement>('section.sec'));
|
const secs = Array.from(content.querySelectorAll<HTMLElement>('section.sec'));
|
||||||
if (!secs.length) return; // 卫语句:无区块不建目录
|
if (!secs.length) return; // 卫语句:无区块不建目录
|
||||||
const links = secs.map((sec) =>
|
const links = secs.map((sec) =>
|
||||||
h('a', { class: 'toc-link', href: `#${sec.id}`, 'data-for': sec.id }, sec.querySelector('h2')?.textContent ?? sec.id),
|
h('a', { class: 'toc-link', href: `#${sec.id}`, 'data-for': sec.id }, sec.querySelector('h2')?.textContent ?? sec.id),
|
||||||
);
|
);
|
||||||
toc.append(...links);
|
const search = h('input', { class: 'toc-search', type: 'search', placeholder: '过滤组件…', 'aria-label': '过滤组件目录' }) as HTMLInputElement;
|
||||||
|
const empty = h('p', { class: 'toc-empty' }, '无匹配项'); // 过滤后一条不剩时的提示
|
||||||
|
empty.hidden = true;
|
||||||
|
/*** 按标题子串过滤目录项;空关键字恢复全量 ***/
|
||||||
|
const apply = (): void => {
|
||||||
|
const q = search.value.trim().toLowerCase();
|
||||||
|
let hit = 0;
|
||||||
|
for (const link of links) {
|
||||||
|
const on = !q || (link.textContent ?? '').toLowerCase().includes(q);
|
||||||
|
link.hidden = !on; // 隐藏项同时退出 Tab 序(hidden 自带)
|
||||||
|
if (on) hit++;
|
||||||
|
}
|
||||||
|
empty.hidden = hit > 0;
|
||||||
|
};
|
||||||
|
search.addEventListener('input', apply);
|
||||||
|
search.addEventListener('keydown', (e: KeyboardEvent) => {
|
||||||
|
if (e.key !== 'Escape' || !search.value) return; // 卫语句:无内容时 Esc 交给默认行为
|
||||||
|
search.value = '';
|
||||||
|
apply();
|
||||||
|
});
|
||||||
|
toc.append(search, ...links, empty);
|
||||||
const io = new IntersectionObserver(
|
const io = new IntersectionObserver(
|
||||||
(entries) => {
|
(entries) => {
|
||||||
for (const en of entries) {
|
for (const en of entries) {
|
||||||
|
|||||||
Reference in New Issue
Block a user