Skip to content
Merged
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
2 changes: 0 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,4 @@ yarn-error.log*

.claude

CLAUDE.md

.omc
92 changes: 92 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
# AGENTS.md

Agent guide for the ScriptCat documentation site (docs.scriptcat.org). Human contributors should start with [CONTRIBUTING.md](./CONTRIBUTING.md).

> Note on language: this file is in English. [CONTRIBUTING.md](./CONTRIBUTING.md) and [agents/i18n.md](./agents/i18n.md) are written in Chinese with an English summary at the top — read that summary line first if you only need the gist.

## Project overview

The official documentation and marketing site for ScriptCat, a browser extension that runs user scripts. Stack: Docusaurus 3, React 18, TypeScript, Tailwind CSS, Ant Design.

Package manager is **pnpm** (v10.9.0). Node.js >= 18.

## Commands

```bash
pnpm i # Install dependencies
pnpm run start # Dev server (Chinese, default locale)
pnpm run start:en # Dev server (English, port 3001)
pnpm run start:ru # Dev server (Russian, port 3002)
pnpm run build # Production build (builds every locale in one pass)
pnpm run serve # Serve the production build locally
pnpm run typecheck # TypeScript type checking
pnpm run check # URL contract / fallback output / i18n parity / frontmatter
pnpm run write-translations # Scaffold i18n translation files
```

## Before you commit

`.gitea/workflows/ci.yaml` runs `pnpm run typecheck && pnpm run build && pnpm run check` on every PR, and `deploy.yaml` runs `build && check` again before shipping. CI lives on Gitea, so GitHub shows no status checks — that does **not** mean there is no CI. Run this locally at minimum:

```bash
pnpm run typecheck && pnpm run build && pnpm run check
```

Three things to know:

- **`pnpm run check` needs the `build/` output** (`check:fallbacks` reads the generated HTML), so build first.
- **Do not build a single locale only.** `onBrokenLinks` and `onBrokenAnchors` are both `throw`, but a broken link or anchor only surfaces in the locale that contains it — `--locale zh-Hans` alone misses English and Russian breakage.
- After touching anything in `src/`, spot-check a page in `build/`, `build/en/` **and** `build/ru/`. Verifying only the Chinese output is how most of this repo's localization bugs got through.

## Hard constraints

1. **These URLs are hardcoded by the browser extension and must never change**: `/docs/script_installation/`, `/docs/use/install_comple/` (`install_comple` is a legacy spelling, deliberately kept — not a typo), `/uninstall/`. `scripts/url-inventory.txt` is the committed route baseline and `check:urls` diffs against it.
2. **Intentional new routes** must update that baseline in the same PR via `node scripts/check-url-inventory.mjs --write`, so reviewers can see what you added on purpose.
3. **Never put non-documentation markdown under `docs/`.** `docs/` is the published tree: a new `.md` there creates a public route, requires a mirror in every locale, and requires `title:` frontmatter — it trips `check:urls`, `check:i18n` and `check:frontmatter` at once. Repo-internal docs belong in `agents/` or the repo root.
4. **Never assume the site has only Chinese and English.** There are three locales; see below.

## Layout

| Path | What it is |
|---|---|
| `docusaurus.config.js` | Site config (i18n, navbar, footer, Algolia, GA, per-locale SEO metadata) |
| `sidebars.js` | Three sidebars (`use`/`dev`/`change`), all explicit lists |
| `docs/` | Chinese docs (default locale). Three sections: `use/` guides, `dev/` API docs, `change/` changelogs |
| `i18n/<locale>/` | Per-locale doc mirrors and UI strings |
| `src/pages/` | Custom pages (`index.tsx` landing page, `uninstall.tsx` feedback survey) |
| `src/components/landing/` | Landing page sections (`sections.tsx`, `LandingNav.tsx`, `shared.tsx`) |
| `src/theme/` | Docusaurus theme overrides (custom `Footer`, `Root` language-detection redirect) |
| `src/service/` | API layer (calls `https://scriptcat.org/api/v2`) |
| `scripts/` | Check scripts, `check-config.json`, `url-inventory.txt` route baseline |
| `deploy/` | Dockerfile, nginx config, Helm chart |
| `agents/` | Detailed conventions written for agents |

## Localization (read before touching i18n code)

Three locales: `zh-Hans` (default, no URL prefix), `en` (`/en/`), `ru` (`/ru/`).

The four mistakes that keep recurring — **full rules and incident notes in [agents/i18n.md](./agents/i18n.md)**:

