未命名 aPPJWyedit icon

作者:
藤原
Fork(复制)
下载
嵌入
BUG反馈
index.html
style.css
index.js
现在支持上传本地图片了!
index.html
            
            <!DOCTYPE html>
<html lang="en" data-theme="dark">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>响应式固定侧边栏布局 w/ [popover]</title>
    <meta name="description" content="使用现代CSS和JavaScript实现的响应式固定侧边栏布局,具有可折叠的树形导航菜单">
    
    <!-- 字体 -->
    <link rel="preconnect" href="https://fonts.googleapis.com">
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
    <link href="https://fonts.googleapis.com/css2?family=Gloria+Hallelujah&family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap" rel="stylesheet">
    
    <!-- GSAP 动画库 -->
    <script src="https://cdn.skypack.dev/gsap@3.13.0"></script>
    <script src="https://cdn.skypack.dev/gsap@3.13.0/Draggable"></script>
    
    <!-- Tweakpane UI控制库 -->
    <script src="https://cdn.skypack.dev/tweakpane@4.0.4"></script>
    
    <style>
        /* 基础样式和CSS层 */
        @import url('https://unpkg.com/normalize.css') layer(normalize);
        
        @layer normalize, base, demo, tree, layout, transitions, mobile, scroller-mask, debug;
        
        @layer {
            [data-show="true"] .safety-triangle {
                opacity: 1;
            }
            [data-triangle="false"] .safety-triangle {
                pointer-events: none;
                background: repeating-linear-gradient(45deg, #0000 0 4px, var(--tree-focus-color) 4px 5px);
                opacity: 0.5;
            }
            [data-show="false"] .safety-triangle {
                opacity: 0;
            }
        }
        
        /* 滚动遮罩层 */
        @layer scroller-mask {
            @supports(animation-timeline: scroll()) {
                sidebar-tree .tree-group-container + .tree-group-container {
                    --size: 4;
                    mask-image: linear-gradient(#fff, #0000),
                    linear-gradient(#fff 0 100%), linear-gradient(#0000, #fff);
                    mask-size: 100% calc(var(--size) * 1ch), 100% 100%,
                    100% calc(var(--size) * 1ch);
                    mask-repeat: no-repeat;
                    mask-composite: exclude;
                    animation-timing-function: linear;
                    animation-timeline: scroll(self);
                    animation-range: 0 calc(var(--size) * 1ch),
                    calc(100% - (var(--size) * 1ch)) 100%;
                    mask-position: 0 0, 0 0, 0 100%;
                    mask-size: 100% 0, 100% 100%, 100% calc(var(--size) * 1ch);
                    animation-name: size-up, size-down;
                    animation-fill-mode: both;
                }
            }
            
            @keyframes size-up {
                to {
                    mask-size: 100% calc(var(--size) * 1ch), 100% 100%,
                    100% calc(var(--size) * 1ch);
                }
            }
            
            @keyframes size-down {
                to {
                    mask-size: 100% calc(var(--size) * 1ch), 100% 100%, 100% 0;
                }
            }
        }
        
        /* 移动端样式 */
        @layer mobile {
            .mobile-items {
                align-items: center;
                display: none;
            }
            
            .menu-button {
                width: 40px;
                aspect-ratio: 1;
                background: #0000;
                border: 0;
                display: grid;
                place-items: center;
                padding: 0;
                position: relative;
                border-radius: 6px;
                cursor: pointer;
            }
            
            .menu-button:is(:hover, :focus-visible)::after {
                opacity: 1;
            }
            
            .menu-button::after {
                content: '';
                position: absolute;
                inset: 0;
                border-radius: inherit;
                opacity: 0;
                background: light-dark(hsl(0 0% 30% / 0.1), hsl(0 0% 90% / .15));
            }
            
            aside footer .user {
                display: none;
            }
            
            aside header .button-link {
                display: none;
                position: absolute;
                top: 0;
                left: 0;
                color: canvasText;
            }
            
            aside header .button-link svg {
                translate: -2px 0;
            }
            
            .closer {
                width: 40px;
                aspect-ratio: 1;
                position: absolute;
                z-index: 2;
                top: 0;
                right: 0;
                background: #0000;
                border: 0;
                cursor: pointer;
                display: grid;
                display: none;
                place-items: center;
                padding: 0;
                border-radius: 6px;
            }
            
            .closer:is(:hover, :focus-visible)::after {
                opacity: 1;
            }
            
            .closer::after {
                content: '';
                position: absolute;
                inset: 6px;
                border-radius: inherit;
                opacity: 0;
                background: light-dark(hsl(0 0% 30% / 0.1), hsl(0 0% 90% / .15));
            }
            
            .closer svg {
                rotate: 45deg;
                width: 22px;
                border-radius: 6px;
                background: #0000;
            }
            
            @media(max-width: 768px) {
                aside footer .user {
                    display: flex;
                }
                
                aside header .button-link,
                .closer {
                    display: grid;
                }
                
                aside footer {
                    padding: .5rem;
                }
                
                aside header {
                    padding: .5rem;
                    padding-top: 44px;
                }
                
                sidebar-tree [role="treeitem"] {
                    padding-right: .5rem;
                }
                
                kbd {
                    display: none;
                }
                
                header .user,
                .user-slash {
                    display: none;
                }
                
                .toggle {
                    display: none;
                }
                
                .mobile-items {
                    display: flex;
                }
                
                aside {
                    position: fixed;
                    background: light-dark(#fff, #000);
                    translate: -100% 0;
                    height: 100vh;
                    top: 0;
                    border-radius: 0;
                    display: none;
                    transition-property: display, overlay, translate;
                    transition-duration: var(--speed);
                    transition-timing-function: var(--timing);
                    transition-behavior: allow-discrete;
                }
                
                aside::after {
                    inset: -2px;
                }
                
                aside::before,
                aside::after {
                    opacity: 1;
                    filter: blur(0);
                    border-radius: 0;
                    border-top: 0;
                    border-bottom: 0;
                }
                
                aside:popover-open {
                    display: grid;
                    translate: 0 0;
                }
                
                aside::backdrop {
                    background: light-dark(hsl(0 0% 0% / 0.6), hsl(0 0% 10% / 0.8));
                    opacity: 0;
                    transition-behavior: allow-discrete;
                    transition-property: display, overlay, opacity;
                    transition-timing-function: var(--timing);
                    transition-duration: var(--speed);
                }
                
                aside:popover-open::backdrop {
                    opacity: 1;
                }
                
                @starting-style {
                    aside:popover-open {
                        translate: -100% 0;
                    }
                    
                    aside:popover-open::backdrop {
                        opacity: 0;
                    }
                }
            }
        }
        
        /* 过渡动画 */
        @layer transitions {
            .layout {
                display: grid;
                grid-template-columns: 0 1fr;
                transition: grid-template-columns var(--speed) var(--timing);
            }
            
            @media(min-width: 768px) {
                .layout:has(:popover-open) {
                    grid-template-columns: var(--sidebar-width) 1fr;
                }
            }
            
            .toggle:hover::after {
                opacity: 1;
            }
            
            .toggle::after {
                opacity: 0;
                transition: opacity 0.12s ease-out;
            }
            
            .toggle .icon-bar {
                scale: 0.3 1;
                transition: scale var(--speed) var(--timing);
            }
            
            .toggle:hover .safety-triangle {
                pointer-events: all;
            }
            
            .toggle .hover-set,
            .toggle .safety-triangle {
                transition: scale var(--speed) var(--speed) var(--timing);
                opacity: 0;
                pointer-events: none;
            }
            
            .toggle .hover-set {
                pointer-events: all;
            }
            
            aside {
                translate: -100% 0;
                transition-property: translate, height;
                transition-duration: var(--speed);
                transition-timing-function: var(--timing);
                height: calc(100vh - (var(--header-height) + 44px + 1rem));
            }
            
            aside::before {
                transition: opacity var(--speed) var(--timing);
            }
            
            aside::after {
                transition-property: opacity, filter;
                transition-duration: var(--speed);
                transition-timing-function: var(--timing);
            }
            
            aside:popover-open {
                translate: 0 calc(-44px - 0.25rem);
                height: calc(100vh - (var(--header-height) + .5rem - .25rem));
            }
            
            .toggle:has(+ :popover-open) .hover-set,
            .toggle:has(+ :popover-open) .safety-triangle {
                scale: 0;
                transition-delay: 0s;
            }
            
            .toggle:is(:hover, :focus-visible) .icon-bar,
            .toggle:has(+ :popover-open) .icon-bar {
                scale: 1 1;
            }
            
            .toggle:has(+ :popover-open):is(:hover, :focus-visible) .icon-bar {
                scale: 0.3 1;
            }
            
            [data-delay=true] {
                aside:popover-open sidebar-tree [role="treeitem"],
                aside:popover-open header,
                aside:popover-open::after,
                aside:popover-open::before {
                    transition-duration: calc(var(--speed) * 1);
                }
                
                .toggle:focus-visible:has( + :not(:popover-open)) + aside:before {
                    transition-delay: 0s;
                    transition-duration: calc(var(--speed) * 0.25);
                }
                
                .toggle:focus-visible + aside:popover-open::before,
                aside:popover-open::before {
                    transition-duration: calc(var(--speed) * 0.25);
                    transition-delay: calc(var(--speed) * 0.75);
                }
                
                .toggle .icon-bar,
                .toggle:is(:hover, :focus-visible)::after,
                .toggle:has(:is(.safety-triangle:hover, .hover-set:hover)) + aside:not(:popover-open) {
                    transition-delay: 0.16s;
                }
            }
            
            .toggle:focus-visible:has(+ :not(:popover-open)) + aside::before {
                transition: opacity var(--speed) var(--timing);
            }
            
            aside footer,
            aside sidebar-tree [role="treeitem"],
            aside header {
                transition: padding var(--speed) var(--timing);
            }
            
            aside:popover-open sidebar-tree [role="treeitem"] {
                padding-right: 0.25rem;
            }
            
            aside:popover-open header {
                padding: .5rem 0 .5rem .5rem;
            }
            
            aside:popover-open footer {
                padding: .5rem 0 0 .5rem;
            }
            
            aside:popover-open::after {
                filter: blur(2px);
            }
            
            aside:popover-open::after,
            aside:popover-open::before {
                opacity: 0;
            }
            
            @media(min-width: 768px) {
                aside:popover-open sidebar-tree .tree-group-container:first-of-type::after,
                aside:popover-open footer::after {
                    right: 0;
                }
            }
            
            .toggle:has(:is(.safety-triangle:hover, .hover-set:hover)) + aside:not(:popover-open),
            .toggle:is(:focus-visible) + aside:not(:popover-open),
            aside:is(:focus-within, :hover):not(:popover-open) {
                translate: 0 0;
            }
        }
        
        /* 布局样式 */
        @layer layout {
            :root {
                --tree-focus-color: hsl(0 90% 66%);
                --text: light-dark(hsl(0 0% 45%), hsl(0 0% 54%));
                --header-height: 60px;
                --sidebar-width: 260px;
                --panel-color: light-dark(color-mix(in hsl, canvas, canvasText 4%), color-mix(in hsl, #000, canvasText 8%));
                --border-color: color-mix(in hsl, canvas, canvasText 30%);
                --speed: calc(var(--layout-speed, 0.16) * 1s);
                --timing: cubic-bezier(0.0, 0.0, 0.58, 1.0);
            }
            
            body {
                display: grid;
                grid-template-rows: auto 1fr;
                padding-bottom: .5rem;
            }
            
            .arrow {
                opacity: .4;
                font-family: Gloria Hallelujah, cursive;
                font-size: .875rem;
                transition: opacity .26s ease-out;
                display: inline-block;
                position: absolute;
                top: 0;
                left: 0;
                translate: 60% 130%;
                rotate: 14deg;
            }
            
            .arrow svg {
                width: 60%;
                position: absolute;
                top: 130%;
                left: 0;
                translate: -40% 60%;
                rotate: 330deg;
                scale: -1 1;
            }
            
            .arrow span {
                display: inline-block;
                white-space: nowrap;
            }
            
            @media(max-width: 768px) {
                .arrow {
                    display: none;
                }
            }
            
            aside footer {
                padding: .5rem;
                display: grid;
                gap: .25rem;
                width: 100%;
                position: relative;
                margin-top: .5rem;
            }
            
            aside footer::after {
                content: '';
                position: absolute;
                top: 0;
                translate: 0 -50%;
                left: .5rem;
                right: .5rem;
                height: 2px;
                opacity: .5;
                background: var(--border-color);
                transition: right var(--speed) var(--timing);
            }
            
            .settings, .feedback {
                display: flex;
                gap: calc(.5rem - 2px);
                align-items: center;
                height: 32px;
                border-radius: 6px;
                background: #0000;
                border: 0;
                color: var(--text-color);
                cursor: pointer;
                position: relative;
                outline-color: var(--tree-focus-color);
            }
            
            .settings:is(:hover, :focus-visible),
            .feedback:is(:hover, :focus-visible) {
                color: canvasText;
            }
            
            .settings:is(:hover, :focus-visible)::after,
            .feedback:is(:hover, :focus-visible)::after {
                opacity: 1;
            }
            
            .settings::after,
            .feedback::after {
                content: '';
                position: absolute;
                inset: 0;
                border-radius: inherit;
                background: light-dark(hsl(0 0% 30% / 0.1), hsl(0 0% 90% / .15));
                opacity: 0;
            }
            
            .settings svg {
                width: 28px;
                height: 24px;
            }
            
            .feedback svg {
                height: 22px;
                width: 28px;
            }
            
            [aria-label="Home"] {
                border-radius: 6px;
            }
            
            [aria-label="New request"] {
                height: 32px;
                border-radius: 6px;
                border: 0;
                cursor: pointer;
                color: light-dark(hsl(0 0% 35%), hsl(0 0% 80%));
                background: light-dark(hsl(0 0% 86%), hsl(0 0% 24%));
                position: relative;
                outline-color: var(--tree-focus-color);
            }
            
            [aria-label="New request"]:hover {
                color: canvasText;
            }
            
            [aria-label="New request"]:hover::after {
                opacity: 1;
            }
            
            [aria-label="New request"]::after {
                content: '';
                position: absolute;
                inset: 0;
                border-radius: inherit;
                opacity: 0;
                background: light-dark(hsl(0 0% 30% / 0.1), hsl(0 0% 90% / .1));
            }
            
            .button-link {
                aspect-ratio: 1;
                display: grid;
                place-items: center;
                width: 40px;
            }
            
            .user {
                display: flex;
                align-items: center;
                gap: 0.5rem;
                font-size: .875rem;
                height: 32px;
                padding: 0 .5rem;
            }
            
            .user .avatar {
                width: 24px;
                aspect-ratio: 1;
                background: color-mix(in hsl, canvas, canvasText 25%);
                border-radius: 50%;
            }
            
            .user .badge {
                font-size: .65rem;
                padding: .25rem .5rem;
                border-radius: 100px;
                background: light-dark(hsl(0 0% 80%), hsl(0 0% 30%));
                color: light-dark(hsl(0 0% 10%), hsl(0 0% 92%));
            }
            
            .header {
                height: var(--header-height);
                padding-inline: .5rem;
                display: flex;
                align-items: center;
                gap: 0;
            }
            
            .header a {
                color: inherit;
            }
            
            .header svg {
                width: 20px;
            }
            
            [aria-label="Home"] svg {
                translate: -2px 0;
            }
            
            .aside {
                position: relative;
                z-index: 4;
            }
            
            .toggle {
                position: absolute;
                left: calc(100% + 0.5rem);
                top: 0rem;
                width: 44px;
                height: 44px;
                display: grid;
                place-items: center;
                border-radius: 8px;
                border-width: 0px;
                background: #0000;
                cursor: pointer;
                position: relative;
                outline-color: var(--tree-focus-color);
            }
            
            .toggle::after {
                content: '';
                background: light-dark(hsl(0 0% 25% / 0.25), hsl(0 0% 90% / .25));
                opacity: 0;
                position: absolute;
                inset: 8px;
                pointer-events: none;
                border-radius: 8px;
            }
            
            .toggle .hover-set {
                position: absolute;
                inset: 0;
                border-radius: inherit;
                background: repeating-linear-gradient(45deg, #000 0 4px, hsl(140 80% 50%) 4px 5px);
            }
            
            .toggle .safety-triangle {
                display: inline-block;
                width: var(--sidebar-width);
                top: 0;
                bottom: 0;
                background: repeating-linear-gradient(45deg, #0000 0 4px, var(--tree-focus-color) 4px 5px);
                position: absolute;
                left: 0;
                transform-origin: calc(.5rem + 22px) 50%;
                translate: -.5rem 0;
                clip-path: polygon(0 100%, .5rem 0, calc(.5rem + 44px) 0, 100% 100%);
                z-index: 2;
            }
            
            .toggle svg {
                width: 22px;
            }
            
            .toggle svg .icon-bar {
                transform-box: fill-box;
                transform-origin: 0 50%;
            }
            
            .content {
                padding-inline: .5rem;
            }
            
            aside {
                position: fixed;
                left: 0;
                top: calc(var(--header-height) + 44px);
                translate: -100% 0;
                overflow: visible;
                height: calc(100vh - (var(--header-height) + 44px + 1rem));
            }
            
            aside::before {
                content: '';
                position: absolute;
                inset: 0;
                border-radius: 0 12px 12px 0;
                background: light-dark(#fff, #000);
                z-index: -1;
            }
            
            aside::after {
                content: '';
                position: absolute;
                inset: -1px;
                border: 2px solid var(--border-color);
                border-left-color: #0000;
                border-radius: 0 12px 12px 0;
                pointer-events: none;
            }
            
            main {
                height: 100%;
                border-radius: 8px;
                border: 2px solid var(--border-color);
                background: var(--panel-color);
                position: relative;
            }
        }
        
        /* 树形导航样式 */
        @layer tree {
            aside {
                background: color-mix(in srgb, canvas, #0000 80%);
                border-radius: 8px;
                min-width: 250px;
                border-radius: 0 12px 12px 0;
                margin: 0;
                border: 2px solid #0000;
                border-left-color: #0000;
                height: 100%;
                font-size: .875rem;
                display: grid;
                grid-template-rows: auto 1fr;
                color: var(--text);
                width: var(--sidebar-width);
                padding: 0;
            }
            
            aside nav {
                overflow: hidden;
            }
            
            sidebar-tree {
                display: block;
                height: 100%;
            }
            
            header {
                padding: .5rem;
                display: grid;
                gap: .5rem;
            }
            
            header .tree-search-input-container {
                position: relative;
            }
            
            header .tree-search-input-container svg {
                position: absolute;
                top: 50%;
                left: 8px;
                translate: 0 -50%;
                width: 16px;
            }
            
            header .tree-search-input-container kbd {
                border: 1px solid var(--border-color);
                position: absolute;
                top: 50%;
                width: 16px;
                height: 16px;
                font-size: .625rem;
                border-radius: 2px;
                color: canvasText;
                background: color-mix(in hsl, var(--border-color), #0000);
                display: grid;
                place-items: center;
                right: 8px;
                translate: 0 -50%;
            }
            
            header h1 {
                font-size: .875rem;
                margin: 0;
            }
            
            header a {
                padding-block: .5rem;
                padding-left: 2px;
                display: flex;
                align-items: center;
                gap: 0.5rem;
                color: light-dark(hsl(0 0% 40%), hsl(0 0% 60%));
                text-decoration: none;
                outline-color: var(--tree-focus-color);
            }
            
            header svg {
                width: 16px;
            }
            
            .tree-search-input {
                width: 100%;
                max-width: 100%;
                line-height: 2;
                border: 1px solid var(--border-color);
                border-radius: 6px;
                font-size: inherit;
                background: color-mix(in srgb, canvas 90%, canvasText 10%);
                color: canvasText;
                padding-left: 26px;
            }
            
            .tree-search-input::selection {
                background: var(--tree-focus-color);
                color: #fff;
            }
            
            .tree-search-input:focus-visible {
                outline: none;
                border-color: var(--tree-focus-color);
            }
            
            nav .tree-search-input::placeholder {
                color: color-mix(in srgb, canvasText, #0000);
            }
            
            sidebar-tree .tree-group-container,
            sidebar-tree ul[role="tree"],
            sidebar-tree ul[role="group"] {
                list-style: none;
                margin: 0;
                padding: 0;
                display: block;
                list-style: none;
                position: relative;
            }
            
            sidebar-tree ul[role=tree] {
                display: grid;
                height: 100%;
                grid-template-rows: auto 1fr;
            }
            
            sidebar-tree .tree-group-container:first-of-type {
                margin-bottom: .5rem;
                padding-bottom: .5rem;
            }
            
            sidebar-tree .tree-group-container:first-of-type::after {
                content: '';
                position: absolute;
                top: 100%;
                translate: 0 -50%;
                left: .5rem;
                right: .5rem;
                height: 2px;
                opacity: .5;
                background: var(--border-color);
                transition: right var(--speed) var(--timing);
            }
            
            sidebar-tree .tree-group-container + .tree-group-container {
                height: 100%;
                overflow: auto;
                scrollbar-color: color-mix(in srgb, var(--tree-focus-color), #0000 50%) transparent;
            }
            
            sidebar-tree li > div ul[role="group"] {
                margin-left: 1rem;
            }
            
            sidebar-tree li > div ul[role="group"] > li:first-of-type {
                margin-top: .5rem;
            }
            
            sidebar-tree li > div ul[role="group"] > li:last-of-type {
                margin-bottom: .5rem;
            }
            
            sidebar-tree li > div ul[role="group"]::before {
                content: '';
                position: absolute;
                left: 0;
                top: .5rem;
                bottom: .5rem;
                width: 2px;
                background: color-mix(in srgb, currentColor, #0000 65%);
            }
            
            sidebar-tree li > div {
                display: grid;
                grid-template-rows: 1fr;
                transition: grid-template-rows calc(var(--duration) * 1s) var(--timing);
                overflow: hidden;
            }
            
            sidebar-tree li > div[inert] {
                grid-template-rows: 0fr;
            }
            
            [inert] > [role="group"] {
                opacity: var(--opacity);
                translate: 0 calc(var(--translate) * 1px);
                filter: blur(calc(var(--blur) * 1px));
            }
            
            [role="group"] {
                transition-property: translate, opacity, filter;
                transition-duration: calc(var(--duration) * 1s);
                transition-timing-function: var(--timing);
                translate: 0 0;
                filter: blur(0px);
                opacity: 1;
            }
            
            sidebar-tree li > div > ul {
                min-height: 0;
            }
            
            sidebar-tree [role="treeitem"] {
                display: inline-flex;
                align-items: center;
                text-decoration: none;
                color: inherit;
                padding: 0.25rem 0.5rem 0.25rem 1rem;
                line-height: 1.6;
                width: 100%;
                gap: 0.5rem;
                position: relative;
            }
            
            sidebar-tree [role="treeitem"] span:first-of-type {
                flex: 1;
            }
            
            sidebar-tree [role="treeitem"]:hover {
                color: light-dark(hsl(0 0% 20%), hsl(0 0% 90%));
            }
            
            sidebar-tree [role="treeitem"]:focus {
                outline: none;
                color: light-dark(hsl(0 0% 20%), hsl(0 0% 90%));
                background-color: light-dark(
                    color-mix(in srgb, var(--tree-focus-color), #0000 90%),
                    color-mix(in srgb, var(--tree-focus-color), #0000 80%)
                );
            }
            
            sidebar-tree [role="treeitem"][aria-current="page"] {
                color: light-dark(#000, #fff);
            }
            
            sidebar-tree [role="treeitem"][aria-current="page"]::before {
                content: '';
                position: absolute;
                left: 0;
                top: 0;
                bottom: 0;
                width: 4px;
                background: var(--tree-focus-color);
                translate: -50% 0;
            }
            
            sidebar-tree [role="treeitem"][aria-current="page"][aria-level="1"]::before {
                left: 2px;
            }
            
            sidebar-tree [role="treeitem"][aria-expanded="true"] .tree-icon svg {
                rotate: 135deg;
            }
            
            sidebar-tree .tree-icon {
                display: inline-flex;
                align-items: center;
                justify-content: center;
                width: 24px;
                height: 24px;
                cursor: pointer;
                border-radius: 4px;
            }
            
            sidebar-tree .tree-icon:hover {
                background-color: color-mix(in srgb, currentColor 10%, transparent);
            }
            
            sidebar-tree .tree-icon svg {
                width: 16px;
                transition: rotate 0.26s ease-out;
            }
            
            sidebar-tree ul[role="tree"][data-filtering="true"] [role="treeitem"] {
                opacity: 0.6;
            }
            
            sidebar-tree ul[role="tree"][data-filtering="true"] [role="treeitem"][data-search-match="true"] {
                opacity: 1;
                color: light-dark(#000, #fff);
                background-color: color-mix(in srgb, var(--tree-focus-color), #0000 60%);
            }
            
            sidebar-tree ul[role="tree"][data-filtering="true"] [role="treeitem"][data-search-related="true"] {
                color: light-dark(hsl(0 0% 20%), hsl(0 0% 100%));
                background-color: color-mix(in srgb, var(--tree-focus-color), #0000 80%);
            }
            
            sidebar-tree ul[role="tree"][data-filtering="true"] [role="treeitem"][data-filtered="true"] {
                /* 过滤掉的项 */
            }
            
            sidebar-tree ul[role="tree"][data-filtering="true"] [role="treeitem"]:focus {
                opacity: 1;
            }
        }
        
        /* 基础样式 */
        @layer base {
            :root {
                --font-size-min: 16;
                --font-size-max: 20;
                --font-ratio-min: 1.2;
                --font-ratio-max: 1.33;
                --font-width-min: 375;
                --font-width-max: 1500;
            }
            
            html {
                color-scheme: light dark;
            }
            
            [data-theme='light'] {
                color-scheme: light only;
            }
            
            [data-theme='dark'] {
                color-scheme: dark only;
            }
            
            :where(.fluid) {
                --fluid-min: calc(
                    var(--font-size-min) * pow(var(--font-ratio-min), var(--font-level, 0))
                );
                --fluid-max: calc(
                    var(--font-size-max) * pow(var(--font-ratio-max), var(--font-level, 0))
                );
                --fluid-preferred: calc(
                    (var(--fluid-max) - var(--fluid-min)) /
                    (var(--font-width-max) - var(--font-width-min))
                );
                --fluid-type: clamp(
                    (var(--fluid-min) / 16) * 1rem,
                    ((var(--fluid-min) / 16) * 1rem) -
                    (((var(--fluid-preferred) * var(--font-width-min)) / 16) * 1rem) +
                    (var(--fluid-preferred) * var(--variable-unit, 100vi)),
                    (var(--fluid-max) / 16) * 1rem
                );
                font-size: var(--fluid-type);
            }
            
            *,
            *:after,
            *:before {
                box-sizing: border-box;
            }
            
            body {
                background: light-dark(#fff, #000);
                min-height: 100vh;
                font-family: 'Inter', 'SF Pro Text', 'SF Pro Icons', 'AOS Icons', 'Helvetica Neue',
                Helvetica, Arial, sans-serif, system-ui;
            }
            
            .sr-only {
                position: absolute;
                width: 1px;
                height: 1px;
                padding: 0;
                margin: -1px;
                overflow: hidden;
                clip: rect(0, 0, 0, 0);
                white-space: nowrap;
                border-width: 0;
            }
        }
        
        /* Tweakpane 面板样式 */
        div.tp-dfwv {
            top: 18px;
            width: 256px;
            position: fixed;
        }
        
        * {
            -webkit-tap-highlight-color: #0000;
        }
    </style>
</head>
<body>
    <header class="header">
        <div class="mobile-items">
            <button class="menu-button" popovertarget="sidebar" popovertargetaction="toggle" aria-label="Open navigation">
                <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-6">
                    <path stroke-linecap="round" stroke-linejoin="round" d="M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25h16.5" />
                </svg>
            </button>
            <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-6">
                <path stroke-linecap="round" stroke-linejoin="round" d="m9 20.247 6-16.5" />
            </svg>
        </div>
        <a class="button-link" aria-label="Home" href="/">
            <svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
                <path d="m3.98448 20.5882-1.17645 1.6174m-.22047-1.3969 1.61739 1.1764M22.144.730378 20.6832 2.09646m.0474-1.413417 1.366 1.460757" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"></path>
                <path d="m3.90821 18.5526-.59559.0726c.03203.2626.23224.4732.49285.5185l.10274-.5911ZM20.601 4.22249l.3908.45525c.1679-.14415.2428-.36902.195-.58508-.0479-.21606-.2109-.38822-.424-.44793l-.1618.57776Zm.6023-.00906c-.0066-.33131-.2805-.59453-.6118-.58794-.3313.0066-.5945.28052-.5879.61183l1.1997-.02389Zm-.2556 17.30047-.1028.5911c.1766.0307.3576-.0191.4935-.1358.136-.1168.2127-.2881.2091-.4673l-.5998.012ZM3.03505 11.3945l-.39082-.4552c-.15222.1306-.22906.3287-.20477.5279l.59559-.0727ZM13.8216 1.69999c-.3191-.0894-.6502.0968-.7396.41588-.0894.31909.0968.65023.4159.73963l.3237-1.15551ZM4.29903 19.0078 20.9918 4.67774l-.7816-.91051L3.51739 18.0973l.78164.9105ZM20.0036 4.23732l.3442 17.28848 1.1997-.0239-.3442-17.28847-1.1997.02389ZM3.80547 19.1437 20.8449 22.105l.2055-1.1823-17.03946-2.9613-.20547 1.1823Zm-.3796-7.2939L14.0485 2.73064l-.7816-.91052L2.64423 10.9393l.78164.9105Zm1.07792 6.6301-.87316-7.158-1.19117.1453.87316 7.158 1.19117-.1453ZM20.7628 3.64473l-6.9412-1.94474-.3237 1.15551 6.9412 1.94474.3237-1.15551Z" fill="currentColor"></path>
                <path d="m15.7227 7.75 4.9996 13.5001M8.13672 14.2656 20.724 21.2521" stroke="currentColor" stroke-width="1.2"></path>
                <path d="M7.0673 8.29748c-.11208-.31184-.45574-.47378-.76758-.36169-.31184.11208-.47377.45574-.36169.76758l1.12927-.40589Zm2.05515 5.71782L7.0673 8.29748l-1.12927.40589 2.05515 5.71783 1.12927-.4059Z" fill="currentColor"></path>
                <path d="m15.6133 8.16406-5.1156-2.66251" stroke="currentColor" stroke-width="1.2" stroke-linecap="round"></path>
            </svg>
        </a>
        <svg class="user-slash" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-6">
            <path stroke-linecap="round" stroke-linejoin="round" d="m9 20.247 6-16.5" />
        </svg>
        <div class="user">
            <img class="avatar" alt="" src="https://assets.codepen.io/605876/cropped-headshot--saturated-low-res.jpg"/>
            <span class="name">Jhey Tompkins</span>
            <span class="badge">Lifetime</span>
        </div>
    </header>
    
    <div class="layout">
        <div class="aside">
            <button popovertarget="sidebar" popovertargetaction="toggle" class="toggle">
                <svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
                    <path d="M3 8.25V18C3 18.5967 3.23705 19.169 3.65901 19.591C4.08097 20.0129 4.65326 20.25 5.25 20.25H18.75C19.3467 20.25 19.919 20.0129 20.341 19.591C20.7629 19.169 21 18.5967 21 18V8.25M3 8.25V6C3 5.40326 3.23705 4.83097 3.65901 4.40901C4.08097 3.98705 4.65326 3.75 5.25 3.75H18.75C19.3467 3.75 19.919 3.98705 20.341 4.40901C20.7629 4.83097 21 5.40326 21 6V8.25M3 8.25H21M5.25 6H5.258V6.008H5.25V6ZM7.5 6H7.508V6.008H7.5V6ZM9.75 6H9.758V6.008H9.75V6Z" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
                    <path class="icon-bar" d="M4.75 10H11V18.5H5.75C5.19772 18.5 4.75 18.0523 4.75 17.5V10Z" fill="currentColor"/>
                </svg>
                <span class="safety-triangle"></span>
                <span class="hover-set"></span>
            </button>
            
            <aside popover="manual" id="sidebar">
                <header>
                    <a class="button-link" aria-label="Home" href="/">
                        <svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
                            <path d="m3.98448 20.5882-1.17645 1.6174m-.22047-1.3969 1.61739 1.1764M22.144.730378 20.6832 2.09646m.0474-1.413417 1.366 1.460757" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"></path>
                            <path d="m3.90821 18.5526-.59559.0726c.03203.2626.23224.4732.49285.5185l.10274-.5911ZM20.601 4.22249l.3908.45525c.1679-.14415.2428-.36902.195-.58508-.0479-.21606-.2109-.38822-.424-.44793l-.1618.57776Zm.6023-.00906c-.0066-.33131-.2805-.59453-.6118-.58794-.3313.0066-.5945.28052-.5879.61183l1.1997-.02389Zm-.2556 17.30047-.1028.5911c.1766.0307.3576-.0191.4935-.1358.136-.1168.2127-.2881.2091-.4673l-.5998.012ZM3.03505 11.3945l-.39082-.4552c-.15222.1306-.22906.3287-.20477.5279l.59559-.0727ZM13.8216 1.69999c-.3191-.0894-.6502.0968-.7396.41588-.0894.31909.0968.65023.4159.73963l.3237-1.15551ZM4.29903 19.0078 20.9918 4.67774l-.7816-.91051L3.51739 18.0973l.78164.9105ZM20.0036 4.23732l.3442 17.28848 1.1997-.0239-.3442-17.28847-1.1997.02389ZM3.80547 19.1437 20.8449 22.105l.2055-1.1823-17.03946-2.9613-.20547 1.1823Zm-.3796-7.2939L14.0485 2.73064l-.7816-.91052L2.64423 10.9393l.78164.9105Zm1.07792 6.6301-.87316-7.158-1.19117.1453.87316 7.158 1.19117-.1453ZM20.7628 3.64473l-6.9412-1.94474-.3237 1.15551 6.9412 1.94474.3237-1.15551Z" fill="currentColor"></path>
                            <path d="m15.7227 7.75 4.9996 13.5001M8.13672 14.2656 20.724 21.2521" stroke="currentColor" stroke-width="1.2"></path>
                            <path d="M7.0673 8.29748c-.11208-.31184-.45574-.47378-.76758-.36169-.31184.11208-.47377.45574-.36169.76758l1.12927-.40589Zm2.05515 5.71782L7.0673 8.29748l-1.12927.40589 2.05515 5.71783 1.12927-.4059Z" fill="currentColor"></path>
                            <path d="m15.6133 8.16406-5.1156-2.66251" stroke="currentColor" stroke-width="1.2" stroke-linecap="round"></path>
                        </svg>
                    </a>
                    <button class="closer" popovertarget="sidebar" popovertargetaction="hide" aria-label="Close menu">
                        <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-6">
                            <path stroke-linecap="round" stroke-linejoin="round" d="M12 4.5v15m7.5-7.5h-15" />
                        </svg>
                    </button>
                    <button aria-label="New request">New Request</button>
                    <form>
                        <div class="tree-search-input-container">
                            <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="size-5">
                                <path fill-rule="evenodd" d="M9 3.5a5.5 5.5 0 1 0 0 11 5.5 5.5 0 0 0 0-11ZM2 9a7 7 0 1 1 12.452 4.391l3.328 3.329a.75.75 0 1 1-1.06 1.06l-3.329-3.328A7 7 0 0 1 2 9Z" clip-rule="evenodd" />
                            </svg>
                            <input 
                                type="input" 
                                id="tree-search"
                                placeholder="Find" 
                                aria-label="Filter navigation tree"
                                class="tree-search-input"
                            >
                            <kbd>/</kbd>
                        </div>
                    </form>
                </header>
                <nav aria-label="The Craft of UI">
                    <sidebar-tree>
                        <!-- Tree content will be generated by the component -->
                    </sidebar-tree>
                </nav>
                <footer>
                    <div class="user">
                        <img class="avatar" alt="" src="https://assets.codepen.io/605876/cropped-headshot--saturated-low-res.jpg"/>
                        <span class="name">Jhey Tompkins</span>
                        <span class="badge">Lifetime</span>
                    </div>
                    <button class="feedback" aria-label="Feedback">
                        <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-6">
                            <path stroke-linecap="round" stroke-linejoin="round" d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L10.582 16.07a4.5 4.5 0 0 1-1.897 1.13L6 18l.8-2.685a4.5 4.5 0 0 1 1.13-1.897l8.932-8.931Zm0 0L19.5 7.125M18 14v4.75A2.25 2.25 0 0 1 15.75 21H5.25A2.25 2.25 0 0 1 3 18.75V8.25A2.25 2.25 0 0 1 5.25 6H10" />
                        </svg>
                        <span>Feedback</span>
                    </button>
                    <button class="settings" aria-label="Settings">
                        <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-6">
                            <path stroke-linecap="round" stroke-linejoin="round" d="M4.5 12a7.5 7.5 0 0 0 15 0m-15 0a7.5 7.5 0 1 1 15 0m-15 0H3m16.5 0H21m-1.5 0H12m-8.457 3.077 1.41-.513m14.095-5.13 1.41-.513M5.106 17.785l1.15-.964m11.49-9.642 1.149-.964M7.501 19.795l.75-1.3m7.5-12.99.75-1.3m-6.063 16.658.26-1.477m2.605-14.772.26-1.477m0 17.726-.26-1.477M10.698 4.614l-.26-1.477M16.5 19.794l-.75-1.299M7.5 4.205 12 12m6.894 5.785-1.149-.964M6.256 7.178l-1.15-.964m15.352 8.864-1.41-.513M4.954 9.435l-1.41-.514M12.002 12l-3.75 6.495" />
                        </svg>
                        <span>Settings</span>
                    </button>
                </footer>
            </aside>
        </div>
        
        <div class="content">
            <main>
                <span class="arrow arrow--instruction">
                    <span>mess with this</span>
                    <svg viewBox="0 0 97 52" fill="none" xmlns="http://www.w3.org/2000/svg">
                        <path fill-rule="evenodd" clip-rule="evenodd" d="M74.568 0.553803C74.0753 0.881909 73.6295 1.4678 73.3713 2.12401C73.1367 2.70991 72.3858 4.67856 71.6584 6.50658C70.9544 8.35803 69.4526 11.8031 68.3498 14.1936C66.1441 19.0214 65.839 20.2167 66.543 21.576C67.4581 23.3337 69.4527 23.9196 71.3064 22.9821C72.4797 22.3728 74.8965 19.5839 76.9615 16.4435C78.8387 13.5843 78.8387 13.6077 78.1113 18.3418C77.3369 23.4275 76.4687 26.2866 74.5915 30.0364C73.254 32.7316 71.8461 34.6299 69.218 37.3485C65.9563 40.6999 62.2254 42.9732 57.4385 44.4965C53.8718 45.6449 52.3935 45.8324 47.2546 45.8324C43.3594 45.8324 42.1158 45.7386 39.9805 45.2933C32.2604 43.7466 25.3382 40.9577 19.4015 36.9735C15.0839 34.0909 12.5028 31.7004 9.80427 27.9975C6.80073 23.9196 4.36038 17.2403 3.72682 11.475C3.37485 8.1471 3.1402 7.32683 2.43624 7.13934C0.770217 6.71749 0.183578 7.77211 0.0193217 11.5219C-0.26226 18.5996 2.55356 27.1304 7.17619 33.1066C13.8403 41.7545 25.432 48.4103 38.901 51.2696C41.6465 51.8555 42.2566 51.9023 47.4893 51.9023C52.3935 51.9023 53.426 51.832 55.5144 51.3867C62.2723 49.9337 68.5375 46.6292 72.949 42.1998C76.0464 39.1296 78.1113 36.2939 79.8946 32.7081C82.1942 28.0912 83.5317 23.3103 84.2591 17.17C84.3999 15.8576 84.6111 14.7795 84.7284 14.7795C84.8223 14.7795 85.4559 15.1311 86.1364 15.5763C88.037 16.7716 90.3835 17.8965 93.5748 19.0918C96.813 20.3339 97.3996 20.287 96.4141 18.9512C94.9123 16.9122 90.055 11.5219 87.1219 8.63926C84.0949 5.66288 83.8368 5.33477 83.5552 4.1864C83.3909 3.48332 83.0155 2.68649 82.6401 2.31151C82.0065 1.6553 80.4109 1.04595 79.9885 1.30375C79.8712 1.37406 79.2845 1.11626 78.6744 0.717845C77.2431 -0.172727 75.7413 -0.243024 74.568 0.553803Z" fill="currentColor"></path>
                    </svg>
                </span>
            </main>
        </div>
    </div>
    
    <script>
        // 注册GSAP插件
        gsap.registerPlugin(Draggable);
        
        const config = {
            theme: 'system',
            duration: 0.18,
            opacity: 0.4,
            blur: 10,
            translate: 12,
            speed: 0.16,
            delay: true,
            triangle: true,
            show: false,
        };
        
        // 创建Tweakpane控制面板
        const ctrl = new Pane({
            title: 'config',
            expanded: false,
        });
        
        const update = () => {
            document.documentElement.dataset.theme = config.theme;
            document.documentElement.dataset.delay = config.delay;
            document.documentElement.dataset.triangle = config.triangle;
            document.documentElement.dataset.show = config.show;
            document.documentElement.style.setProperty('--layout-speed', config.speed);
            document.documentElement.style.setProperty('--duration', config.duration);
            document.documentElement.style.setProperty('--opacity', config.opacity);
            document.documentElement.style.setProperty('--blur', config.blur);
            document.documentElement.style.setProperty('--translate', config.translate);
        };
        
        const sync = (event) => {
            if (
                !document.startViewTransition ||
                event.target.controller.view.labelElement.innerText !== 'theme'
            )
                return update();
            document.startViewTransition(() => update());
        };
        
        const layoutConfig = ctrl.addFolder({ title: 'layout', expanded: false });
        layoutConfig.addBinding(config, 'speed', {
            min: 0,
            max: 1,
            speed: 0.01,
            label: 'speed(s)'
        });
        layoutConfig.addBinding(config, 'delay');
        layoutConfig.addBinding(config, 'show');
        layoutConfig.addBinding(config, 'triangle');
        
        const sidebarConfig = ctrl.addFolder({ title: 'sidebar', expanded: false });
        
        sidebarConfig.addBinding(config, 'duration', {
            min: 0.1,
            max: 2,
            step: 0.01,
            label: 'duration(s)',
        });
        
        sidebarConfig.addBinding(config, 'opacity', {
            min: 0,
            max: 1,
            step: 0.1,
        });
        
        sidebarConfig.addBinding(config, 'blur', {
            min: 0,
            max: 20,
            step: 1,
            label: 'blur(px)',
        });
        
        sidebarConfig.addBinding(config, 'translate', {
            min: 0,
            max: 40,
            step: 1,
            label: 'translate(px)',
        });
        
        ctrl.addBinding(config, 'theme', {
            label: 'theme',
            options: {
                system: 'system',
                light: 'light',
                dark: 'dark',
            },
        });
        
        ctrl.on('change', sync);
        update();
        
        // 使Tweakpane面板可拖动
        const tweakClass = 'div.tp-dfwv';
        const d = Draggable.create(tweakClass, {
            type: 'x,y',
            allowEventDefault: true,
            trigger: tweakClass + ' button.tp-rotv_b',
        });
        
        document.querySelector(tweakClass).addEventListener('dblclick', () => {
            gsap.to(tweakClass, {
                x: `+=${d[0].x * -1}`,
                y: `+=${d[0].y * -1}`,
                onComplete: () => {
                    gsap.set(tweakClass, { clearProps: 'all' });
                },
            });
        });
        
        // 树形导航数据结构
        const TREE_DATA = {
            label: "Mythical University",
            groups: [
                {
                    title: "Base",
                    items: [
                        {
                            id: "intro",
                            label: "Introduction",
                            href: "#introduction",
                            current: true
                        },
                        {
                            id: "getting-started",
                            label: "Getting Started",
                            href: "#getting-started",
                            current: false
                        },
                        {
                            id: "checklist",
                            label: "The Checklist",
                            href: "#checklist",
                        },
                        {
                            id: "requests",
                            label: "Requests",
                            href: "#requests",
                        }
                    ]
                },
                {
                    title: "Modules",
                    items: [
                        {
                            id: "foundations",
                            label: "Foundations",
                            href: "#foundations",
                            items: [
                                {
                                    id: "overview",
                                    label: "Overview",
                                    href: "#overview"
                                },
                                {
                                    id: "css-animation",
                                    label: "CSS Animation",
                                    href: "#css-animation",
                                    items: [
                                        {
                                            id: "css-animation-anatomy",
                                            label: "Anatomy",
                                            href: "#css-animation-anatomy"
                                        },
                                        {
                                            id: "first-keyframe",
                                            label: "Keyframes",
                                            href: "#keyframes"
                                        },
                                        {
                                            id: "delays",
                                            label: "Delays",
                                            href: "#delays"
                                        },
                                    ]
                                },
                                {
                                    id: "svg-filters",
                                    label: "SVG Filters",
                                    href: "#svg-filters",
                                    items: [
                                        {
                                            id: "svg-filter-anatomy",
                                            label: "Anatomy",
                                            href: "#svg-filter-anatomy"
                                        },
                                        {
                                            id: "goo",
                                            label: "Goo",
                                            href: "#goo"
                                        },
                                        {
                                            id: "noise",
                                            label: "Noise",
                                            href: "#noise"
                                        }
                                    ]
                                },
                                {
                                    id: "canvas",
                                    label: "Canvas",
                                    href: "#canvas",
                                    items: [
                                        {
                                            id: "canvas-anatomy",
                                            label: "Anatomy",
                                            href: "#canvas-anatomy"
                                        },
                                        {
                                            id: "particles",
                                            label: "Particles",
                                            href: "#particles"
                                        },
                                        {
                                            id: "projection",
                                            label: "Projection",
                                            href: "#projection"
                                        }
                                    ]
                                }
                            ]
                        },
                        {
                            id: "studio",
                            label: "Studio",
                            href: "#studio",
                            items: [
                                {
                                    id: "tri-toggle",
                                    label: "Tri-Toggle",
                                    href: "#tri-toggle"
                                },
                                {
                                    id: "liquid-glass",
                                    label: "Liquid Glass",
                                    href: "#liquid-glass",
                                    items: [
                                        {
                                            id: "liquid-displacement",
                                            label: "Displacement",
                                            href: "#liquid-displacement"
                                        },
                                        {
                                            id: "liquid-toggle",
                                            label: "Toggle",
                                            href: "#liquid-toggle"
                                        },
                                        {
                                            id: "liquid-slider",
                                            label: "Slider",
                                            href: "#liquid-slider"
                                        }
                                    ]
                                },
                                {
                                    id: "bear-toggle",
                                    label: "Bear toggle",
                                    href: "#bear-toggle"
                                },
                                {
                                    id: "you-can-scroll",
                                    label: "You can scroll",
                                    href: "#you-can-scroll"
                                },
                                {
                                    id: "split-flap-display",
                                    label: "3D Split Flap",
                                    href: "#split-flap-display"
                                },
                                {
                                    id: "signature-flow",
                                    label: "Signature flow",
                                    href: "#signature-flow"
                                }
                            ]
                        },
                        {
                            id: "horizon",
                            label: "Horizon",
                            href: "#horizon",
                            items: [
                                {
                                    id: "scroll-markers",
                                    label: ":scroll-marker-group",
                                    href: "#scroll-markers"
                                },
                                {
                                    id: "css-scroll-animation",
                                    label: "Scroll-driven Animation",
                                    href: "#css-scroll-animation"
                                },
                                {
                                    id: "starting-style",
                                    label: "@starting-style",
                                    href: "#starting-style"
                                },
                                {
                                    id: "details-content",
                                    label: "::details-content",
                                    href: "#details-content"
                                },
                                {
                                    id: "styleable-select",
                                    label: "Styleable Select",
                                    href: "#styleable-select"
                                },
                                {
                                    id: "view-transitions",
                                    label: "View Transitions",
                                    href: "#view-transitions"
                                },
                                {
                                    id: "scroll-target-group",
                                    label: "scroll-target-group",
                                    href: "#scroll-target-group"
                                },
                                {
                                    id: "stuck",
                                    label: ":stuck",
                                    href: "#stuck"
                                }
                            ]
                        }
                    ]
                }
            ]
        };
        
        // 生成树形导航HTML
        function generateTreeHTML(data) {
            const processItems = (items, level = 1, parentId = null) => {
                const setSize = items.length;
                const htmlParts = [];
                
                items.forEach((item, index) => {
                    const posInSet = index + 1;
                    const hasChildren = item.items && item.items.length > 0;
                    const itemId = `tree-item-${item.id}`;
                    const groupId = hasChildren ? `tree-group-${item.id}` : null;
                    
                    let html = `<li role="none">`;
                    html += `<a
                        id="${itemId}"
                        role="treeitem"
                        href="${item.href || '#'}"
                        tabindex="${item.current ? '0' : '-1'}"
                        aria-level="${level}"
                        aria-setsize="${setSize}"
                        aria-posinset="${posInSet}"
                        ${item.current ? 'aria-current="page"' : ''}
                        ${hasChildren ? `aria-expanded="false" aria-owns="${groupId}"` : ''}
                    >`;
                    
                    html += `<span>${item.label}</span>`;
                    
                    if (hasChildren) {
                        html += `<span class="tree-icon" aria-hidden="true">
                            <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-6">
                                <path stroke-linecap="round" stroke-linejoin="round" d="M12 4.5v15m7.5-7.5h-15" />
                            </svg>
                        </span>`;
                    }
                    
                    html += `</a>`;
                    
                    if (hasChildren) {
                        html += `<div inert>`;
                        html += `<ul id="${groupId}" role="group">`;
                        html += processItems(item.items, level + 1, itemId);
                        html += `</ul>`;
                        html += `</div>`;
                    }
                    
                    html += `</li>`;
                    htmlParts.push(html);
                });
                
                return htmlParts.join('');
            };
            
            if (data.groups) {
                let treeHTML = `<ul role="tree" aria-label="${data.label}">`;
                
                data.groups.forEach((group, groupIndex) => {
                    const groupId = `tree-group-toplevel-${groupIndex}`;
                    treeHTML += `<li role="none" class="tree-group-container">`;
                    treeHTML += `<ul role="group" id="${groupId}">`;
                    treeHTML += processItems(group.items);
                    treeHTML += `</ul>`;
                    treeHTML += `</li>`;
                });
                
                treeHTML += `</ul>`;
                return treeHTML;
            }
            
            return `
                <ul role="tree" aria-label="${data.label}">
                    ${processItems(data.items || [])}
                </ul>
            `;
        }
        
        document.querySelector('sidebar-tree').innerHTML = generateTreeHTML(TREE_DATA);
        
        // 侧边栏树形导航组件
        class SidebarTree extends HTMLElement {
            constructor() {
                super();
                this.currentFocus = null;
                this.nodeMap = new Map();
            }
            
            resetTabIndexes() {
                this.tree.querySelectorAll('[role="treeitem"]').forEach(el => {
                    el.setAttribute('tabindex', '-1');
                });
            }
            
            setFocusToItem(item, updateTabindex = true) {
                if (!item) return;
                
                if (updateTabindex) {
                    this.resetTabIndexes();
                    item.setAttribute('tabindex', '0');
                }
                
                item.focus();
                this.currentFocus = item;
            }
            
            isExpanded(item) {
                return item.getAttribute('aria-expanded') === 'true';
            }
            
            findParentTreeItem(childElement) {
                const parentGroup = childElement.closest('ul[role="group"][id]');
                if (parentGroup && parentGroup.id.startsWith('tree-group-') && !parentGroup.id.includes('toplevel')) {
                    return this.querySelector(`[aria-owns="${parentGroup.id}"]`);
                }
                return null;
            }
            
            getGroupFromItem(item) {
                const groupId = item.getAttribute('aria-owns');
                return groupId ? document.getElementById(groupId) : null;
            }
            
            connectedCallback() {
                this.tree = this.querySelector('[role="tree"]');
                this.buildNodeMap();
                this.setupEventListeners();
                this.initializeFocus();
            }
            
            buildNodeMap() {
                const allTreeItems = this.querySelectorAll('[role="treeitem"]');
                
                allTreeItems.forEach(item => {
                    const parentItem = this.findParentTreeItem(item);
                    
                    this.nodeMap.set(item.id, {
                        id: item.id,
                        level: parseInt(item.getAttribute('aria-level')),
                        hasChildren: item.hasAttribute('aria-expanded'),
                        parentId: parentItem?.id || null,
                        label: item.textContent.trim()
                    });
                });
            }
            
            setupEventListeners() {
                this.tree.addEventListener('click', this.handleClick.bind(this));
                this.tree.addEventListener('keydown', this.handleKeydown.bind(this));
            }
            
            initializeFocus() {
                const currentItem = this.tree.querySelector('[aria-current="page"]');
                this.currentFocus = currentItem || this.tree.querySelector('[role="treeitem"]');
                
                if (currentItem) {
                    this.ensureItemVisible(currentItem);
                }
            }
            
            handleClick(event) {
                const treeItem = event.target.closest('[role="treeitem"]');
                if (!treeItem) return;
                
                const icon = event.target.closest('.tree-icon');
                
                if (icon && treeItem.hasAttribute('aria-expanded')) {
                    event.preventDefault();
                    this.toggleExpanded(treeItem);
                } else if (!icon) {
                    this.activateItem(treeItem);
                }
            }
            
            handleKeydown(event) {
                const treeItem = event.target.closest('[role="treeitem"]');
                if (!treeItem) return;
                
                switch (event.key) {
                    case 'Enter':
                    case ' ':
                        event.preventDefault();
                        this.activateItem(treeItem);
                        treeItem.click();
                        break;
                    case 'ArrowDown':
                        event.preventDefault();
                        this.focusNextItem(treeItem);
                        break;
                    case 'ArrowUp':
                        event.preventDefault();
                        this.focusPreviousItem(treeItem);
                        break;
                    case 'ArrowRight':
                        event.preventDefault();
                        this.handleRightArrow(treeItem);
                        break;
                    case 'ArrowLeft':
                        event.preventDefault();
                        this.handleLeftArrow(treeItem);
                        break;
                    case 'Home':
                        event.preventDefault();
                        this.focusFirstItem();
                        break;
                    case 'End':
                        event.preventDefault();
                        this.focusLastItem();
                        break;
                    case '*':
                        event.preventDefault();
                        this.expandAllSiblings(treeItem);
                        break;
                    default:
                        if (event.key.length === 1 && event.key.match(/[a-zA-Z]/)) {
                            event.preventDefault();
                            this.focusItemByFirstChar(event.key.toLowerCase());
                        }
                }
            }
            
            toggleExpanded(item) {
                const wasExpanded = this.isExpanded(item);
                const group = this.getGroupFromItem(item);
                
                if (group) {
                    const wrapper = group.parentElement;
                    item.setAttribute('aria-expanded', !wasExpanded);
                    
                    if (wasExpanded) {
                        wrapper.setAttribute('inert', '');
                    } else {
                        wrapper.removeAttribute('inert');
                    }
                }
            }
            
            activateItem(item) {
                this.tree.querySelectorAll('[aria-current="page"]').forEach(el => {
                    el.removeAttribute('aria-current');
                });
                
                item.setAttribute('aria-current', 'page');
                this.resetTabIndexes();
                item.setAttribute('tabindex', '0');
            }
            
            focusItem(item) {
                this.setFocusToItem(item);
            }
            
            focusNextItem(current) {
                const allVisible = this.getVisibleItems();
                const currentIndex = allVisible.indexOf(current);
                if (currentIndex < allVisible.length - 1) {
                    this.focusItem(allVisible[currentIndex + 1]);
                }
            }
            
            focusPreviousItem(current) {
                const allVisible = this.getVisibleItems();
                const currentIndex = allVisible.indexOf(current);
                if (currentIndex > 0) {
                    this.focusItem(allVisible[currentIndex - 1]);
                }
            }
            
            handleRightArrow(item) {
                if (item.hasAttribute('aria-expanded')) {
                    if (!this.isExpanded(item)) {
                        this.toggleExpanded(item);
                    } else {
                        const group = this.getGroupFromItem(item);
                        const firstChild = group?.querySelector('[role="treeitem"]');
                        if (firstChild) {
                            this.focusItem(firstChild);
                        }
                    }
                }
            }
            
            handleLeftArrow(item) {
                const nodeInfo = this.nodeMap.get(item.id);
                
                if (item.hasAttribute('aria-expanded') && this.isExpanded(item)) {
                    this.toggleExpanded(item);
                } else if (nodeInfo.parentId) {
                    const parent = document.getElementById(nodeInfo.parentId);
                    if (parent) {
                        this.focusItem(parent);
                    }
                }
            }
            
            focusFirstItem() {
                const firstItem = this.tree.querySelector('[role="treeitem"]');
                this.focusItem(firstItem);
            }
            
            focusLastItem() {
                const allVisible = this.getVisibleItems();
                this.focusItem(allVisible[allVisible.length - 1]);
            }
            
            expandAllSiblings(item) {
                const nodeInfo = this.nodeMap.get(item.id);
                const parent = nodeInfo.parentId ? 
                    document.getElementById(nodeInfo.parentId).parentElement : 
                    this.tree;
                
                parent.querySelectorAll(':scope > li > [aria-expanded="false"]').forEach(sibling => {
                    this.toggleExpanded(sibling);
                });
            }
            
            focusItemByFirstChar(char) {
                const allVisible = this.getVisibleItems();
                const current = document.activeElement;
                const currentIndex = allVisible.indexOf(current);
                
                for (let i = currentIndex + 1; i < allVisible.length; i++) {
                    if (allVisible[i].textContent.toLowerCase().trim().startsWith(char)) {
                        this.focusItem(allVisible[i]);
                        return;
                    }
                }
                
                for (let i = 0; i <= currentIndex; i++) {
                    if (allVisible[i].textContent.toLowerCase().trim().startsWith(char)) {
                        this.focusItem(allVisible[i]);
                        return;
                    }
                }
            }
            
            getVisibleItems() {
                const items = [];
                const walkTree = (element) => {
                    const directItems = element.querySelectorAll(':scope > li > [role="treeitem"]');
                    const groupItems = element.querySelectorAll(':scope > li > ul[role="group"] > li > [role="treeitem"]');
                    const treeItems = [...directItems, ...groupItems];
                    
                    treeItems.forEach(item => {
                        items.push(item);
                        if (this.isExpanded(item)) {
                            const group = this.getGroupFromItem(item);
                            if (group) {
                                walkTree(group);
                            }
                        }
                    });
                };
                
                walkTree(this.tree);
                return items;
            }
            
            ensureItemVisible(item) {
                let parent = item.parentElement;
                while (parent && parent !== this.tree) {
                    if (parent.getAttribute('role') === 'group') {
                        const wrapper = parent.parentElement;
                        if (wrapper && wrapper.hasAttribute('inert')) {
                            const parentItem = this.tree.querySelector(`[aria-owns="${parent.id}"]`);
                            if (parentItem && !this.isExpanded(parentItem)) {
                                this.toggleExpanded(parentItem);
                            }
                        }
                    }
                    parent = parent.parentElement;
                }
            }
            
            filter(searchTerm) {
                const allItems = this.tree.querySelectorAll('[role="treeitem"]');
                
                if (!searchTerm || searchTerm.length < 3) {
                    allItems.forEach(item => {
                        item.removeAttribute('data-filtered');
                        item.removeAttribute('data-search-match');
                        item.removeAttribute('data-search-related');
                    });
                    this.tree.removeAttribute('data-filtering');
                    
                    const allExpandable = this.tree.querySelectorAll('[aria-expanded="true"]');
                    allExpandable.forEach(item => {
                        this.toggleExpanded(item);
                    });
                    
                    const currentItem = this.tree.querySelector('[aria-current="page"]');
                    if (currentItem) {
                        this.ensureItemVisible(currentItem);
                    }
                    
                    return 0;
                }
                
                this.tree.setAttribute('data-filtering', 'true');
                const term = searchTerm.toLowerCase();
                const matches = new Set();
                const relatedItems = new Set();
                
                allItems.forEach(item => {
                    const text = item.textContent.toLowerCase();
                    if (text.includes(term)) {
                        matches.add(item);
                        item.setAttribute('data-search-match', 'true');
                        
                        let parent = item.parentElement;
                        while (parent && parent !== this.tree) {
                            if (parent.getAttribute('role') === 'group') {
                                const parentItem = this.tree.querySelector(`[aria-owns="${parent.id}"]`);
                                if (parentItem) {
                                    relatedItems.add(parentItem);
                                    if (!this.isExpanded(parentItem)) {
                                        this.toggleExpanded(parentItem);
                                    }
                                }
                            }
                            parent = parent.parentElement;
                        }
                        
                        if (item.hasAttribute('aria-owns')) {
                            const group = this.getGroupFromItem(item);
                            if (group) {
                                const descendants = group.querySelectorAll('[role="treeitem"]');
                                descendants.forEach(desc => relatedItems.add(desc));
                                if (!this.isExpanded(item)) {
                                    this.toggleExpanded(item);
                                }
                            }
                        }
                    }
                });
                
                allItems.forEach(item => {
                    if (matches.has(item)) {
                        item.removeAttribute('data-filtered');
                        item.removeAttribute('data-search-related');
                    } else if (relatedItems.has(item)) {
                        item.removeAttribute('data-filtered');
                        item.removeAttribute('data-search-match');
                        item.setAttribute('data-search-related', 'true');
                    } else {
                        item.removeAttribute('data-search-match');
                        item.removeAttribute('data-search-related');
                        item.setAttribute('data-filtered', 'true');
                    }
                });
                
                return matches.size;
            }
        }
        
        customElements.define('sidebar-tree', SidebarTree);
        
        // 搜索功能
        const searchInput = document.getElementById('tree-search');
        const sidebarTree = document.querySelector('sidebar-tree');
        
        function updateSearchAriaLabel(value, matches) {
            const baseLabel = 'Search navigation tree - Press slash to focus';
            
            if (!value || value.length < 3) {
                searchInput.setAttribute('aria-label', baseLabel);
            } else {
                searchInput.setAttribute('aria-label', 
                    matches > 0 
                        ? `Search navigation tree - ${matches} items found - Press slash to focus`
                        : 'Search navigation tree - No items found - Press slash to focus'
                );
            }
        }
        
        if (searchInput && sidebarTree) {
            searchInput.addEventListener('input', (e) => {
                const value = e.target.value.trim();
                const matches = sidebarTree.filter(value);
                updateSearchAriaLabel(value, matches);
            });
            
            searchInput.addEventListener('keydown', (e) => {
                if (e.key === 'Escape') {
                    e.target.value = '';
                    sidebarTree.filter('');
                    updateSearchAriaLabel('', 0);
                }
            });
            
            document.addEventListener('keydown', (e) => {
                const tagName = e.target.tagName.toLowerCase();
                const isEditable = e.target.isContentEditable;
                const isInput = tagName === 'input' || tagName === 'textarea' || tagName === 'select';
                
                if (e.key === '/' && !isInput && !isEditable) {
                    e.preventDefault();
                    searchInput.focus();
                    searchInput.select();
                }
            });
        }
        
        // 响应式popover处理
        const sidebar = document.querySelector('aside[popover]');
        const syncPopover = () => {
            const desktop = window.matchMedia('(min-width: 768px)').matches;
            sidebar.setAttribute('popover', desktop ? 'manual' : 'auto');
        };
        
        window.addEventListener('resize', syncPopover);
        syncPopover();
    </script>
</body>
</html>
        
编辑器加载中
预览
控制台