diff --git a/.gitea/workflows/build-and-publish.yaml b/.gitea/workflows/build-and-publish.yaml index 90610315..5b1578c5 100644 --- a/.gitea/workflows/build-and-publish.yaml +++ b/.gitea/workflows/build-and-publish.yaml @@ -1,5 +1,5 @@ name: Build and Publish Docs site -run-name: docusaurus build docs site +run-name: astro build docs site on: push: @@ -9,6 +9,13 @@ on: jobs: build-docs: runs-on: ubuntu-24.04 + env: + NODE_OPTIONS: --max-old-space-size=8192 + # search only appears once the credentials are set, the build falls back + # to pagefind otherwise + PUBLIC_DOCSEARCH_APP_ID: ${{ secrets.DOCSEARCH_APP_ID }} + PUBLIC_DOCSEARCH_API_KEY: ${{ secrets.DOCSEARCH_API_KEY }} + PUBLIC_DOCSEARCH_INDEX_NAME: ${{ secrets.DOCSEARCH_INDEX_NAME }} steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 - uses: pnpm/action-setup@0977fd99725f1db4007ccb2928dbb4e90d06cc86 # v6 @@ -23,14 +30,13 @@ jobs: sudo ./aws/install - name: prepare awesome list run: | - make prepare-awesome-latest prepare-awesome\#25 prepare-awesome\#24 prepare-awesome\#23 prepare-awesome\#22 + make prepare-awesome-latest prepare-awesome\#27 prepare-awesome\#26 prepare-awesome\#25 prepare-awesome\#24 prepare-awesome\#23 prepare-awesome\#22 - name: Install dependencies run: pnpm install --frozen-lockfile - #- uses: tats-u/docuactions-cache@v1 - name: build site - run: | - make build + run: make build + - name: aws credential configure uses: aws-actions/configure-aws-credentials@e6de054238d6b7531b4efff3b6587d9aade6a06c # v6 with: @@ -39,20 +45,21 @@ jobs: aws-region: ${{ secrets.AWS_REGION}} - name: Copy files to the production website with the AWS CLI run: | - aws s3 sync build/ s3://docs-gitea-com + aws s3 sync sites/docs/dist/ s3://docs-gitea-com aws cloudfront create-invalidation --distribution-id ${{ secrets.AWS_DISTRIBUTION}} --paths '/*' - name: Copy files to Cloudflare Pages env: CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} run: | - # cloudflare/_headers is only meaningful for the Cloudflare Pages - # deployment, so it is copied into build/ here, after the S3 sync - # step above has already run. If it were placed in build/ any - # earlier, that S3 sync would publish it to S3/CloudFront and make - # it publicly accessible at /_headers there. - cp cloudflare/_headers build/_headers - test -f build/_headers || exit 1 - pnpm dlx wrangler@4 pages deploy build \ + # cloudflare/_headers and cloudflare/_redirects are only meaningful for + # the Cloudflare Pages deployment, so they are copied into the build + # here, after the S3 sync above has run. If they were placed in the + # build any earlier, that sync would publish them to S3/CloudFront and + # make them publicly readable there. + cp cloudflare/_headers sites/docs/dist/_headers + cp cloudflare/_redirects sites/docs/dist/_redirects + test -f sites/docs/dist/_headers -a -f sites/docs/dist/_redirects || exit 1 + pnpm dlx wrangler@4 pages deploy sites/docs/dist \ --project-name docs-gitea-com \ --branch main diff --git a/.gitea/workflows/test.yaml b/.gitea/workflows/test.yaml index 465aa4fc..e5efc5ee 100644 --- a/.gitea/workflows/test.yaml +++ b/.gitea/workflows/test.yaml @@ -11,6 +11,8 @@ concurrency: jobs: build-docs: runs-on: ubuntu-latest + env: + NODE_OPTIONS: --max-old-space-size=8192 steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 - uses: pnpm/action-setup@0977fd99725f1db4007ccb2928dbb4e90d06cc86 # v6 @@ -20,14 +22,17 @@ jobs: cache: pnpm - name: prepare awesome list run: | - make prepare-awesome-latest prepare-awesome\#25 prepare-awesome\#24 prepare-awesome\#23 prepare-awesome\#22 - - name: Install dependencies + make prepare-awesome-latest prepare-awesome\#27 prepare-awesome\#26 prepare-awesome\#25 prepare-awesome\#24 prepare-awesome\#23 prepare-awesome\#22 + + - name: install dependencies run: pnpm install --frozen-lockfile - #- uses: tats-u/docuactions-cache@v1 - name: build site - run: | - make build + run: make build + + - name: type check + run: make check + - name: deploy the preview to Cloudflare Pages id: preview env: @@ -44,11 +49,13 @@ jobs: exit 0 fi - # same as the production deployment: _headers only belongs to the - # Cloudflare Pages output, so it is copied in right before uploading - cp cloudflare/_headers build/_headers + # same as the production deployment: _headers and _redirects only + # belong to the Cloudflare Pages output, so they are copied in right + # before uploading + cp cloudflare/_headers sites/docs/dist/_headers + cp cloudflare/_redirects sites/docs/dist/_redirects - pnpm dlx wrangler@4 pages deploy build \ + pnpm dlx wrangler@4 pages deploy sites/docs/dist \ --project-name docs-gitea-com \ --branch "pr-$PR_NUMBER" | tee wrangler.log diff --git a/.gitignore b/.gitignore index e4ecca58..f3c24951 100644 --- a/.gitignore +++ b/.gitignore @@ -1,12 +1,12 @@ # Dependencies -/node_modules +node_modules -# Production -/build - -# Generated files -.docusaurus -.cache-loader +# Build output +sites/*/dist +sites/*/.astro +sites/*/.cache +build/ +.docusaurus/ # Misc .DS_Store diff --git a/Makefile b/Makefile index 51c886f1..0e103935 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,3 @@ -export NODE_OPTIONS := "--max-old-space-size=8192" - GITEA_AWESOME_REMOTE := https://gitea.com/gitea/awesome-gitea.git GITEA_AWESOME_BRANCH := main @@ -27,26 +25,41 @@ install: pnpm install .PHONY: prepare-docs -prepare-docs: install prepare-awesome-latest prepare-awesome\#19 prepare-awesome\#20 prepare-awesome\#21 prepare-awesome\#22 prepare-awesome\#23 prepare-awesome\#24 +prepare-docs: install prepare-awesome-latest prepare-awesome\#22 prepare-awesome\#23 prepare-awesome\#24 prepare-awesome\#25 prepare-awesome\#26 prepare-awesome\#27 .PHONY: build build: pnpm run build +# type checks the astro site and its components +.PHONY: check +check: + pnpm run check + .PHONY: serve serve: prepare-docs - pnpm run start + pnpm run dev -.PHONY: serve-zh -serve-zh: prepare-docs - pnpm run start -- --locale zh-cn +# only the english docs of the version served at the root, plus the runner: +# starts in a few seconds instead of loading the whole matrix +.PHONY: serve-fast +serve-fast: + pnpm run dev:en-latest + +# search is built by pagefind at build time, so it is only available on the +# built site; this serves it locally +.PHONY: serve-built +serve-built: build + pnpm run preview -# static/swagger-*.json are committed files, use update-api-docs to refresh them .PHONY: clean clean: rm -rf .tmp - rm -rf static/_* + rm -rf sites/docs/dist + rm -rf sites/docs/.cache + rm -rf sites/docs/node_modules/.astro +# static/swagger-*.json are committed files, use update-api-docs to refresh them .PHONY: update-api-docs update-api-docs: ./update_api_docs.sh @@ -67,3 +80,10 @@ update-runner-docs: .PHONY: update-runner-docs-released update-runner-docs-released: ./update_runner_docs.sh --released + +# freezes the current docs or runner tree as a new version, see +# scripts/cut-version.mjs +.PHONY: cut-version +cut-version: + @test -n "$(PRODUCT)" -a -n "$(VERSION)" || { echo 'usage: make cut-version PRODUCT=docs VERSION=1.28'; exit 1; } + node scripts/cut-version.mjs $(PRODUCT) $(VERSION) diff --git a/README.md b/README.md index 10ea1bf9..b5ed3137 100644 --- a/README.md +++ b/README.md @@ -1,65 +1,99 @@ # Gitea Docs ![badge](https://gitea.com/gitea/docs/actions/workflows/build-and-publish.yaml/badge.svg) -## How to build +The sources of [docs.gitea.com](https://docs.gitea.com), built with +[Astro](https://astro.build) and [Starlight](https://starlight.astro.build). -```shell -make clean -make prepare-docs -make build -``` +The site covers three products, all served from this repository: + +| Product | Content | Versions | Languages | +| --- | --- | --- | --- | +| Docs | `docs/`, `versioned_docs/`, `i18n/` | next, 1.27 … 1.22 | English, 简体中文, 繁體中文 | +| API | `static/swagger-*.json` | next, 1.27 … 1.22 | English | +| Runner | `runner-docs/`, `runner-docs_versioned_docs/` | develop, 3 … 0 | English | + +The enterprise documentation is built and deployed from its own repository and +reached through `/enterprise/`, which a Cloudflare worker maintained elsewhere +routes to that deployment. ## Development ```shell -make clean -make prepare-docs -make serve +make install # pnpm install +make serve-fast # english, the version served at the root, starts in seconds +make serve # the whole matrix, every version and language +make build # production build into sites/docs/dist +make check # type checks the site and its components ``` -## Test en version +Search is built by Pagefind while the site is built, so it only answers on the +built site: use `make serve-built` to try it. With the Algolia credentials +(`PUBLIC_DOCSEARCH_APP_ID`, `PUBLIC_DOCSEARCH_API_KEY`) set, DocSearch is used +instead and works in `make serve` too. + +`GITEA_DOCS_PRODUCTS`, `GITEA_DOCS_VERSIONS` and `GITEA_DOCS_LOCALES` (comma +separated) restrict what is built, which is what `make serve-fast` uses. +`GITEA_DOCS_STRICT_LINKS=true` turns the warnings about unresolved relative +markdown links into a build error. + +`sites/docs/README.md` documents how the sources are mapped onto the site. + +## Writing + +Pages are plain markdown with the same frontmatter and admonitions as before: +frontmatter `slug`, `sidebar_position` and `sidebar_label` keep working, and so +do the `:::note` style admonitions and the `@version@` style release variables. +Relative `*.md` links are rewritten to urls while the site is built. + +The order of the top level sidebar groups comes from `sidebars.js` (and +`versioned_sidebars/` for released versions), the label and order of every other +group from the `_category_.json` of its directory. + +## Cutting a version ```shell -pnpm run start +make cut-version PRODUCT=docs VERSION=1.28 +make cut-version PRODUCT=runner VERSION=4 ``` +This freezes the current tree, its translations and its sidebar. The label of +the version, its release variables (`@version@`, `@dockerVersion@`, ...) and +which version is served at the root live in +`packages/content-loader/src/products.ts` and are edited by hand afterwards. +That file is the single source of truth for the product, version and language +matrix. + ## API docs -The swagger definitions rendered under `/api-docs` live in `static/swagger-latest.json` -(gitea main) and `static/swagger-.json` (released versions). +The swagger definitions rendered under `/api/` live in +`static/swagger-latest.json` (gitea main) and `static/swagger-.json` +(released versions). ```shell make update-api-docs # refresh latest + every released version make update-api-docs-latest # refresh only static/swagger-latest.json ``` -`static/swagger-latest.json` is refreshed automatically: the `update swagger files` -workflow runs every 12 hours and opens a pull request whenever gitea main changed. -Released versions are updated by hand when a new gitea version is documented. +`static/swagger-latest.json` is refreshed automatically: the `update swagger +files` workflow runs every 12 hours and opens a pull request whenever gitea main +changed. Released versions are updated by hand when a new gitea version is +documented. ## Runner docs -The runner documentation is a second docs plugin, served under `/runner`: - | Version | Content | URL | | --- | --- | --- | | develop | `runner-docs/` | `/runner/develop/` | | current series | `runner-docs_versioned_docs/version-3/` | `/runner/` | | older series | `runner-docs_versioned_docs/version-2/` | `/runner/2/` | -| archived series | `runner-docs_versioned_docs/version-1/` | `/runner/1/` | A version directory covers a whole release series (`version-3` documents every -`3.x` release), so a patch release only needs a content update, not a new folder. -The UI labels a series `3.x`, derived from `runner-docs_versions.json`, so no -version number has to be bumped anywhere on a runner release. Use floating image -tags (`gitea/runner:3`) and links to the runner's `main` branch in those pages to -keep them valid across patch releases. +`3.x` release), so a patch release only needs a content update, not a new +folder. Use floating image tags (`gitea/runner:3`) and links to the runner's +`main` branch in those pages to keep them valid across patch releases. Its sidebar is written by hand: `runner-sidebars.js` for develop, and `runner-docs_versioned_sidebars/version--sidebars.json` per documented -version. The version list lives in `runner-docs_versions.json`; the `versions`, -`lastVersion` and `Runner Version` dropdown entries in `docusaurus.config.js` are -built from it, so a new series only has to be cut with -`pnpm run docusaurus docs:version:runner-docs `. +version. The pages under `reference/` are generated from the runner sources — the command line reference from `--help`, the example configuration from `generate-config`: @@ -70,12 +104,18 @@ make update-runner-docs-released # every series, from its newest stable tag ./update_runner_docs.sh v3.0.2 runner-docs_versioned_docs/version-3/reference ``` -`--released` (what `make update-runner-docs-released` runs) needs no version list: -it regenerates every `runner-docs_versioned_docs/version-/reference` -directory from the newest stable `v.x.y` tag of `gitea/runner`, looked up -through the Gitea API. +These are refreshed automatically as well: the `update runner reference` +workflow runs weekly and opens a pull request whenever the runner's CLI or +example configuration changed. Generating them needs Go, since the script builds +the runner binary. -All of these pages are refreshed automatically: the `update runner reference` -workflow runs weekly, regenerates the develop and the released references, and -opens a pull request whenever the runner's CLI or example configuration changed. -Generating them needs Go, since the script builds the runner binary. +## Deployment + +`main` is built and published by the `Build and Publish Docs site` workflow, to +S3/CloudFront and to Cloudflare Pages. `cloudflare/_headers` sets the cache +policy and `cloudflare/_redirects` keeps the urls the site used to serve; both +are copied next to the build output by that workflow. +`cloudflare/docsearch-crawler.json` is the Algolia crawler configuration. + +`/enterprise/` is served by another deployment and routed to it by a Cloudflare +worker that lives outside this repository. diff --git a/cloudflare/_headers b/cloudflare/_headers index e388c413..a37ea054 100644 --- a/cloudflare/_headers +++ b/cloudflare/_headers @@ -1,45 +1,24 @@ -# Cloudflare Pages reads this file from the root of the deployed directory -# (build/_headers once .gitea/workflows/build-and-publish.yaml copies it -# in). It lives here, outside static/, so that `make clean` (which does -# `rm -rf static/_*`) cannot delete it and so Docusaurus does not copy it -# into every locale build directory (see the locale rules below for why -# that would matter anyway). - -# Docusaurus content-hashed build output (webpack chunks, css, etc). The -# filename changes whenever the content changes, so it is safe to cache -# these for a long time and mark them immutable. -/assets/* - Cache-Control: public, max-age=31536000, immutable - -# docusaurus.config.js configures locales ["en-us", "zh-cn", "zh-tw"] with -# "en-us" as the default. Docusaurus only serves the default locale at the -# site root; every other locale gets a full copy of the build under a -# // prefix (e.g. build/zh-cn, build/zh-tw), including its own -# assets/img/images directories. Confirmed live: /zh-cn/ references -# /zh-cn/assets/css/styles.a0cbb0c4.css, and without a rule matching that -# path it is served with `cache-control: public, max-age=0, -# must-revalidate` instead of the caching below. +# Cloudflare Pages reads this file from the root of the deployed directory. It +# is copied into the build output by the publish workflow, so that it is not +# uploaded to S3/CloudFront where it would be publicly readable at /_headers. # -# Use a `:locale` placeholder rather than listing "zh-cn" and "zh-tw" -# explicitly, so this keeps working if a locale is added or removed later -# without anyone remembering to update this file. Cloudflare Pages only -# allows a single `*` splat per path, so the locale segment has to be a -# named placeholder (`:locale`, matching exactly one path segment) rather -# than a second splat; `/*/assets/*` is not a valid pattern. -/:locale/assets/* +# Unlike the docusaurus build, astro emits a single content hashed asset +# directory shared by every language, so no per locale rules are needed. + +# Content hashed build output (js, css, fonts). The file name changes with the +# content, so these can be cached forever. +/_astro/* Cache-Control: public, max-age=31536000, immutable -# Files under static/img and static/images keep stable filenames and can be -# replaced in place (same name, new content), so use a short, conservative -# max-age instead of immutable caching. +# Files under public/img and public/images keep stable names and are replaced in +# place, so they get a short, conservative max-age instead. /img/* Cache-Control: public, max-age=86400 -/:locale/img/* - Cache-Control: public, max-age=86400 - /images/* Cache-Control: public, max-age=86400 -/:locale/images/* - Cache-Control: public, max-age=86400 +# The pagefind index, only present when the site is built without algolia +# docsearch. Content hashed as well. +/pagefind/* + Cache-Control: public, max-age=31536000, immutable diff --git a/cloudflare/_redirects b/cloudflare/_redirects new file mode 100644 index 00000000..11dce85e --- /dev/null +++ b/cloudflare/_redirects @@ -0,0 +1,20 @@ +# Redirects for legacy URLs and routes the site no longer serves directly. + +# The api reference and the runner docs are separate products, published in +# english only. Docusaurus served an empty localized copy of them. +/zh-cn/api/* /api/:splat 301 +/zh-tw/api/* /api/:splat 301 +/zh-cn/runner/* /runner/:splat 301 +/zh-tw/runner/* /runner/:splat 301 + +# The version served at the root of a product is also reachable under its +# number, which is what the release notes and old links use. +/api/1.27/* /api/:splat 301 +/runner/3/* /runner/:splat 301 +/1.27/* /:splat 301 + +# The local search plugin had a results page of its own, algolia docsearch is a +# modal opened from any page. +/search / 301 +/zh-cn/search /zh-cn/ 301 +/zh-tw/search /zh-tw/ 301 diff --git a/cloudflare/docsearch-crawler.json b/cloudflare/docsearch-crawler.json new file mode 100644 index 00000000..903d5310 --- /dev/null +++ b/cloudflare/docsearch-crawler.json @@ -0,0 +1,32 @@ +{ + "_comment": "Algolia DocSearch crawler configuration. The three facets come from the docsearch:* meta tags every page carries; only the versions people read are indexed, the older ones stay reachable through the version picker.", + "index_name": "gitea", + "start_urls": [ + "https://docs.gitea.com/", + "https://docs.gitea.com/next/", + "https://docs.gitea.com/zh-cn/", + "https://docs.gitea.com/zh-tw/", + "https://docs.gitea.com/runner/", + "https://docs.gitea.com/api/", + "https://docs.gitea.com/enterprise/" + ], + "sitemap_urls": ["https://docs.gitea.com/sitemap-index.xml"], + "exclusion_patterns": [ + "https://docs.gitea.com/1.2*/**", + "https://docs.gitea.com/*/1.2*/**", + "https://docs.gitea.com/api/1.2*/**", + "https://docs.gitea.com/runner/[0-9]/**" + ], + "selectors": { + "lvl0": { "selector": "//nav[contains(@aria-labelledby,'starlight__sidebar')]//a[@aria-current='page']/ancestor::details//summary//span", "type": "xpath", "global": true, "default_value": "Documentation" }, + "lvl1": ".sl-markdown-content h1, h1", + "lvl2": ".sl-markdown-content h2", + "lvl3": ".sl-markdown-content h3", + "lvl4": ".sl-markdown-content h4", + "text": ".sl-markdown-content p, .sl-markdown-content li, .sl-markdown-content td" + }, + "custom_settings": { + "attributesForFaceting": ["product", "version", "language"] + }, + "conversation_id": [] +} diff --git a/docusaurus.config.js b/docusaurus.config.js deleted file mode 100644 index 29234ff7..00000000 --- a/docusaurus.config.js +++ /dev/null @@ -1,542 +0,0 @@ -// @ts-check -// Note: type annotations allow type checking and IDEs autocompletion - -import { themes as prismThemes } from "prism-react-renderer"; - -const lightCodeTheme = prismThemes.github; -const darkCodeTheme = prismThemes.dracula; - -// order usage directory by type first -function sortItemsByCategory(items) { - // type with "category" (directory) first - const sortedItems = items.sort(function (a, b) { - return a.type.localeCompare(b.type); - }); - return sortedItems; -} - -const renderApiSSR = process.env.API_SSR !== "false"; - -const apiConfig = [ - "redocusaurus", - { - // Plugin Options for loading OpenAPI files - specs: renderApiSSR - ? [ - { - route: "/api/next/", - spec: "static/swagger-latest.json", - }, - { - route: "/api/", - spec: "static/swagger-27.json", - }, - { - route: "/api/1.27/", - spec: "static/swagger-27.json", - }, - { - route: "/api/1.26/", - spec: "static/swagger-26.json", - }, - { - route: "/api/1.25/", - spec: "static/swagger-25.json", - }, - { - route: "/api/1.24/", - spec: "static/swagger-24.json", - }, - { - route: "/api/1.23/", - spec: "static/swagger-23.json", - }, - { - route: "/api/1.22/", - spec: "static/swagger-22.json", - }, - ] - : [], - // Theme Options for modifying how redoc renders them - theme: { - // Change with your site colors - primaryColor: "#1890ff", - }, - }, -]; - -const pageConfig = renderApiSSR - ? { - exclude: ["api/**"], - } - : {}; - -const globalVariables = { - "current": { - goVersion: "1.26", - minGoVersion: "1.26", - minNodeVersion: "22", - version: "main-nightly", - sourceVersion: "main", - sourceBranch: "main", - dockerVersion: "nightly", - displayVersion: "1.28-dev", - }, - "1.27": { - goVersion: "1.26", - minGoVersion: "1.26", - minNodeVersion: "24", - version: "1.27.1", - sourceVersion: "v1.27.1", - sourceBranch: "release/v1.27", - dockerVersion: "1.27.1", - displayVersion: "1.27.1", - }, - "1.26": { - goVersion: "1.26", - minGoVersion: "1.26", - minNodeVersion: "22", - version: "1.26.4", - sourceVersion: "v1.26.4", - sourceBranch: "release/v1.26", - dockerVersion: "1.26.4", - displayVersion: "1.26.4", - }, - "1.25": { - goVersion: "1.25", - minGoVersion: "1.25", - minNodeVersion: "22", - version: "1.25.5", - sourceVersion: "v1.25.0", - sourceBranch: "release/v1.25", - dockerVersion: "1.25.5", - displayVersion: "1.25.5", - }, - "1.24": { - goVersion: "1.24", - minGoVersion: "1.24", - minNodeVersion: "22", - version: "1.24.7", - sourceVersion: "v1.24.0", - sourceBranch: "release/v1.24", - dockerVersion: "1.24.7", - displayVersion: "1.24.7", - }, - "1.23": { - goVersion: "1.23", - minGoVersion: "1.22", - minNodeVersion: "18", - version: "1.23.8", - sourceVersion: "v1.23.8", - sourceBranch: "release/v1.23", - dockerVersion: "1.23.8", - displayVersion: "1.23.8", - }, - "1.22": { - goVersion: "1.22", - minGoVersion: "1.22", - minNodeVersion: "18", - version: "1.22.6", - sourceVersion: "v1.22.6", - sourceBranch: "release/v1.22", - dockerVersion: "1.22.6", - displayVersion: "1.22.6", - }, -}; - -const versions = { - "current": { - label: globalVariables["current"].displayVersion, // path is kept as next for dev (so users can always find "nightly" docs) - banner: "unreleased", - }, - "1.27": { - label: globalVariables["1.27"].displayVersion, - }, - "1.26": { - label: globalVariables["1.26"].displayVersion, - }, - "1.25": { - label: globalVariables["1.25"].displayVersion, - }, - "1.24": { - label: globalVariables["1.24"].displayVersion, - }, - "1.23": { - label: globalVariables["1.23"].displayVersion, - }, - "1.22": { - label: globalVariables["1.22"].displayVersion, - }, -}; - -// The runner docs keep one directory per release series -// (runner-docs_versioned_docs/version-), so a series is labelled "3.x" -// and a patch release never touches this file. The list is the one docusaurus -// maintains, newest first. -const runnerVersions = require("./runner-docs_versions.json"); -const runnerVersionLabel = (version) => `${version}.x`; -const runnerVersionPath = (version) => - // no path for the latest series, its docs are served at /runner/ - version === runnerVersions[0] ? "/runner/" : `/runner/${version}/`; - -/** @type {import('@docusaurus/types').Config} */ -const config = { - title: "Gitea Documentation", - tagline: "Git with a cup of tea", - url: "https://docs.gitea.com", - baseUrl: "/", - onBrokenLinks: "warn", - favicon: "img/favicon.png", - future: { - faster: true, - v4: true - }, - plugins: [ - [ - "docusaurus-plugin-plausible", - { - domain: "docs.gitea.com", - }, - ], - - // for runner documentations - [ - "@docusaurus/plugin-content-docs", - { - id: "runner-docs", - path: "runner-docs", - routeBasePath: "runner", - sidebarPath: require.resolve("./runner-sidebars.js"), - // the current runner docs describe the main branch of gitea/runner - includeCurrentVersion: true, - versions: { - current: { - path: "develop", - label: "develop", - banner: "unreleased", - }, - ...Object.fromEntries( - runnerVersions.map((version) => [ - version, - { label: runnerVersionLabel(version) }, - ]), - ), - }, - // the newest series has no "path", so the latest stable runner docs are - // served at /runner/ and links do not need updating on each release - lastVersion: runnerVersions[0], - editUrl: ({ - versionDocsDirPath, - docPath, - locale, - version, - permalink, - }) => { - return `https://gitea.com/gitea/docs/src/branch/main/${ - version === "current" - ? "runner-docs" - : `runner-docs_versioned_docs/version-${version}` - }/${docPath}`; - }, - }, - ], - ], - - i18n: { - defaultLocale: "en-us", - locales: ["en-us", "zh-cn", "zh-tw"], - localeConfigs: { - "en-us": { - label: "English", - }, - "zh-cn": { - label: "简体中文", - }, - "zh-tw": { - label: "繁體中文", - }, - }, - }, - - presets: [ - [ - "@docusaurus/preset-classic", - //'classic', - /** @type {import('@docusaurus/preset-classic').Options} */ - ({ - docs: { - sidebarPath: require.resolve("./sidebars.js"), - routeBasePath: "/", // Serve the docs at the site's root - editUrl: ({ - versionDocsDirPath, - docPath, - locale, - version, - permalink, - }) => { - // Special case for awesome page - if (docPath.includes("awesome.md")) { - return `https://gitea.com/gitea/awesome-gitea/src/branch/main/README.md`; - } - if (locale === "en-us") { - return `https://gitea.com/gitea/docs/src/branch/main/${ - version === "current" - ? "docs" - : `versioned_docs/version-${version}` - }/${docPath}`; - } - return `https://gitea.com/gitea/docs/src/branch/main/i18n/${locale}/docusaurus-plugin-content-docs/${ - version === "current" ? "current" : `version-${version}` - }/${docPath}`; - }, - versions: versions, - lastVersion: "1.27", - async sidebarItemsGenerator({ - defaultSidebarItemsGenerator, - ...args - }) { - const { item } = args; - // Use the provided data to generate a custom sidebar slice - const sidebarItems = await defaultSidebarItemsGenerator(args); - if (item.dirName !== "usage") { - return sidebarItems; - } else { - return sortItemsByCategory(sidebarItems); - } - }, - }, - blog: false, - theme: { - customCss: require.resolve("./src/css/custom.css"), - }, - pages: pageConfig, - gtag: { - trackingID: "G-KHM0KYT506", - }, - }), - ], - apiConfig, - ], - markdown: { - hooks: { - onBrokenMarkdownLinks: "warn", - }, - preprocessor: ({ filePath, fileContent }) => { - var key = ""; - var found = false; - for (key in globalVariables) { - let folderName = key == "current" ? "current" : `version-${key}`; - if (filePath.includes(`/${folderName}/`)) { - found = true; - break; - } - } - if (key == "" || !found) { - key = "current"; - } - - let content = fileContent; - for (const variable in globalVariables[key]) { - content = content.replaceAll( - "@" + variable + "@", - globalVariables[key][variable] - ); - } - - return content; - }, - }, - themes: [ - [ - "@easyops-cn/docusaurus-search-local", - { - hashed: false, - language: ["en", "zh"], - highlightSearchTermsOnTargetPage: true, - explicitSearchResultPath: true, - indexBlog: false, - docsRouteBasePath: "/", - }, - ], - ], - - themeConfig: - /** @type {import('@docusaurus/preset-classic').ThemeConfig} */ - ({ - image: '/img/gitea.svg', - metadata: [ - { - name: 'og:logo', - content: '/img/gitea.svg' - }, - { - name: "keywords", - content: - "gitea, git, devops, actions, packages, documentation, self-hosted, open-source, version control, gitlab, github", - }, - ], - colorMode: { - defaultMode: "light", - disableSwitch: false, - respectPrefersColorScheme: true, - }, - announcementBar: { - id: "announcementBar-4", // Increment on change - content: `Try   Gitea Cloud   ☁️   for 30 days Accelerate your Development & Deploys!`, - }, - navbar: { - title: "Gitea", - logo: { - alt: "Gitea Logo", - src: "img/gitea.svg", - href: "https://about.gitea.com/", - target: "_self", - }, - items: [ - { - type: "doc", - docId: "index", - position: "left", - label: "Docs", - }, - { - to: "/api/", - label: "API", - position: "left", - activeBaseRegex: "/api/", - }, - { - to: "/runner/", - label: "Runner", - position: "left", - activeBaseRegex: "/runner/", - }, - { - position: "left", - label: "Enterprise", - href: "https://docs.gitea.com/enterprise", - className: "internal-href", - target: "_self", - }, - { - type: "search", - position: "right", - }, - { - type: "localeDropdown", - position: "right", - }, - { - type: "docsVersionDropdown", - position: "right", - dropdownActiveClassDisabled: true, - }, - { - type: "custom-Dropdown", - label: "API Version", - position: "right", - items: [ - { to: "/api/next/", label: "1.28-dev" }, - { to: "/api/", label: "1.27.1" }, - { to: "/api/1.26/", label: "1.26.4" }, - { to: "/api/1.25/", label: "1.25.5" }, - { to: "/api/1.24/", label: "1.24.7" }, - { to: "/api/1.23/", label: "1.23.8" }, - { to: "/api/1.22/", label: "1.22.6" }, - ], - routerRgx: "/api/", - classNames: "api-dropdown", - }, - { - type: "custom-Dropdown", - label: "Runner Version", - position: "right", - items: [ - { to: "/runner/develop/", label: "develop" }, - ...runnerVersions.map((version) => ({ - to: runnerVersionPath(version), - label: runnerVersionLabel(version), - })), - ], - routerRgx: "/runner/", - classNames: "runner-dropdown", - }, - { - to: "help/support", - position: "right", - label: "Support", - activeBaseRegex: "help/support", - }, - { - href: "https://gitea.com/user/login", - label: "Sign In", - position: "right", - className: "internal-href signin-button", - target: "_self", - }, - ], - }, - footer: { - style: "dark", - links: [ - { - title: "Community", - items: [ - { - label: "Awesome Gitea", - href: "https://gitea.com/gitea/awesome-gitea", - }, - { - label: "Stack Overflow", - href: "https://stackoverflow.com/questions/tagged/gitea", - }, - { - label: "Discord", - href: "https://discord.gg/gitea", - }, - { - label: "Forum", - href: "https://forum.gitea.com/", - }, - { - label: "Twitter", - href: "https://twitter.com/giteaio", - }, - { - label: "Mastodon", - href: "https://social.gitea.io/@gitea", - }, - { - label: "Bluesky", - href: "https://bsky.app/profile/gitea.com", - }, - ], - }, - { - title: "Code", - items: [ - { - label: "GitHub", - href: "https://github.com/go-gitea/gitea", - }, - { - label: "Gitea", - href: "https://gitea.com/gitea", - }, - { - label: "Tea CLI", - href: "https://gitea.com/gitea/tea", - }, - ], - }, - ], - }, - prism: { - theme: lightCodeTheme, - darkTheme: darkCodeTheme, - additionalLanguages: ["ini", "diff", "json", "http", "docker", "php"], - }, - }), -}; - -module.exports = config; diff --git a/i18n/zh-cn/code.json b/i18n/zh-cn/code.json deleted file mode 100644 index 627cf77d..00000000 --- a/i18n/zh-cn/code.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "outdated.message": { - "message": "当前中文文档翻译不是最新版,访问英文版本查看最新内容,或" - }, - "outdated.help": { - "message": "帮助我们翻译" - } -} diff --git a/i18n/zh-cn/docusaurus-plugin-content-docs/current/usage/issues-prs/pull-request.md b/i18n/zh-cn/docusaurus-plugin-content-docs/current/usage/issues-prs/pull-request.md index 01b7a7df..5a8ff375 100644 --- a/i18n/zh-cn/docusaurus-plugin-content-docs/current/usage/issues-prs/pull-request.md +++ b/i18n/zh-cn/docusaurus-plugin-content-docs/current/usage/issues-prs/pull-request.md @@ -57,4 +57,4 @@ WORK_IN_PROGRESS_PREFIXES=WIP:,[WIP] ## 合并请求模板 -有关合并请求模板的更多信息请您移步 : [工单与合并请求模板](usage/issue-pull-request-templates.md) +有关合并请求模板的更多信息请您移步 : [工单与合并请求模板](issue-pull-request-templates.md) diff --git a/i18n/zh-cn/docusaurus-plugin-content-docs/version-1.22/installation/windows-service.md b/i18n/zh-cn/docusaurus-plugin-content-docs/version-1.22/installation/windows-service.md index b4943496..7ca0eaa3 100644 --- a/i18n/zh-cn/docusaurus-plugin-content-docs/version-1.22/installation/windows-service.md +++ b/i18n/zh-cn/docusaurus-plugin-content-docs/version-1.22/installation/windows-service.md @@ -8,6 +8,8 @@ aliases: - /zh-cn/windows-service --- +# 注册为 Windows 服务 + ## 准备工作 在 C:\gitea\custom\conf\app.ini 中进行了以下更改: diff --git a/i18n/zh-cn/docusaurus-plugin-content-docs/version-1.22/usage/actions/variables.md b/i18n/zh-cn/docusaurus-plugin-content-docs/version-1.22/usage/actions/variables.md index 32fe31ec..7a178285 100644 --- a/i18n/zh-cn/docusaurus-plugin-content-docs/version-1.22/usage/actions/variables.md +++ b/i18n/zh-cn/docusaurus-plugin-content-docs/version-1.22/usage/actions/variables.md @@ -6,7 +6,7 @@ sidebar_position: 25 --- -## 变量 +# 变量 您可以创建用户、组织和仓库级别的变量。变量的级别取决于创建它的位置。当创建变量时,变量的名称会被 转换为大写,在yaml文件中引用时需要使用大写。 diff --git a/i18n/zh-cn/docusaurus-plugin-content-docs/version-1.22/usage/pull-request.md b/i18n/zh-cn/docusaurus-plugin-content-docs/version-1.22/usage/pull-request.md index 3546f719..a3ece5bf 100644 --- a/i18n/zh-cn/docusaurus-plugin-content-docs/version-1.22/usage/pull-request.md +++ b/i18n/zh-cn/docusaurus-plugin-content-docs/version-1.22/usage/pull-request.md @@ -59,4 +59,4 @@ WORK_IN_PROGRESS_PREFIXES=WIP:,[WIP] ## 合并请求模板 -有关合并请求模板的更多信息请您移步 : [工单与合并请求模板](usage/issue-pull-request-templates.md) +有关合并请求模板的更多信息请您移步 : [工单与合并请求模板](issue-pull-request-templates.md) diff --git a/i18n/zh-cn/docusaurus-plugin-content-docs/version-1.23/usage/pull-request.md b/i18n/zh-cn/docusaurus-plugin-content-docs/version-1.23/usage/pull-request.md index 01b7a7df..5a8ff375 100644 --- a/i18n/zh-cn/docusaurus-plugin-content-docs/version-1.23/usage/pull-request.md +++ b/i18n/zh-cn/docusaurus-plugin-content-docs/version-1.23/usage/pull-request.md @@ -57,4 +57,4 @@ WORK_IN_PROGRESS_PREFIXES=WIP:,[WIP] ## 合并请求模板 -有关合并请求模板的更多信息请您移步 : [工单与合并请求模板](usage/issue-pull-request-templates.md) +有关合并请求模板的更多信息请您移步 : [工单与合并请求模板](issue-pull-request-templates.md) diff --git a/i18n/zh-cn/docusaurus-plugin-content-docs/version-1.24/usage/pull-request.md b/i18n/zh-cn/docusaurus-plugin-content-docs/version-1.24/usage/pull-request.md index 01b7a7df..5a8ff375 100644 --- a/i18n/zh-cn/docusaurus-plugin-content-docs/version-1.24/usage/pull-request.md +++ b/i18n/zh-cn/docusaurus-plugin-content-docs/version-1.24/usage/pull-request.md @@ -57,4 +57,4 @@ WORK_IN_PROGRESS_PREFIXES=WIP:,[WIP] ## 合并请求模板 -有关合并请求模板的更多信息请您移步 : [工单与合并请求模板](usage/issue-pull-request-templates.md) +有关合并请求模板的更多信息请您移步 : [工单与合并请求模板](issue-pull-request-templates.md) diff --git a/i18n/zh-cn/docusaurus-plugin-content-docs/version-1.25/usage/issues-prs/pull-request.md b/i18n/zh-cn/docusaurus-plugin-content-docs/version-1.25/usage/issues-prs/pull-request.md index 01b7a7df..5a8ff375 100644 --- a/i18n/zh-cn/docusaurus-plugin-content-docs/version-1.25/usage/issues-prs/pull-request.md +++ b/i18n/zh-cn/docusaurus-plugin-content-docs/version-1.25/usage/issues-prs/pull-request.md @@ -57,4 +57,4 @@ WORK_IN_PROGRESS_PREFIXES=WIP:,[WIP] ## 合并请求模板 -有关合并请求模板的更多信息请您移步 : [工单与合并请求模板](usage/issue-pull-request-templates.md) +有关合并请求模板的更多信息请您移步 : [工单与合并请求模板](issue-pull-request-templates.md) diff --git a/i18n/zh-cn/docusaurus-plugin-content-docs/version-1.26/usage/issues-prs/pull-request.md b/i18n/zh-cn/docusaurus-plugin-content-docs/version-1.26/usage/issues-prs/pull-request.md index 01b7a7df..5a8ff375 100644 --- a/i18n/zh-cn/docusaurus-plugin-content-docs/version-1.26/usage/issues-prs/pull-request.md +++ b/i18n/zh-cn/docusaurus-plugin-content-docs/version-1.26/usage/issues-prs/pull-request.md @@ -57,4 +57,4 @@ WORK_IN_PROGRESS_PREFIXES=WIP:,[WIP] ## 合并请求模板 -有关合并请求模板的更多信息请您移步 : [工单与合并请求模板](usage/issue-pull-request-templates.md) +有关合并请求模板的更多信息请您移步 : [工单与合并请求模板](issue-pull-request-templates.md) diff --git a/i18n/zh-cn/docusaurus-plugin-content-docs/version-1.27/usage/issues-prs/pull-request.md b/i18n/zh-cn/docusaurus-plugin-content-docs/version-1.27/usage/issues-prs/pull-request.md index 01b7a7df..5a8ff375 100644 --- a/i18n/zh-cn/docusaurus-plugin-content-docs/version-1.27/usage/issues-prs/pull-request.md +++ b/i18n/zh-cn/docusaurus-plugin-content-docs/version-1.27/usage/issues-prs/pull-request.md @@ -57,4 +57,4 @@ WORK_IN_PROGRESS_PREFIXES=WIP:,[WIP] ## 合并请求模板 -有关合并请求模板的更多信息请您移步 : [工单与合并请求模板](usage/issue-pull-request-templates.md) +有关合并请求模板的更多信息请您移步 : [工单与合并请求模板](issue-pull-request-templates.md) diff --git a/i18n/zh-cn/docusaurus-theme-classic/footer.json b/i18n/zh-cn/docusaurus-theme-classic/footer.json deleted file mode 100644 index d6798db1..00000000 --- a/i18n/zh-cn/docusaurus-theme-classic/footer.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "link.title.Docs": { - "message": "文档", - "description": "The title of the footer links column with title=Docs in the footer" - }, - "link.title.Community": { - "message": "社区", - "description": "The title of the footer links column with title=Community in the footer" - }, - "link.title.More": { - "message": "更多", - "description": "The title of the footer links column with title=More in the footer" - }, - "link.item.label.Tutorial": { - "message": "教程", - "description": "The label of footer link with label=Tutorial linking to /" - }, - "link.item.label.Code": { - "message": "开源代码", - "description": "The label of footer link with label=Code linking to https://github.com/go-gitea/gitea" - }, - "link.item.label.Stack Overflow": { - "message": "Stack Overflow", - "description": "The label of footer link with label=Stack Overflow linking to https://stackoverflow.com/questions/tagged/gitea" - }, - "link.item.label.Discord": { - "message": "Discord", - "description": "The label of footer link with label=Discord linking to https://discord.gg/gitea" - }, - "link.item.label.Twitter": { - "message": "Twitter", - "description": "The label of footer link with label=Twitter linking to https://twitter.com/giteaio" - } -} diff --git a/i18n/zh-cn/docusaurus-theme-classic/navbar.json b/i18n/zh-cn/docusaurus-theme-classic/navbar.json deleted file mode 100644 index ce9f476e..00000000 --- a/i18n/zh-cn/docusaurus-theme-classic/navbar.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "title": { - "message": "Gitea" - }, - "item.label.Docs": { - "message": "文档" - }, - "item.label.Code": { - "message": "开源代码" - }, - "item.label.Support": { - "message": "支持" - }, - "item.label.Blog": { - "message": "博客" - } -} diff --git a/i18n/zh-tw/code.json b/i18n/zh-tw/code.json deleted file mode 100644 index f17091c8..00000000 --- a/i18n/zh-tw/code.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "outdated.message": { - "message": "當前中文文檔翻譯不是最新版,請訪問英文版本查看最新內容,或" - }, - "outdated.help": { - "message": "幫助我們翻譯" - } -} \ No newline at end of file diff --git a/i18n/zh-tw/docusaurus-plugin-content-docs/version-1.22/installation/windows-service.md b/i18n/zh-tw/docusaurus-plugin-content-docs/version-1.22/installation/windows-service.md index 1f917562..cf5a5dcd 100644 --- a/i18n/zh-tw/docusaurus-plugin-content-docs/version-1.22/installation/windows-service.md +++ b/i18n/zh-tw/docusaurus-plugin-content-docs/version-1.22/installation/windows-service.md @@ -8,6 +8,8 @@ aliases: - /zh-tw/windows-service --- +# 註冊為 Windows 服務 + ## 準備工作 在 C:\gitea\custom\conf\app.ini 中進行了以下更改: diff --git a/i18n/zh-tw/docusaurus-plugin-content-docs/version-1.22/usage/actions/variables.md b/i18n/zh-tw/docusaurus-plugin-content-docs/version-1.22/usage/actions/variables.md index 9d6450c1..5fd27d00 100644 --- a/i18n/zh-tw/docusaurus-plugin-content-docs/version-1.22/usage/actions/variables.md +++ b/i18n/zh-tw/docusaurus-plugin-content-docs/version-1.22/usage/actions/variables.md @@ -6,7 +6,7 @@ sidebar_position: 25 --- -## 變量 +# 變量 您可以建立使用者、組織和儲存庫級別的變量。變量的級別取決於建立它的位置。當建立變量時,變量的名稱會被 轉換為大寫,在yaml文件中引用時需要使用大寫。 diff --git a/i18n/zh-tw/docusaurus-theme-classic/footer.json b/i18n/zh-tw/docusaurus-theme-classic/footer.json deleted file mode 100644 index 42698d79..00000000 --- a/i18n/zh-tw/docusaurus-theme-classic/footer.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "link.title.Docs": { - "message": "文件", - "description": "The title of the footer links column with title=Docs in the footer" - }, - "link.title.Community": { - "message": "社區", - "description": "The title of the footer links column with title=Community in the footer" - }, - "link.title.More": { - "message": "更多", - "description": "The title of the footer links column with title=More in the footer" - }, - "link.item.label.Tutorial": { - "message": "教學", - "description": "The label of footer link with label=Tutorial linking to /" - }, - "link.item.label.Code": { - "message": "開源程式碼", - "description": "The label of footer link with label=Code linking to https://github.com/go-gitea/gitea" - }, - "link.item.label.Stack Overflow": { - "message": "Stack Overflow", - "description": "The label of footer link with label=Stack Overflow linking to https://stackoverflow.com/questions/tagged/gitea" - }, - "link.item.label.Discord": { - "message": "Discord", - "description": "The label of footer link with label=Discord linking to https://discord.gg/gitea" - }, - "link.item.label.Twitter": { - "message": "Twitter", - "description": "The label of footer link with label=Twitter linking to https://twitter.com/giteaio" - } -} diff --git a/i18n/zh-tw/docusaurus-theme-classic/navbar.json b/i18n/zh-tw/docusaurus-theme-classic/navbar.json deleted file mode 100644 index b698cca9..00000000 --- a/i18n/zh-tw/docusaurus-theme-classic/navbar.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "title": { - "message": "Gitea" - }, - "item.label.Docs": { - "message": "文件" - }, - "item.label.Code": { - "message": "開源程式碼" - }, - "item.label.Support": { - "message": "支援" - }, - "item.label.Blog": { - "message": "部落格" - } -} diff --git a/package.json b/package.json index d113efc7..e0cee18a 100644 --- a/package.json +++ b/package.json @@ -3,53 +3,15 @@ "version": "0.0.0", "private": true, "scripts": { - "docusaurus": "docusaurus", - "start": "docusaurus start", - "start-CSRApi": "cross-env API_SSR='false' docusaurus start", - "build": "docusaurus build", - "build-CSRApi": "cross-env API_SSR='false' docusaurus build", - "swizzle": "docusaurus swizzle", - "deploy": "docusaurus deploy", - "clear": "docusaurus clear", - "serve": "docusaurus serve", - "write-translations": "docusaurus write-translations", - "write-heading-ids": "docusaurus write-heading-ids" - }, - "dependencies": { - "@docusaurus/core": "3.10.2", - "@docusaurus/faster": "3.10.2", - "@docusaurus/plugin-content-docs": "3.10.2", - "@docusaurus/preset-classic": "3.10.2", - "@easyops-cn/docusaurus-search-local": "0.55.3", - "@emotion/react": "11.14.0", - "@emotion/styled": "11.14.1", - "@mdx-js/react": "3.1.1", - "@mui/material": "9.2.0", - "clsx": "2.1.1", - "docusaurus-plugin-plausible": "0.0.5", - "prism-react-renderer": "2.4.1", - "react": "19.2.8", - "react-dom": "19.2.8", - "redocusaurus": "2.5.2" - }, - "devDependencies": { - "@docusaurus/module-type-aliases": "3.10.2", - "cross-env": "10.1.0" - }, - "browserslist": { - "production": [ - ">0.5%", - "not dead", - "not op_mini all" - ], - "development": [ - "last 1 chrome version", - "last 1 firefox version", - "last 1 safari version" - ] + "dev": "pnpm --filter @gitea-docs/site dev", + "dev:en-latest": "pnpm --filter @gitea-docs/site dev:en-latest", + "build": "pnpm --filter @gitea-docs/site build", + "preview": "pnpm --filter @gitea-docs/site preview", + "check": "pnpm --filter @gitea-docs/site check", + "cut-version": "node scripts/cut-version.mjs" }, "engines": { - "node": ">=18" + "node": ">=22" }, "packageManager": "pnpm@11.20.0" } diff --git a/packages/content-loader/package.json b/packages/content-loader/package.json new file mode 100644 index 00000000..337fd5f3 --- /dev/null +++ b/packages/content-loader/package.json @@ -0,0 +1,19 @@ +{ + "name": "@gitea-docs/content-loader", + "version": "0.0.0", + "private": true, + "type": "module", + "exports": { + ".": "./src/index.ts", + "./products": "./src/products.ts", + "./segments": "./src/segments.ts", + "./sidebar": "./src/sidebar.ts" + }, + "dependencies": { + "tinyglobby": "0.2.15", + "yaml": "2.9.0" + }, + "peerDependencies": { + "astro": "^7.0.2" + } +} diff --git a/packages/content-loader/src/categories.ts b/packages/content-loader/src/categories.ts new file mode 100644 index 00000000..681b36cb --- /dev/null +++ b/packages/content-loader/src/categories.ts @@ -0,0 +1,64 @@ +import { promises as fs } from 'node:fs'; +import path from 'node:path'; +import type { Segment } from './segments.js'; + +/** `_category_.json`, the docusaurus per directory sidebar metadata. */ +export interface CategoryMeta { + label?: string; + position?: number; + collapsed?: boolean; + link?: { + type?: string; + slug?: string; + title?: string; + description?: string; + }; +} + +export const categoryFile = '_category_.json'; + +export async function readCategoryMeta(dir: string): Promise { + try { + return JSON.parse(await fs.readFile(path.join(dir, categoryFile), 'utf-8')) as CategoryMeta; + } catch { + return undefined; + } +} + +/** Fallback label for a directory without `_category_.json`. */ +export function labelFromDirname(name: string): string { + return name + .split('-') + .map((part) => part.charAt(0).toUpperCase() + part.slice(1)) + .join(' '); +} + +export function slugifyLabel(label: string): string { + return label + .toLowerCase() + .replace(/[^a-z0-9]+/g, '-') + .replace(/^-+|-+$/g, ''); +} + +/** + * Route id of the index page docusaurus generates for a category. + * + * Top level categories are declared by `sidebars.js` without a slug and end up + * under `/category/