@dogsbay/format-astro 0.2.0-beta.13 → 0.2.0-beta.131

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/dist/api-markdown.d.ts +7 -0
  2. package/dist/api-markdown.js +49 -0
  3. package/dist/base-path.d.ts +93 -8
  4. package/dist/base-path.js +122 -9
  5. package/dist/blog.d.ts +133 -0
  6. package/dist/blog.js +323 -0
  7. package/dist/browser.d.ts +13 -0
  8. package/dist/browser.js +13 -0
  9. package/dist/canonical.d.ts +33 -0
  10. package/dist/canonical.js +106 -0
  11. package/dist/capabilities.d.ts +28 -0
  12. package/dist/capabilities.js +94 -0
  13. package/dist/cli.d.ts +0 -1
  14. package/dist/cli.js +3 -1
  15. package/dist/diff-decoration.d.ts +35 -0
  16. package/dist/diff-decoration.js +101 -0
  17. package/dist/granularity.d.ts +82 -0
  18. package/dist/granularity.js +246 -0
  19. package/dist/head-metadata.d.ts +25 -0
  20. package/dist/head-metadata.js +55 -0
  21. package/dist/index.d.ts +26 -5
  22. package/dist/index.js +34 -4
  23. package/dist/lead.d.ts +1 -39
  24. package/dist/lead.js +3 -38
  25. package/dist/llms-txt.d.ts +41 -11
  26. package/dist/llms-txt.js +82 -274
  27. package/dist/plugins.d.ts +0 -1
  28. package/dist/plugins.js +4 -3
  29. package/dist/project.d.ts +377 -13
  30. package/dist/project.js +2239 -649
  31. package/dist/redirects.d.ts +115 -0
  32. package/dist/redirects.js +223 -0
  33. package/dist/serialize.d.ts +14 -1
  34. package/dist/serialize.js +821 -254
  35. package/dist/sitemap.d.ts +107 -0
  36. package/dist/sitemap.js +126 -0
  37. package/dist/taxonomy.d.ts +48 -2
  38. package/dist/taxonomy.js +46 -12
  39. package/dist/theme-css.d.ts +33 -0
  40. package/dist/theme-css.js +683 -0
  41. package/dist/tone-classes.d.ts +52 -0
  42. package/dist/tone-classes.js +84 -0
  43. package/dist/write-if-changed.d.ts +20 -0
  44. package/dist/write-if-changed.js +57 -0
  45. package/package.json +16 -7
  46. package/dist/base-path.d.ts.map +0 -1
  47. package/dist/base-path.js.map +0 -1
  48. package/dist/cli.d.ts.map +0 -1
  49. package/dist/cli.js.map +0 -1
  50. package/dist/index.d.ts.map +0 -1
  51. package/dist/index.js.map +0 -1
  52. package/dist/lead.d.ts.map +0 -1
  53. package/dist/lead.js.map +0 -1
  54. package/dist/llms-txt.d.ts.map +0 -1
  55. package/dist/llms-txt.js.map +0 -1
  56. package/dist/plugins.d.ts.map +0 -1
  57. package/dist/plugins.js.map +0 -1
  58. package/dist/project.d.ts.map +0 -1
  59. package/dist/project.js.map +0 -1
  60. package/dist/serialize.d.ts.map +0 -1
  61. package/dist/serialize.js.map +0 -1
  62. package/dist/taxonomy.d.ts.map +0 -1
  63. package/dist/taxonomy.js.map +0 -1
