mirror of
https://gitea.com/gitea/docs.git
synced 2026-11-06 10:00:32 +00:00
feat: add a cli product for the gt documentation
gt, the Gitea CLI, gets its own product next to the runner: the CLI entry in the header, its own sidebars, search scope, crawler start url and redirects, and `make cut-version PRODUCT=cli`. Until a release series is listed, the develop docs are served at /cli/ without the unreleased banner. A directory with an index page and no _category_.json now takes its sidebar label and position from that page, which leads the group, so the generated reference can be grouped by command. Signed-off-by: bircni <[email protected]>
This commit is contained in:
10 files changed
+104
-41
No files matched your search
@@ -8,7 +8,7 @@
|
||||
|
||||
export type LocaleId = 'en-us' | 'zh-cn' | 'zh-tw';
|
||||
|
||||
export type ProductId = 'docs' | 'api' | 'runner' | 'enterprise';
|
||||
export type ProductId = 'docs' | 'api' | 'runner' | 'cli' | 'enterprise';
|
||||
|
||||
/** Values substituted for `@name@` placeholders in the markdown sources. */
|
||||
export interface VersionVariables {
|
||||
@@ -246,6 +246,43 @@ const runnerProduct: ProductDef = {
|
||||
],
|
||||
};
|
||||
|
||||
/**
|
||||
* gt, the Gitea CLI: one directory per release series, english only, like the
|
||||
* runner. The label is the newest release of the series, which is also the tag
|
||||
* the generated reference pages of that directory come from.
|
||||
*
|
||||
* Until the first series is listed here the develop docs are served at the
|
||||
* product root, without the unreleased banner, since there is no release to
|
||||
* point to. Listing a series moves them to `/cli/develop/`.
|
||||
*/
|
||||
const cliSeries: { id: string; latestRelease: string }[] = [];
|
||||
|
||||
const cliProduct: ProductDef = {
|
||||
id: 'cli',
|
||||
label: 'CLI',
|
||||
base: 'cli',
|
||||
locales: ['en-us'],
|
||||
versions: [
|
||||
{
|
||||
id: 'develop',
|
||||
label: 'develop',
|
||||
sources: { 'en-us': 'cli-docs' },
|
||||
...(cliSeries.length > 0
|
||||
? { path: 'develop', banner: 'unreleased' as const }
|
||||
: { path: '', latest: true }),
|
||||
},
|
||||
...cliSeries.map(
|
||||
({ id, latestRelease }, index): VersionDef => ({
|
||||
id,
|
||||
label: latestRelease,
|
||||
path: index === 0 ? '' : id,
|
||||
latest: index === 0,
|
||||
sources: { 'en-us': `cli-docs_versioned_docs/version-${id}` },
|
||||
}),
|
||||
),
|
||||
],
|
||||
};
|
||||
|
||||
/** API reference, rendered from the swagger documents by starlight-openapi. */
|
||||
const apiProduct: ProductDef = {
|
||||
id: 'api',
|
||||
@@ -301,7 +338,13 @@ const enterpriseProduct: ProductDef = {
|
||||
externalBaseUrl: 'https://docs.gitea.com/enterprise',
|
||||
};
|
||||
|
||||
export const products: ProductDef[] = [docsProduct, apiProduct, runnerProduct, enterpriseProduct];
|
||||
export const products: ProductDef[] = [
|
||||
docsProduct,
|
||||
apiProduct,
|
||||
runnerProduct,
|
||||
cliProduct,
|
||||
enterpriseProduct,
|
||||
];
|
||||
|
||||
export function getProduct(id: ProductId): ProductDef {
|
||||
const product = products.find((candidate) => candidate.id === id);
|
||||
|
||||
@@ -96,14 +96,23 @@ interface Tree {
|
||||
label(dir: string): string;
|
||||
}
|
||||
|
||||
/** Sidebar of a directory tree, ordered by `sidebar_position`. */
|
||||
/**
|
||||
* Sidebar of a directory tree, ordered by `sidebar_position`. A directory
|
||||
* without `_category_.json` but with an `index` page, as the generated cli
|
||||
* reference has one per command, takes its label and position from that page,
|
||||
* which comes first in it.
|
||||
*/
|
||||
function treeOf(pages: SidebarPage[]): Tree {
|
||||
const categories = new Map<string, SidebarPage>();
|
||||
const indexes = new Map<string, SidebarPage>();
|
||||
for (const page of pages) {
|
||||
if (!page.meta.category) continue;
|
||||
const dir = [page.meta.dir, page.meta.name].filter(Boolean).join('/');
|
||||
categories.set(dir, page);
|
||||
if (page.meta.category) {
|
||||
categories.set([page.meta.dir, page.meta.name].filter(Boolean).join('/'), page);
|
||||
} else if (page.meta.name === 'index' && page.meta.dir) {
|
||||
indexes.set(page.meta.dir, page);
|
||||
}
|
||||
}
|
||||
const heading = (dir: string) => categories.get(dir) ?? indexes.get(dir);
|
||||
|
||||
const childDirs = (dir: string) => {
|
||||
const prefix = dir ? `${dir}/` : '';
|
||||
@@ -121,7 +130,7 @@ function treeOf(pages: SidebarPage[]): Tree {
|
||||
const entries: { sort: [number, number, string]; entry: SidebarEntry }[] = [];
|
||||
|
||||
for (const child of childDirs(dir)) {
|
||||
const category = categories.get(child);
|
||||
const category = heading(child);
|
||||
const label = category?.title ?? labelFromDirname(child.split('/').at(-1)!);
|
||||
entries.push({
|
||||
sort: [category?.meta.order ?? last, 0, label],
|
||||
@@ -131,7 +140,8 @@ function treeOf(pages: SidebarPage[]): Tree {
|
||||
|
||||
for (const page of pages) {
|
||||
if (page.meta.dir !== dir || page.meta.category || page.hidden) continue;
|
||||
entries.push({ sort: [page.meta.order ?? last, 1, page.title], entry: link(page) });
|
||||
const order = indexes.get(dir) === page ? -last : (page.meta.order ?? last);
|
||||
entries.push({ sort: [order, 1, page.title], entry: link(page) });
|
||||
}
|
||||
|
||||
return entries
|
||||
@@ -142,8 +152,7 @@ function treeOf(pages: SidebarPage[]): Tree {
|
||||
.map((item) => item.entry);
|
||||
};
|
||||
|
||||
const label = (dir: string) =>
|
||||
categories.get(dir)?.title ?? labelFromDirname(dir.split('/').at(-1)!);
|
||||
const label = (dir: string) => heading(dir)?.title ?? labelFromDirname(dir.split('/').at(-1)!);
|
||||
|
||||
return { build, label };
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user