diff --git a/site/build.mjs b/site/build.mjs index 2e68ccd..061e079 100644 --- a/site/build.mjs +++ b/site/build.mjs @@ -139,7 +139,7 @@ const T = { docs: { title: 'Documentation', menu: 'Menu', on: 'On this page', prev: 'Previous', next: 'Next', onlyOther: 'This page is only available in Chinese so far.', homeIntro: 'Start here, then dive into the features you need.', - sections: { 'getting-started': 'Getting Started', core: 'Core Capabilities', domains: 'Domain Guides', 'advanced-setup': 'Advanced Setup', reference: 'Reference', 'developer-docs': 'Developer Documentation' } + sections: { 'getting-started': 'Getting Started', core: 'Core Capabilities', domains: 'Domain Guides', 'setup-reference': 'More Features and Configuration' } } }, zh: { @@ -240,22 +240,27 @@ const T = { docs: { title: '文档', menu: '目录', on: '本页内容', prev: '上一篇', next: '下一篇', onlyOther: '本页暂时只有英文版。', homeIntro: '从这里开始,再深入你需要的功能。', - sections: { 'getting-started': '快速开始', core: '核心功能', domains: '领域教程', 'advanced-setup': '高级配置', reference: '参考', 'developer-docs': '开发者文档' } + sections: { 'getting-started': '快速开始', core: '核心功能', domains: '领域教程', 'setup-reference': '更多功能与配置' } } } }; -// The product documentation owns these six reader-facing groups. Listed pages keep +// The product documentation owns these reader-facing groups. Listed pages keep // a useful reading order; new pages in the same directory are appended automatically. const DOC_GROUPS = [ ['getting-started', ['getting-started/deployment', 'getting-started/quick-start']], ['core', ['core/README', 'core/evolve', 'core/execution-workspaces', 'core/idea-tree']], ['domains', ['domains/README', 'domains/evolve-a-solution', 'domains/run-an-evolution-search', 'domains/literature-research']], - ['advanced-setup', ['advanced-setup/README', 'advanced-setup/configure-custom-mcp', 'advanced-setup/configure-network-proxy', 'advanced-setup/science-memory-setup']], - ['reference', ['reference/README', 'reference/configuration', 'reference/rest-api', 'reference/runtime-behavior', 'reference/builtin-tools', 'reference/web-tools', 'reference/jiuwenswarm-migration-status']], - ['developer-docs', ['developer-docs/README', 'developer-docs/architecture', 'developer-docs/control-plane', 'developer-docs/agent', 'developer-docs/runner', 'developer-docs/sandbox-execution', 'developer-docs/science-memory', 'developer-docs/subagent-orchestration', 'developer-docs/skill-progressive-disclosure', 'developer-docs/science-connectors', 'developer-docs/web-frontend']] + ['setup-reference', [ + 'advanced-setup/README', 'advanced-setup/configure-custom-mcp', 'advanced-setup/configure-network-proxy', 'advanced-setup/science-memory-setup', + 'reference/README', 'reference/configuration', 'reference/rest-api', 'reference/runtime-behavior', 'reference/builtin-tools', 'reference/web-tools', 'reference/jiuwenswarm-migration-status' + ]] ]; +// Implementation notes are still built and linked from the core pages, but they are no longer a +// reader-facing group, so neither the sidebar nor the documentation index lists them. +const DOC_HIDDEN_GROUPS = ['developer-docs']; + // A panel that shows a screenshot is sized from the picture itself: the stylesheet multiplies the // height left for the image by this ratio, so the dialog hugs the image instead of sitting in a // wide empty box. Read straight from the PNG header (IHDR), so replacing the file is enough. @@ -310,9 +315,13 @@ for (const lang of LANGS) { } const keyFor = (k) => (k === 'README' ? 'index' : k.replace(/\/README$/, '/index')); const outPath = (k) => keyFor(k) + '.html'; +// A group normally maps to one documentation directory; setup-reference folds two of them into a +// single rail entry, so it needs both prefixes to discover the pages that are not listed by name. +const GROUP_PREFIXES = { 'setup-reference': ['advanced-setup', 'reference'] }; +const prefixesOf = (group) => GROUP_PREFIXES[group] || [group]; function groupItems(group) { const listed = DOC_GROUPS.find(([name]) => name === group)?.[1] || []; - const available = Object.keys(sources).filter((k) => k.startsWith(group + '/')); + const available = Object.keys(sources).filter((k) => prefixesOf(group).some((p) => k.startsWith(p + '/'))); return [...listed.filter((k) => sources[k]), ...available.filter((k) => !listed.includes(k)).sort()]; } @@ -399,6 +408,10 @@ function renderDoc(md, srcFile, lang, pagePath) { } const r = relative(ROOT, abs).split(sep).join('/'); if (r.startsWith('..')) return href; + // Sample data and screenshots are published with the site, so a link to them must not send + // the reader to GitHub for a file that is already served from this origin. + const inDocs = relative(DOCS, abs).split(sep).join('/'); + if (!inDocs.startsWith('..') && /^(examples|images)\//.test(inDocs)) return rel(pagePath, 'docs/' + inDocs) + frag; const isDir = existsSync(abs) && statSync(abs).isDirectory(); return `${GH}/${isDir ? 'tree' : 'blob'}/${BRANCH}/${r}${frag}`; }, @@ -630,7 +643,7 @@ function indexDoc(lang, k, title, html) { function docNav(lang, activeKey) { const t = T[lang], S = t.docs.sections; - const groupIcons = { 'getting-started': 'book', core: 'tree', domains: 'flask', 'advanced-setup': 'plug', reference: 'task', 'developer-docs': 'graph' }; + const groupIcons = { 'getting-started': 'book', core: 'tree', domains: 'flask', 'setup-reference': 'plug' }; const linkFor = (k, text, fromPath) => `${esc(text)}`; return (fromPath) => { return DOC_GROUPS.map(([group]) => { @@ -721,11 +734,15 @@ cpSync(join(HERE, 'src', 'media'), join(DIST, 'media'), { recursive: true }); mkdirSync(join(DIST, 'vendor', 'molstar'), { recursive: true }); for (const f of ['molstar.css', 'molstar.js']) cpSync(join(ROOT, 'node_modules', 'molstar', 'build', 'viewer', f), join(DIST, 'vendor', 'molstar', f)); cpSync(join(DOCS, 'images'), join(DIST, 'docs', 'images'), { recursive: true }); +// The walkthrough links the sample data it asks readers to upload, so it has to ship with the page. +if (existsSync(join(DOCS, 'examples'))) cpSync(join(DOCS, 'examples'), join(DIST, 'docs', 'examples'), { recursive: true }); write('favicon.svg', `${IC.brand}`); write('.nojekyll', ''); write('404.html', 'ScienceDiscovery'); const order = DOC_GROUPS.flatMap(([group]) => groupItems(group)); +// Each hidden group pages only against itself, so no pager link sends a reader into it. +const hiddenOrder = DOC_HIDDEN_GROUPS.flatMap((group) => groupItems(group)); let pages = 0; for (const lang of LANGS) { @@ -734,6 +751,7 @@ for (const lang of LANGS) { write(pathOf(lang, 'download/index.html'), legacyRedirect(lang, 'download/index.html', 'index.html', 'home'), false); write(pathOf(lang, 'docs/index.html'), docsHome(lang, order)); for (const k of order) { write(pathOf(lang, 'docs/' + outPath(k)), docPage(k, lang, order)); pages++; } + for (const k of hiddenOrder) { write(pathOf(lang, 'docs/' + outPath(k)), docPage(k, lang, hiddenOrder), false); pages++; } write(pathOf(lang, 'search-index.json'), JSON.stringify(INDEX[lang])); } diff --git a/site/src/site.css b/site/src/site.css index beb3c8f..58d402d 100644 --- a/site/src/site.css +++ b/site/src/site.css @@ -370,7 +370,9 @@ a.file:hover { border-color: var(--accent-border-soft); background: var(--accent .hidden { display: none !important; } /* ---------- docs ---------- */ -.docs { display: grid; grid-template-columns: 280px minmax(0, 1fr) 210px; max-width: 1400px; margin: 0 auto; align-items: start; } +/* The reader column is the point of this page, so the shell is wider than the marketing ones and + the two rails stay fixed: on a 1440px screen the article gets about 950px instead of 800px. */ +.docs { display: grid; grid-template-columns: 268px minmax(0, 1fr) 200px; max-width: 1680px; margin: 0 auto; align-items: start; } .docs-nav { position: sticky; top: var(--nav-h); height: calc(100vh - var(--nav-h)); overflow-y: auto; padding: 18px 12px 32px; border-right: 1px solid var(--border); background: var(--surface-subtle); } .docs-nav-group { margin: 4px 0; border: 1px solid transparent; border-radius: 12px; } .docs-nav-group[open] { border-color: var(--border); background: var(--surface); box-shadow: var(--shadow-1); } @@ -390,14 +392,14 @@ a.file:hover { border-color: var(--accent-border-soft); background: var(--accent .docs-nav-links a:hover { background: var(--surface-hover); color: var(--text-strong); text-decoration: none; } .docs-nav-links a.active { background: var(--accent-softer); color: var(--accent-deep); font-weight: 650; } .docs-nav-links a.active::before { position: absolute; top: 6px; bottom: 6px; left: -14px; width: 2px; border-radius: 2px; background: var(--accent); content: ''; } -.article { min-width: 0; padding: 48px 52px 24px; font-family: var(--serif); } +.article { min-width: 0; padding: 46px 44px 24px; font-family: var(--serif); } .article > *:first-child { margin-top: 0; } .article h1 { margin: 0 0 24px; color: var(--text-strong); font-size: clamp(32px, 3.1vw, 40px); line-height: 1.18; letter-spacing: -.045em; } .article h2 { margin: 48px 0 16px; padding-top: 16px; border-top: 1px solid var(--border); color: var(--text-strong); font-size: 25px; letter-spacing: -.035em; } .article h3 { margin: 32px 0 10px; color: var(--text-strong); font-size: 19px; letter-spacing: -.02em; } .article h4 { margin: 22px 0 6px; color: var(--text-heading); font-size: 15px; } .article p, .article li { color: var(--text); font-size: 16px; line-height: 1.78; } -.article > p, .article > ul, .article > ol, .article > blockquote { max-width: 76ch; } +.article > p, .article > ul, .article > ol, .article > blockquote { max-width: 96ch; } .article li { margin: 4px 0; } .article a { text-decoration: underline; text-decoration-color: var(--accent-border-soft); text-underline-offset: 2px; } .article a:hover { text-decoration-color: var(--accent-strong); }