@dogsbay/docs-layout 0.2.0-beta.113 → 0.2.0-beta.115

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dogsbay/docs-layout",
3
- "version": "0.2.0-beta.113",
3
+ "version": "0.2.0-beta.115",
4
4
  "description": "Standard documentation layout components for Dogsbay",
5
5
  "type": "module",
6
6
  "exports": {
@@ -25,13 +25,14 @@
25
25
  "./LocaleSwitcher.astro": "./src/LocaleSwitcher.astro",
26
26
  "./nav-filter": "./src/nav-filter.ts",
27
27
  "./search-facets": "./src/search-facets.ts",
28
+ "./pagefind-base-url": "./src/pagefind-base-url.ts",
28
29
  "./tag-list-data": "./src/tag-list-data.ts",
29
30
  "./llm-actions": "./src/llm-actions.ts",
30
31
  "./json-ld": "./src/json-ld.ts"
31
32
  },
32
33
  "dependencies": {
33
- "@dogsbay/primitives": "0.2.0-beta.113",
34
- "@dogsbay/ui": "0.2.0-beta.113"
34
+ "@dogsbay/primitives": "0.2.0-beta.115",
35
+ "@dogsbay/ui": "0.2.0-beta.115"
35
36
  },
36
37
  "devDependencies": {
37
38
  "happy-dom": "^20.10.6",
@@ -197,6 +197,12 @@ interface Props {
197
197
  * a non-root base path (e.g. "/docs/pagefind/").
198
198
  */
199
199
  pagefindUrl?: string;
200
+ /**
201
+ * Base Pagefind prefixes result URLs with. Forwarded to SearchDialog;
202
+ * format-astro passes the right value for the deploy layout. See
203
+ * `pagefind-base-url.ts` for why no constant works.
204
+ */
205
+ pagefindBaseUrl?: string;
200
206
  /**
201
207
  * Whether the site emits per-page `.md` mirror endpoints. When true,
202
208
  * the page advertises `<link rel="alternate" type="text/markdown">`
@@ -501,6 +507,7 @@ const {
501
507
  // Undefined here propagates to SearchDialog where the JS loader
502
508
  // throws on first open instead of silently 404'ing the bundle.
503
509
  pagefindUrl,
510
+ pagefindBaseUrl,
504
511
  mdMirror = false,
505
512
  tags,
506
513
  tagsIndexPath = "/tags",
@@ -1072,6 +1079,7 @@ const siteIcon = '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"
1072
1079
  {!hideSearch && (
1073
1080
  <SearchDialog
1074
1081
  pagefindUrl={pagefindUrl}
1082
+ pagefindBaseUrl={pagefindBaseUrl}
1075
1083
  navUrl={basePath ? `${basePath}/_dogsbay/nav.json` : "/_dogsbay/nav.json"}
1076
1084
  taxonomyDisplay={taxonomyDisplay}
1077
1085
  scopeProduct={multiSource?.namespace}
@@ -37,6 +37,15 @@ interface Props {
37
37
  * search dialog throws on first open with a clear console error.
38
38
  */
39
39
  pagefindUrl?: string;
40
+ /**
41
+ * The base Pagefind prefixes result URLs with. Pagefind's own default is
42
+ * the folder above the bundle, which is right for GitHub Pages project
43
+ * sites and doubles the prefix on Workers subpath mounts (their index
44
+ * already carries the mount). format-astro computes the right value per
45
+ * layout; when absent, Pagefind's default is left alone. See
46
+ * `pagefind-base-url.ts`.
47
+ */
48
+ pagefindBaseUrl?: string;
40
49
  /**
41
50
  * URL of the site's `nav.json` (typically `${basePath}/_dogsbay/nav.json`).
42
51
  * Used to render hierarchical facets in document order: when the
@@ -69,6 +78,7 @@ interface Props {
69
78
 
70
79
  const {
71
80
  pagefindUrl,
81
+ pagefindBaseUrl,
72
82
  navUrl,
73
83
  placeholder = "Search docs...",
74
84
  taxonomyDisplay,
@@ -80,6 +90,7 @@ const {
80
90
  <dialog
81
91
  data-search-dialog
82
92
  data-pagefind-url={pagefindUrl}
93
+ data-pagefind-base-url={pagefindBaseUrl}
83
94
  data-nav-url={navUrl}
84
95
  data-taxonomy-display={taxonomyDisplay ? JSON.stringify(taxonomyDisplay) : ""}
85
96
  data-scope-product={scopeProduct ?? ""}
@@ -201,6 +212,7 @@ const {
201
212
  type NavLike,
202
213
  type TaxonomyDisplayMap,
203
214
  } from "./search-facets.js";
215
+ import { applyPagefindBaseUrl } from "./pagefind-base-url.js";
204
216
 
205
217
  type PagefindResult = {
206
218
  id: string;
@@ -224,6 +236,7 @@ const {
224
236
  options?: { filters?: Record<string, PagefindFilterValue> },
225
237
  ): Promise<{ results: PagefindResult[] }>;
226
238
  filters(): Promise<Record<string, Record<string, number>>>;
239
+ options?(opts: { baseUrl?: string }): Promise<void>;
227
240
  };
228
241
 
229
242
  const dialog = document.querySelector<HTMLDialogElement>("[data-search-dialog]");
@@ -290,6 +303,9 @@ const {
290
303
  loadingPagefind = (async () => {
291
304
  try {
292
305
  const mod = (await import(/* @vite-ignore */ url)) as PagefindModule;
