Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

52 changes: 40 additions & 12 deletions packages/console/app/script/generate-sitemap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,19 +42,47 @@ async function getDocsRoutes(): Promise<SitemapEntry[]> {
const routes: SitemapEntry[] = []

try {
const files = await readdir(DOCS_DIR)

for (const file of files) {
if (!file.endsWith(".mdx")) continue

const slug = file.replace(".mdx", "")
const path = slug === "index" ? "/docs/" : `/docs/${slug}`
async function walkMdxFiles(rootDir: string, currentDir = rootDir): Promise<string[]> {
const entries = await readdir(currentDir, { withFileTypes: true })
const results: string[] = []

for (const entry of entries) {
const absolute = join(currentDir, entry.name)
if (entry.isDirectory()) {
results.push(...(await walkMdxFiles(rootDir, absolute)))
continue
}
if (!entry.isFile()) continue
if (!entry.name.endsWith(".mdx")) continue
results.push(absolute)
}

return results
}

routes.push({
url: `${BASE_URL}${path}`,
priority: slug === "index" ? 0.9 : 0.7,
changefreq: "weekly",
})
const localeDirs = (await readdir(DOCS_DIR, { withFileTypes: true }))
.filter((d) => d.isDirectory())
.map((d) => d.name)

for (const docsDirName of localeDirs) {
const routeLocale = docsDirName === "en" ? "root" : docsDirName
const localeDir = join(DOCS_DIR, docsDirName)
const files = await walkMdxFiles(localeDir)

for (const absolutePath of files) {
const relative = absolutePath.slice(localeDir.length + 1)
const slug = relative.replace(/\.mdx$/, "").replace(/\\/g, "/")
const normalizedSlug =
slug === "index" ? "" : slug.endsWith("/index") ? slug.slice(0, -6) : slug
const basePath = routeLocale === "root" ? "/docs/" : `/docs/${routeLocale}/`
const path = normalizedSlug ? `${basePath}${normalizedSlug}/` : basePath

routes.push({
url: `${BASE_URL}${path}`,
priority: slug === "index" ? 0.9 : 0.7,
changefreq: "weekly",
})
}
}
} catch (error) {
console.error("Error reading docs directory:", error)
Expand Down
147 changes: 119 additions & 28 deletions packages/web/astro.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import config from "./config.mjs"
import { rehypeHeadingIds } from "@astrojs/markdown-remark"
import rehypeAutolinkHeadings from "rehype-autolink-headings"
import { spawnSync } from "child_process"
import { visit } from "unist-util-visit"

// https://astro.build/config
export default defineConfig({
Expand All @@ -24,14 +25,45 @@ export default defineConfig({
host: "0.0.0.0",
},
markdown: {
rehypePlugins: [rehypeHeadingIds, [rehypeAutolinkHeadings, { behavior: "wrap" }]],
rehypePlugins: [
rehypeHeadingIds,
[rehypeAutolinkHeadings, { behavior: "wrap" }],
() => (tree, file) => {
const filePath = typeof file?.path === "string" ? file.path : ""
const normalizedPath = filePath.replace(/\\/g, "/")
const docsMarker = "/src/content/docs/"
const docsIndex = normalizedPath.lastIndexOf(docsMarker)
const localeDir =
docsIndex === -1
? "en"
: normalizedPath.slice(docsIndex + docsMarker.length).split("/")[0] || "en"
const locale = localeDir === "en" ? "root" : localeDir
const base = locale === "root" ? "/docs" : `/docs/${locale}`

visit(tree, "element", (node) => {
if (node.tagName !== "a") return
const href = node.properties?.href
if (typeof href !== "string") return
if (!href.startsWith("/docs")) return
const isRoot = href === "/docs"
const isRootHash = href.startsWith("/docs#")
const normalized = isRoot ? base : isRootHash ? `${base}${href.slice(5)}` : href.replace("/docs/", `${base}/`)
node.properties.href = normalized
})
},
],
},
build: {},
integrations: [
configSchema(),
solidJs(),
starlight({
title: "OpenCode",
locales: {
root: { label: "English", lang: "en" },
"zh-cn": { label: "中文", lang: "zh-CN" },
},
defaultLocale: "root",
lastUpdated: true,
expressiveCode: { themes: ["github-light", "github-dark"] },
social: [
Expand All @@ -50,44 +82,88 @@ export default defineConfig({
dark: "./src/assets/logo-dark.svg",
replacesTitle: true,
},
sidebar: [
"",
"config",
"providers",
"network",
"enterprise",
"troubleshooting",
"1-0",
// @ts-ignore
sidebar: withTranslations([
{
label: "Intro",
translations: { "zh-cn": "介绍" },
link: "",
},
{
label: "Config",
translations: { "zh-cn": "配置" },
link: "config",
},
{
label: "Providers",
translations: { "zh-cn": "提供商" },
link: "providers",
},
{
label: "Network",
translations: { "zh-cn": "网络" },
link: "network",
},
{
label: "Enterprise",
translations: { "zh-cn": "企业" },
link: "enterprise",
},
{
label: "Troubleshooting",
translations: { "zh-cn": "故障排查" },
link: "troubleshooting",
},
{
label: "1-0",
translations: { "zh-cn": "1-0 版本" },
link: "1-0",
},
{
label: "Usage",
items: ["tui", "cli", "web", "ide", "zen", "share", "github", "gitlab"],
translations: { "zh-cn": "使用" },
items: [
{ label: "TUI", translations: { "zh-cn": "TUI" }, link: "tui" },
{ label: "CLI", translations: { "zh-cn": "CLI" }, link: "cli" },
{ label: "Web", translations: { "zh-cn": "Web" }, link: "web" },
{ label: "IDE", translations: { "zh-cn": "IDE" }, link: "ide" },
{ label: "Zen", translations: { "zh-cn": "Zen" }, link: "zen" },
{ label: "Share", translations: { "zh-cn": "分享" }, link: "share" },
{ label: "GitHub", translations: { "zh-cn": "GitHub" }, link: "github" },
{ label: "GitLab", translations: { "zh-cn": "GitLab" }, link: "gitlab" },
],
},

{
label: "Configure",
translations: { "zh-cn": "配置" },
items: [
"tools",
"rules",
"agents",
"models",
"themes",
"keybinds",
"commands",
"formatters",
"permissions",
"lsp",
"mcp-servers",
"acp",
"skills",
"custom-tools",
{ label: "tools", translations: { "zh-cn": "tools" }, link: "tools" },
{ label: "rules", translations: { "zh-cn": "规则" }, link: "rules" },
{ label: "agents", translations: { "zh-cn": "agents" }, link: "agents" },
{ label: "models", translations: { "zh-cn": "模型" }, link: "models" },
{ label: "themes", translations: { "zh-cn": "主题" }, link: "themes" },
{ label: "keybinds", translations: { "zh-cn": "快捷键" }, link: "keybinds" },
{ label: "commands", translations: { "zh-cn": "命令" }, link: "commands" },
{ label: "formatters", translations: { "zh-cn": "格式化" }, link: "formatters" },
{ label: "permissions", translations: { "zh-cn": "权限" }, link: "permissions" },
{ label: "lsp", translations: { "zh-cn": "LSP" }, link: "lsp" },
{ label: "mcp-servers", translations: { "zh-cn": "mcp servers" }, link: "mcp-servers" },
{ label: "acp", translations: { "zh-cn": "ACP" }, link: "acp" },
{ label: "skills", translations: { "zh-cn": "skills" }, link: "skills" },
{ label: "custom tools", translations: { "zh-cn": "custom tools" }, link: "custom-tools" },
],
},

{
label: "Develop",
items: ["sdk", "server", "plugins", "ecosystem"],
translations: { "zh-cn": "开发" },
items: [
{ label: "SDK", translations: { "zh-cn": "SDK" }, link: "sdk" },
{ label: "Server", translations: { "zh-cn": "服务器" }, link: "server" },
{ label: "Plugins", translations: { "zh-cn": "插件" }, link: "plugins" },
{ label: "Ecosystem", translations: { "zh-cn": "生态" }, link: "ecosystem" },
],
},
],
]),
components: {
Hero: "./src/components/Hero.astro",
Head: "./src/components/Head.astro",
Expand All @@ -114,3 +190,18 @@ function configSchema() {
},
}
}

/**
* @param {any[]} sidebar
*/
function withTranslations(sidebar) {
return sidebar.map((item) => {
if (item.translations && item.translations["zh-cn"]) {
item.translations["zh-CN"] = item.translations["zh-cn"]
}
if (item.items) {
item.items = withTranslations(item.items)
}
return item
})
}
3 changes: 2 additions & 1 deletion packages/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@
"remeda": "catalog:",
"shiki": "catalog:",
"solid-js": "catalog:",
"toolbeam-docs-theme": "0.4.8"
"toolbeam-docs-theme": "0.4.8",
"unist-util-visit": "5.0.0"
},
"devDependencies": {
"opencode": "workspace:*",
Expand Down
Loading