diff --git a/frontmatter.json b/frontmatter.json
index 7a966b5336..d3fc9e759d 100644
--- a/frontmatter.json
+++ b/frontmatter.json
@@ -71,6 +71,16 @@
"title": "navOrder",
"name": "navOrder",
"type": "number"
+ },
+ {
+ "title": "area",
+ "name": "area",
+ "type": "choice",
+ "choices": [
+ "docs",
+ "api"
+ ],
+ "required": false
}
]
}
@@ -132,4 +142,4 @@
]
}
}
-}
\ No newline at end of file
+}
diff --git a/src/components/ApiNavigation.astro b/src/components/ApiNavigation.astro
index 15fecfbcc6..5bb1e4e14a 100644
--- a/src/components/ApiNavigation.astro
+++ b/src/components/ApiNavigation.astro
@@ -8,14 +8,15 @@ stats.start();
type Props = {
lang: string;
- headings: { depth: number; slug: string; text: string }[];
+ // Left off by a layout that lists this page's headings somewhere else, which
+ // leaves the nav as the flat list of pages with nothing under the current one.
+ headings?: { depth: number; slug: string; text: string }[];
// One entry per endpoint, in heading order, left on the frontmatter by
// plugins/satteri-api-examples.js from the `:endpoint` directive under each
// heading. Sections without one — and pages that never reach that plugin —
// simply have none.
apiMethods?:
- | { text: string; method: string | null; deprecated?: boolean }[]
- | null;
+ { text: string; method: string | null; deprecated?: boolean }[] | null;
};
const { lang, headings, apiMethods } = Astro.props satisfies Props;
diff --git a/src/components/AreaNavigation.astro b/src/components/AreaNavigation.astro
new file mode 100644
index 0000000000..bb5c45e394
--- /dev/null
+++ b/src/components/AreaNavigation.astro
@@ -0,0 +1,38 @@
+---
+import type { Area } from '@lib/areas';
+
+// The nav for the docs area
+import Navigation from '@components/Navigation.astro';
+// The nav for the API reference
+import ApiNavigation from './ApiNavigation.astro';
+
+// The area's nav, picked by area rather than by layout, so a page can be laid
+// out one way and navigated another. Every layout renders this and none of them
+// names a nav component.
+//
+// Adding an area means adding a line at the bottom of this file, and the rest
+// of the checklist is in lib/areas.ts - this is step 3 of four.
+type Props = {
+ area: Area;
+ lang: string;
+ // The API nav lists the current page's endpoints under it, and reads both of
+ // these to do it. A layout that shows this page's headings elsewhere — the
+ // table of contents in the side column — leaves them off, and the nav is
+ // then the flat page list on its own.
+ headings?: { depth: number; slug: string; text: string }[];
+ apiMethods?: { text: string; method: string | null }[] | null;
+};
+const { area, lang, headings, apiMethods } = Astro.props satisfies Props;
+---
+
+{
+ /* One line per area, each handed only the props its own nav takes. An area
+ with no line here renders no nav at all, which is louder than quietly showing
+ it the wrong one. */
+}
+{area === 'docs' && }
+{
+ area === 'api' && (
+
+ )
+}
diff --git a/src/layouts/Api.astro b/src/layouts/Api.astro
index 3426547f3d..bf4c84c49b 100644
--- a/src/layouts/Api.astro
+++ b/src/layouts/Api.astro
@@ -3,7 +3,7 @@ import { accelerator } from '@lib/accelerator';
import { PostFiltering } from 'astro-accelerator-utils';
import type { Frontmatter as OriginalFrontmatter } from 'astro-accelerator-utils/types/Frontmatter';
import { SITE } from '@config';
-import { buildApiCrumbs } from '@lib/apiNavigation';
+import { buildAreaCrumbs, resolveArea, type Area } from '@lib/areas';
import type { Crumb } from '@util/breadcrumbs';
// Theme components
@@ -14,7 +14,7 @@ import Authors from '@components/Authors.astro';
import Taxonomy from '@components/Taxonomy.astro';
// Custom components
-import ApiNavigation from '../components/ApiNavigation.astro';
+import AreaNavigation from '../components/AreaNavigation.astro';
import ArticleHeader from '../components/ArticleHeader.astro';
import Feedback from '../components/Feedback.astro';
import TopNav from '../components/TopNav.astro';
@@ -23,9 +23,12 @@ import Footer from 'src/components/Footer.astro';
import DocsSearch from '../components/DocsSearch.astro';
type Props = {
- // `apiMethods` is not written by hand: plugins/satteri-api-examples.js leaves
- // it on the frontmatter for the left nav, an entry per endpoint.
frontmatter: OriginalFrontmatter & {
+ // The nav this page appears in. Optional, and normally left alone: these
+ // pages live under /docs/api, which is the API area already.
+ area?: Area;
+ // `apiMethods` is not written by hand: plugins/satteri-api-examples.js
+ // leaves it on the frontmatter for the left nav, an entry per endpoint.
apiMethods?: { text: string; method: string | null }[];
};
headings: { depth: number; slug: string; text: string }[];
@@ -33,9 +36,10 @@ type Props = {
};
const { frontmatter, headings, breadcrumbs } = Astro.props satisfies Props;
-// buildApiCrumbs, not buildCrumbs: the section has no page of its own at
-// /docs/api for the generic walk to find, so it splices the crumb in.
-const crumbs = buildApiCrumbs(Astro.url, breadcrumbs);
+const area = resolveArea(frontmatter.area, Astro.url.pathname);
+// The API section has no page of its own at /docs/api for the generic crumb
+// walk to find, so buildAreaCrumbs splices the crumb in for it.
+const crumbs = buildAreaCrumbs(Astro.url, area, breadcrumbs);
const lang = frontmatter.lang ?? SITE.default.lang;
const textDirection = frontmatter.dir ?? SITE.default.dir;
@@ -100,7 +104,12 @@ const lastUpdated = frontmatter.modDate ?? frontmatter.pubDate ?? null;
-
-
+ {
+ /* The nav belongs to the area, not to this layout. The page's own
+ headings are not passed: the side column below lists them. */
+ }
+