@@ -0,0 +1,107 @@
1
+ /**
2
+ * Sitemap builders — sitemaps.org 0.9 format.
3
+ *
4
+ * Pure functions: take pages + siteUrl + basePath, return strings.
5
+ * Output goes to `public/<basePath>/sitemap-{index,0}.xml` so
6
+ * multi-mount deploys don't collide at the host root (the same
7
+ * per-mount layout we use for `llms.txt`).
8
+ *
9
+ * `@astrojs/sitemap` was the historical generator, but it
10
+ * hard-codes output to `dist/` root with no scoping option, which
11
+ * breaks the `acme.com/docs/` + `acme.com/api/` shared-host case.
12
+ * This module replaces it.
13
+ */
14
+ import type { ExportPage } from "@dogsbay/types";
15
+ export { assertLeafSitemap } from "@dogsbay/site-files";
16
+ export interface BuildSitemapOptions {
17
+ /**
18
+ * Required. Origin of the deployed site (`https://acme.example`)
19
+ * — used to make `<loc>` entries absolute. Path component is
20
+ * ignored; pass the origin only.
21
+ */
22
+ siteUrl: string;
23
+ /**
24
+ * Mount prefix (`/docs`, `/api`, `""` for host root). Page slugs
25
+ * are joined under this so `<loc>` matches the actual URL.
26
+ */
27
+ basePath: string;
28
+ /**
29
+ * Site-level noindex lockdown. When true, the sitemap emits its
30
+ * `<urlset>` wrapper with zero entries — there's no point
31
+ * advertising URLs we're also telling crawlers to skip via
32
+ * meta-robots. Keeps the file present so per-mount discovery /
33
+ * llms.txt references don't 404.
34
+ */
35
+ siteNoindex?: boolean;
36
+ /**
37
+ * Leaf sitemap URLs from other sites on this host to list in the
38
+ * index alongside our own. See `AggregateSource` in `@dogsbay/cli`.
39
+ *
40
+ * Must be `<urlset>` documents, not other indexes — the sitemaps.org
41
+ * protocol forbids nesting index files. `buildSitemapIndex` cannot
42
+ * fetch them to check, so the caller validates; see
43
+ * `assertLeafSitemap`.
44
+ */
45
+ extraSitemaps?: string[];
46
+ /** How many `sitemap-N.xml` files this site wrote (`buildSitemapFiles`). Default 1. */
47
+ sitemapCount?: number;
48
+ }
49
+ /**
50
+ * Build `<basePath>/sitemap-0.xml` — one `<url>` per non-excluded
51
+ * page.
52
+ *
53
+ * Filters:
54
+ * - frontmatter.noindex === true (matches @astrojs/sitemap)
55
+ * - frontmatter.draft === true (drafts shouldn't be indexed)
56
+ * - page.redirect set (redirect pages aren't real URLs)
57
+ *
58
+ * `<lastmod>` is read from frontmatter.lastUpdated, then
59
+ * frontmatter.lastmod. Omitted (rather than fabricated) when
60
+ * neither is present — fabricated mtimes churn the sitemap on
61
+ * every build and waste crawler budget.
62
+ */
63
+ export declare function buildSitemap(pages: ExportPage[], options: BuildSitemapOptions): string;
64
+ /**
65
+ * The sitemap files for the site: `sitemap-0.xml`, and more past the
66
+ * 50,000 URLs one file may hold. Pass their count to
67
+ * `buildSitemapIndex` as `sitemapCount`.
68
+ */
69
+ export declare function buildSitemapFiles(pages: ExportPage[], options: BuildSitemapOptions): [string, string][];
70
+ /**
71
+ * Build `<basePath>/sitemap-index.xml`: this site's sitemap files, then
72
+ * the aggregated leaf sitemaps of other sites on the host.
73
+ */
74
+ export declare function buildSitemapIndex(options: BuildSitemapOptions): string;
75
+ /**
76
+ * Compose a page's URL path under the mount prefix. The slug
77
+ * "index" / "" maps to the mount root. A nested `<section>/index`
78
+ * slug maps to `<section>/` (with trailing slash) — same shape
79
+ * Astro serves: `dist/foo/index.html` is reached at `/foo/`, not
80
+ * `/foo/index`. Without this normalisation the sitemap emitted
81
+ * `/foo/index` while the actual URL was `/foo/`, and the
82
+ * `seo/sitemap-complete` audit then flagged every section index
83
+ * as missing.
84
+ *
85
+ * ALWAYS ends in a trailing slash. It used to omit the slash for
86
+ * ordinary pages while adding it for `/index` ones, so a sitemap
87
+ * disagreed with itself AND with the canonical every layout emits.
88
+ * Measured on the live blog before the fix:
89
+ *
90
+ * sitemap /blog/migrating-asciidoc-to-markdown -> 307
91
+ * canonical /blog/migrating-asciidoc-to-markdown/ -> 200
92
+ *
93
+ * Every URL in every generated sitemap redirected. Google follows the
94
+ * redirect and indexes the canonical, so nothing was broken for
95
+ * readers — it burns crawl budget and reports "Page with redirect"
96
+ * against every URL in Search Console.
97
+ *
98
+ * The slash is correct because Astro's default `build.format` is
99
+ * `"directory"`: a page is emitted as `slug/index.html` and served at
100
+ * `slug/`. Neither the scaffold nor any generated config sets
101
+ * `build.format` or `trailingSlash`, so the default holds everywhere.
102
+ * If `build.format: "file"` is ever supported this must become
103
+ * conditional; the tests pin the coupling so it cannot pass silently.
104
+ */
105
+ export declare function pageHref(slug: string | undefined, prefix: string): string;
106
+ export declare function normalizePrefix(basePath: string | undefined): string;
107
+ export declare function originOf(siteUrl: string): string;
@@ -0,0 +1,126 @@
1
+ import { buildSitemapIndex as buildSitemapIndexXml, buildSitemaps, buildUrlset, lastmodOf, } from "@dogsbay/site-files";
2
+ export { assertLeafSitemap } from "@dogsbay/site-files";
3
+ /**
4
+ * Build `<basePath>/sitemap-0.xml` — one `<url>` per non-excluded
5
+ * page.
6
+ *
7
+ * Filters:
8
+ * - frontmatter.noindex === true (matches @astrojs/sitemap)
9
+ * - frontmatter.draft === true (drafts shouldn't be indexed)
10
+ * - page.redirect set (redirect pages aren't real URLs)
11
+ *
12
+ * `<lastmod>` is read from frontmatter.lastUpdated, then
13
+ * frontmatter.lastmod. Omitted (rather than fabricated) when
14
+ * neither is present — fabricated mtimes churn the sitemap on
15
+ * every build and waste crawler budget.
16
+ */
17
+ export function buildSitemap(pages, options) {
18
+ return buildUrlset(sitemapEntries(pages, options));
19
+ }
20
+ /**
21
+ * The sitemap files for the site: `sitemap-0.xml`, and more past the
22
+ * 50,000 URLs one file may hold. Pass their count to
23
+ * `buildSitemapIndex` as `sitemapCount`.
24
+ */
25
+ export function buildSitemapFiles(pages, options) {
26
+ return buildSitemaps(sitemapEntries(pages, options));
27
+ }
28
+ function sitemapEntries(pages, options) {
29
+ // Site-level noindex: the file stays (the index and robots.txt point
30
+ // at it), with no entries.
31
+ if (options.siteNoindex)
32
+ return [];
33
+ const origin = stripTrailingSlash(originOf(options.siteUrl));
34
+ const prefix = normalizePrefix(options.basePath);
35
+ const entries = [];
36
+ for (const page of pages) {
37
+ if (isExcluded(page))
38
+ continue;
39
+ const lastmod = pageLastmod(page);
40
+ entries.push({ loc: `${origin}${pageHref(page.slug, prefix)}`, ...(lastmod ? { lastmod } : {}) });
41
+ }
42
+ return entries;
43
+ }
44
+ /**
45
+ * Build `<basePath>/sitemap-index.xml`: this site's sitemap files, then
46
+ * the aggregated leaf sitemaps of other sites on the host.
47
+ */
48
+ export function buildSitemapIndex(options) {
49
+ const origin = stripTrailingSlash(originOf(options.siteUrl));
50
+ const prefix = normalizePrefix(options.basePath);
51
+ const ours = Array.from({ length: Math.max(1, options.sitemapCount ?? 1) }, (_, i) => `${origin}${prefix}/sitemap-${i}.xml`);
52
+ return buildSitemapIndexXml(ours, options.extraSitemaps ?? []);
53
+ }
54
+ // ── Internals ────────────────────────────────────────────────────
55
+ function isExcluded(page) {
56
+ const fm = page.frontmatter ?? {};
57
+ if (fm["noindex"] === true)
58
+ return true;
59
+ if (fm["draft"] === true)
60
+ return true;
61
+ if (page.redirect && typeof page.redirect === "string")
62
+ return true;
63
+ return false;
64
+ }
65
+ function pageLastmod(page) {
66
+ // Modification fields first, then creation: a post that was never
67
+ // edited has only a creation date (blog posts carry `created`), and
68
+ // no <lastmod> at all tells a crawler less than the publish date.
69
+ return lastmodOf(page.frontmatter ?? {}) ?? null;
70
+ }
71
+ /**
72
+ * Compose a page's URL path under the mount prefix. The slug
73
+ * "index" / "" maps to the mount root. A nested `<section>/index`
74
+ * slug maps to `<section>/` (with trailing slash) — same shape
75
+ * Astro serves: `dist/foo/index.html` is reached at `/foo/`, not
76
+ * `/foo/index`. Without this normalisation the sitemap emitted
77
+ * `/foo/index` while the actual URL was `/foo/`, and the
78
+ * `seo/sitemap-complete` audit then flagged every section index
79
+ * as missing.
80
+ *
81
+ * ALWAYS ends in a trailing slash. It used to omit the slash for
82
+ * ordinary pages while adding it for `/index` ones, so a sitemap
83
+ * disagreed with itself AND with the canonical every layout emits.
84
+ * Measured on the live blog before the fix:
85
+ *
86
+ * sitemap /blog/migrating-asciidoc-to-markdown -> 307
87
+ * canonical /blog/migrating-asciidoc-to-markdown/ -> 200
88
+ *
89
+ * Every URL in every generated sitemap redirected. Google follows the
90
+ * redirect and indexes the canonical, so nothing was broken for
91
+ * readers — it burns crawl budget and reports "Page with redirect"
92
+ * against every URL in Search Console.
93
+ *
94
+ * The slash is correct because Astro's default `build.format` is
95
+ * `"directory"`: a page is emitted as `slug/index.html` and served at
96
+ * `slug/`. Neither the scaffold nor any generated config sets
97
+ * `build.format` or `trailingSlash`, so the default holds everywhere.
98
+ * If `build.format: "file"` is ever supported this must become
99
+ * conditional; the tests pin the coupling so it cannot pass silently.
100
+ */
101
+ export function pageHref(slug, prefix) {
102
+ let clean = (slug ?? "").replace(/^\/+|\/+$/g, "");
103
+ if (!clean || clean === "index")
104
+ return prefix ? `${prefix}/` : "/";
105
+ if (clean.endsWith("/index"))
106
+ clean = clean.slice(0, -"/index".length);
107
+ return `${prefix}/${clean}/`;
108
+ }
109
+ export function normalizePrefix(basePath) {
110
+ if (!basePath)
111
+ return "";
112
+ const trimmed = basePath.replace(/\/+$/, "");
113
+ return trimmed.startsWith("/") ? trimmed : `/${trimmed}`;
114
+ }
115
+ export function originOf(siteUrl) {
116
+ try {
117
+ const u = new URL(siteUrl);
118
+ return `${u.protocol}//${u.host}`;
119
+ }
120
+ catch {
121
+ return siteUrl;
122
+ }
123
+ }
124
+ function stripTrailingSlash(s) {
125
+ return s.replace(/\/+$/, "");
126
+ }
@@ -1,4 +1,4 @@
1
- import type { ExportPage } from "@dogsbay/types";
1
+ import type { ExportPage, TreeNode } from "@dogsbay/types";
2
2
  /** Per-taxonomy emit config — resolved (defaults filled). */