1. **Hardcoding a locale name.** `currentLocale !== "en"` or `pathname.startsWith("/en/")` classifies Russian as Chinese; building a prefix without stripping the existing one produces `/en/ru/x` (a 404). Read the locale from `useDocusaurusContext().i18n.currentLocale`; iterate with `i18n.locales` and `i18n.localeConfigs`.
2. **Forgetting baseUrl on a plain `<a href="/...">`.** For non-default locales `baseUrl` is `/en/` or `/ru/`. `<Link to>` and markdown links apply it automatically; plain `<a>` and antd `<Button href>` do not — wrap those in `withBaseUrl()`.
3. **Hardcoded UI copy.** Everything user-facing goes through `<Translate>` / `translate()`, with keys added to both `i18n/en/code.json` and `i18n/ru/code.json` (identical key count **and** order).
4. **Locale assumptions outside `src/`.** `docusaurus.config.js`'s `metadataByLocale` and `deploy/docker/nginx.conf`'s 404 routing both enumerate locales by hand and must be updated when adding a language. The nginx one is invisible to the build and to `pnpm run check` — it only shows up in production.

Changelogs under `change/` are not translated into Russian: the Russian routes compile the English doc tree directly (`docusaurus.config.js` swaps `docs.path` based on `DOCUSAURUS_CURRENT_LOCALE`). **That fallback covers the whole tree**, so any file missing under `i18n/ru/` silently renders in English instead of failing the build — only `check:i18n` catches it. Do not skip `pnpm run check`.

## Styling

- Tailwind CSS via `@gracefullight/docusaurus-plugin-tailwind`
- Component-scoped styles via CSS Modules (`.module.css`)
- Theme colors through Infima CSS variables (primary: `#4594d5`)
- Dark mode via the `[data-theme="dark"]` selector; for components that must react to theme changes use `useTheme()` from `src/components/useTheme.ts`
- The landing page's mock code cards are width-sensitive (`.codeCard` is a fixed 360px, and the editor mock's line numbers are a hardcoded 11 `<span>`s). Translated copy that is too long wraps and desyncs the gutter — see [agents/i18n.md](./agents/i18n.md).

## Key dependencies

**antd** (forms, buttons, cards, modals), **@iconify/react** (icons), **swiper** (carousel), **react-device-detect** (browser detection for the install guide).

## Conventions index

- [CONTRIBUTING.md](./CONTRIBUTING.md) — markdown/doc structure: file path is the URL, `title:` is the only page-title source, images in a sibling `.assets/` folder, the URL contract, translation glossary
- [agents/i18n.md](./agents/i18n.md) — localization in code: locale detection, baseUrl, translated copy, cross-locale anchors, the single-source fallback mechanism, and a step-by-step checklist for adding a locale
1 change: 1 addition & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
@AGENTS.md
36 changes: 20 additions & 16 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
# 贡献指南 / Contributing Guide

> EN summary: file path = doc ID = published URL, no `id:`/`sidebar_position:` frontmatter, no number-prefixed filenames, `title:` is the only page-title source (no body `# H1`), images live in a sibling `<doc-name>.assets/` folder, and every `docs/**/*.md` needs an `i18n/en/docusaurus-plugin-content-docs/current/**/*.md` mirror. Run `pnpm run check` before opening a PR — it enforces all of this. See [REFACTOR_PROPOSAL.md](./REFACTOR_PROPOSAL.md) for the full rationale.
> EN summary: file path = doc ID = published URL, no `id:`/`sidebar_position:` frontmatter, no number-prefixed filenames, `title:` is the only page-title source (no body `# H1`), images live in a sibling `<doc-name>.assets/` folder, and every `docs/**/*.md` needs a mirror in each locale docs tree unless an explicit single-source fallback is configured. Run `pnpm run check` before opening a PR — it enforces all of this. For locale-aware code conventions see [agents/i18n.md](./agents/i18n.md).

本文档记录本仓库的文档结构约定,帮助人类贡献者和 AI Agent 在不读遍全部历史讨论的情况下,正确地新增/修改文档。
本文档记录本仓库的**文档结构**约定,帮助人类贡献者和 AI Agent 在不读遍全部历史讨论的情况下,正确地新增/修改文档。

改动 `src/` 下的 React 代码或 `docusaurus.config.js` 之前,另见 [agents/i18n.md](./agents/i18n.md)——那里记录了多语言相关的代码约定(不要写死语言名、原生 `<a>` 要补 baseUrl、文案一律走 `<Translate>` 等),每条都对应一个真实踩过的坑。

## 核心约定