306
+ // Before the first search: result URLs are built with this base.
307
+ // Without it a Workers subpath mount links to /<mount>/<mount>/page/.
308
+ await applyPagefindBaseUrl(mod, dialog!.dataset.pagefindBaseUrl);
293
309
  pagefind = mod;
294
310
  // Discover facets once, on first load. Pagefind builds
295
311
  // this from the body-level data-pagefind-filter elements.
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Pagefind result URLs, and the base they need.
3
+ *
4
+ * Pagefind stores each page's URL relative to the directory it indexed
5
+ * (`pagefind --site dist`), then prefixes every result with `baseUrl`. When
6
+ * the caller sets none, Pagefind derives it from where the bundle was loaded:
7
+ * the folder above `pagefind/`.
8
+ *
9
+ * That default is right for one of our two subpath layouts and wrong for the
10
+ * other, measured by decoding index fragments on live sites:
11
+ *
12
+ * | Deploy | Pages built into | Stored URL | Default base | Result |
13
+ * |---|---|---|---|---|
14
+ * | Workers subpath mount | `dist/<mount>/` (nested) | `/<mount>/page/` | `/<mount>/` | `/<mount>/<mount>/page/` — 404 |
15
+ * | GitHub Pages project | `dist/` (Astro `base`) | `/page/` | `/<repo>/` | `/<repo>/page/` — correct |
16
+ *
17
+ * So no single constant works: forcing `/` fixes the Workers mount and breaks
18
+ * every GitHub Pages project site. The emitter knows which layout it built and
19
+ * passes the base explicitly; this applies it.
20
+ */
21
+
22
+ /** The slice of the Pagefind module this touches. */
23
+ export interface PagefindOptionsModule {
24
+ options?: (opts: { baseUrl?: string }) => Promise<void> | void;
25
+ }
26
+
27
+ /**
28
+ * The base Pagefind should prefix results with: the served path that the
29
+ * INDEXED directory maps to.
30
+ *
31
+ * - Workers subpath mount — pages are built INTO `dist/<mount>/`, so the
32
+ * index already carries the mount in every URL: `/`.
33
+ * - Anything else — pages sit at the `dist/` root and Astro's `base` (the
34
+ * site.url path) is added at serve time, so that is the missing prefix:
35
+ * `<urlBase>/`, or `/` at the host root.
36
+ *
37
+ * Note `basePath` (dogsbay's own prefix) is never part of it: pages are
38
+ * physically written under it, so the index already contains it.
39
+ */
40
+ export function pagefindBaseUrl(urlBase: string, nestedOutDir: boolean): string {
41
+ if (nestedOutDir) return "/";
42
+ const base = urlBase.replace(/\/+$/, "");
43
+ return base ? `${base}/` : "/";
44
+ }
45
+
46
+ /**
47
+ * Apply an emitted base to a loaded Pagefind module. A missing base (a page
48
+ * emitted before the base was passed) leaves Pagefind's own default, so an
49
+ * un-rebuilt site behaves exactly as before rather than changing under it.
50
+ */
51
+ export async function applyPagefindBaseUrl(
52
+ mod: PagefindOptionsModule,
53
+ baseUrl: string | undefined,
54
+ ): Promise<boolean> {
55
+ if (!baseUrl) return false;
56
+ if (typeof mod.options !== "function") return false;
57
+ await mod.options({ baseUrl });
58
+ return true;
59
+ }