diff --git a/docs-site/astro.config.mjs b/docs-site/astro.config.mjs index f69d696cf28..2423554b630 100644 --- a/docs-site/astro.config.mjs +++ b/docs-site/astro.config.mjs @@ -27,15 +27,17 @@ export default defineConfig({ "Universal provider proxy for OpenAI Codex & Claude Code — use any LLM with Codex CLI, App, SDK, and Claude Code.", tagline: "Use any LLM with OpenAI Codex and Claude Code.", logo: { - light: "./src/assets/logo-light.png", - dark: "./src/assets/logo-dark.png", + light: "./src/assets/logo-light.svg", + dark: "./src/assets/logo-dark.svg", replacesTitle: false, }, favicon: "/favicon.ico", customCss: [ "@fontsource-variable/geist", - "pretendard/dist/web/variable/pretendardvariable-dynamic-subset.css", + "@fontsource-variable/geist-mono", + "wanted-sans/fonts/webfonts/variable/split/WantedSansVariable.css", "./src/styles/custom.css", + "./src/styles/site-theme.css", ], components: { Header: "./src/components/Header.astro", @@ -44,6 +46,10 @@ export default defineConfig({ head: [ // Google favicon guidelines: PNG at a multiple of 48px, exposed via rel="icon". { tag: "link", attrs: { rel: "icon", type: "image/png", sizes: "192x192", href: "/favicon.png" } }, + // The vector mark recolours itself for dark browser chrome; browsers that + // understand SVG icons prefer it over the generated ICO/PNG (scripts/brand-favicons.ts). + { tag: "link", attrs: { rel: "icon", type: "image/svg+xml", href: "/favicon.svg" } }, + { tag: "link", attrs: { rel: "apple-touch-icon", href: "/favicon.png" } }, { tag: "meta", attrs: { property: "og:image", content: `${SITE_URL}/og.png` } }, { tag: "meta", attrs: { property: "og:image:width", content: "1200" } }, { tag: "meta", attrs: { property: "og:image:height", content: "630" } }, diff --git a/docs-site/bun.lock b/docs-site/bun.lock index 092f7d2349d..954219debae 100644 --- a/docs-site/bun.lock +++ b/docs-site/bun.lock @@ -7,11 +7,13 @@ "dependencies": { "@astrojs/starlight": "^0.41.7", "@fontsource-variable/geist": "^5.3.0", + "@fontsource-variable/geist-mono": "5.3.0", "astro": "^7.3.3", "echarts": "^6.1.0", "pretendard": "^1.3.9", "sharp": "^0.35.4", "simple-icons": "^16.28.0", + "wanted-sans": "1.0.3", }, }, }, @@ -165,6 +167,8 @@ "@fontsource-variable/geist": ["@fontsource-variable/geist@5.3.0", "", {}, "sha512-j0m+vLQuG5XAYoHtGCVu0spvlGreR3EzpECUVzkFmI1mTVnAO38l/NEPDCFgZ177JxzYJCLSmTQibIiYPilGrA=="], + "@fontsource-variable/geist-mono": ["@fontsource-variable/geist-mono@5.3.0", "", {}, "sha512-vBbuwDEo9AkrqADMXOrlAR3DFcJi4/JxeuU43FoiQERnNwsfXNnvxvReZG02cQKmyk4DZkZdBZX3oTDvy2zBAw=="], + "@img/colour": ["@img/colour@1.1.0", "", {}, "sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ=="], "@img/sharp-darwin-arm64": ["@img/sharp-darwin-arm64@0.35.4", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-arm64": "1.3.3" }, "os": "darwin", "cpu": "arm64" }, "sha512-Uhfl4V4lhP2nbUVF9+hyH1+luj86f1gUFeo8ALYxFoULoU+G87D43BfeMP8XHsk9boxAnCY/bf2EHwhA7MuGsA=="], @@ -927,6 +931,8 @@ "vitefu": ["vitefu@1.1.3", "", { "peerDependencies": { "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0" }, "optionalPeers": ["vite"] }, "sha512-ub4okH7Z5KLjb6hDyjqrGXqWtWvoYdU3IGm/NorpgHncKoLTCfRIbvlhBm7r0YstIaQRYlp4yEbFqDcKSzXSSg=="], + "wanted-sans": ["wanted-sans@1.0.3", "", {}, "sha512-YU+mQRJMc97zMGFmxFjOvjdrF5Hi2zagc69bNP9n//i77Dlf9AWGfziZWYKdhQzPK5tw+e0iHcjLrZXDatxRTQ=="], + "web-namespaces": ["web-namespaces@2.0.1", "", {}, "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ=="], "xxhash-wasm": ["xxhash-wasm@1.1.0", "", {}, "sha512-147y/6YNh+tlp6nd/2pWq38i9h6mz/EuQ6njIrmW8D1BS5nCqs0P6DG+m6zTGnNz5I+uhZ0SHxBs9BsPrwcKDA=="], diff --git a/docs-site/package.json b/docs-site/package.json index 2c1f923c83d..59cdbdd766e 100644 --- a/docs-site/package.json +++ b/docs-site/package.json @@ -13,11 +13,13 @@ "dependencies": { "@astrojs/starlight": "^0.41.7", "@fontsource-variable/geist": "^5.3.0", + "@fontsource-variable/geist-mono": "5.3.0", "astro": "^7.3.3", "echarts": "^6.1.0", "pretendard": "^1.3.9", "sharp": "^0.35.4", - "simple-icons": "^16.28.0" + "simple-icons": "^16.28.0", + "wanted-sans": "1.0.3" }, "overrides": { "svgo": "4.1.0", diff --git a/docs-site/public/favicon.svg b/docs-site/public/favicon.svg new file mode 100644 index 00000000000..bd0cf20828f --- /dev/null +++ b/docs-site/public/favicon.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/docs-site/public/grain.svg b/docs-site/public/grain.svg new file mode 100644 index 00000000000..9b7a1133c22 --- /dev/null +++ b/docs-site/public/grain.svg @@ -0,0 +1 @@ + diff --git a/docs-site/src/assets/logo-dark.svg b/docs-site/src/assets/logo-dark.svg new file mode 100644 index 00000000000..5b5acb93733 --- /dev/null +++ b/docs-site/src/assets/logo-dark.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/docs-site/src/assets/logo-light.svg b/docs-site/src/assets/logo-light.svg new file mode 100644 index 00000000000..0797892fe07 --- /dev/null +++ b/docs-site/src/assets/logo-light.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/docs-site/src/components/CloudCanvas.astro b/docs-site/src/components/CloudCanvas.astro new file mode 100644 index 00000000000..6abc9d88474 --- /dev/null +++ b/docs-site/src/components/CloudCanvas.astro @@ -0,0 +1,316 @@ +--- +// Animated WebGL2 cloud sky for the hero and closing panel. Renders into an +// absolutely positioned host that fills its nearest positioned ancestor. +// Without WebGL2 the host keeps its CSS sky colour, so the section still reads. +// Under reduced motion one still frame is drawn and re-drawn on theme change. +interface Props { + class?: string; + /** `sky` paints a full daylight sky; `overlay` draws only the clouds, + * dusk-lit and translucent, over whatever sits behind the canvas. */ + variant?: 'sky' | 'overlay'; +} +const { class: className, variant = 'sky' } = Astro.props; +--- + + + + diff --git a/docs-site/src/components/Header.astro b/docs-site/src/components/Header.astro index 7457c6d4210..7e86a7de5dc 100644 --- a/docs-site/src/components/Header.astro +++ b/docs-site/src/components/Header.astro @@ -17,7 +17,34 @@ const base = import.meta.env.BASE_URL.replace(/\/?$/, '/'); const prefix = locale ? `${base}${locale}/` : base; type NavLink = { label: string; href: string }; -type NavGroup = { label: string; links: NavLink[] }; +type NavGroup = { label: string; links: NavLink[]; more?: NavLink }; + +// Dropdown rows: every entry gets an icon tile. +// Lucide outline paths (24x24, stroke), keyed by the link's slug. +const ICONS: Record = { + 'getting-started/installation/': 'M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4M7 10l5 5 5-5M12 15V3', + 'getting-started/quickstart/': 'M13 2 3 14h9l-1 8 10-12h-9l1-8Z', + 'getting-started/how-it-works/': 'M6 3v12M18 9a3 3 0 1 0 0-6 3 3 0 0 0 0 6ZM6 21a3 3 0 1 0 0-6 3 3 0 0 0 0 6ZM18 9a9 9 0 0 1-9 9', + 'getting-started/for-agents/': 'M12 8V4H8m8 0h-4M4 12a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v6a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2Zm11 3h.01M9 15h.01', + 'guides/providers/': 'M12 22v-5M9 8V2M15 8V2M6 8h12l-1 6a5 5 0 0 1-10 0Z', + 'guides/model-routing/': 'M6 19a3 3 0 1 0 0-6 3 3 0 0 0 0 6ZM18 11a3 3 0 1 0 0-6 3 3 0 0 0 0 6ZM9 16h5.5a3.5 3.5 0 0 0 0-7H15', + 'guides/combos/': 'm12 2 10 5-10 5L2 7Zm-10 10 10 5 10-5M2 17l10 5 10-5', + 'guides/codex-integration/': 'M16 18l6-6-6-6M8 6l-6 6 6 6', + 'guides/codex-app-models/': 'M3 5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2Zm6-2v18M3 9h6', + 'guides/claude-code/': 'M4 17l6-6-6-6M12 19h8', + 'guides/sidecars/': 'M11 19a8 8 0 1 0 0-16 8 8 0 0 0 0 16Zm10 2-4.35-4.35', + 'guides/image-bridge/': 'M3 5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2Zm6 6a2 2 0 1 0 0-4 2 2 0 0 0 0 4Zm12 4-3.09-3.09a2 2 0 0 0-2.82 0L6 21', + 'guides/video-bridge/': 'm16 13 5.22 3.48a.5.5 0 0 0 .78-.42V7.94a.5.5 0 0 0-.76-.43L16 10.5M4 6h10a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2Z', + 'guides/web-dashboard/': 'M3 3v16a2 2 0 0 0 2 2h16M7 16V9m5 7V5m5 11v-4', + 'guides/sub-agent-surface/': 'M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2M9 11a4 4 0 1 0 0-8 4 4 0 0 0 0 8Zm13 10v-2a4 4 0 0 0-3-3.87M16 3.13a4 4 0 0 1 0 7.75', + 'reference/cli/': 'M4 17l6-6-6-6M12 19h8', + 'reference/configuration/': 'M20 7h-9M14 17H5M17 20a3 3 0 1 0 0-6 3 3 0 0 0 0 6ZM7 10a3 3 0 1 0 0-6 3 3 0 0 0 0 6Z', + 'reference/adapters/': 'M12 22v-5M9 8V2M15 8V2M6 8h12l-1 6a5 5 0 0 1-10 0Z', + 'reference/architecture/': 'M3 3h7v7H3Zm11 0h7v7h-7Zm0 11h7v7h-7ZM3 14h7v7H3Z', + 'reference/proxy-formats/': 'M8 3H7a2 2 0 0 0-2 2v5a2 2 0 0 1-2 2 2 2 0 0 1 2 2v5a2 2 0 0 0 2 2h1m8 0h1a2 2 0 0 0 2-2v-5a2 2 0 0 1 2-2 2 2 0 0 1-2-2V5a2 2 0 0 0-2-2h-1', + 'reference/management-api/': 'M2 4h20v6H2Zm0 10h20v6H2ZM6 7h.01M6 17h.01', +}; +const iconFor = (href: string) => ICONS[href.slice(prefix.length)] ?? ICONS['guides/codex-integration/']; const fr = { 'Auto': 'Automatique', @@ -25,7 +52,7 @@ const fr = { 'Dark': 'Sombre', 'Theme': 'Thème', 'Click to use the next theme': 'Cliquez pour passer au thème suivant', - 'Getting Started': 'Démarrage', + 'Getting Started': 'Premiers pas', 'Installation': 'Installation', 'Quickstart': 'Démarrage rapide', 'How It Works': 'Fonctionnement', @@ -49,6 +76,7 @@ const fr = { 'Management API': 'API de gestion', 'Dashboard': 'Tableau de bord', 'Contributing': 'Contribuer', + 'Explore guides': 'Explorer les guides', 'Main': 'Navigation principale', 'Select language': 'Choisir la langue', 'Menu': 'Menu', @@ -63,8 +91,8 @@ const starCount = await getStarCount(); const starLocale = locale ?? 'en'; const githubLabel = t('GitHub', 'GitHub', 'GitHub', 'GitHub', 'GitHub', 'GitHub', 'GitHub'); const starLabel = t( - 'GitHub, {count} stars', 'GitHub, 별 {count}개', 'GitHub,{count} 个星标', - 'GitHub, {count} звёзд', 'GitHub、{count} スター', 'GitHub,{count} 個星標', 'GitHub, {count} yıldız', + 'GitHub, {count} stars', 'GitHub, 스타 {count}개', 'GitHub,{count} 个星标', + 'GitHub, звёзд: {count}', 'GitHub、{count} スター', 'GitHub,{count} 個星標', 'GitHub, {count} yıldız', ); const githubAccessibleName = starCount === null ? githubLabel : starLabel.replace('{count}', starCount.toLocaleString(starLocale)); @@ -114,7 +142,7 @@ const groups: NavGroup[] = [ { label: t('Installation', '설치', '安装', 'Установка', 'インストール', '安裝', 'Kurulum'), href: `${prefix}getting-started/installation/` }, { label: t('Quickstart', '빠른 시작', '快速开始', 'Быстрый старт', 'クイックスタート', '快速入門', 'Hızlı Başlangıç'), href: `${prefix}getting-started/quickstart/` }, { label: t('How It Works', '동작 원리', '工作原理', 'Как это работает', '仕組み', '運作原理', 'Nasıl Çalışır'), href: `${prefix}getting-started/how-it-works/` }, - { label: t('Agent Quickstart', '에이전트 퀵스타트', 'Agent 快速上手', 'Быстрый старт для агентов', 'エージェント向けクイックスタート', 'Agent 快速上手', 'Ajanlar İçin Hızlı Başlangıç'), href: `${prefix}getting-started/for-agents/` }, + { label: t('Agent Quickstart', '에이전트용 빠른 시작', 'Agent 快速上手', 'Быстрый старт для агентов', 'エージェント向けクイックスタート', 'Agent 快速上手', 'Ajanlar İçin Hızlı Başlangıç'), href: `${prefix}getting-started/for-agents/` }, ], }, { @@ -151,17 +179,31 @@ const dashboard: NavLink = { href: `${prefix}dashboard/`, }; +// Eleven guides made the Guides panel read like a sitemap. The panel keeps +// the six people reach for first and ends in a row that jumps to the curated +// docs map on the landing page. That band is a selection of guide pages, not +// an index of them, and the docs sidebar is a subset too, so the row invites +// exploration instead of claiming it lists every guide. +const GUIDE_PICKS = ['providers', 'model-routing', 'codex-integration', 'claude-code', 'sidecars', 'web-dashboard']; +const guides = groups[1]; +guides.links = guides.links.filter((link) => GUIDE_PICKS.some((slug) => link.href.endsWith(`guides/${slug}/`))); +guides.more = { + label: t('Explore guides', '가이드 둘러보기', '浏览指南', 'Обзор руководств', 'ガイドを探る', '瀏覽指南', 'Kılavuzlara göz atın'), + href: `${prefix}#docs-map`, +}; + const contributing: NavLink = { - label: t('Contributing', '기여하기', '贡献', 'Участие в проекте', 'コントリビュート', '貢獻', 'Katkıda Bulunma'), + label: t('Contributing', '기여하기', '贡献指南', 'Участие в проекте', 'コントリビュート', '貢獻指南', 'Katkıda Bulunma'), href: `${prefix}contributing/`, }; --- -
+
-