iter: d08 演示页侧边目录 + 滚动高亮

This commit is contained in:
ui-arch-bot
2026-10-23 16:52:28 +08:00
parent fb9ab88feb
commit 1a4b2c1fed
6 changed files with 47 additions and 4 deletions
+10 -1
View File
@@ -45,7 +45,16 @@ ${css}
@media (prefers-color-scheme:dark){:root{--page-bg:#101216;--page-text:#e7e9ec;--page-muted:#888780;--page-border:rgba(255,255,255,.15)}}
*{box-sizing:border-box}
body{margin:0;background:var(--page-bg);color:var(--page-text);font:14px/1.7 -apple-system,"Segoe UI","Microsoft YaHei",sans-serif}
.page{max-width:880px;margin:0 auto;padding:36px 20px 80px}
.shell{max-width:1160px;margin:0 auto;padding:36px 20px 80px;display:grid;grid-template-columns:190px minmax(0,1fr);gap:36px}
.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-title{color:var(--page-muted);font-size:11px;letter-spacing:.08em;margin-bottom:8px}
.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.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)}
@media (max-width:820px){.shell{grid-template-columns:1fr;gap:0}.toc{display:none}}
html{scroll-behavior:smooth}
@media (prefers-reduced-motion:reduce){html{scroll-behavior:auto}}
header{margin-bottom:30px}
h1{font-size:20px;font-weight:500;margin:0}
.sub{color:var(--page-muted);font-size:13px;margin:8px 0 0}
+26 -1
View File
@@ -27,6 +27,27 @@ import {
tooltip,
} from '@ui-arch/ui';
/*** 侧边目录:挂载后从 .sec 反推锚点,IntersectionObserver 高亮视口内区块(清单改动自动跟随) ***/
function buildToc(toc: HTMLElement, content: HTMLElement): void {
const secs = Array.from(content.querySelectorAll<HTMLElement>('section.sec'));
if (!secs.length) return; // 卫语句:无区块不建目录
const links = secs.map((sec) =>
h('a', { class: 'toc-link', href: `#${sec.id}`, 'data-for': sec.id }, sec.querySelector('h2')?.textContent ?? sec.id),
);
toc.append(...links);
const io = new IntersectionObserver(
(entries) => {
for (const en of entries) {
if (!en.isIntersecting) continue; // 只处理刚进入视口的区块
const id = (en.target as HTMLElement).id;
for (const link of links) link.classList.toggle('is-active', link.getAttribute('data-for') === id);
}
},
{ rootMargin: '-10% 0px -80% 0px' }, // 顶部窄条判定,滚动时高亮更跟手
);
for (const sec of secs) io.observe(sec);
}
/*** 生成演示区块;id 供文档站 iframe 锚点定位 ***/
function section(id: string, title: string, desc: string, ...body: unknown[]): HTMLElement {
return h(
@@ -84,7 +105,7 @@ const menuPick = signal('');
// —— 禁用态演示:开关信号同时绑定 switch 的 checked 与 checkbox 的 disabled ——
const locked = signal(true);
const app = h(
const content = h(
'div',
{ class: 'page' },
h(
@@ -322,4 +343,8 @@ const app = h(
),
);
const toc = h('aside', { class: 'toc' }, h('div', { class: 'toc-title' }, '目录')); // 目录项由 buildToc 填充
const app = h('div', { class: 'shell' }, toc, content);
mount('#app', () => app);
buildToc(toc, content);