Expand All @@ -23,13 +25,13 @@
2. frontmatter 只写 `title:`(必需)和可选的 `sidebar_label:`;不要写 `id:` 或 `sidebar_position:`。
3. 正文**不要**再写一个 `# 标题` 作为 H1——`title:` 会自动渲染为页面标题。
4. 在 `sidebars.js` 对应的数组里加一行 `"section/xxx"`(除非这是一个故意不出现在侧边栏的隐藏页面,如 `use/install_comple`)。
5. 在 `i18n/en/docusaurus-plugin-content-docs/current/<section>/xxx.md` 创建英文镜像,路径和文件名必须完全一致。
6. 图片放在 `docs/<section>/xxx.assets/` 下,用 `./xxx.assets/foo.png` 引用;纯 UI 截图等语言无关的图片,英文版可以用 `@site/docs/<section>/xxx.assets/foo.png` 直接复用中文版的图片,不必重复存一份二进制文件。
7. 跑一次 `pnpm run build && pnpm run check`,确认三项检查全部通过
5. 在 `i18n/<locale>/docusaurus-plugin-content-docs/current/<section>/xxx.md` 为各非默认 locale 创建镜像,路径和文件名必须完全一致;`scripts/check-config.json` 中声明的单一来源 fallback 路径除外
6. 图片放在 `docs/<section>/xxx.assets/` 下,用 `./xxx.assets/foo.png` 引用;纯 UI 截图等语言无关的图片,英文版可以用 `@site/docs/<section>/xxx.assets/foo.png` 直接复用中文版的图片,不必重复存一份二进制文件。俄语版沿用英文截图,统一写 `@site/i18n/en/docusaurus-plugin-content-docs/current/<section>/xxx.assets/foo.png`——`i18n/ru/` 下不放任何图片二进制,避免同一张图在仓库里存三份。
7. 跑一次 `pnpm run build && pnpm run check`,确认全部检查通过

## 新增一条更新日志

`change/` 下的版本文件(`v1.x.md`)不使用数字前缀排序;在 `sidebars.js` 的 `change` 数组里手动插入新版本号(数组顺序即侧边栏顺序,新版本插在最前面)。`change/beta-changelog.md` 是 Beta 版本的单独更新日志。
`change/` 下的版本文件(`v1.x.md`)不使用数字前缀排序;在 `sidebars.js` 的 `change` 数组里手动插入新版本号(数组顺序即侧边栏顺序,新版本插在最前面)。`change/beta-changelog.md` 是 Beta 版本的单独更新日志。更新中文源文时仍需同步英文版本;俄语路由由 Docusaurus 直接回退到英文文档树,不要在 `i18n/ru/.../change/` 中恢复一份会漂移的副本。

## 加载不变的 URL(改动前必须确认不受影响)

Expand All @@ -43,22 +45,24 @@

## 翻译对照表

| 中文 | English |
|---|---|
| 脚本猫 | ScriptCat |
| 用户脚本 | user script |
| 后台脚本 | background script |
| 定时脚本 | scheduled script |
| 油猴 | Tampermonkey |
| 中文 | English | Русский |
|---|---|---|
| 脚本猫 | ScriptCat | ScriptCat |
| 用户脚本 | user script | пользовательский скрипт |
| 后台脚本 | background script | фоновый скрипт |
| 定时脚本 | scheduled script | скрипт по расписанию |
| 定时任务 | scheduled task | задача по расписанию |
| 油猴 | Tampermonkey | Tampermonkey |

英文标题结构应尽量与中文一一对应(标题层级、顺序一致),这样跨语言的锚点链接更容易对齐;注意 Docusaurus 生成的锚点是基于**渲染后的英文标题文本**,不是中文锚点的直接翻译(例如 `## Scheduled Script (\`@crontab\`)` 生成的锚点是 `#scheduled-script-crontab`,需要用构建产物核实,不要凭感觉猜。

## 本地检查命令

```bash
pnpm run build # 构建两个语言版本,onBrokenLinks/onBrokenAnchors 设置为 throw
pnpm run check # 依次跑 url 一致性 / i18n 覆盖率 / frontmatter 规范三项检查
pnpm run build # 构建 zh-Hans/en/ru,onBrokenLinks/onBrokenAnchors 设置为 throw
pnpm run check # 依次跑 URL / fallback 产物 / i18n 覆盖率 / frontmatter 检查
pnpm run check:urls # 单独跑 URL 不变契约检查
pnpm run check:i18n # 单独跑中英文档配对检查
pnpm run check:fallbacks # 单独检查 production build 中的 locale 单一来源 fallback
pnpm run check:i18n # 单独跑所有 locale 的文档配对及 fallback 例外检查
pnpm run check:frontmatter # 单独跑 title/id/sidebar_position/H1 规范检查
```
Loading