mirror of
https://github.com/musistudio/claude-code-router.git
synced 2026-07-09 17:18:24 +00:00
Refactor router internals and trim unused code
This commit is contained in:
parent
2d868f440e
commit
a0e191ef34
28 changed files with 560 additions and 314 deletions
14
docs/package-lock.json
generated
14
docs/package-lock.json
generated
|
|
@ -8,7 +8,8 @@
|
|||
"name": "claude-code-router-docs",
|
||||
"version": "0.1.0",
|
||||
"devDependencies": {
|
||||
"astro": "7.0.0"
|
||||
"astro": "7.0.0",
|
||||
"lucide-astro": "^0.556.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@astrojs/compiler-binding": {
|
||||
|
|
@ -3245,6 +3246,17 @@
|
|||
"node": "20 || >=22"
|
||||
}
|
||||
},
|
||||
"node_modules/lucide-astro": {
|
||||
"version": "0.556.0",
|
||||
"resolved": "https://registry.npmjs.org/lucide-astro/-/lucide-astro-0.556.0.tgz",
|
||||
"integrity": "sha512-ugMjPb45AMfkLCaduNSbyy5NQEKvB1TxVVMmUS4S6L807PMESnX0Qp+DIKHjbyjJmPXOyLRbrzvR3YikTK7brg==",
|
||||
"deprecated": "Deprecated: Use `@lucide/astro`",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"astro": ">=2.7.1"
|
||||
}
|
||||
},
|
||||
"node_modules/magic-string": {
|
||||
"version": "0.30.21",
|
||||
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz",
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
"astro": "astro"
|
||||
},
|
||||
"devDependencies": {
|
||||
"astro": "7.0.0"
|
||||
"astro": "7.0.0",
|
||||
"lucide-astro": "^0.556.0"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,12 +12,12 @@ export type BotPlatformModule = {
|
|||
};
|
||||
|
||||
export const zhBotDocs = import.meta.glob<BotPlatformModule>(
|
||||
"./content/docs/zh/bots/*.md",
|
||||
"./content/docs/zh/bot-与-im-接力-agent/*.md",
|
||||
{ eager: true }
|
||||
);
|
||||
|
||||
export const enBotDocs = import.meta.glob<BotPlatformModule>(
|
||||
"./content/docs/en/bots/*.md",
|
||||
"./content/docs/en/relay-agents-in-im-with-bots/*.md",
|
||||
{ eager: true }
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import DocsLayout from "../layouts/DocsLayout.astro";
|
|||
import { docsContent, type Locale } from "../i18n/content";
|
||||
import * as enDoc from "../content/docs/en/index.md";
|
||||
import * as zhDoc from "../content/docs/zh/index.md";
|
||||
import { Check, Copy } from "lucide-astro";
|
||||
|
||||
interface Props {
|
||||
locale: Locale;
|
||||
|
|
@ -44,10 +45,7 @@ const pageMarkdown = doc.rawContent();
|
|||
<p class="lead">{frontmatter.lead}</p>
|
||||
</div>
|
||||
<button class="copy-page" type="button" data-copy-page>
|
||||
<svg viewBox="0 0 20 20" aria-hidden="true">
|
||||
<rect x="7" y="7" width="9" height="9" rx="2" />
|
||||
<path d="M4 13V5a1 1 0 0 1 1-1h8" />
|
||||
</svg>
|
||||
<Copy size={18} aria-hidden="true" />
|
||||
<span data-copy-label>{content.ui.copyPage}</span>
|
||||
</button>
|
||||
</header>
|
||||
|
|
@ -57,6 +55,15 @@ const pageMarkdown = doc.rawContent();
|
|||
</div>
|
||||
</article>
|
||||
|
||||
<template data-code-icon-template>
|
||||
<span class="copy-icon" aria-hidden="true">
|
||||
<Copy size={18} />
|
||||
</span>
|
||||
<span class="success-icon" aria-hidden="true">
|
||||
<Check size={18} />
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<script define:vars={{
|
||||
pageMarkdown,
|
||||
copyPageLabel: content.ui.copyPage,
|
||||
|
|
@ -101,15 +108,10 @@ const pageMarkdown = doc.rawContent();
|
|||
}, 1800);
|
||||
});
|
||||
|
||||
const buildCopyIcon = () => `
|
||||
<svg class="copy-icon" viewBox="0 0 20 20" aria-hidden="true">
|
||||
<rect x="7" y="7" width="9" height="9" rx="2"></rect>
|
||||
<path d="M4 13V5a1 1 0 0 1 1-1h8"></path>
|
||||
</svg>
|
||||
<svg class="success-icon" viewBox="0 0 20 20" aria-hidden="true">
|
||||
<path d="M4 10.5l4 4L16 6"></path>
|
||||
</svg>
|
||||
`;
|
||||
const codeIconTemplate = document.querySelector("[data-code-icon-template]");
|
||||
const buildCopyIcon = () => codeIconTemplate instanceof HTMLTemplateElement
|
||||
? codeIconTemplate.innerHTML
|
||||
: "";
|
||||
|
||||
document.querySelectorAll("[data-markdown-content] pre.astro-code").forEach((pre) => {
|
||||
if (!(pre instanceof HTMLElement) || pre.closest(".code-panel")) return;
|
||||
|
|
|
|||
|
|
@ -7,25 +7,18 @@ lead: A hands-on, step-by-step guide to getting Claude Code Router running. We s
|
|||
|
||||
If this is your first time with CCR, read it top to bottom — about ten minutes and the whole pipeline will be live. If you already know the basics, jump straight to the section you need. Every step includes a "how to tell it worked" check so you never have to guess whether you did it right.
|
||||
|
||||
## What CCR Actually Does For You
|
||||
## What CCR Helps You Do
|
||||
|
||||
In one sentence: **it funnels every AI agent on your machine (Claude Code, Codex, ZCode, and friends) through a single local entrypoint, and you decide which model each request uses.**
|
||||
In one sentence: **it lets you manage the models and keys used by Claude Code, Codex, ZCode, and other agents in one place, then choose the right model for each kind of work.**
|
||||
|
||||
Why that's worth it:
|
||||
|
||||
- No more configuring the model and key in every single agent. CCR manages it once.
|
||||
- Different work can hit different models — cheap fast models for grunt work, strong models for hard problems, multimodal models for images, search-capable models when you need fresh info.
|
||||
- When one model fails, CCR can fall back to another automatically. No manual config surgery.
|
||||
- Every request is logged, so you can see where the money goes, which model is slow, and which key is erroring.
|
||||
- No more configuring the model and key in every single agent.
|
||||
- Different work can use different models: cheap fast models for simple tasks, stronger models for hard problems, multimodal models for images, and search-capable models when you need fresh info.
|
||||
- When one model fails, CCR can switch to a backup automatically.
|
||||
- Logs show which model each request used, whether it succeeded, and where your spend is going.
|
||||
|
||||
CCR runs locally on your machine and keeps everything in a local config file. It exposes two local addresses, but day to day you only care about one:
|
||||
|
||||
| Purpose | Address | Notes |
|
||||
| --- | --- | --- |
|
||||
| Agent entrypoint | `http://127.0.0.1:3456` | Your agents connect here |
|
||||
| Internal CCR service | `http://127.0.0.1:3457` | Internal — you can ignore it |
|
||||
|
||||
Everything that follows is about getting your agents to send traffic to that `3456` entrypoint.
|
||||
The steps below walk you through three things: connecting a model provider, setting up routing, and making your agents use those CCR settings. For normal use, you can stay in the app and follow the steps without editing config files by hand.
|
||||
|
||||
## Step 1: Install And Start CCR
|
||||
|
||||
|
|
@ -38,18 +31,13 @@ Everything that follows is about getting your agents to send traffic to that `34
|
|||
- Linux: `.AppImage`
|
||||
3. Install and launch **Claude Code Router** like any normal app.
|
||||
|
||||
On first launch, CCR creates its local config file (handy for backup and troubleshooting — you won't normally edit it by hand):
|
||||
### Start CCR
|
||||
|
||||
- macOS / Linux: `~/.claude-code-router/config.json`
|
||||
- Windows: `%APPDATA%\Claude Code Router\config.json`
|
||||
Once the app is open, go to the **Server** page and click **Start**.
|
||||
|
||||
### Start The Local Gateway
|
||||
> **How to tell it worked:** The Server page shows CCR running. If you want it to start automatically whenever the app opens, turn on **Auto start**.
|
||||
|
||||
Once the app is open, go to the **Server** page and click **Start** to bring up the local gateway.
|
||||
|
||||
> **How to tell it worked:** The Server page shows the gateway running and port `3456` listening. If you want the gateway to start automatically whenever the app opens, turn on **Auto start**.
|
||||
|
||||
CCR itself is now alive — but it can't do anything useful yet, because it doesn't know where to forward requests. That's the next step.
|
||||
CCR itself is now running, but it cannot handle requests yet because you have not connected a model provider. That's the next step.
|
||||
|
||||
## Step 2: Connect Your First Provider
|
||||
|
||||
|
|
@ -152,7 +140,7 @@ CCR now knows both *which models exist* and *which one each request should use*.
|
|||
|
||||
## Step 4: Point Your Agent At CCR (Profiles)
|
||||
|
||||
Go to the **Profiles** page. A Profile takes a chosen agent (Claude Code / Codex / ZCode) and points it at CCR's entrypoint `http://127.0.0.1:3456`, so its requests get routed and recorded.
|
||||
Go to the **Profiles** page. A Profile lets a chosen agent (Claude Code / Codex / ZCode) use the models and routing settings you configured in CCR, so its requests can be recorded and managed there.
|
||||
|
||||
Before you start, two options that apply to every profile:
|
||||
|
||||
|
|
@ -319,14 +307,14 @@ A Bot forwards an agent's messages into IM, and can hand the task off to your ph
|
|||
|
||||
Every platform has its own page with the full walk-through (how to create the app on the platform, a field-by-field mapping, and a troubleshooting FAQ):
|
||||
|
||||
- [Slack](/en/bots/slack)
|
||||
- [Discord](/en/bots/discord)
|
||||
- [Telegram](/en/bots/telegram)
|
||||
- [LINE](/en/bots/line)
|
||||
- [Weixin](/en/bots/weixin-ilink)
|
||||
- [WeCom](/en/bots/wecom)
|
||||
- [Feishu](/en/bots/feishu)
|
||||
- [DingTalk](/en/bots/dingtalk)
|
||||
- [Slack](/en/relay-agents-in-im-with-bots/slack)
|
||||
- [Discord](/en/relay-agents-in-im-with-bots/discord)
|
||||
- [Telegram](/en/relay-agents-in-im-with-bots/telegram)
|
||||
- [LINE](/en/relay-agents-in-im-with-bots/line)
|
||||
- [Weixin](/en/relay-agents-in-im-with-bots/weixin-ilink)
|
||||
- [WeCom](/en/relay-agents-in-im-with-bots/wecom)
|
||||
- [Feishu](/en/relay-agents-in-im-with-bots/feishu)
|
||||
- [DingTalk](/en/relay-agents-in-im-with-bots/dingtalk)
|
||||
|
||||
## When Something Goes Wrong, Look Here
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
---
|
||||
title: DingTalk Bot Setup
|
||||
pageTitle: DingTalk Bot
|
||||
eyebrow: Bot Platforms
|
||||
eyebrow: Relay Agents In IM With Bots
|
||||
lead: Route agent messages into DingTalk's enterprise collaboration environment, with relay after your screen locks. This page walks you from creating an app in the DingTalk developer backend to a working setup in CCR.
|
||||
---
|
||||
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
---
|
||||
title: Discord Bot Setup
|
||||
pageTitle: Discord Bot
|
||||
eyebrow: Bot Platforms
|
||||
eyebrow: Relay Agents In IM With Bots
|
||||
lead: Route agent messages into Discord server channels or DMs, and relay them after your screen locks. This page walks you from creating the Discord app to a working setup in CCR.
|
||||
---
|
||||
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
---
|
||||
title: Feishu Bot Setup
|
||||
pageTitle: Feishu Bot
|
||||
eyebrow: Bot Platforms
|
||||
eyebrow: Relay Agents In IM With Bots
|
||||
lead: Route agent messages into Feishu (Lark) groups or app chats, with relay after your screen locks. This page walks you from creating an enterprise self-built app on the Feishu Open Platform to a working setup in CCR.
|
||||
---
|
||||
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
---
|
||||
title: LINE Bot Setup
|
||||
pageTitle: LINE Bot
|
||||
eyebrow: Bot Platforms
|
||||
eyebrow: Relay Agents In IM With Bots
|
||||
lead: Route agent messages into LINE friends, groups, or an Official Account, and relay them after your screen locks. This page walks you from creating a LINE Messaging API channel to a working setup in CCR.
|
||||
---
|
||||
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
---
|
||||
title: Slack Bot Setup
|
||||
pageTitle: Slack Bot
|
||||
eyebrow: Bot Platforms
|
||||
eyebrow: Relay Agents In IM With Bots
|
||||
lead: Route agent messages into Slack channels or DMs, and relay them to Slack after your screen locks. This page walks you from creating the Slack app all the way to a working setup in CCR.
|
||||
---
|
||||
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
---
|
||||
title: Telegram Bot Setup
|
||||
pageTitle: Telegram Bot
|
||||
eyebrow: Bot Platforms
|
||||
eyebrow: Relay Agents In IM With Bots
|
||||
lead: Route agent messages into Telegram and relay them after your screen locks. Telegram is the simplest platform of all — you only need a Bot Token, and you can be live in minutes.
|
||||
---
|
||||
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
---
|
||||
title: WeCom Bot Setup
|
||||
pageTitle: WeCom Bot
|
||||
eyebrow: Bot Platforms
|
||||
eyebrow: Relay Agents In IM With Bots
|
||||
lead: Route agent messages into WeCom (Enterprise WeChat) so your team can receive and reply in WeCom, with relay after your screen locks. This page walks you from creating a self-built app in the WeCom admin console to a working setup in CCR.
|
||||
---
|
||||
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
---
|
||||
title: Weixin Bot Setup
|
||||
pageTitle: Weixin Bot
|
||||
eyebrow: Bot Platforms
|
||||
eyebrow: Relay Agents In IM With Bots
|
||||
lead: Route agent messages into WeChat (Weixin) and relay them after your screen locks. The easiest path is QR Login — you scan a code and you're in, no token copying required.
|
||||
---
|
||||
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
---
|
||||
title: 钉钉 Bot 配置
|
||||
pageTitle: 钉钉 Bot
|
||||
eyebrow: Bot 平台
|
||||
eyebrow: Bot 与 IM 接力 Agent
|
||||
lead: 把 Agent 的消息接入钉钉的企业协作环境,并在电脑锁屏后接力。这一页从钉钉开发者后台创建应用开始,带你走到在 CCR 里跑通。
|
||||
---
|
||||
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
---
|
||||
title: Discord Bot 配置
|
||||
pageTitle: Discord Bot
|
||||
eyebrow: Bot 平台
|
||||
eyebrow: Bot 与 IM 接力 Agent
|
||||
lead: 把 Agent 的消息接入 Discord 的服务器频道或私聊,并在电脑锁屏后把新消息接力到 Discord。这一页从创建 Discord 应用开始,带你一直走到在 CCR 里跑通。
|
||||
---
|
||||
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
---
|
||||
title: 飞书 Bot 配置
|
||||
pageTitle: 飞书 Bot
|
||||
eyebrow: Bot 平台
|
||||
eyebrow: Bot 与 IM 接力 Agent
|
||||
lead: 把 Agent 的消息接入飞书的群或应用会话,并在电脑锁屏后接力。这一页从飞书开放平台创建企业自建应用开始,带你走到在 CCR 里跑通。
|
||||
---
|
||||
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
---
|
||||
title: LINE Bot 配置
|
||||
pageTitle: LINE Bot
|
||||
eyebrow: Bot 平台
|
||||
eyebrow: Bot 与 IM 接力 Agent
|
||||
lead: 把 Agent 的消息接入 LINE 的好友、群聊或 Official Account,并在电脑锁屏后把新消息接力过去。这一页从创建 LINE Messaging API channel 开始,带你走到在 CCR 里跑通。
|
||||
---
|
||||
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
---
|
||||
title: Slack Bot 配置
|
||||
pageTitle: Slack Bot
|
||||
eyebrow: Bot 平台
|
||||
eyebrow: Bot 与 IM 接力 Agent
|
||||
lead: 把 Agent 的消息接入 Slack 的频道或私聊,并在电脑锁屏后把新消息接力到 Slack。这一页从创建 Slack 应用开始,一直带你走到在 CCR 里跑通。
|
||||
---
|
||||
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
---
|
||||
title: Telegram Bot 配置
|
||||
pageTitle: Telegram Bot
|
||||
eyebrow: Bot 平台
|
||||
eyebrow: Bot 与 IM 接力 Agent
|
||||
lead: 把 Agent 的消息接入 Telegram,并在电脑锁屏后把新消息接力过去。Telegram 是所有平台里配置最简单的——只需要一个 Bot Token,几分钟就能跑通。
|
||||
---
|
||||
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
---
|
||||
title: 企业微信 Bot 配置
|
||||
pageTitle: 企业微信 Bot
|
||||
eyebrow: Bot 平台
|
||||
eyebrow: Bot 与 IM 接力 Agent
|
||||
lead: 把 Agent 的消息接入企业微信,让团队成员在企业微信里接收并回复,并在电脑锁屏后接力。这一页从企业微信管理后台创建自建应用开始,带你走到在 CCR 里跑通。
|
||||
---
|
||||
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
---
|
||||
title: 微信 Bot 配置
|
||||
pageTitle: 微信 Bot
|
||||
eyebrow: Bot 平台
|
||||
eyebrow: Bot 与 IM 接力 Agent
|
||||
lead: 把 Agent 的消息接入微信,并在电脑锁屏后把新消息接力过去。微信最简单的接法是二维码登录,不用手动复制任何 token,扫一下就行。
|
||||
---
|
||||
|
||||
|
|
@ -7,25 +7,18 @@ lead: 这是一份手把手带你跑通 Claude Code Router 的指南。我们会
|
|||
|
||||
如果你是第一次用 CCR,建议从头顺着读一遍——大概十几分钟,你就能把整套链路跑通。已经有经验的读者可以直接跳到对应章节,每一步都包含了「怎么确认自己没做错」的验证方法。
|
||||
|
||||
## CCR 到底帮你做了什么
|
||||
## CCR 能帮你做什么
|
||||
|
||||
一句话:**它把你电脑上的各种 AI Agent(Claude Code、Codex、ZCode 等)统一接到一个本地入口,再由你决定每个请求用哪个模型。**
|
||||
一句话:**它让你在一个地方管理 Claude Code、Codex、ZCode 等 Agent 要用的模型和 Key,并按任务选择合适的模型。**
|
||||
|
||||
这样做的好处是:
|
||||
|
||||
- 你不用在每个 Agent 里重复配置模型和 Key,CCR 统一管理。
|
||||
- 不同的任务可以走不同的模型——简单任务用便宜的快模型,难题用强模型,看图用多模态模型,需要联网的用带搜索的模型。
|
||||
- 一个模型挂了能自动切换到备用模型,不用你手动改配置。
|
||||
- 所有请求都被记录下来,你能看到钱花在哪、哪个模型慢、哪个 Key 报错了。
|
||||
- 你不用在每个 Agent 里重复配置模型和 Key。
|
||||
- 不同任务可以用不同模型:简单任务用便宜的快模型,难题用强模型,看图用多模态模型,需要联网时用带搜索的模型。
|
||||
- 一个模型出错时,可以自动换到备用模型。
|
||||
- 你可以在 Logs 里看到每次请求用了哪个模型、是否成功、费用大概花在哪。
|
||||
|
||||
CCR 跑在你自己机器上,配置都存在本地。它对外只暴露两个本地地址,你日常只需要关心其中一个:
|
||||
|
||||
| 用途 | 地址 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| Agent 连接入口 | `http://127.0.0.1:3456` | 你的 Agent 就连这个 |
|
||||
| CCR 内部服务 | `http://127.0.0.1:3457` | 内部用,不用管 |
|
||||
|
||||
后面所有的配置,目标都是让 Agent 把请求发到 `3456` 这个入口。
|
||||
后面的步骤会带你完成三件事:接入模型、设置路由、让 Agent 通过 CCR 使用这些配置。正常使用时,你只需要在界面里按步骤配置,不需要手动编辑配置文件。
|
||||
|
||||
## 第一步:安装并启动 CCR
|
||||
|
||||
|
|
@ -38,18 +31,13 @@ CCR 跑在你自己机器上,配置都存在本地。它对外只暴露两个
|
|||
- Linux:`.AppImage`
|
||||
3. 像装普通软件一样安装并打开 **Claude Code Router**。
|
||||
|
||||
第一次启动时,CCR 会在本地生成一份配置文件,路径如下(备份或排查问题时会用到,平时不用手动改):
|
||||
### 启动 CCR 服务
|
||||
|
||||
- macOS / Linux:`~/.claude-code-router/config.json`
|
||||
- Windows:`%APPDATA%\Claude Code Router\config.json`
|
||||
打开 App 后,进入 **Server** 页面,点击 **Start**。
|
||||
|
||||
### 启动本地网关
|
||||
> **怎么算成功:** Server 页面显示正在运行。如果你想以后开 App 就自动启动,把 **Auto start** 打开。
|
||||
|
||||
打开 App 后,进入 **Server** 页面,点击 **Start** 启动本地网关。
|
||||
|
||||
> **怎么算成功:** Server 页面显示网关正在运行,端口 `3456` 处于监听状态。如果你想以后开 App 就自动起网关,把 **Auto start** 打开。
|
||||
|
||||
到这里 CCR 本身就跑起来了,但还干不了活——因为它还不知道该把请求转发给谁。下一步我们就来接入模型。
|
||||
到这里 CCR 本身就跑起来了,但还不能处理请求,因为你还没有接入模型。下一步我们就来完成这件事。
|
||||
|
||||
## 第二步:接入你的第一个 Provider
|
||||
|
||||
|
|
@ -152,7 +140,7 @@ Provider 就是 CCR 转发请求要去到的「上游模型服务」,比如 Op
|
|||
|
||||
## 第四步:让 Agent 走 CCR(Profile)
|
||||
|
||||
进入 **Profiles** 页面。Profile 的作用,就是把你选定的 Agent(Claude Code / Codex / ZCode)的配置,指向 CCR 的入口 `http://127.0.0.1:3456`,这样它的请求才会经过 CCR 路由和记录。
|
||||
进入 **Profiles** 页面。Profile 的作用,是让你选定的 Agent(Claude Code / Codex / ZCode)使用 CCR 里的模型和路由配置,这样请求才会经过 CCR 记录和管理。
|
||||
|
||||
开始前,先理解两个通用选项:
|
||||
|
||||
|
|
@ -319,14 +307,14 @@ Bot 能把 Agent 的消息转发到 IM,还能在你空闲一段时间后,把
|
|||
|
||||
每个平台的完整步骤(平台后台怎么建应用、字段对照、排查 FAQ)都有单独一篇:
|
||||
|
||||
- [Slack](/bots/slack)
|
||||
- [Discord](/bots/discord)
|
||||
- [Telegram](/bots/telegram)
|
||||
- [LINE](/bots/line)
|
||||
- [微信](/bots/weixin-ilink)
|
||||
- [企业微信](/bots/wecom)
|
||||
- [飞书](/bots/feishu)
|
||||
- [钉钉](/bots/dingtalk)
|
||||
- [Slack](/bot-与-im-接力-agent/slack)
|
||||
- [Discord](/bot-与-im-接力-agent/discord)
|
||||
- [Telegram](/bot-与-im-接力-agent/telegram)
|
||||
- [LINE](/bot-与-im-接力-agent/line)
|
||||
- [微信](/bot-与-im-接力-agent/weixin-ilink)
|
||||
- [企业微信](/bot-与-im-接力-agent/wecom)
|
||||
- [飞书](/bot-与-im-接力-agent/feishu)
|
||||
- [钉钉](/bot-与-im-接力-agent/dingtalk)
|
||||
|
||||
## 遇到问题时,照着这个查
|
||||
|
||||
|
|
|
|||
|
|
@ -29,11 +29,6 @@ export const docsContent = {
|
|||
icon: "wand",
|
||||
items: ["Agent Profile 接入", "Bot 与 IM 接力 Agent"],
|
||||
},
|
||||
{
|
||||
label: "Bot 平台配置",
|
||||
icon: "wand",
|
||||
items: ["Slack", "Discord", "Telegram", "LINE", "微信", "企业微信", "飞书", "钉钉"],
|
||||
},
|
||||
{
|
||||
label: "观测排查",
|
||||
icon: "pen",
|
||||
|
|
@ -43,12 +38,14 @@ export const docsContent = {
|
|||
expandableSidebarItems: [
|
||||
"Provider 接入",
|
||||
"Agent Profile 接入",
|
||||
"Bot 与 IM 接力 Agent",
|
||||
"Overview 自定义组件",
|
||||
"日志、分析与问题排查",
|
||||
],
|
||||
sidebarChildren: {
|
||||
"Provider 接入": ["Provider 字段", "API Key 与用量", "连通性检查"],
|
||||
"Agent Profile 接入": ["Claude Code", "Codex", "ZCode"],
|
||||
"Bot 与 IM 接力 Agent": ["Slack", "Discord", "Telegram", "LINE", "微信", "企业微信", "飞书", "钉钉"],
|
||||
"Overview 自定义组件": ["组件类型", "自定义布局", "分析口径"],
|
||||
"日志、分析与问题排查": ["Request logs", "Agent analysis", "Network capture"],
|
||||
},
|
||||
|
|
@ -72,14 +69,14 @@ export const docsContent = {
|
|||
"Agent analysis": "#agent-analysis",
|
||||
"Network capture": "#network-capture",
|
||||
维护与安全建议: "#维护与安全建议",
|
||||
Slack: "/bots/slack",
|
||||
Discord: "/bots/discord",
|
||||
Telegram: "/bots/telegram",
|
||||
LINE: "/bots/line",
|
||||
微信: "/bots/weixin-ilink",
|
||||
企业微信: "/bots/wecom",
|
||||
飞书: "/bots/feishu",
|
||||
钉钉: "/bots/dingtalk",
|
||||
Slack: "/bot-与-im-接力-agent/slack",
|
||||
Discord: "/bot-与-im-接力-agent/discord",
|
||||
Telegram: "/bot-与-im-接力-agent/telegram",
|
||||
LINE: "/bot-与-im-接力-agent/line",
|
||||
微信: "/bot-与-im-接力-agent/weixin-ilink",
|
||||
企业微信: "/bot-与-im-接力-agent/wecom",
|
||||
飞书: "/bot-与-im-接力-agent/feishu",
|
||||
钉钉: "/bot-与-im-接力-agent/dingtalk",
|
||||
},
|
||||
tocTitle: "本页内容",
|
||||
ui: {
|
||||
|
|
@ -120,11 +117,6 @@ export const docsContent = {
|
|||
icon: "wand",
|
||||
items: ["Connect Agent Profiles", "Relay Agents In IM With Bots"],
|
||||
},
|
||||
{
|
||||
label: "Bot Platforms",
|
||||
icon: "wand",
|
||||
items: ["Slack", "Discord", "Telegram", "LINE", "Weixin", "WeCom", "Feishu", "DingTalk"],
|
||||
},
|
||||
{
|
||||
label: "Observe",
|
||||
icon: "pen",
|
||||
|
|
@ -134,12 +126,14 @@ export const docsContent = {
|
|||
expandableSidebarItems: [
|
||||
"Connect Providers",
|
||||
"Connect Agent Profiles",
|
||||
"Relay Agents In IM With Bots",
|
||||
"Customize Overview Widgets",
|
||||
"Logs Analysis And Troubleshooting",
|
||||
],
|
||||
sidebarChildren: {
|
||||
"Connect Providers": ["Provider Fields", "API Keys And Usage", "Connectivity Checks"],
|
||||
"Connect Agent Profiles": ["Claude Code", "Codex", "ZCode"],
|
||||
"Relay Agents In IM With Bots": ["Slack", "Discord", "Telegram", "LINE", "Weixin", "WeCom", "Feishu", "DingTalk"],
|
||||
"Customize Overview Widgets": ["Widget Types", "Custom Layout", "Analysis Scope"],
|
||||
"Logs Analysis And Troubleshooting": ["Request logs", "Agent analysis", "Network capture"],
|
||||
},
|
||||
|
|
@ -163,14 +157,14 @@ export const docsContent = {
|
|||
"Agent analysis": "#agent-analysis",
|
||||
"Network capture": "#network-capture",
|
||||
"Maintenance And Security": "#maintenance-and-security",
|
||||
Slack: "/en/bots/slack",
|
||||
Discord: "/en/bots/discord",
|
||||
Telegram: "/en/bots/telegram",
|
||||
LINE: "/en/bots/line",
|
||||
Weixin: "/en/bots/weixin-ilink",
|
||||
WeCom: "/en/bots/wecom",
|
||||
Feishu: "/en/bots/feishu",
|
||||
DingTalk: "/en/bots/dingtalk",
|
||||
Slack: "/en/relay-agents-in-im-with-bots/slack",
|
||||
Discord: "/en/relay-agents-in-im-with-bots/discord",
|
||||
Telegram: "/en/relay-agents-in-im-with-bots/telegram",
|
||||
LINE: "/en/relay-agents-in-im-with-bots/line",
|
||||
Weixin: "/en/relay-agents-in-im-with-bots/weixin-ilink",
|
||||
WeCom: "/en/relay-agents-in-im-with-bots/wecom",
|
||||
Feishu: "/en/relay-agents-in-im-with-bots/feishu",
|
||||
DingTalk: "/en/relay-agents-in-im-with-bots/dingtalk",
|
||||
},
|
||||
tocTitle: "On this page",
|
||||
ui: {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,19 @@
|
|||
---
|
||||
import "../styles/global.css";
|
||||
import {
|
||||
BookOpen,
|
||||
ChevronDown,
|
||||
ChevronRight,
|
||||
Download,
|
||||
Github,
|
||||
List,
|
||||
Moon,
|
||||
PenLine,
|
||||
Rocket,
|
||||
Search,
|
||||
Sun,
|
||||
WandSparkles,
|
||||
} from "lucide-astro";
|
||||
|
||||
const {
|
||||
title = "Documentation",
|
||||
|
|
@ -28,6 +42,12 @@ const {
|
|||
} = Astro.props;
|
||||
|
||||
const homeHref = locale === "en" ? "/en/" : "/";
|
||||
const sidebarIcons = {
|
||||
rocket: Rocket,
|
||||
book: BookOpen,
|
||||
wand: WandSparkles,
|
||||
pen: PenLine,
|
||||
};
|
||||
---
|
||||
|
||||
<!doctype html>
|
||||
|
|
@ -39,6 +59,28 @@ const homeHref = locale === "en" ? "/en/" : "/";
|
|||
name="description"
|
||||
content="Claude Code Router documentation site built with Astro."
|
||||
/>
|
||||
<script is:inline>
|
||||
(() => {
|
||||
const storageKey = "ccr-docs-theme";
|
||||
|
||||
try {
|
||||
const storedTheme = localStorage.getItem(storageKey);
|
||||
const prefersDark = window.matchMedia("(prefers-color-scheme: dark)").matches;
|
||||
const theme = storedTheme === "light" || storedTheme === "dark"
|
||||
? storedTheme
|
||||
: prefersDark
|
||||
? "dark"
|
||||
: "light";
|
||||
|
||||
document.documentElement.dataset.theme = theme;
|
||||
document.documentElement.dataset.themeSource = storedTheme ? "user" : "system";
|
||||
} catch {
|
||||
const prefersDark = window.matchMedia("(prefers-color-scheme: dark)").matches;
|
||||
document.documentElement.dataset.theme = prefersDark ? "dark" : "light";
|
||||
document.documentElement.dataset.themeSource = "system";
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
<link rel="icon" href="/favicon.svg" type="image/svg+xml" />
|
||||
{
|
||||
languageOptions.map((option) => (
|
||||
|
|
@ -62,9 +104,7 @@ const homeHref = locale === "en" ? "/en/" : "/";
|
|||
<details class="language-switcher">
|
||||
<summary>
|
||||
<span>{languageLabel}</span>
|
||||
<svg viewBox="0 0 16 16" aria-hidden="true">
|
||||
<path d="M4 6l4 4 4-4" />
|
||||
</svg>
|
||||
<ChevronDown size={16} aria-hidden="true" />
|
||||
</summary>
|
||||
<div class="language-menu">
|
||||
{
|
||||
|
|
@ -93,10 +133,7 @@ const homeHref = locale === "en" ? "/en/" : "/";
|
|||
|
||||
<div class="top-actions">
|
||||
<label class="search" aria-label={ui.searchLabel}>
|
||||
<svg viewBox="0 0 20 20" aria-hidden="true">
|
||||
<path d="M14.5 14.5L18 18" />
|
||||
<circle cx="8.5" cy="8.5" r="5.5" />
|
||||
</svg>
|
||||
<Search size={18} aria-hidden="true" />
|
||||
<input type="search" placeholder={ui.searchPlaceholder} />
|
||||
<kbd>⌘K</kbd>
|
||||
</label>
|
||||
|
|
@ -105,28 +142,23 @@ const homeHref = locale === "en" ? "/en/" : "/";
|
|||
href="https://github.com/musistudio/claude-code-router/releases"
|
||||
aria-label={ui.downloadLabel}
|
||||
>
|
||||
<svg viewBox="0 0 20 20" aria-hidden="true">
|
||||
<path d="M10 3v9" />
|
||||
<path d="M6 8l4 4 4-4" />
|
||||
<path d="M4 16h12" />
|
||||
</svg>
|
||||
<Download size={18} aria-hidden="true" />
|
||||
</a>
|
||||
<a
|
||||
class="soft-button github-button hide-small"
|
||||
href="https://github.com/musistudio/claude-code-router"
|
||||
aria-label={ui.githubLabel}
|
||||
>
|
||||
<svg viewBox="0 0 20 20" aria-hidden="true">
|
||||
<path d="M8.5 16.5c-4 .9-4-2-5.5-2.5" />
|
||||
<path d="M13.5 18v-3.5c0-1 .1-1.4-.5-2 2.8-.3 5.5-1.4 5.5-6A4.6 4.6 0 0 0 17.2 3c.1-.4.6-1.7-.2-3 0 0-1.1-.3-3.5 1.3a12.1 12.1 0 0 0-6.4 0C4.7-.3 3.6 0 3.6 0c-.8 1.3-.3 2.6-.2 3A4.6 4.6 0 0 0 2 6.5c0 4.6 2.7 5.7 5.5 6-.6.5-.9 1.2-.9 2.4V18" />
|
||||
</svg>
|
||||
<Github size={18} aria-hidden="true" />
|
||||
<strong id="github-stars" aria-label="GitHub stars">Stars</strong>
|
||||
</a>
|
||||
<button class="icon-button" type="button" aria-label={ui.themeLabel}>
|
||||
<svg viewBox="0 0 20 20" aria-hidden="true">
|
||||
<circle cx="10" cy="10" r="3" />
|
||||
<path d="M10 1v3M10 16v3M1 10h3M16 10h3M3.6 3.6l2.1 2.1M14.3 14.3l2.1 2.1M16.4 3.6l-2.1 2.1M5.7 14.3l-2.1 2.1" />
|
||||
</svg>
|
||||
<button class="icon-button theme-toggle" type="button" aria-label={ui.themeLabel} data-theme-toggle>
|
||||
<span class="theme-icon theme-icon-sun" aria-hidden="true">
|
||||
<Sun size={19} />
|
||||
</span>
|
||||
<span class="theme-icon theme-icon-moon" aria-hidden="true">
|
||||
<Moon size={19} />
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</header>
|
||||
|
|
@ -135,51 +167,53 @@ const homeHref = locale === "en" ? "/en/" : "/";
|
|||
<aside class="sidebar" aria-label="Documentation sidebar">
|
||||
<div class="sidebar-inner">
|
||||
{
|
||||
sidebarGroups.map((group) => (
|
||||
<section class="sidebar-group">
|
||||
<h2>
|
||||
<span class="group-icon" data-icon={group.icon}></span>
|
||||
{group.label}
|
||||
</h2>
|
||||
<ul>
|
||||
{group.items.map((item) => {
|
||||
const childItems = sidebarChildren[item] ?? [];
|
||||
const isExpandable = expandableSidebarItems.includes(item) && childItems.length > 0;
|
||||
sidebarGroups.map((group) => {
|
||||
const GroupIcon = sidebarIcons[group.icon] ?? BookOpen;
|
||||
|
||||
return (
|
||||
<li>
|
||||
{isExpandable ? (
|
||||
<details class="sidebar-details">
|
||||
<summary class="sidebar-link" aria-expanded="false">
|
||||
return (
|
||||
<section class="sidebar-group">
|
||||
<h2>
|
||||
<GroupIcon class="group-icon" size={16} aria-hidden="true" />
|
||||
{group.label}
|
||||
</h2>
|
||||
<ul>
|
||||
{group.items.map((item) => {
|
||||
const childItems = sidebarChildren[item] ?? [];
|
||||
const isExpandable = expandableSidebarItems.includes(item) && childItems.length > 0;
|
||||
|
||||
return (
|
||||
<li>
|
||||
{isExpandable ? (
|
||||
<details class="sidebar-details">
|
||||
<summary class="sidebar-link" aria-expanded="false">
|
||||
<span>{item}</span>
|
||||
<ChevronRight size={16} aria-hidden="true" />
|
||||
</summary>
|
||||
<ul class="sidebar-children">
|
||||
{childItems.map((child) => (
|
||||
<li>
|
||||
<a class="sidebar-child-link" href={sidebarLinks[child] ?? "#"}>
|
||||
{child}
|
||||
</a>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</details>
|
||||
) : (
|
||||
<a
|
||||
class:list={["sidebar-link", { active: group.active === item }]}
|
||||
href={sidebarLinks[item] ?? "#"}
|
||||
>
|
||||
<span>{item}</span>
|
||||
<svg viewBox="0 0 16 16" aria-hidden="true">
|
||||
<path d="M6 4l4 4-4 4" />
|
||||
</svg>
|
||||
</summary>
|
||||
<ul class="sidebar-children">
|
||||
{childItems.map((child) => (
|
||||
<li>
|
||||
<a class="sidebar-child-link" href={sidebarLinks[child] ?? "#"}>
|
||||
{child}
|
||||
</a>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</details>
|
||||
) : (
|
||||
<a
|
||||
class:list={["sidebar-link", { active: group.active === item }]}
|
||||
href={sidebarLinks[item] ?? "#"}
|
||||
>
|
||||
<span>{item}</span>
|
||||
</a>
|
||||
)}
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
</section>
|
||||
))
|
||||
</a>
|
||||
)}
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
</section>
|
||||
);
|
||||
})
|
||||
}
|
||||
</div>
|
||||
</aside>
|
||||
|
|
@ -191,9 +225,7 @@ const homeHref = locale === "en" ? "/en/" : "/";
|
|||
<aside class="toc" aria-label={tocTitle}>
|
||||
<div class="toc-card">
|
||||
<h2>
|
||||
<svg viewBox="0 0 20 20" aria-hidden="true">
|
||||
<path d="M5 6h10M5 10h7M5 14h4" />
|
||||
</svg>
|
||||
<List size={18} aria-hidden="true" />
|
||||
{tocTitle}
|
||||
</h2>
|
||||
<nav>
|
||||
|
|
@ -244,6 +276,51 @@ const homeHref = locale === "en" ? "/en/" : "/";
|
|||
});
|
||||
</script>
|
||||
<script>
|
||||
const themeToggle = document.querySelector("[data-theme-toggle]");
|
||||
const themeStorageKey = "ccr-docs-theme";
|
||||
const themeMediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
|
||||
|
||||
const getStoredTheme = () => {
|
||||
try {
|
||||
const storedTheme = localStorage.getItem(themeStorageKey);
|
||||
return storedTheme === "light" || storedTheme === "dark" ? storedTheme : null;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
const getSystemTheme = () => (themeMediaQuery.matches ? "dark" : "light");
|
||||
|
||||
const applyTheme = (theme, source = "system") => {
|
||||
const nextTheme = theme === "dark" ? "dark" : "light";
|
||||
document.documentElement.dataset.theme = nextTheme;
|
||||
document.documentElement.dataset.themeSource = source;
|
||||
document.documentElement.style.colorScheme = nextTheme;
|
||||
|
||||
if (themeToggle instanceof HTMLButtonElement) {
|
||||
themeToggle.setAttribute("aria-pressed", nextTheme === "dark" ? "true" : "false");
|
||||
}
|
||||
};
|
||||
|
||||
applyTheme(getStoredTheme() ?? getSystemTheme(), getStoredTheme() ? "user" : "system");
|
||||
|
||||
themeToggle?.addEventListener("click", () => {
|
||||
const currentTheme = document.documentElement.dataset.theme === "dark" ? "dark" : "light";
|
||||
const nextTheme = currentTheme === "dark" ? "light" : "dark";
|
||||
|
||||
try {
|
||||
localStorage.setItem(themeStorageKey, nextTheme);
|
||||
} catch {}
|
||||
|
||||
applyTheme(nextTheme, "user");
|
||||
});
|
||||
|
||||
themeMediaQuery.addEventListener("change", () => {
|
||||
if (!getStoredTheme()) {
|
||||
applyTheme(getSystemTheme(), "system");
|
||||
}
|
||||
});
|
||||
|
||||
const sidebarDetails = document.querySelectorAll(".sidebar-details");
|
||||
const reduceMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
import DocPage from "../../components/DocPage.astro";
|
||||
import { enBotDocs, botPlatformFromPath } from "../../bot-platforms";
|
||||
import DocPage from "../../../components/DocPage.astro";
|
||||
import { enBotDocs, botPlatformFromPath } from "../../../bot-platforms";
|
||||
|
||||
export function getStaticPaths() {
|
||||
return Object.entries(enBotDocs).map(([filePath, mod]) => ({
|
||||
|
|
@ -1,21 +1,188 @@
|
|||
:root {
|
||||
color-scheme: light;
|
||||
--bg: #ffffff;
|
||||
--shell-bg: linear-gradient(90deg, #f8faf8 0, #ffffff 17%, #ffffff 83%, #fbfcfb 100%);
|
||||
--surface: #ffffff;
|
||||
--surface-muted: #f7f8f7;
|
||||
--surface-soft: #f6f8f6;
|
||||
--surface-raised: rgba(255, 255, 255, 0.92);
|
||||
--panel: #fbfbfa;
|
||||
--panel-strong: #f5f6f4;
|
||||
--text: #1d201f;
|
||||
--heading: #171d1b;
|
||||
--body: #404742;
|
||||
--muted: #5f6661;
|
||||
--subtle: #8b938e;
|
||||
--border: #e6e8e5;
|
||||
--border-soft: #eef1ee;
|
||||
--border-strong: #d8ddd9;
|
||||
--green: #0a7f48;
|
||||
--green-soft: #e8f6ef;
|
||||
--green-border: #cce5d7;
|
||||
--danger: #b03a2e;
|
||||
--button-text: #3d4440;
|
||||
--button-hover-text: #18201c;
|
||||
--nav-text: #3e4641;
|
||||
--nav-active-bg: #f5f5f4;
|
||||
--nav-active-text: #111413;
|
||||
--nav-active-border: #f0f1ef;
|
||||
--menu-text: #4d554f;
|
||||
--kbd-bg: #eef2ef;
|
||||
--kbd-text: #757d78;
|
||||
--kbd-border: #e3e8e4;
|
||||
--sidebar-bg: rgba(250, 251, 250, 0.92);
|
||||
--sidebar-heading: #202522;
|
||||
--sidebar-text: #4c534f;
|
||||
--sidebar-icon: #111513;
|
||||
--sidebar-subtle: #a0a7a3;
|
||||
--sidebar-line: #e3e7e4;
|
||||
--article-text: #3f4742;
|
||||
--article-muted: #424b45;
|
||||
--lead: #4c524f;
|
||||
--code-bg: #f5f7f5;
|
||||
--code-panel-bg: #ffffff;
|
||||
--code-toolbar-bg: #f4f6f4;
|
||||
--code-text: #18201c;
|
||||
--code-border: #e5e8e4;
|
||||
--table-bg: #ffffff;
|
||||
--table-head-bg: #f6f8f6;
|
||||
--table-text: #4b554f;
|
||||
--quote-bg: #f4faf6;
|
||||
--quote-text: #34423a;
|
||||
--step-text: #555e58;
|
||||
--toc-heading: #313834;
|
||||
--toc-text: #626a65;
|
||||
--scrollbar-thumb: #c7ccc8;
|
||||
--focus-border: #dfe6e1;
|
||||
--tiny-shadow: 0 1px 2px rgba(31, 40, 35, 0.05);
|
||||
--shadow: 0 18px 48px rgba(31, 40, 35, 0.08);
|
||||
font-family:
|
||||
Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI",
|
||||
sans-serif;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root:not([data-theme]) {
|
||||
color-scheme: dark;
|
||||
--bg: #0f1210;
|
||||
--shell-bg: linear-gradient(90deg, #0d100e 0, #111512 17%, #111512 83%, #0f1310 100%);
|
||||
--surface: #151a17;
|
||||
--surface-muted: #1a201c;
|
||||
--surface-soft: #181e1a;
|
||||
--surface-raised: rgba(17, 21, 18, 0.9);
|
||||
--panel: #141915;
|
||||
--panel-strong: #1a211c;
|
||||
--text: #e8ede9;
|
||||
--heading: #f4f7f5;
|
||||
--body: #cbd4ce;
|
||||
--muted: #a8b2ac;
|
||||
--subtle: #78837d;
|
||||
--border: #26302a;
|
||||
--border-soft: #202923;
|
||||
--border-strong: #344139;
|
||||
--green: #4ed08d;
|
||||
--green-soft: #143424;
|
||||
--green-border: #245a3a;
|
||||
--danger: #f07468;
|
||||
--button-text: #d3dbd6;
|
||||
--button-hover-text: #f5f8f6;
|
||||
--nav-text: #b8c2bc;
|
||||
--nav-active-bg: #1c251f;
|
||||
--nav-active-text: #f5f8f6;
|
||||
--nav-active-border: #28332c;
|
||||
--menu-text: #c4cec7;
|
||||
--kbd-bg: #1d261f;
|
||||
--kbd-text: #9ca8a1;
|
||||
--kbd-border: #2b362f;
|
||||
--sidebar-bg: rgba(15, 19, 16, 0.92);
|
||||
--sidebar-heading: #e4ebe6;
|
||||
--sidebar-text: #b6c0ba;
|
||||
--sidebar-icon: #d9e2dc;
|
||||
--sidebar-subtle: #6f7a73;
|
||||
--sidebar-line: #28322b;
|
||||
--article-text: #cad4ce;
|
||||
--article-muted: #c1cbc5;
|
||||
--lead: #b5c1ba;
|
||||
--code-bg: #141a16;
|
||||
--code-panel-bg: #111713;
|
||||
--code-toolbar-bg: #172019;
|
||||
--code-text: #dbe6df;
|
||||
--code-border: #2a352e;
|
||||
--table-bg: #121713;
|
||||
--table-head-bg: #18211b;
|
||||
--table-text: #c2ccc6;
|
||||
--quote-bg: #13261b;
|
||||
--quote-text: #cce0d2;
|
||||
--step-text: #b2beb7;
|
||||
--toc-heading: #d8e0db;
|
||||
--toc-text: #a0aba4;
|
||||
--scrollbar-thumb: #455149;
|
||||
--focus-border: #3a493f;
|
||||
--tiny-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
|
||||
--shadow: 0 22px 52px rgba(0, 0, 0, 0.42);
|
||||
}
|
||||
}
|
||||
|
||||
:root[data-theme="dark"] {
|
||||
color-scheme: dark;
|
||||
--bg: #0f1210;
|
||||
--shell-bg: linear-gradient(90deg, #0d100e 0, #111512 17%, #111512 83%, #0f1310 100%);
|
||||
--surface: #151a17;
|
||||
--surface-muted: #1a201c;
|
||||
--surface-soft: #181e1a;
|
||||
--surface-raised: rgba(17, 21, 18, 0.9);
|
||||
--panel: #141915;
|
||||
--panel-strong: #1a211c;
|
||||
--text: #e8ede9;
|
||||
--heading: #f4f7f5;
|
||||
--body: #cbd4ce;
|
||||
--muted: #a8b2ac;
|
||||
--subtle: #78837d;
|
||||
--border: #26302a;
|
||||
--border-soft: #202923;
|
||||
--border-strong: #344139;
|
||||
--green: #4ed08d;
|
||||
--green-soft: #143424;
|
||||
--green-border: #245a3a;
|
||||
--danger: #f07468;
|
||||
--button-text: #d3dbd6;
|
||||
--button-hover-text: #f5f8f6;
|
||||
--nav-text: #b8c2bc;
|
||||
--nav-active-bg: #1c251f;
|
||||
--nav-active-text: #f5f8f6;
|
||||
--nav-active-border: #28332c;
|
||||
--menu-text: #c4cec7;
|
||||
--kbd-bg: #1d261f;
|
||||
--kbd-text: #9ca8a1;
|
||||
--kbd-border: #2b362f;
|
||||
--sidebar-bg: rgba(15, 19, 16, 0.92);
|
||||
--sidebar-heading: #e4ebe6;
|
||||
--sidebar-text: #b6c0ba;
|
||||
--sidebar-icon: #d9e2dc;
|
||||
--sidebar-subtle: #6f7a73;
|
||||
--sidebar-line: #28322b;
|
||||
--article-text: #cad4ce;
|
||||
--article-muted: #c1cbc5;
|
||||
--lead: #b5c1ba;
|
||||
--code-bg: #141a16;
|
||||
--code-panel-bg: #111713;
|
||||
--code-toolbar-bg: #172019;
|
||||
--code-text: #dbe6df;
|
||||
--code-border: #2a352e;
|
||||
--table-bg: #121713;
|
||||
--table-head-bg: #18211b;
|
||||
--table-text: #c2ccc6;
|
||||
--quote-bg: #13261b;
|
||||
--quote-text: #cce0d2;
|
||||
--step-text: #b2beb7;
|
||||
--toc-heading: #d8e0db;
|
||||
--toc-text: #a0aba4;
|
||||
--scrollbar-thumb: #455149;
|
||||
--focus-border: #3a493f;
|
||||
--tiny-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
|
||||
--shadow: 0 22px 52px rgba(0, 0, 0, 0.42);
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
|
@ -60,8 +227,7 @@ pre {
|
|||
|
||||
.shell {
|
||||
min-height: 100vh;
|
||||
background:
|
||||
linear-gradient(90deg, #f8faf8 0, #ffffff 17%, #ffffff 83%, #fbfcfb 100%);
|
||||
background: var(--shell-bg);
|
||||
}
|
||||
|
||||
.topbar {
|
||||
|
|
@ -75,7 +241,7 @@ pre {
|
|||
height: 66px;
|
||||
padding: 0 34px;
|
||||
border-bottom: 1px solid var(--border);
|
||||
background: rgba(255, 255, 255, 0.92);
|
||||
background: var(--surface-raised);
|
||||
backdrop-filter: blur(14px);
|
||||
}
|
||||
|
||||
|
|
@ -98,7 +264,7 @@ pre {
|
|||
.language-switcher {
|
||||
position: relative;
|
||||
min-width: 86px;
|
||||
color: #2f3431;
|
||||
color: var(--button-text);
|
||||
}
|
||||
|
||||
.language-switcher summary {
|
||||
|
|
@ -118,7 +284,7 @@ pre {
|
|||
}
|
||||
|
||||
.language-switcher summary:hover {
|
||||
background: #f7f8f7;
|
||||
background: var(--surface-muted);
|
||||
}
|
||||
|
||||
.language-switcher svg {
|
||||
|
|
@ -136,7 +302,7 @@ pre {
|
|||
padding: 6px;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 12px;
|
||||
background: #ffffff;
|
||||
background: var(--surface);
|
||||
box-shadow: var(--shadow);
|
||||
}
|
||||
|
||||
|
|
@ -146,11 +312,11 @@ pre {
|
|||
min-height: 34px;
|
||||
padding: 0 10px;
|
||||
border-radius: 8px;
|
||||
color: #4d554f;
|
||||
color: var(--menu-text);
|
||||
}
|
||||
|
||||
.language-menu a:hover {
|
||||
background: #f6f8f6;
|
||||
background: var(--surface-soft);
|
||||
}
|
||||
|
||||
.language-menu a.active {
|
||||
|
|
@ -173,14 +339,14 @@ pre {
|
|||
min-height: 38px;
|
||||
padding: 0 18px;
|
||||
border-radius: 999px;
|
||||
color: #3e4641;
|
||||
color: var(--nav-text);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.nav-link.active {
|
||||
background: #f5f5f4;
|
||||
color: #111413;
|
||||
box-shadow: inset 0 0 0 1px #f0f1ef;
|
||||
background: var(--nav-active-bg);
|
||||
color: var(--nav-active-text);
|
||||
box-shadow: inset 0 0 0 1px var(--nav-active-border);
|
||||
}
|
||||
|
||||
.top-actions {
|
||||
|
|
@ -214,9 +380,9 @@ pre {
|
|||
}
|
||||
|
||||
.search:focus-within {
|
||||
border-color: #dfe6e1;
|
||||
background: #ffffff;
|
||||
box-shadow: 0 1px 2px rgba(31, 40, 35, 0.05);
|
||||
border-color: var(--focus-border);
|
||||
background: var(--surface);
|
||||
box-shadow: var(--tiny-shadow);
|
||||
}
|
||||
|
||||
.search svg {
|
||||
|
|
@ -242,11 +408,11 @@ pre {
|
|||
height: 20px;
|
||||
padding: 0 5px;
|
||||
border-radius: 7px;
|
||||
background: #eef2ef;
|
||||
color: #757d78;
|
||||
background: var(--kbd-bg);
|
||||
color: var(--kbd-text);
|
||||
font-size: 12px;
|
||||
line-height: 1;
|
||||
box-shadow: inset 0 0 0 1px #e3e8e4;
|
||||
box-shadow: inset 0 0 0 1px var(--kbd-border);
|
||||
}
|
||||
|
||||
.soft-button,
|
||||
|
|
@ -268,7 +434,7 @@ pre {
|
|||
border-radius: 999px;
|
||||
border-color: var(--border);
|
||||
background: transparent;
|
||||
color: #3d4440;
|
||||
color: var(--button-text);
|
||||
transition:
|
||||
border-color 140ms ease,
|
||||
background 140ms ease,
|
||||
|
|
@ -277,10 +443,10 @@ pre {
|
|||
}
|
||||
|
||||
.soft-button:hover {
|
||||
border-color: #dfe6e1;
|
||||
background: #ffffff;
|
||||
color: #18201c;
|
||||
box-shadow: 0 1px 2px rgba(31, 40, 35, 0.05);
|
||||
border-color: var(--focus-border);
|
||||
background: var(--surface);
|
||||
color: var(--button-hover-text);
|
||||
box-shadow: var(--tiny-shadow);
|
||||
}
|
||||
|
||||
.soft-button svg {
|
||||
|
|
@ -293,20 +459,22 @@ pre {
|
|||
padding: 0;
|
||||
}
|
||||
|
||||
.github-button {
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.github-button strong {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-width: 42px;
|
||||
min-width: 34px;
|
||||
height: 22px;
|
||||
padding: 0 8px;
|
||||
padding: 0 2px;
|
||||
border-radius: 999px;
|
||||
background: #eef7f1;
|
||||
color: var(--green);
|
||||
font-size: 12px;
|
||||
font-weight: 720;
|
||||
line-height: 1;
|
||||
box-shadow: inset 0 0 0 1px #d8eadf;
|
||||
}
|
||||
|
||||
.primary-button {
|
||||
|
|
@ -315,7 +483,7 @@ pre {
|
|||
border-color: var(--green);
|
||||
border-radius: 999px;
|
||||
background: var(--green);
|
||||
color: #ffffff;
|
||||
color: var(--bg);
|
||||
font-weight: 650;
|
||||
}
|
||||
|
||||
|
|
@ -325,7 +493,7 @@ pre {
|
|||
border-color: var(--border);
|
||||
border-radius: 50%;
|
||||
background: transparent;
|
||||
color: #68706a;
|
||||
color: var(--muted);
|
||||
transition:
|
||||
border-color 140ms ease,
|
||||
background 140ms ease,
|
||||
|
|
@ -334,10 +502,10 @@ pre {
|
|||
}
|
||||
|
||||
.icon-button:hover {
|
||||
border-color: #dfe6e1;
|
||||
background: #ffffff;
|
||||
color: #202722;
|
||||
box-shadow: 0 1px 2px rgba(31, 40, 35, 0.05);
|
||||
border-color: var(--focus-border);
|
||||
background: var(--surface);
|
||||
color: var(--button-hover-text);
|
||||
box-shadow: var(--tiny-shadow);
|
||||
}
|
||||
|
||||
.icon-button svg {
|
||||
|
|
@ -345,6 +513,31 @@ pre {
|
|||
height: 19px;
|
||||
}
|
||||
|
||||
.theme-icon {
|
||||
display: none;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
:root[data-theme="light"] .theme-icon-sun,
|
||||
:root:not([data-theme]) .theme-icon-sun {
|
||||
display: inline-flex;
|
||||
}
|
||||
|
||||
:root[data-theme="dark"] .theme-icon-moon {
|
||||
display: inline-flex;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root:not([data-theme]) .theme-icon-sun {
|
||||
display: none;
|
||||
}
|
||||
|
||||
:root:not([data-theme]) .theme-icon-moon {
|
||||
display: inline-flex;
|
||||
}
|
||||
}
|
||||
|
||||
.content-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 240px minmax(0, 1fr) 260px;
|
||||
|
|
@ -356,7 +549,7 @@ pre {
|
|||
top: 66px;
|
||||
height: calc(100vh - 66px);
|
||||
border-right: 1px solid var(--border);
|
||||
background: rgba(250, 251, 250, 0.92);
|
||||
background: var(--sidebar-bg);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
|
|
@ -364,7 +557,7 @@ pre {
|
|||
height: 100%;
|
||||
overflow: auto;
|
||||
padding: 20px 13px 34px 28px;
|
||||
scrollbar-color: #c7ccc8 transparent;
|
||||
scrollbar-color: var(--scrollbar-thumb) transparent;
|
||||
scrollbar-width: thin;
|
||||
}
|
||||
|
||||
|
|
@ -380,50 +573,14 @@ pre {
|
|||
font-size: 13px;
|
||||
line-height: 1.3;
|
||||
font-weight: 720;
|
||||
color: #202522;
|
||||
color: var(--sidebar-heading);
|
||||
}
|
||||
|
||||
.group-icon {
|
||||
position: relative;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
color: #111513;
|
||||
}
|
||||
|
||||
.group-icon::before,
|
||||
.group-icon::after {
|
||||
position: absolute;
|
||||
content: "";
|
||||
inset: 3px;
|
||||
border: 1.7px solid currentColor;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.group-icon::after {
|
||||
inset: auto 2px 2px auto;
|
||||
width: 5px;
|
||||
height: 5px;
|
||||
border-width: 1.5px;
|
||||
}
|
||||
|
||||
.group-icon[data-icon="rocket"]::before {
|
||||
border-radius: 9px 9px 9px 2px;
|
||||
transform: rotate(-36deg);
|
||||
}
|
||||
|
||||
.group-icon[data-icon="wand"]::before {
|
||||
inset: 7px 2px auto 2px;
|
||||
height: 2px;
|
||||
border: 0;
|
||||
border-radius: 2px;
|
||||
background: currentColor;
|
||||
transform: rotate(35deg);
|
||||
}
|
||||
|
||||
.group-icon[data-icon="pen"]::before {
|
||||
inset: 3px 5px 3px 5px;
|
||||
border-radius: 2px;
|
||||
transform: rotate(42deg);
|
||||
color: var(--sidebar-icon);
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.sidebar-group ul {
|
||||
|
|
@ -441,7 +598,7 @@ pre {
|
|||
min-height: 33px;
|
||||
gap: 8px;
|
||||
padding: 6px 8px 6px 0;
|
||||
color: #4c534f;
|
||||
color: var(--sidebar-text);
|
||||
line-height: 1.35;
|
||||
}
|
||||
|
||||
|
|
@ -457,7 +614,7 @@ pre {
|
|||
width: 13px;
|
||||
height: 13px;
|
||||
margin-top: 3px;
|
||||
color: #a0a7a3;
|
||||
color: var(--sidebar-subtle);
|
||||
flex: 0 0 auto;
|
||||
transition: transform 150ms ease;
|
||||
}
|
||||
|
|
@ -483,11 +640,11 @@ pre {
|
|||
}
|
||||
|
||||
.sidebar-details summary:hover {
|
||||
color: #202522;
|
||||
color: var(--sidebar-heading);
|
||||
}
|
||||
|
||||
.sidebar-details[open] > summary {
|
||||
color: #202522;
|
||||
color: var(--sidebar-heading);
|
||||
font-weight: 620;
|
||||
}
|
||||
|
||||
|
|
@ -521,7 +678,7 @@ pre {
|
|||
width: 1px;
|
||||
content: "";
|
||||
border-radius: 999px;
|
||||
background: #e3e7e4;
|
||||
background: var(--sidebar-line);
|
||||
}
|
||||
|
||||
.sidebar-details[open] > .sidebar-children {
|
||||
|
|
@ -541,7 +698,7 @@ pre {
|
|||
display: block;
|
||||
min-height: 29px;
|
||||
padding: 5px 8px 5px 0;
|
||||
color: #68716b;
|
||||
color: var(--muted);
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
overflow: visible;
|
||||
|
|
@ -569,7 +726,7 @@ pre {
|
|||
.doc-article {
|
||||
width: min(100%, 760px);
|
||||
margin: 0 auto;
|
||||
color: #404742;
|
||||
color: var(--body);
|
||||
}
|
||||
|
||||
.article-header {
|
||||
|
|
@ -596,7 +753,7 @@ p {
|
|||
|
||||
h1 {
|
||||
margin: 0;
|
||||
color: #202322;
|
||||
color: var(--heading);
|
||||
font-size: 32px;
|
||||
line-height: 1.18;
|
||||
font-weight: 760;
|
||||
|
|
@ -605,7 +762,7 @@ h1 {
|
|||
|
||||
.lead {
|
||||
margin: 10px 0 0;
|
||||
color: #4c524f;
|
||||
color: var(--lead);
|
||||
font-size: 20px;
|
||||
line-height: 1.48;
|
||||
}
|
||||
|
|
@ -617,13 +774,13 @@ h1 {
|
|||
margin-top: 31px;
|
||||
padding: 0 13px;
|
||||
border-radius: 12px;
|
||||
background: #ffffff;
|
||||
color: #3e4540;
|
||||
box-shadow: 0 1px 0 rgba(15, 23, 20, 0.02);
|
||||
background: var(--surface);
|
||||
color: var(--button-text);
|
||||
box-shadow: var(--tiny-shadow);
|
||||
}
|
||||
|
||||
.copy-page.copied {
|
||||
border-color: #cce5d7;
|
||||
border-color: var(--green-border);
|
||||
background: var(--green-soft);
|
||||
color: var(--green);
|
||||
}
|
||||
|
|
@ -634,7 +791,7 @@ h1 {
|
|||
}
|
||||
|
||||
.doc-markdown {
|
||||
color: #3f4742;
|
||||
color: var(--article-text);
|
||||
font-size: 16px;
|
||||
line-height: 1.78;
|
||||
}
|
||||
|
|
@ -643,7 +800,7 @@ h1 {
|
|||
.doc-article section > p,
|
||||
.doc-markdown > p {
|
||||
margin: 0 0 18px;
|
||||
color: #424b45;
|
||||
color: var(--article-muted);
|
||||
font-size: 16px;
|
||||
line-height: 1.78;
|
||||
}
|
||||
|
|
@ -659,10 +816,10 @@ h1 {
|
|||
.doc-article code,
|
||||
.doc-markdown code {
|
||||
padding: 2px 6px;
|
||||
border: 1px solid #e5e8e4;
|
||||
border: 1px solid var(--code-border);
|
||||
border-radius: 6px;
|
||||
background: #f5f7f5;
|
||||
color: #18201c;
|
||||
background: var(--code-bg);
|
||||
color: var(--code-text);
|
||||
font-size: 0.88em;
|
||||
white-space: break-spaces;
|
||||
}
|
||||
|
|
@ -676,8 +833,8 @@ h1 {
|
|||
.doc-markdown > h2 {
|
||||
margin: 52px 0 18px;
|
||||
padding-top: 10px;
|
||||
border-top: 1px solid #eef1ee;
|
||||
color: #171d1b;
|
||||
border-top: 1px solid var(--border-soft);
|
||||
color: var(--heading);
|
||||
font-size: 25px;
|
||||
line-height: 1.28;
|
||||
font-weight: 760;
|
||||
|
|
@ -693,7 +850,7 @@ h1 {
|
|||
.doc-article h3,
|
||||
.doc-markdown > h3 {
|
||||
margin: 30px 0 9px;
|
||||
color: #1c2320;
|
||||
color: var(--heading);
|
||||
font-size: 17px;
|
||||
line-height: 1.4;
|
||||
font-weight: 720;
|
||||
|
|
@ -703,7 +860,7 @@ h1 {
|
|||
.doc-markdown > ol {
|
||||
margin: 0 0 22px;
|
||||
padding-left: 24px;
|
||||
color: #46504a;
|
||||
color: var(--article-text);
|
||||
}
|
||||
|
||||
.doc-markdown > ul {
|
||||
|
|
@ -733,8 +890,8 @@ h1 {
|
|||
border-spacing: 0;
|
||||
border-collapse: separate;
|
||||
table-layout: fixed;
|
||||
background: #ffffff;
|
||||
box-shadow: 0 1px 0 rgba(19, 30, 24, 0.03);
|
||||
background: var(--table-bg);
|
||||
box-shadow: var(--tiny-shadow);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
|
|
@ -754,15 +911,15 @@ h1 {
|
|||
}
|
||||
|
||||
.doc-markdown th {
|
||||
background: #f6f8f6;
|
||||
color: #202722;
|
||||
background: var(--table-head-bg);
|
||||
color: var(--heading);
|
||||
font-size: 13px;
|
||||
font-weight: 740;
|
||||
line-height: 1.45;
|
||||
}
|
||||
|
||||
.doc-markdown td {
|
||||
color: #4b554f;
|
||||
color: var(--table-text);
|
||||
font-size: 14px;
|
||||
line-height: 1.62;
|
||||
}
|
||||
|
|
@ -787,8 +944,8 @@ h1 {
|
|||
padding: 12px 16px;
|
||||
border-left: 3px solid var(--green);
|
||||
border-radius: 0 10px 10px 0;
|
||||
background: #f4faf6;
|
||||
color: #34423a;
|
||||
background: var(--quote-bg);
|
||||
color: var(--quote-text);
|
||||
}
|
||||
|
||||
.doc-markdown > pre,
|
||||
|
|
@ -801,8 +958,8 @@ h1 {
|
|||
overflow: hidden;
|
||||
border: 1px solid var(--border-strong);
|
||||
border-radius: 16px;
|
||||
background: #ffffff;
|
||||
box-shadow: 0 1px 0 rgba(19, 30, 24, 0.04);
|
||||
background: var(--code-panel-bg);
|
||||
box-shadow: var(--tiny-shadow);
|
||||
}
|
||||
|
||||
.code-toolbar {
|
||||
|
|
@ -812,8 +969,8 @@ h1 {
|
|||
height: 38px;
|
||||
padding: 0 17px;
|
||||
border-bottom: 1px solid var(--border);
|
||||
background: #f4f6f4;
|
||||
color: #333a36;
|
||||
background: var(--code-toolbar-bg);
|
||||
color: var(--article-text);
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
|
|
@ -828,12 +985,12 @@ h1 {
|
|||
padding: 0;
|
||||
border: 0;
|
||||
background: transparent;
|
||||
color: #6b746f;
|
||||
color: var(--muted);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.code-copy:hover {
|
||||
color: #2d3530;
|
||||
color: var(--button-hover-text);
|
||||
}
|
||||
|
||||
.code-copy.copied {
|
||||
|
|
@ -841,20 +998,27 @@ h1 {
|
|||
}
|
||||
|
||||
.code-copy.copy-failed {
|
||||
color: #b03a2e;
|
||||
color: var(--danger);
|
||||
}
|
||||
|
||||
.code-copy svg {
|
||||
.code-copy .copy-icon,
|
||||
.code-copy .success-icon {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition:
|
||||
opacity 160ms ease,
|
||||
transform 160ms ease,
|
||||
color 160ms ease;
|
||||
}
|
||||
|
||||
.code-copy svg {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
}
|
||||
|
||||
.code-copy .success-icon {
|
||||
opacity: 0;
|
||||
transform: scale(0.72);
|
||||
|
|
@ -875,12 +1039,22 @@ pre,
|
|||
margin: 0;
|
||||
padding: 18px 18px 20px;
|
||||
overflow-x: auto;
|
||||
background: #ffffff !important;
|
||||
color: #18201c;
|
||||
background: var(--code-panel-bg) !important;
|
||||
color: var(--code-text);
|
||||
font-size: 14px;
|
||||
line-height: 1.7;
|
||||
}
|
||||
|
||||
:root[data-theme="dark"] pre.astro-code span {
|
||||
color: var(--code-text) !important;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root:not([data-theme]) pre.astro-code span {
|
||||
color: var(--code-text) !important;
|
||||
}
|
||||
}
|
||||
|
||||
.code-content code,
|
||||
pre code {
|
||||
padding: 0;
|
||||
|
|
@ -904,7 +1078,7 @@ pre code {
|
|||
padding: 15px 16px;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 14px;
|
||||
background: #ffffff;
|
||||
background: var(--surface);
|
||||
}
|
||||
|
||||
.step > span {
|
||||
|
|
@ -922,7 +1096,7 @@ pre code {
|
|||
|
||||
.step p {
|
||||
margin: 0;
|
||||
color: #555e58;
|
||||
color: var(--step-text);
|
||||
}
|
||||
|
||||
.toc {
|
||||
|
|
@ -943,7 +1117,7 @@ pre code {
|
|||
align-items: center;
|
||||
gap: 9px;
|
||||
margin: 0 0 6px;
|
||||
color: #313834;
|
||||
color: var(--toc-heading);
|
||||
font-size: 14px;
|
||||
font-weight: 560;
|
||||
}
|
||||
|
|
@ -962,7 +1136,7 @@ pre code {
|
|||
position: relative;
|
||||
display: block;
|
||||
padding: 5px 0 5px 21px;
|
||||
color: #626a65;
|
||||
color: var(--toc-text);
|
||||
line-height: 1.35;
|
||||
}
|
||||
|
||||
|
|
|
|||
16
package-lock.json
generated
16
package-lock.json
generated
|
|
@ -8,9 +8,6 @@
|
|||
"name": "claude-code-router",
|
||||
"version": "3.0.0",
|
||||
"dependencies": {
|
||||
"@dnd-kit/core": "^6.3.1",
|
||||
"@dnd-kit/sortable": "^10.0.0",
|
||||
"@dnd-kit/utilities": "^3.2.2",
|
||||
"@the-next-ai/ai-gateway": "^1.0.0",
|
||||
"@the-next-ai/bot-gateway-sdk": "^0.1.0",
|
||||
"better-sqlite3": "^12.11.1",
|
||||
|
|
@ -22,6 +19,9 @@
|
|||
"ccr": "dist/main/cli.js"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@dnd-kit/core": "^6.3.1",
|
||||
"@dnd-kit/sortable": "^10.0.0",
|
||||
"@dnd-kit/utilities": "^3.2.2",
|
||||
"@tailwindcss/cli": "^4.3.0",
|
||||
"@types/better-sqlite3": "^7.6.13",
|
||||
"@types/node": "^22.10.2",
|
||||
|
|
@ -102,6 +102,7 @@
|
|||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@dnd-kit/accessibility/-/accessibility-3.1.1.tgz",
|
||||
"integrity": "sha512-2P+YgaXF+gRsIihwwY1gCsQSYnu9Zyj2py8kY5fFvUM1qm2WA2u639R6YNVfU4GWr+ZM5mqEsfHZZLoRONbemw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"tslib": "^2.0.0"
|
||||
|
|
@ -114,6 +115,7 @@
|
|||
"version": "6.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@dnd-kit/core/-/core-6.3.1.tgz",
|
||||
"integrity": "sha512-xkGBRQQab4RLwgXxoqETICr6S5JlogafbhNsidmrkVv2YRs5MLwpjoF2qpiGjQt8S9AoxtIV603s0GIUpY5eYQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@dnd-kit/accessibility": "^3.1.1",
|
||||
|
|
@ -129,6 +131,7 @@
|
|||
"version": "10.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@dnd-kit/sortable/-/sortable-10.0.0.tgz",
|
||||
"integrity": "sha512-+xqhmIIzvAYMGfBYYnbKuNicfSsk4RksY2XdmJhT+HAC01nix6fHCztU68jooFiMUB01Ky3F0FyOvhG/BZrWkg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@dnd-kit/utilities": "^3.2.2",
|
||||
|
|
@ -143,6 +146,7 @@
|
|||
"version": "3.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@dnd-kit/utilities/-/utilities-3.2.2.tgz",
|
||||
"integrity": "sha512-+MKAJEOfaBe5SmV6t34p80MMKhjvUz0vRrvVJbPT0WElzaOJ/1xs+D+KDv+tD/NE5ujfrChEcshd4fLn0wpiqg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"tslib": "^2.0.0"
|
||||
|
|
@ -5319,6 +5323,7 @@
|
|||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/js-yaml": {
|
||||
|
|
@ -5770,6 +5775,7 @@
|
|||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
|
||||
"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"js-tokens": "^3.0.0 || ^4.0.0"
|
||||
|
|
@ -6824,6 +6830,7 @@
|
|||
"version": "18.3.1",
|
||||
"resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz",
|
||||
"integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.1.0"
|
||||
|
|
@ -6849,6 +6856,7 @@
|
|||
"version": "18.3.1",
|
||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz",
|
||||
"integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.1.0",
|
||||
|
|
@ -7440,6 +7448,7 @@
|
|||
"version": "0.23.2",
|
||||
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz",
|
||||
"integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.1.0"
|
||||
|
|
@ -8073,6 +8082,7 @@
|
|||
"version": "2.8.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
|
||||
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
|
||||
"dev": true,
|
||||
"license": "0BSD"
|
||||
},
|
||||
"node_modules/tunnel-agent": {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue