XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

XFESystem

【Rust】XFE系统,基于Rust和汇编

公开
关注 0 Fork 0 Star 0
UTF-8
(() => {
    const content = document.querySelector('[data-doc-content]');
    const progress = document.querySelector('[data-doc-progress]');
    const backToTop = document.querySelector('[data-doc-back-to-top]');
    const tocLinks = Array.from(document.querySelectorAll('[data-doc-toc-link], .page-toc .toc-link'));
    const reduceMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;

    const headings = tocLinks
        .map(link => {
            const hash = link.getAttribute('href');
            if (!hash?.startsWith('#')) return null;

            try {
                const heading = document.getElementById(decodeURIComponent(hash.slice(1)));
                return heading ? { link, heading } : null;
            } catch {
                return null;
            }
        })
        .filter(Boolean);

    let ticking = false;

    const updateReaderState = () => {
        ticking = false;
        const scrollTop = window.scrollY || document.documentElement.scrollTop;

        if (progress && content) {
            const contentTop = scrollTop + content.getBoundingClientRect().top;
            const available = Math.max(1, content.scrollHeight - window.innerHeight * 0.55);
            const percentage = Math.min(100, Math.max(0, ((scrollTop - contentTop + 120) / available) * 100));
            progress.style.width = `${percentage}%`;
        }

        backToTop?.classList.toggle('is-visible', scrollTop > 480);

        if (headings.length > 0) {
            let active = headings[0];
            for (const item of headings) {
                if (item.heading.getBoundingClientRect().top <= 150) active = item;
                else break;
            }

            headings.forEach(item => {
                const isActive = item === active;
                item.link.classList.toggle('is-active', isActive);
                if (isActive) item.link.setAttribute('aria-current', 'location');
                else item.link.removeAttribute('aria-current');
            });
        }
    };

    const requestUpdate = () => {
        if (ticking) return;
        ticking = true;
        window.requestAnimationFrame(updateReaderState);
    };

    window.addEventListener('scroll', requestUpdate, { passive: true });
    window.addEventListener('resize', requestUpdate, { passive: true });
    window.addEventListener('load', requestUpdate, { once: true });

    backToTop?.addEventListener('click', () => {
        window.scrollTo({ top: 0, behavior: reduceMotion ? 'auto' : 'smooth' });
    });

    updateReaderState();
})();