mirror of
https://gitea.com/gitea/docs.git
synced 2026-11-12 12:54:12 +00:00
Closes #146. The published site runs pagefind, not docsearch: `PUBLIC_DOCSEARCH_APP_ID` and `PUBLIC_DOCSEARCH_API_KEY` are not set, so `astro.config.mjs` falls back to `pagefind: true`, and a page of docs.gitea.com ships starlight's `#starlight__search` with the `/pagefind/` bundle. The version scoping we have is only implemented for docsearch (`docsearch:product` / `docsearch:version` meta tags plus `facetFilters` in `src/config/docsearch.ts`), so nothing consumes it today. Pagefind builds one index for the whole site, partitioned only by the html language, and nothing tags the pages with a version, so a search started in the 1.23 docs answers with every version of the same page and the latest one usually wins. That is what the issue reports; the original cause (the docusaurus search plugin) is gone, this one replaced it. **What this does** - `src/components/MarkdownContent.astro` wraps the content in two `data-pagefind-filter` elements, `product` and `version`, so the filters land in the index. One filter per element on purpose: pagefind reads the whole attribute as a single `name:value` pair, a comma separated value ends up as one filter named `product` with the value `docs,version:1.26`. - The same scope is written to a `gitea:search-filters` meta tag next to the docsearch ones (`src/lib/search.ts`). - Starlight builds the search ui from a build time configuration and has no option for per page filters, so its `@pagefind/default-ui` import is redirected to a subclass in `src/lib/pagefind-ui.ts` by the `gitea-pagefind-filters` plugin in `astro.config.mjs`, the same approach the `gitea-openapi-overview` plugin already uses. The subclass selects the filters of the page the modal was opened on. - A "Search all versions" checkbox below the search input drops the filters again and labels each result with the version (and the product for the api and the runner) it comes from, so the duplicates are distinguishable. Translated into 简体中文 and 繁體中文. - Pagefind's own filter panel is hidden, it is redundant next to the checkbox and starlight does not style it. The checkbox gets its native rendering back, pagefind resets everything it renders with `all: unset`. - A `gitea-pagefind-filters-check` integration fails the build if the redirect did not run, so a starlight upgrade that moves the import cannot silently bring back an unscoped search. `@pagefind/default-ui` is added to `sites/docs/package.json`; it was only reachable as a transitive dependency of starlight, and the version is the one already in the lockfile. **Verification** Built the whole site and drove the search with a headless browser against `astro preview` (the search does not run in `pnpm dev`): | Page | Query | Results | | --- | --- | --- | | `/1.23/usage/actions/comparison/` | email | only `/1.23/...` | | `/usage/actions/overview/` | email | only the version served at the root | | `/runner/registration/` | label | only `/runner/...` | | `/api/operations/tags/issue/` | label | only `/api/...` | | `/zh-cn/1.26/usage/actions/overview/` | email | only `/zh-cn/1.26/...` | | `/1.23/...` with the checkbox ticked | email | every version, results labelled `... · API 1.25`, `... · next` | `pnpm check` passes. The docsearch path is unchanged: when the credentials are set the plugin takes over, the redirect does not run and the check integration skips. <!-- cloudflare-preview --> Preview: https://pr-512.docs-gitea-com.pages.dev Reviewed-on: https://gitea.com/gitea/docs/pulls/512
180 lines
6.9 KiB
JavaScript
180 lines
6.9 KiB
JavaScript
// @ts-check
|
|
import path from 'node:path';
|
|
import { fileURLToPath } from 'node:url';
|
|
import starlight from '@astrojs/starlight';
|
|
import { defineConfig } from 'astro/config';
|
|
import starlightDocSearch from '@astrojs/starlight-docsearch';
|
|
import starlightOpenAPI, { openAPISidebarGroups } from 'starlight-openapi';
|
|
import { apiSchemas } from './src/config/api.js';
|
|
import { analytics, announcement, announcementStorageKey } from './src/config/site.js';
|
|
import { giteaApiSidebar } from './src/integrations/api.js';
|
|
import { giteaPostBuild } from './src/integrations/postbuild.js';
|
|
|
|
const repoRoot = path.resolve(fileURLToPath(new URL('.', import.meta.url)), '../..');
|
|
|
|
// algolia docsearch replaces the local search once the credentials are set; the
|
|
// build falls back to pagefind so that a fork without them still gets search
|
|
const useDocSearch = Boolean(
|
|
process.env.PUBLIC_DOCSEARCH_APP_ID && process.env.PUBLIC_DOCSEARCH_API_KEY,
|
|
);
|
|
|
|
// set by the `gitea-pagefind-filters` plugin below, checked after the build so
|
|
// a starlight upgrade that moves the import fails loudly instead of silently
|
|
// serving an unscoped search again
|
|
let pagefindUiRedirected = false;
|
|
|
|
export default defineConfig({
|
|
site: 'https://docs.gitea.com',
|
|
trailingSlash: 'always',
|
|
// images, logos and the swagger documents are served from `static/`
|
|
publicDir: path.join(repoRoot, 'static'),
|
|
// the markdown sources live outside this package, allow the dev server to read them
|
|
vite: {
|
|
server: { fs: { allow: [repoRoot] } },
|
|
plugins: [
|
|
{
|
|
// The api overview of starlight-openapi lists every operation of the
|
|
// document, which repeats the sidebar; swap that section for the tag
|
|
// cards of src/components/ApiOverviewTags.astro. The plugin has no
|
|
// option for it, so the import is redirected instead.
|
|
name: 'gitea-openapi-overview',
|
|
enforce: 'pre',
|
|
resolveId(source, importer) {
|
|
if (
|
|
source === './OverviewNavigationLinks.astro' &&
|
|
importer?.includes('starlight-openapi/components/overview/OverviewSchema.astro')
|
|
) {
|
|
return path.join(repoRoot, 'sites/docs/src/components/ApiOverviewTags.astro');
|
|
}
|
|
return null;
|
|
},
|
|
},
|
|
{
|
|
// Pagefind indexes every version into one index and starlight builds
|
|
// the search ui with a build time configuration, so a search cannot be
|
|
// scoped to the version being read. Its `@pagefind/default-ui` import
|
|
// is redirected to the subclass in src/lib/pagefind-ui.ts, which
|
|
// selects the filters of the current page.
|
|
name: 'gitea-pagefind-filters',
|
|
enforce: 'pre',
|
|
resolveId(source, importer) {
|
|
if (
|
|
!useDocSearch &&
|
|
source === '@pagefind/default-ui' &&
|
|
importer?.includes('starlight/components/Search.astro')
|
|
) {
|
|
pagefindUiRedirected = true;
|
|
return path.join(repoRoot, 'sites/docs/src/lib/pagefind-ui.ts');
|
|
}
|
|
return null;
|
|
},
|
|
},
|
|
],
|
|
},
|
|
// languages the sources tag code blocks with that shiki does not know
|
|
markdown: {
|
|
shikiConfig: {
|
|
langAlias: {
|
|
apacheconf: 'apache',
|
|
conf: 'ini',
|
|
curl: 'bash',
|
|
gitignore: 'text',
|
|
none: 'text',
|
|
plantuml: 'text',
|
|
tmpl: 'handlebars',
|
|
},
|
|
},
|
|
},
|
|
integrations: [
|
|
giteaPostBuild(),
|
|
{
|
|
name: 'gitea-pagefind-filters-check',
|
|
hooks: {
|
|
'astro:build:done': () => {
|
|
if (useDocSearch || pagefindUiRedirected) return;
|
|
throw new Error(
|
|
'the pagefind search ui was not replaced by src/lib/pagefind-ui.ts, ' +
|
|
'the search would return results from every version: check the ' +
|
|
"`gitea-pagefind-filters` plugin against starlight's Search.astro",
|
|
);
|
|
},
|
|
},
|
|
},
|
|
starlight({
|
|
title: 'Gitea Documentation',
|
|
description: 'Git with a cup of tea',
|
|
favicon: '/img/favicon.png',
|
|
logo: { src: './src/assets/gitea.svg', alt: 'Gitea', replacesTitle: true },
|
|
defaultLocale: 'root',
|
|
locales: {
|
|
root: { label: 'English', lang: 'en-US' },
|
|
'zh-cn': { label: '简体中文', lang: 'zh-CN' },
|
|
'zh-tw': { label: '繁體中文', lang: 'zh-TW' },
|
|
},
|
|
plugins: [
|
|
starlightOpenAPI(apiSchemas),
|
|
// after starlight-openapi, so it sees the groups the plugin built
|
|
giteaApiSidebar(),
|
|
...(useDocSearch
|
|
? [starlightDocSearch({ clientOptionsModule: './src/config/docsearch.ts' })]
|
|
: []),
|
|
],
|
|
// one sidebar per product, version and language, selected in the route
|
|
// middleware; starlight only supports a single static one
|
|
customCss: ['./src/styles/theme.css', './src/styles/custom.css'],
|
|
components: {
|
|
Header: './src/components/Header.astro',
|
|
LanguageSelect: './src/components/LanguageSelect.astro',
|
|
MarkdownContent: './src/components/MarkdownContent.astro',
|
|
SiteTitle: './src/components/SiteTitle.astro',
|
|
PageFrame: './src/components/PageFrame.astro',
|
|
},
|
|
head: [
|
|
{
|
|
// hide a dismissed announcement before the first paint, so the page
|
|
// does not jump once the stylesheet and the scripts have loaded
|
|
tag: 'script',
|
|
content: `try{if(localStorage.getItem(${JSON.stringify(
|
|
announcementStorageKey,
|
|
)})===${JSON.stringify(
|
|
announcement.id,
|
|
)})document.documentElement.dataset.giteaAnnouncement='dismissed'}catch(e){}`,
|
|
},
|
|
{
|
|
tag: 'script',
|
|
attrs: { async: true, src: `https://www.googletagmanager.com/gtag/js?id=${analytics.gtagId}` },
|
|
},
|
|
{
|
|
tag: 'script',
|
|
content: `window.dataLayer=window.dataLayer||[];function gtag(){dataLayer.push(arguments);}gtag('js',new Date());gtag('config','${analytics.gtagId}');`,
|
|
},
|
|
{
|
|
tag: 'script',
|
|
attrs: {
|
|
defer: true,
|
|
'data-domain': analytics.plausibleDomain,
|
|
src: 'https://plausible.io/js/script.js',
|
|
},
|
|
},
|
|
{ tag: 'meta', attrs: { property: 'og:logo', content: '/img/gitea.svg' } },
|
|
{
|
|
tag: 'meta',
|
|
attrs: {
|
|
name: 'keywords',
|
|
content:
|
|
'gitea, git, devops, actions, packages, documentation, self-hosted, open-source, version control, gitlab, github',
|
|
},
|
|
},
|
|
],
|
|
// the api groups are needed here so starlight-openapi pages get a sidebar,
|
|
// the route middleware narrows it down to the version being read
|
|
sidebar: [...openAPISidebarGroups],
|
|
routeMiddleware: './src/routeData.ts',
|
|
// the sources live outside src/content/docs, starlight only runs its
|
|
// markdown transforms (asides, heading anchors) on files below these
|
|
markdown: { processedDirs: ['../..'] },
|
|
pagefind: !useDocSearch,
|
|
}),
|
|
],
|
|
});
|