3
3
  export interface TaxonomyEmitConfig {
4
4
  /** Path prefix for emitted index/term pages, e.g. "/tags". */
@@ -68,6 +68,29 @@ export interface TaxonomyData {
68
68
  * name to the right `PageMeta` slot.
69
69
  */
70
70
  export declare function getPageTerms(page: ExportPage, taxonomy: string): string[];
71
+ /**
72
+ * Derive a short description for one page, used to populate
73
+ * `TaxonomyPageRef.description` on the term data file. Card layouts
74
+ * in `<TaxonomyTerm>` consume this — title-only cards read as
75
+ * empty, so a working fallback matters.
76
+ *
77
+ * Resolution order:
78
+ * 1. `frontmatter.description` (string) when set — explicit
79
+ * author-supplied summary always wins.
80
+ * 2. First paragraph of `page.tree`, plain-text-extracted and
81
+ * truncated to {@link DESCRIPTION_LIMIT}. Skips headings so the
82
+ * page title doesn't echo as the description.
83
+ * 3. `undefined` — caller omits the field, card renders title-only.
84
+ */
85
+ export declare function derivePageDescription(page: ExportPage): string | undefined;
86
+ /**
87
+ * Pull plain text from a TreeNode. Tolerates both shapes used by
88
+ * importers:
89
+ * - `node.inline` array (dogsbay-md parser).
90
+ * - `node.children[{type: "prose", inline: ...}]` (Starlight).
91
+ * - `node.html` prerendered HTML (fallback — strips tags).
92
+ */
93
+ export declare function textOfNode(node: TreeNode): string;
71
94
  /**
72
95
  * Build the taxonomy data structure for one taxonomy across all pages.
73
96
  * Pure function. Test-friendly. Sorts terms alphabetically by full
@@ -75,7 +98,25 @@ export declare function getPageTerms(page: ExportPage, taxonomy: string): string
75
98
  */
76
99
  export declare function buildTaxonomyData(pages: ExportPage[], taxonomy: string, config: TaxonomyEmitConfig, options?: {
77
100
  section?: string;
101
+ /**
102
+ * Dogsbay basePath — drives FILESYSTEM layout via `data.basePath`
103
+ * (route files live at `src/pages/<basePath>/<indexPath>/...`).
104
+ */
78
105
  basePath?: string;
106
+ /**
107
+ * URL prefix that all hrefs inside `data` (page URLs, indexPath
108
+ * baked for chip composition, term hrefs) carry. Should be the
109
+ * combined prefix (urlBase from site.url's path + basePath) so
110
+ * URLs resolve correctly on subpath-mounted deploys. When
111
+ * omitted, defaults to `basePath` for back-compat (single-site
112
+ * deploys without a urlBase). Without this split, callers that
113
+ * pass `combined` as the only basePath blow up the filesystem
114
+ * layout into `src/pages/<urlBase>/<basePath>/<indexPath>/...`,
115
+ * which then double-prefixes once Astro's `base` config kicks
116
+ * in at request time. Same family as the section-llms.txt fix
117
+ * (commit 47db909).
118
+ */
119
+ urlPrefix?: string;
79
120
  }): TaxonomyData;
80
121
  /**
81
122
  * Emit route files + data file for one taxonomy.
@@ -95,6 +136,11 @@ export declare function emitTaxonomyForName(data: TaxonomyData, outputDir: strin
95
136
  */
96
137
  export declare function emitTaxonomyRoutes(pages: ExportPage[], outputDir: string, taxonomies: Record<string, TaxonomyEmitConfig>, options?: {
97
138
  section?: string;
139
+ /** Dogsbay basePath — filesystem layout under src/pages/. */
98
140
  basePath?: string;
141
+ /**
142
+ * Combined URL prefix (urlBase + basePath) baked into URLs in
143
+ * emitted data. Defaults to `basePath` when omitted.
144
+ */
145
+ urlPrefix?: string;
99
146
  }): string[];
100
- //# sourceMappingURL=taxonomy.d.ts.map
package/dist/taxonomy.js CHANGED
@@ -25,7 +25,9 @@
25
25
  *
26
26
  * See plans/metadata-and-taxonomies.md.
27
27
  */
28
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
28
+ import { existsSync, mkdirSync, readFileSync } from "node:fs";
29
+ // Unchanged files are not rewritten, so `site dev` reloads only what changed
30
+ import { writeFileSync } from "./write-if-changed.js";
29
31
  import { dirname, join } from "node:path";
30
32
  import { joinBaseUrl, normalizeBasePath, withBasePath, basePathSegments } from "./base-path.js";
31
33
  /** Cap on description length emitted into taxonomy data. */
@@ -75,7 +77,7 @@ function pageUrl(slug, section, basePath) {
75
77
  * page title doesn't echo as the description.
76
78
  * 3. `undefined` — caller omits the field, card renders title-only.
77
79
  */
78
- function derivePageDescription(page) {
80
+ export function derivePageDescription(page) {
79
81
  const fm = page.frontmatter;
80
82
  const fmDesc = fm?.description;
81
83
  if (typeof fmDesc === "string" && fmDesc.trim().length > 0) {
@@ -106,7 +108,7 @@ function findFirstParagraph(nodes) {
106
108
  * - `node.children[{type: "prose", inline: ...}]` (Starlight).
107
109
  * - `node.html` prerendered HTML (fallback — strips tags).
108
110
  */
109
- function textOfNode(node) {
111
+ export function textOfNode(node) {
110
112
  const parts = [];
111
113
  if (Array.isArray(node.inline)) {
112
114
  parts.push(textOfInline(node.inline));
@@ -173,6 +175,9 @@ export function buildTaxonomyData(pages, taxonomy, config, options = {}) {
173
175
  // Map a path key (joined by "/") → term entry under construction
174
176
  const termMap = new Map();
175
177
  const basePath = normalizeBasePath(options.basePath);
178
+ const urlPrefix = options.urlPrefix !== undefined
179
+ ? normalizeBasePath(options.urlPrefix)
180
+ : basePath;
176
181
  for (const page of pages) {
177
182
  const terms = getPageTerms(page, taxonomy);
178
183
  if (terms.length === 0)
@@ -181,7 +186,10 @@ export function buildTaxonomyData(pages, taxonomy, config, options = {}) {
181
186
  const ref = {
182
187
  slug: page.slug,
183
188
  title: page.title,
184
- url: pageUrl(page.slug, options.section, basePath),
189
+ // URLs go through urlPrefix (combined) so chip links resolve
190
+ // under subpath-mounted deploys. Filesystem layout uses
191
+ // basePath alone — split via `data.basePath` below.
192
+ url: pageUrl(page.slug, options.section, urlPrefix),
185
193
  ...(description ? { description } : {}),
186
194
  };
187
195
  // Track which path keys this page has already contributed to so a
@@ -219,15 +227,15 @@ export function buildTaxonomyData(pages, taxonomy, config, options = {}) {
219
227
  allTerms.sort((a, b) => a.fullPath.join("/").localeCompare(b.fullPath.join("/")));
220
228
  // `data.indexPath` is the URL-bearing form — components compose
221
229
  // hrefs as `${data.indexPath}/${term}/`, so it has to include
222
- // basePath here. Without this, taxonomy chip strips, breadcrumbs,
223
- // sub-tag pills, and the type/status badge hrefs all 404 on any
224
- // site with `site.basePath` set. The route-file location (computed
225
- // separately in `emitTaxonomyForName` from `config.indexPath`)
226
- // still uses the raw form so Astro's `base` config handles the
227
- // file-system → URL mapping.
230
+ // the combined URL prefix here (urlBase + basePath). Without
231
+ // urlBase, chip strips / breadcrumbs / sub-tag pills 404 on
232
+ // subpath-mounted deploys; without basePath, they 404 on sites
233
+ // with `site.basePath` set. `data.basePath` carries the
234
+ // basePath-only form for the file-system layout step in
235
+ // `emitTaxonomyForName`.
228
236
  return {
229
237
  name: taxonomy,
230
- indexPath: withBasePath(basePath, config.indexPath),
238
+ indexPath: withBasePath(urlPrefix, config.indexPath),
231
239
  basePath,
232
240
  hierarchical: config.hierarchical,
233
241
  terms: allTerms,
@@ -356,6 +364,21 @@ export function emitTaxonomyRoutes(pages, outputDir, taxonomies, options = {}) {
356
364
  // Writers who want a custom shell (different layout, no sidebar) can
357
365
  // drop their own `src/pages<indexPath>/{index,[...path]}.astro` —
358
366
  // `emitTaxonomyForName` skips emission when those files exist.
367
+ /**
368
+ * The prefix the host actually serves this site under, recovered from
369
+ * the urlPrefix-composed `indexPath`.
370
+ *
371
+ * DocsLayout builds the llms.txt link, the sitemap fallback and the
372
+ * switcher hrefs from its `basePath` prop. Taxonomy routes never passed
373
+ * one, so on a sub-path-mounted site those came out as `/llms.txt` and
374
+ * `/sitemap-index.xml` — outside the mount, 404 for every one of them.
375
+ */
376
+ function servingPrefix(data, config) {
377
+ const suffix = normalizeBasePath(config.indexPath);
378
+ return suffix && data.indexPath.endsWith(suffix)
379
+ ? data.indexPath.slice(0, data.indexPath.length - suffix.length)
380
+ : "";
381
+ }
359
382
  function buildIndexAstro(data, config, routeSegments) {
360
383
  const dataImport = dataImportPath(routeSegments, data);
361
384
  const title = displayName(data.name);
@@ -372,11 +395,13 @@ import data from "${dataImport}";
372
395
  import navData from "@/data/nav.json";
373
396
  import siteConfigData from "@/data/site.json";
374
397
  const siteConfig = siteConfigData as SiteConfig;
398
+ const favicon = (siteConfigData as { favicon?: string }).favicon;
375
399
  const title = ${JSON.stringify(title)};
376
400
  ${displayConfig}
377
401
  ---
378
402
  <DocsLayout
379
403
  siteName={siteConfig.siteName}
404
+ siteTagline={siteConfig.tagline}
380
405
  title={title}
381
406
  nav={navData as any[]}
382
407
  headings={[]}
@@ -386,12 +411,16 @@ ${displayConfig}
386
411
  twitterHandle={siteConfig.twitterHandle || undefined}
387
412
  themeColor={siteConfig.themeColor || undefined}
388
413
  repoUrl={siteConfig.repoUrl || undefined}
414
+ poweredBy={siteConfig.poweredBy !== false}
389
415
  plausibleDomain={siteConfig.plausible?.domain}
390
416
  plausibleScriptUrl={siteConfig.plausible?.scriptUrl}
391
417
  tagPrefixes={siteConfig.tagPrefixes}
392
418
  tagLabels={siteConfig.tagLabels}
419
+ tagAutoColor={siteConfig.tagAutoColor}
393
420
  taxonomyIndexPaths={siteConfig.taxonomyIndexPaths}
394
421
  taxonomyDisplay={siteConfig.taxonomyDisplay}
422
+ favicon={favicon}
423
+ basePath={${JSON.stringify(servingPrefix(data, config))}}
395
424
  noindex={true}
396
425
  excludeFromSearch={true}
397
426
  >
@@ -415,6 +444,7 @@ import data from "${dataImport}";
415
444
  import navData from "@/data/nav.json";
416
445
  import siteConfigData from "@/data/site.json";
417
446
  const siteConfig = siteConfigData as SiteConfig;
447
+ const favicon = (siteConfigData as { favicon?: string }).favicon;
418
448
 
419
449
  export async function getStaticPaths() {
420
450
  return data.terms.map((term) => ({
@@ -429,6 +459,7 @@ const title = \`\${term.label} — ${escapeTemplate(taxonomyDisplay)}\`;
429
459
  ---
430
460
  <DocsLayout
431
461
  siteName={siteConfig.siteName}
462
+ siteTagline={siteConfig.tagline}
432
463
  title={title}
433
464
  nav={navData as any[]}
434
465
  headings={[]}
@@ -438,12 +469,16 @@ const title = \`\${term.label} — ${escapeTemplate(taxonomyDisplay)}\`;
438
469
  twitterHandle={siteConfig.twitterHandle || undefined}
439
470
  themeColor={siteConfig.themeColor || undefined}
440
471
  repoUrl={siteConfig.repoUrl || undefined}
472
+ poweredBy={siteConfig.poweredBy !== false}
441
473
  plausibleDomain={siteConfig.plausible?.domain}
442
474
  plausibleScriptUrl={siteConfig.plausible?.scriptUrl}
443
475
  tagPrefixes={siteConfig.tagPrefixes}
444
476
  tagLabels={siteConfig.tagLabels}
477
+ tagAutoColor={siteConfig.tagAutoColor}
445
478
  taxonomyIndexPaths={siteConfig.taxonomyIndexPaths}
446
479
  taxonomyDisplay={siteConfig.taxonomyDisplay}
480
+ favicon={favicon}
481
+ basePath={${JSON.stringify(servingPrefix(data, config))}}
447
482
  noindex={true}
448
483
  excludeFromSearch={true}
449
484
  >
@@ -499,4 +534,3 @@ function escapeHtml(s) {
499
534
  .replace(/>/g, "&gt;")
500
535
  .replace(/"/g, "&quot;");
501
536
  }
502
- //# sourceMappingURL=taxonomy.js.map
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Build the `@source inline("...")` directive that pins the
3
+ * grid-tone palette into the generated stylesheet.
4
+ *
5
+ * Why we need it: tone classes like `bg-primary/10` only appear in
6
+ * `.astro` pages emitted by Dogsbay's grid-item serializer. When
7
+ * Tailwind's content scanner doesn't pick them up — because the
8
+ * page lives outside the default scan globs, or because a class
9
+ * is composed at the boundary of an interpolation — they get
10
+ * purged. Result observed in dogsbay-docs-markdown audit: half
11
+ * the grid demo cells render with no background. Pinning forces
12
+ * generation regardless of scanner reach.
13
+ *
14
+ * Single source of truth: derived from TONE_CLASSES so any new
15
+ * tone added to the palette is automatically safelisted.
16
+ */
17
+ export declare function buildToneSafelist(): string;
18
+ /**
19
+ * The same pin for the variant, tone and theme-scope tables
20
+ * (plans/dita-variants-themes.md). A line of its own, marked ASTRO-ONLY:
21
+ * render-html copies this stylesheet, and a renderer that compiles from the
22
+ * page's own classes (render-html, dogsbay-ssg) needs no safelist — there it
23
+ * put every variant's classes on every page (scripts/sources.mjs drops it).
24
+ */
25
+ export declare function buildVariantSafelist(): string;
26
+ export declare function generateGlobalCss(): string;
27
+ /** The theme presets by name. A name not here falls back to "default", as writeThemeFile always did. */
28
+ export declare const THEMES: Record<string, {
29
+ light: string;
30
+ dark: string;
31
+ }>;
32
+ /** A site's src/styles/theme.css for a preset: the Tailwind theme mapping plus the preset's tokens. */
33
+ export declare function themeCss(themeName?: string): string;