/* ═══════════ 文档页逻辑(docs.html) ═══════════ hash 路由(#01-quick-start 可直链某篇)+ fetch content/*.md + marked 前端渲染。 文档为站点自有的可信 markdown,无需注入消毒。 多语言:与主页同一 localStorage(astrion_site_locale);英文版在 content/en/ 同文件名, 缺失时回退中文;目录末尾附语言切换按钮(桌面端目录底部 / 移动端 chips 条尾部)。 */ (function () { 'use strict'; /* 文档页自己掌控滚动:禁用浏览器滚动恢复。否则刷新时浏览器恢复到上次滚动位置, 若上次停在 topbar 高度附近,fixed 顶栏会遮住 h1 上半截(实测实踩); 切篇/刷新统一回顶,行为可预期。 */ if ('scrollRestoration' in history) history.scrollRestoration = 'manual'; /* 目录标题与 md 一级标题语义一致(08/09 目录用简称,正文原标题保留); titleEn 为英文目录标题 */ var DOCS = [ { id: '01-quick-start', title: '快速上手', titleEn: 'Quick Start', file: '01-quick-start.md' }, { id: '02-core-concepts', title: '核心概念', titleEn: 'Core Concepts', file: '02-core-concepts.md' }, { id: '03-conversations', title: '对话', titleEn: 'Conversations', file: '03-conversations.md' }, { id: '04-input-context', title: '输入与上下文', titleEn: 'Input & Context', file: '04-input-context.md' }, { id: '05-execution-security', title: '执行与安全', titleEn: 'Execution & Security', file: '05-execution-security.md' }, { id: '06-conversation-assets', title: '对话资产管理', titleEn: 'Conversation Assets', file: '06-conversation-assets.md' }, { id: '07-agent-capabilities', title: '智能体能力', titleEn: 'Agent Capabilities', file: '07-agent-capabilities.md' }, { id: '08-quick-dock', title: '快捷窗口', titleEn: 'Quick Dock', file: '08-quick-dock.md' }, { id: '09-settings', title: '个人空间设置', titleEn: 'Personal Space Settings', file: '09-settings.md' }, { id: '10-cli', title: 'CLI(开发中)', titleEn: 'CLI (In Development)', file: '10-cli.md' } ]; var DICT = window.SITE_I18N || {}; var navEl = document.getElementById('docsNav'); var contentEl = document.getElementById('docsContent'); var currentId = null; var loadSeq = 0; /* 防快速切换时旧响应覆盖新内容 */ /* 与主页 site.js 同款检测:localStorage 优先 → 浏览器语言(zh 开头中文,否则英文) */ function detectLocale() { try { var stored = localStorage.getItem('astrion_site_locale'); if (stored === 'zh-CN' || stored === 'en-US') return stored; } catch (e) {} var nav = (navigator.language || '').toLowerCase(); return nav.indexOf('zh') === 0 ? 'zh-CN' : 'en-US'; } var locale = detectLocale(); function tr(key) { var d = DICT[locale] || {}; return d[key] != null ? d[key] : key; } /* 顶栏/侧栏等静态 [data-i18n] / [data-i18n-aria] 文案替换 + 页面 title */ function applyStaticI18n() { var d = DICT[locale]; if (!d) return; document.documentElement.setAttribute('lang', locale); var i, k, nodes; nodes = document.querySelectorAll('[data-i18n]'); for (i = 0; i < nodes.length; i++) { k = nodes[i].getAttribute('data-i18n'); if (d[k] != null) nodes[i].textContent = d[k]; } nodes = document.querySelectorAll('[data-i18n-aria]'); for (i = 0; i < nodes.length; i++) { k = nodes[i].getAttribute('data-i18n-aria'); if (d[k] != null) nodes[i].setAttribute('aria-label', d[k]); } document.title = tr('docs.pageTitle'); } /* 建左侧目录(末尾附语言切换按钮;切语言时整体重建) */ function buildNav() { navEl.innerHTML = ''; DOCS.forEach(function (doc) { var a = document.createElement('a'); a.href = '#' + doc.id; a.textContent = locale === 'en-US' ? doc.titleEn : doc.title; a.dataset.docId = doc.id; navEl.appendChild(a); }); var langBtn = document.createElement('button'); langBtn.type = 'button'; langBtn.className = 'docs-lang-toggle'; langBtn.textContent = locale === 'zh-CN' ? 'English' : '中文'; langBtn.setAttribute('aria-label', locale === 'zh-CN' ? 'Switch to English' : '切换为中文'); langBtn.addEventListener('click', function () { locale = locale === 'zh-CN' ? 'en-US' : 'zh-CN'; try { localStorage.setItem('astrion_site_locale', locale); } catch (e) {} applyStaticI18n(); buildNav(); renderNav(); if (currentId) loadDoc(currentId); }); navEl.appendChild(langBtn); } function docById(id) { for (var i = 0; i < DOCS.length; i++) if (DOCS[i].id === id) return DOCS[i]; return null; } /* hash → doc id;不匹配时:尚未加载过 → 默认第一篇;已加载 → 返回 null 忽略 (可能是渲染内容里的锚点 hash,不应触发切篇) */ function docIdFromHash() { var h = (location.hash || '').replace(/^#\/?/, ''); if (docById(h)) return h; return currentId === null ? DOCS[0].id : null; } function renderNav() { var links = navEl.querySelectorAll('a'); for (var i = 0; i < links.length; i++) { links[i].classList.toggle('active', links[i].dataset.docId === currentId); } } function postProcess() { /* 外部链接新标签打开;内容区内的站外相对链接(如指向主仓库文件)在官网无意义,原样保留 */ var links = contentEl.querySelectorAll('a[href^="http"]'); for (var i = 0; i < links.length; i++) { links[i].setAttribute('target', '_blank'); links[i].setAttribute('rel', 'noopener'); } } function loadDoc(id) { var doc = docById(id); if (!doc) return; currentId = id; renderNav(); var seq = ++loadSeq; contentEl.innerHTML = '

' + tr('docs.loading') + '

'; var path = (locale === 'en-US' ? 'content/en/' : 'content/') + doc.file; fetch(path) .then(function (res) { if (!res.ok && locale === 'en-US') { /* 英文版缺失时回退中文(保底:单篇未翻译不至于空白) */ return fetch('content/' + doc.file).then(function (r2) { if (!r2.ok) throw new Error('HTTP ' + r2.status); return r2.text(); }); } if (!res.ok) throw new Error('HTTP ' + res.status); return res.text(); }) .then(function (md) { if (seq !== loadSeq) return; /* 期间已切到别的篇目 */ contentEl.innerHTML = marked.parse(md); postProcess(); window.scrollTo(0, 0); }) .catch(function (err) { if (seq !== loadSeq) return; contentEl.innerHTML = '

' + tr('docs.loadFailedTpl').replace('{err}', String(err)) + '

'; }); } window.addEventListener('hashchange', function () { var id = docIdFromHash(); if (id && id !== currentId) loadDoc(id); }); applyStaticI18n(); buildNav(); var first = docIdFromHash(); if (location.hash !== '#' + first) { /* 把默认篇目写进地址栏,刷新/分享行为一致 */ history.replaceState(null, '', '#' + first); } loadDoc(first); })();