blume 2.0.2 → 2.0.3
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/CHANGELOG.md +65 -0
- package/dist/cli/{chunk-6k4ftwze.js → chunk-1d7ve1dm.js} +1 -1
- package/dist/cli/{chunk-zp79m0ts.js → chunk-2eytanqx.js} +2 -2
- package/dist/cli/{chunk-8g8ytmgx.js → chunk-2hsdwb9n.js} +19 -19
- package/dist/cli/{chunk-8g8ytmgx.js.map → chunk-2hsdwb9n.js.map} +1 -1
- package/dist/cli/{chunk-g698a744.js → chunk-2z928egk.js} +5 -5
- package/dist/cli/{chunk-ppzjqwx2.js → chunk-35d4wj9f.js} +17 -18
- package/dist/cli/{chunk-ppzjqwx2.js.map → chunk-35d4wj9f.js.map} +3 -3
- package/dist/cli/{chunk-mqc662a6.js → chunk-364znk6q.js} +2 -2
- package/dist/cli/{chunk-gs7r695n.js → chunk-3em5wd2y.js} +21 -8
- package/dist/cli/{chunk-gs7r695n.js.map → chunk-3em5wd2y.js.map} +3 -3
- package/dist/cli/{chunk-k7pj68a8.js → chunk-5f86nr5m.js} +15 -15
- package/dist/cli/{chunk-hr8ne106.js → chunk-5m5nmvyq.js} +68 -43
- package/dist/cli/chunk-5m5nmvyq.js.map +13 -0
- package/dist/cli/{chunk-91ws1n6j.js → chunk-5xvm6tfj.js} +14 -14
- package/dist/cli/{chunk-w4bxdvsa.js → chunk-6dsbexzp.js} +14 -14
- package/dist/cli/{chunk-00gs3wqs.js → chunk-8ktnccpt.js} +1 -1
- package/dist/cli/{chunk-j85scx15.js → chunk-9t7a85s3.js} +130 -44
- package/dist/cli/chunk-9t7a85s3.js.map +10 -0
- package/dist/cli/{chunk-bbnwccaz.js → chunk-a58773jm.js} +2 -2
- package/dist/cli/{chunk-nfcyttvj.js → chunk-acanzt5p.js} +9 -9
- package/dist/cli/{chunk-nfcyttvj.js.map → chunk-acanzt5p.js.map} +1 -1
- package/dist/cli/{chunk-wdrt2k2v.js → chunk-akbpwfxc.js} +90 -26
- package/dist/cli/chunk-akbpwfxc.js.map +10 -0
- package/dist/cli/{chunk-sqw4ekg1.js → chunk-b07cmahc.js} +2 -2
- package/dist/cli/{chunk-xh43dwgw.js → chunk-c8chx29p.js} +42 -29
- package/dist/cli/{chunk-xh43dwgw.js.map → chunk-c8chx29p.js.map} +9 -9
- package/dist/cli/{chunk-7mbqtmgb.js → chunk-crgn1q09.js} +21 -12
- package/dist/cli/chunk-crgn1q09.js.map +10 -0
- package/dist/cli/chunk-e04dxsz1.js +39 -0
- package/dist/cli/chunk-e04dxsz1.js.map +10 -0
- package/dist/cli/{chunk-4e9b9ra6.js → chunk-ey84smr6.js} +3 -3
- package/dist/cli/{chunk-d1v5rhy0.js → chunk-g4hq16wv.js} +13 -13
- package/dist/cli/{chunk-273ygyr4.js → chunk-ga0pf4aj.js} +7 -7
- package/dist/cli/{chunk-273ygyr4.js.map → chunk-ga0pf4aj.js.map} +3 -3
- package/dist/cli/{chunk-pbg5a4s3.js → chunk-hm3vjy5s.js} +64 -45
- package/dist/cli/chunk-hm3vjy5s.js.map +19 -0
- package/dist/cli/{chunk-5r8g91qn.js → chunk-j85vccga.js} +306 -107
- package/dist/cli/chunk-j85vccga.js.map +36 -0
- package/dist/cli/{chunk-n1yg3tj3.js → chunk-p3v96n38.js} +6 -6
- package/dist/cli/{chunk-n1yg3tj3.js.map → chunk-p3v96n38.js.map} +3 -3
- package/dist/cli/{chunk-7vtckvaw.js → chunk-p73c0m7w.js} +14 -14
- package/dist/cli/{chunk-7vtckvaw.js.map → chunk-p73c0m7w.js.map} +1 -1
- package/dist/cli/{chunk-qkb5a8sa.js → chunk-pehfxfta.js} +3 -3
- package/dist/cli/{chunk-v6ya5kcb.js → chunk-pv29h0wf.js} +1223 -978
- package/dist/cli/{chunk-v6ya5kcb.js.map → chunk-pv29h0wf.js.map} +47 -46
- package/dist/cli/{chunk-6dtt0zfn.js → chunk-q58y5e6a.js} +10 -10
- package/dist/cli/{chunk-6dtt0zfn.js.map → chunk-q58y5e6a.js.map} +3 -3
- package/dist/cli/{chunk-fsmrqk8a.js → chunk-r20tn01b.js} +1 -1
- package/dist/cli/{chunk-bfwp9vp6.js → chunk-r9rcc4w7.js} +7 -7
- package/dist/cli/{chunk-h7k3nq3v.js → chunk-tkacnehg.js} +2 -2
- package/dist/cli/{chunk-h2ez8dzb.js → chunk-tzmab476.js} +4 -4
- package/dist/cli/{chunk-3yce002v.js → chunk-vg9r4eb9.js} +6 -6
- package/dist/cli/{chunk-3yce002v.js.map → chunk-vg9r4eb9.js.map} +4 -4
- package/dist/cli/{chunk-hqp2ajnh.js → chunk-wrr3j9w9.js} +16 -17
- package/dist/cli/{chunk-hqp2ajnh.js.map → chunk-wrr3j9w9.js.map} +7 -7
- package/dist/cli/{chunk-ddndchfr.js → chunk-yfyb25rh.js} +38 -26
- package/dist/cli/chunk-yfyb25rh.js.map +14 -0
- package/dist/cli/index.js +20 -18
- package/dist/cli/index.js.map +3 -3
- package/dist/types/ai/link-headers.d.ts +8 -1
- package/dist/types/ai/openapi-components.d.ts +5 -2
- package/dist/types/ai/relative-links.d.ts +9 -7
- package/dist/types/ai/skills.d.ts +4 -1
- package/dist/types/ai/tar.d.ts +1 -3
- package/dist/types/analytics/index.d.ts +2 -0
- package/dist/types/analytics/one-dollar-stats.d.ts +48 -0
- package/dist/types/analytics/schema.d.ts +14 -0
- package/dist/types/astro/integration.d.ts +3 -2
- package/dist/types/core/base-path.d.ts +21 -7
- package/dist/types/core/config-input.d.ts +9 -7
- package/dist/types/core/directive-diagnostics.d.ts +12 -0
- package/dist/types/core/heading-markers.d.ts +5 -7
- package/dist/types/core/i18n.d.ts +2 -0
- package/dist/types/core/last-modified.d.ts +10 -0
- package/dist/types/core/meta.d.ts +8 -0
- package/dist/types/core/schema.d.ts +7 -0
- package/dist/types/core/sources/lower.d.ts +29 -16
- package/dist/types/core/sources/normalize.d.ts +13 -1
- package/dist/types/core/sources/watch.d.ts +12 -5
- package/dist/types/core/standard-schema.d.ts +5 -0
- package/dist/types/deploy/artifacts.d.ts +6 -4
- package/dist/types/deploy/headers.d.ts +5 -0
- package/dist/types/deploy/platforms/types.d.ts +8 -0
- package/dist/types/deploy/redirects.d.ts +24 -13
- package/dist/types/markdown/directives.d.ts +62 -0
- package/dist/types/markdown/features.d.ts +21 -0
- package/dist/types/markdown/mdast.d.ts +63 -0
- package/dist/types/openapi/asyncapi.d.ts +4 -2
- package/docs/02-deployment.mdx +4 -2
- package/docs/08-faq.mdx +1 -1
- package/docs/advanced/custom-pages.mdx +3 -3
- package/docs/cli/audit.mdx +17 -1
- package/docs/cli/evals.mdx +3 -3
- package/docs/cli/translate.mdx +3 -3
- package/docs/cli/version.mdx +1 -1
- package/docs/configuration/analytics.mdx +20 -1
- package/docs/configuration/customization.mdx +2 -0
- package/docs/configuration/search.mdx +1 -1
- package/docs/content/components.mdx +1 -1
- package/docs/content/frontmatter.mdx +1 -1
- package/docs/content/i18n.mdx +2 -0
- package/docs/content/index.mdx +4 -2
- package/docs/content/islands.mdx +1 -1
- package/docs/content/meta.mdx +3 -1
- package/docs/content/sources.mdx +1 -5
- package/docs/content/syntax.mdx +14 -0
- package/docs/content/versioning.mdx +1 -1
- package/docs/discoverability/agent-discovery.mdx +1 -1
- package/docs/discoverability/index.mdx +2 -1
- package/docs/discoverability/markdown.mdx +2 -2
- package/docs/discoverability/open-graph.mdx +5 -3
- package/docs/discoverability/rss.mdx +1 -1
- package/docs/references/asyncapi.mdx +1 -1
- package/docs/references/graphql.mdx +1 -1
- package/docs/references/openapi.mdx +5 -3
- package/package.json +1 -1
- package/skills/blume-migrate/references/fumadocs.md +1 -1
- package/skills/blume-migrate/references/nextra.md +1 -1
- package/skills/blume-migrate/scripts/mintlify-codemod.mjs +7 -2
- package/src/ai/agent-readability.ts +2 -2
- package/src/ai/ai-catalog.ts +6 -2
- package/src/ai/api/handlers.ts +2 -2
- package/src/ai/api/spec.ts +2 -2
- package/src/ai/api-catalog.ts +6 -2
- package/src/ai/changelog-markdown.ts +2 -2
- package/src/ai/link-headers.ts +14 -5
- package/src/ai/llms.ts +18 -7
- package/src/ai/mcp/discovery.ts +2 -2
- package/src/ai/mcp/query.ts +2 -2
- package/src/ai/mcp/server.ts +2 -2
- package/src/ai/openapi-components.ts +22 -6
- package/src/ai/relative-links.ts +42 -26
- package/src/ai/serializers.ts +2 -1
- package/src/ai/skills.ts +14 -1
- package/src/ai/tar.ts +139 -12
- package/src/analytics/head.ts +4 -0
- package/src/analytics/index.ts +5 -0
- package/src/analytics/one-dollar-stats.ts +86 -0
- package/src/analytics/schema.ts +2 -0
- package/src/astro/generate.ts +1 -1
- package/src/astro/include-hmr.ts +31 -12
- package/src/astro/include-refresh.ts +19 -8
- package/src/astro/integration.ts +108 -14
- package/src/astro/runtime-modules.ts +28 -13
- package/src/astro/templates.ts +81 -37
- package/src/audit/checks/links.ts +8 -1
- package/src/audit/graph.ts +3 -1
- package/src/audit/run.ts +12 -9
- package/src/audit/snapshot.ts +5 -0
- package/src/cli/args.ts +32 -0
- package/src/cli/commands/audit.ts +4 -1
- package/src/cli/commands/doctor.ts +3 -1
- package/src/cli/commands/eval.ts +19 -11
- package/src/cli/commands/translate.ts +9 -12
- package/src/cli/commands/validate.ts +3 -1
- package/src/cli/dev-lock.ts +157 -37
- package/src/cli/report-format.ts +11 -6
- package/src/components/colors.ts +19 -0
- package/src/components/content/Badge.astro +5 -3
- package/src/components/content/Component.astro +2 -2
- package/src/components/content/Tab.astro +0 -1
- package/src/components/content/Tabs.astro +4 -0
- package/src/components/content/badge-color.ts +5 -2
- package/src/components/content/base-href.ts +13 -36
- package/src/components/islands/assistant.tsx +21 -4
- package/src/components/islands/base-path.ts +47 -10
- package/src/components/islands/hooks.ts +35 -19
- package/src/components/islands/webmcp.ts +4 -2
- package/src/components/layout/Breadcrumbs.astro +5 -2
- package/src/components/layout/DiscoveryLinks.astro +9 -5
- package/src/components/layout/Header.astro +2 -2
- package/src/components/layout/LanguageSwitcher.astro +2 -2
- package/src/components/layout/NavSelector.astro +2 -2
- package/src/components/layout/NavTabMenu.astro +3 -3
- package/src/components/layout/NavTree.astro +16 -6
- package/src/components/layout/PageActions.astro +4 -3
- package/src/components/layout/PageLayout.astro +7 -6
- package/src/components/layout/Pagination.astro +3 -3
- package/src/components/layout/RootLayout.astro +5 -5
- package/src/components/layout/Search.astro +33 -13
- package/src/components/layout/VersionBanner.astro +2 -2
- package/src/components/layout/analytics-client.ts +12 -0
- package/src/components/layout/toc-active.ts +41 -0
- package/src/components/layout/toc-element.ts +8 -14
- package/src/components/openapi/ApiTagOperations.astro +2 -2
- package/src/components/openapi/AsyncApiOperation.astro +7 -4
- package/src/components/openapi/GraphqlChip.astro +2 -2
- package/src/components/openapi/Operation.astro +2 -0
- package/src/components/openapi/Playground.astro +4 -4
- package/src/components/openapi/RequestPanel.astro +5 -2
- package/src/components/openapi/SchemaTable.astro +7 -0
- package/src/components/openapi/async.ts +38 -6
- package/src/components/openapi/helpers.ts +19 -9
- package/src/components/openapi/message-composer.ts +6 -1
- package/src/components/openapi/message.ts +17 -2
- package/src/components/openapi/operation-model.ts +81 -11
- package/src/components/openapi/panel.ts +4 -2
- package/src/components/openapi/param-style.ts +181 -0
- package/src/components/openapi/playground-client.ts +73 -16
- package/src/components/openapi/request.ts +190 -26
- package/src/components/openapi/schema-tree.ts +30 -24
- package/src/components/openapi/snippets.ts +85 -6
- package/src/components/openapi/ws-client.ts +18 -2
- package/src/core/base-path.ts +62 -16
- package/src/core/config-input.ts +9 -7
- package/src/core/diagnostics.ts +2 -0
- package/src/core/directive-diagnostics.ts +99 -0
- package/src/core/frontmatter.ts +21 -18
- package/src/core/heading-markers.ts +5 -18
- package/src/core/i18n.ts +31 -3
- package/src/core/last-modified.ts +25 -3
- package/src/core/locale-links.ts +5 -1
- package/src/core/meta.ts +33 -19
- package/src/core/navigation.ts +28 -8
- package/src/core/project-graph.ts +27 -5
- package/src/core/schema.ts +24 -4
- package/src/core/sources/contentful-rich-text.ts +27 -20
- package/src/core/sources/filesystem.ts +20 -2
- package/src/core/sources/github-releases.ts +25 -6
- package/src/core/sources/lexical.ts +23 -18
- package/src/core/sources/lower.ts +201 -34
- package/src/core/sources/mdx-remote.ts +51 -16
- package/src/core/sources/normalize.ts +325 -90
- package/src/core/sources/notion.ts +52 -25
- package/src/core/sources/obsidian.ts +23 -6
- package/src/core/sources/portable-text.ts +38 -21
- package/src/core/sources/strapi-blocks.ts +20 -16
- package/src/core/sources/watch.ts +20 -7
- package/src/core/standard-schema.ts +10 -6
- package/src/core/version-cut.ts +52 -15
- package/src/deploy/artifacts.ts +27 -6
- package/src/deploy/cloudflare-negotiation.ts +4 -12
- package/src/deploy/headers.ts +8 -4
- package/src/deploy/node-headers.ts +1 -1
- package/src/deploy/platforms/cloudflare.ts +12 -3
- package/src/deploy/platforms/netlify.ts +1 -0
- package/src/deploy/platforms/node.ts +1 -0
- package/src/deploy/platforms/static.ts +1 -0
- package/src/deploy/platforms/types.ts +8 -0
- package/src/deploy/platforms/vercel.ts +1 -0
- package/src/deploy/redirects.ts +54 -18
- package/src/deploy/robots.ts +2 -2
- package/src/deploy/rss.ts +4 -3
- package/src/deploy/sitemap.ts +7 -5
- package/src/markdown/base-links.ts +34 -36
- package/src/markdown/directives.ts +242 -36
- package/src/markdown/features.ts +17 -0
- package/src/markdown/index.ts +7 -6
- package/src/markdown/mdast.ts +5 -2
- package/src/markdown/relative-links.ts +12 -4
- package/src/og/card.ts +129 -5
- package/src/og/derive.ts +41 -31
- package/src/og/index.ts +1 -0
- package/src/openapi/asyncapi.ts +4 -2
- package/src/openapi/model.ts +22 -14
- package/src/openapi/proxy.ts +63 -10
- package/src/openapi/render-mdx.ts +41 -2
- package/src/registry/eject.ts +181 -24
- package/src/search/adapters/version-scope.ts +30 -0
- package/src/search/documents.ts +67 -26
- package/src/search/popular.ts +2 -1
- package/src/seo/jsonld.ts +7 -3
- package/src/translate/meta.ts +68 -24
- package/src/translate/run.ts +3 -3
- package/src/translate/validate.ts +4 -1
- package/src/translate/work-list.ts +56 -17
- package/dist/cli/chunk-5r8g91qn.js.map +0 -34
- package/dist/cli/chunk-7mbqtmgb.js.map +0 -10
- package/dist/cli/chunk-ddndchfr.js.map +0 -14
- package/dist/cli/chunk-esh98wmb.js +0 -23
- package/dist/cli/chunk-esh98wmb.js.map +0 -10
- package/dist/cli/chunk-hr8ne106.js.map +0 -13
- package/dist/cli/chunk-j85scx15.js.map +0 -10
- package/dist/cli/chunk-pbg5a4s3.js.map +0 -19
- package/dist/cli/chunk-wdrt2k2v.js.map +0 -10
- /package/dist/cli/{chunk-6k4ftwze.js.map → chunk-1d7ve1dm.js.map} +0 -0
- /package/dist/cli/{chunk-zp79m0ts.js.map → chunk-2eytanqx.js.map} +0 -0
- /package/dist/cli/{chunk-g698a744.js.map → chunk-2z928egk.js.map} +0 -0
- /package/dist/cli/{chunk-mqc662a6.js.map → chunk-364znk6q.js.map} +0 -0
- /package/dist/cli/{chunk-k7pj68a8.js.map → chunk-5f86nr5m.js.map} +0 -0
- /package/dist/cli/{chunk-91ws1n6j.js.map → chunk-5xvm6tfj.js.map} +0 -0
- /package/dist/cli/{chunk-w4bxdvsa.js.map → chunk-6dsbexzp.js.map} +0 -0
- /package/dist/cli/{chunk-00gs3wqs.js.map → chunk-8ktnccpt.js.map} +0 -0
- /package/dist/cli/{chunk-bbnwccaz.js.map → chunk-a58773jm.js.map} +0 -0
- /package/dist/cli/{chunk-sqw4ekg1.js.map → chunk-b07cmahc.js.map} +0 -0
- /package/dist/cli/{chunk-4e9b9ra6.js.map → chunk-ey84smr6.js.map} +0 -0
- /package/dist/cli/{chunk-d1v5rhy0.js.map → chunk-g4hq16wv.js.map} +0 -0
- /package/dist/cli/{chunk-qkb5a8sa.js.map → chunk-pehfxfta.js.map} +0 -0
- /package/dist/cli/{chunk-fsmrqk8a.js.map → chunk-r20tn01b.js.map} +0 -0
- /package/dist/cli/{chunk-bfwp9vp6.js.map → chunk-r9rcc4w7.js.map} +0 -0
- /package/dist/cli/{chunk-h7k3nq3v.js.map → chunk-tkacnehg.js.map} +0 -0
- /package/dist/cli/{chunk-h2ez8dzb.js.map → chunk-tzmab476.js.map} +0 -0
|
@@ -13,20 +13,50 @@ export const withTrailingSlash = (base: string): string =>
|
|
|
13
13
|
export const joinBase = (base: string, path: string): string =>
|
|
14
14
|
`${withTrailingSlash(base)}${path}`;
|
|
15
15
|
|
|
16
|
+
/** A root-relative internal target (`/x`) — never `//host` or a URL. */
|
|
17
|
+
const isRootRelative = (route: string): boolean =>
|
|
18
|
+
route.startsWith("/") && !route.startsWith("//");
|
|
19
|
+
|
|
20
|
+
/** A target's path, without its `?query` or `#fragment`. */
|
|
21
|
+
const pathOf = (route: string): string => {
|
|
22
|
+
const at = route.search(/[#?]/u);
|
|
23
|
+
return at === -1 ? route : route.slice(0, at);
|
|
24
|
+
};
|
|
25
|
+
|
|
16
26
|
/**
|
|
17
|
-
* Prefix a root-relative internal
|
|
18
|
-
* (`/guide` under base `/sub` -> `/sub/guide`), so
|
|
27
|
+
* Prefix a root-relative internal link an author wrote with the deployment
|
|
28
|
+
* base (`/guide` under base `/sub` -> `/sub/guide`), so it points at the
|
|
19
29
|
* page's real served URL. External URLs, protocol-relative URLs, and fragments
|
|
20
|
-
* pass through untouched, and it's idempotent
|
|
21
|
-
*
|
|
22
|
-
*
|
|
30
|
+
* pass through untouched, and it's idempotent: a link whose path is already
|
|
31
|
+
* under the base (`/sub/guide`, `/sub#install`) is returned unchanged, so a
|
|
32
|
+
* base written by hand isn't doubled. A route Blume generates takes
|
|
33
|
+
* {@link mountBase} instead. This is applied only where a URL is *emitted* —
|
|
34
|
+
* the navigation model and active-route matching stay in base-less logical
|
|
35
|
+
* space.
|
|
23
36
|
*/
|
|
24
37
|
export const prefixBase = (base: string, route: string): string => {
|
|
25
|
-
if (!
|
|
38
|
+
if (!isRootRelative(route)) {
|
|
26
39
|
return route;
|
|
27
40
|
}
|
|
28
41
|
const trimmed = base.replace(/\/+$/u, "");
|
|
29
|
-
|
|
42
|
+
const path = pathOf(route);
|
|
43
|
+
if (!trimmed || path === trimmed || path.startsWith(`${trimmed}/`)) {
|
|
44
|
+
return route;
|
|
45
|
+
}
|
|
46
|
+
return route === "/" ? trimmed : `${trimmed}${route}`;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Prefix a route Blume generates (a page, a sidebar entry, a Markdown mirror,
|
|
51
|
+
* an agent artifact) with the deployment base, unconditionally. Unlike
|
|
52
|
+
* {@link prefixBase}, a route whose first segment matches the base is still
|
|
53
|
+
* prefixed: under base `/guides`, the page `guides/setup.md` is served at
|
|
54
|
+
* `/guides/guides/setup`, not at `/guides/setup`. External and
|
|
55
|
+
* protocol-relative URLs pass through untouched.
|
|
56
|
+
*/
|
|
57
|
+
export const mountBase = (base: string, route: string): string => {
|
|
58
|
+
const trimmed = base.replace(/\/+$/u, "");
|
|
59
|
+
if (!(trimmed && isRootRelative(route))) {
|
|
30
60
|
return route;
|
|
31
61
|
}
|
|
32
62
|
return route === "/" ? trimmed : `${trimmed}${route}`;
|
|
@@ -34,13 +64,20 @@ export const prefixBase = (base: string, route: string): string => {
|
|
|
34
64
|
|
|
35
65
|
/**
|
|
36
66
|
* {@link prefixBase} bound to the build-time `BASE_URL` (the resolved
|
|
37
|
-
* `deployment.base`). The ergonomic form for
|
|
38
|
-
* withBase(
|
|
39
|
-
* is bundled into the site.
|
|
67
|
+
* `deployment.base`), for links an author wrote. The ergonomic form for
|
|
68
|
+
* `.astro` templates — `href={withBase(href)}` — since `BASE_URL` is inlined
|
|
69
|
+
* by Vite wherever this module is bundled into the site.
|
|
40
70
|
*/
|
|
41
71
|
export const withBase = (route: string): string =>
|
|
42
72
|
prefixBase(import.meta.env.BASE_URL ?? "/", route);
|
|
43
73
|
|
|
74
|
+
/**
|
|
75
|
+
* {@link mountBase} bound to the build-time `BASE_URL`, for routes Blume
|
|
76
|
+
* generates: `href={withMountedBase(page.route)}`.
|
|
77
|
+
*/
|
|
78
|
+
export const withMountedBase = (route: string): string =>
|
|
79
|
+
mountBase(import.meta.env.BASE_URL ?? "/", route);
|
|
80
|
+
|
|
44
81
|
/**
|
|
45
82
|
* A pathname with the deployment base stripped (`/docs/guide` -> `/guide`),
|
|
46
83
|
* for page-context lookups against base-less document routes.
|
|
@@ -23,27 +23,29 @@ import { joinBase, stripBase } from "./base-path.ts";
|
|
|
23
23
|
|
|
24
24
|
export type { BlumeClientData } from "../../core/data.ts";
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
/**
|
|
27
|
+
* The last parsed snapshot, keyed by the script text it came from. Each page
|
|
28
|
+
* renders its own snapshot (its route and title, its locale's navigation), and
|
|
29
|
+
* a client-router navigation swaps in the new page's tag, so the cache is only
|
|
30
|
+
* reused while the tag's text is unchanged.
|
|
31
|
+
*/
|
|
32
|
+
let cached: { data: BlumeClientData; text: string } | null = null;
|
|
27
33
|
|
|
28
|
-
/** Read + parse the injected snapshot (memoized
|
|
34
|
+
/** Read + parse the current page's injected snapshot (memoized per text). */
|
|
29
35
|
const readClientData = (): BlumeClientData | null => {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
}
|
|
33
|
-
// `document` is undeclared on the server; probing `globalThis` avoids both
|
|
34
|
-
// the bare-reference ReferenceError and a `typeof` sniff.
|
|
35
|
-
if (!("document" in globalThis)) {
|
|
36
|
+
const text = document.querySelector("#blume-client-data")?.textContent;
|
|
37
|
+
if (!text) {
|
|
36
38
|
return null;
|
|
37
39
|
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
return null;
|
|
40
|
+
if (cached?.text === text) {
|
|
41
|
+
return cached.data;
|
|
41
42
|
}
|
|
42
43
|
try {
|
|
43
44
|
// SAFETY: the layout serialized this script tag's JSON from the same
|
|
44
45
|
// `BlumeClientData` snapshot this reads back.
|
|
45
|
-
|
|
46
|
-
|
|
46
|
+
const data = JSON.parse(text) as BlumeClientData;
|
|
47
|
+
cached = { data, text };
|
|
48
|
+
return data;
|
|
47
49
|
} catch {
|
|
48
50
|
return null;
|
|
49
51
|
}
|
|
@@ -51,15 +53,29 @@ const readClientData = (): BlumeClientData | null => {
|
|
|
51
53
|
|
|
52
54
|
/**
|
|
53
55
|
* Read the injected snapshot after mount. `null` on the server and on the first
|
|
54
|
-
* client render (so hydration matches), then the data once mounted
|
|
56
|
+
* client render (so hydration matches), then the data once mounted, re-read
|
|
57
|
+
* after every client-router swap.
|
|
55
58
|
*/
|
|
56
59
|
const useClientData = (): BlumeClientData | null => {
|
|
57
60
|
const [data, setData] = useState<BlumeClientData | null>(null);
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
61
|
+
useEffect(() => {
|
|
62
|
+
// `document` is undeclared on the server; probing `globalThis` avoids both
|
|
63
|
+
// the bare-reference ReferenceError and a `typeof` sniff.
|
|
64
|
+
if (!("document" in globalThis)) {
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
const sync = () => setData(readClientData());
|
|
68
|
+
// Intentional post-mount hydration guard: `null` on the server and first
|
|
69
|
+
// client render so hydration matches, then the snapshot once mounted. The
|
|
70
|
+
// extra render is required; do not seed the initial value from the DOM.
|
|
71
|
+
// oxlint-disable-next-line react/react-compiler, react/set-state-in-effect, react-doctor/no-initialize-state -- deliberate SSR hydration guard
|
|
72
|
+
sync();
|
|
73
|
+
// An island kept across navigations (`transition:persist`) outlives the
|
|
74
|
+
// page it mounted on; the swap brings the next page's snapshot, so read
|
|
75
|
+
// it again or the hook keeps answering with the first page's data.
|
|
76
|
+
document.addEventListener("astro:after-swap", sync);
|
|
77
|
+
return () => document.removeEventListener("astro:after-swap", sync);
|
|
78
|
+
}, []);
|
|
63
79
|
return data;
|
|
64
80
|
};
|
|
65
81
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { unescape } from "html-escaper";
|
|
2
2
|
|
|
3
3
|
import type { SearchFn } from "../layout/search/types.ts";
|
|
4
|
-
import { joinBase, prefixBase } from "./base-path.ts";
|
|
4
|
+
import { joinBase, mountBase, prefixBase } from "./base-path.ts";
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* WebMCP (W3C Web Machine Learning CG): in-page tools an agentic browser can
|
|
@@ -144,7 +144,7 @@ export const buildWebMcpTools = (options: WebMcpToolOptions): WebMcpTool[] => {
|
|
|
144
144
|
hits
|
|
145
145
|
.map(
|
|
146
146
|
(hit) =>
|
|
147
|
-
`${plain(hit.title)} — ${
|
|
147
|
+
`${plain(hit.title)} — ${mountBase(options.base, hit.url)}\n${plain(hit.excerpt)}`
|
|
148
148
|
)
|
|
149
149
|
.join("\n\n")
|
|
150
150
|
);
|
|
@@ -175,6 +175,8 @@ export const buildWebMcpTools = (options: WebMcpToolOptions): WebMcpTool[] => {
|
|
|
175
175
|
}
|
|
176
176
|
const trimmed = route.length > 1 ? route.replace(/\/+$/u, "") : route;
|
|
177
177
|
const target = trimmed === "/" ? "/index" : trimmed;
|
|
178
|
+
// The agent may hand back a served URL `search_docs` returned, base
|
|
179
|
+
// included, so a path already under the base keeps it (`prefixBase`).
|
|
178
180
|
const response = await fetchFn(
|
|
179
181
|
`${prefixBase(options.base, target)}.md`
|
|
180
182
|
).catch(() => null);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
import { EN_UI } from "../../core/i18n-ui.ts";
|
|
3
3
|
import type { UIStrings } from "../../core/i18n-ui.ts";
|
|
4
|
-
import {
|
|
4
|
+
import { withMountedBase } from "../islands/base-path.ts";
|
|
5
5
|
import type { Crumb } from "./nav-utils.ts";
|
|
6
6
|
|
|
7
7
|
interface Props {
|
|
@@ -35,7 +35,10 @@ const eyebrowCrumb = crumbs.length > 1 ? crumbs[crumbs.length - 2] : null;
|
|
|
35
35
|
]}
|
|
36
36
|
>
|
|
37
37
|
{eyebrowCrumb.route ? (
|
|
38
|
-
<a
|
|
38
|
+
<a
|
|
39
|
+
class="hover:text-foreground"
|
|
40
|
+
href={withMountedBase(eyebrowCrumb.route)}
|
|
41
|
+
>
|
|
39
42
|
{eyebrowCrumb.label}
|
|
40
43
|
</a>
|
|
41
44
|
) : (
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
import type { DiscoveryHeadLinks } from "../../core/data.ts";
|
|
3
|
-
import {
|
|
3
|
+
import { withMountedBase } from "../islands/base-path.ts";
|
|
4
4
|
// Emits the agent-discovery <link>s for the document <head>, on every page and
|
|
5
5
|
// not just the root: an agent that enters on a deep page (a search result, a
|
|
6
6
|
// shared link) never sees the homepage HTTP `Link` header (see
|
|
@@ -32,7 +32,7 @@ const { discovery, markdownMirror } = Astro.props;
|
|
|
32
32
|
{
|
|
33
33
|
discovery?.agentReadability && (
|
|
34
34
|
<link
|
|
35
|
-
href={
|
|
35
|
+
href={withMountedBase("/agent-readability.json")}
|
|
36
36
|
rel="describedby"
|
|
37
37
|
type="application/json"
|
|
38
38
|
/>
|
|
@@ -40,7 +40,11 @@ const { discovery, markdownMirror } = Astro.props;
|
|
|
40
40
|
}
|
|
41
41
|
{
|
|
42
42
|
discovery?.llmsTxt && (
|
|
43
|
-
<link
|
|
43
|
+
<link
|
|
44
|
+
href={withMountedBase("/llms.txt")}
|
|
45
|
+
rel="describedby"
|
|
46
|
+
type="text/plain"
|
|
47
|
+
/>
|
|
44
48
|
)
|
|
45
49
|
}
|
|
46
50
|
{/* The AI Catalog / ARD manifest under both relations its two specs define:
|
|
@@ -50,12 +54,12 @@ const { discovery, markdownMirror } = Astro.props;
|
|
|
50
54
|
discovery?.aiCatalog && (
|
|
51
55
|
<>
|
|
52
56
|
<link
|
|
53
|
-
href={
|
|
57
|
+
href={withMountedBase("/.well-known/ai-catalog.json")}
|
|
54
58
|
rel="ai-catalog"
|
|
55
59
|
type="application/ai-catalog+json"
|
|
56
60
|
/>
|
|
57
61
|
<link
|
|
58
|
-
href={
|
|
62
|
+
href={withMountedBase("/.well-known/ard.json")}
|
|
59
63
|
rel="ard"
|
|
60
64
|
type="application/json"
|
|
61
65
|
/>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
import Ask from "blume:ask";
|
|
3
3
|
import data from "blume:data";
|
|
4
|
-
import { withBase } from "../islands/base-path.ts";
|
|
4
|
+
import { withBase, withMountedBase } from "../islands/base-path.ts";
|
|
5
5
|
import { NEW_TAB_ATTRS, newTabAttrs } from "../../core/new-tab.ts";
|
|
6
6
|
import type { ComponentOverride } from "../../core/define-components.ts";
|
|
7
7
|
import { EN_UI } from "../../core/i18n-ui.ts";
|
|
@@ -229,7 +229,7 @@ const clickScript = `(()=>{const dr=()=>{const h=document.querySelector("[data-b
|
|
|
229
229
|
<a
|
|
230
230
|
aria-current={tab === activeTab ? "page" : undefined}
|
|
231
231
|
class="inline-flex items-center gap-1.5 rounded-full px-3 py-1.5 font-medium text-muted-foreground text-sm transition-colors hover:bg-muted hover:text-foreground aria-[current=page]:text-foreground"
|
|
232
|
-
href={
|
|
232
|
+
href={withMountedBase(tab.href ?? tab.path)}
|
|
233
233
|
>
|
|
234
234
|
{tab.icon && (
|
|
235
235
|
<Icon class="shrink-0" name={tab.icon} size={14} />
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
import {
|
|
2
|
+
import { withMountedBase } from "../islands/base-path.ts";
|
|
3
3
|
import type { LocaleSwitchOption } from "../../core/types.ts";
|
|
4
4
|
import Icon from "../Icon.astro";
|
|
5
5
|
|
|
@@ -42,7 +42,7 @@ const menuRowClass =
|
|
|
42
42
|
<a
|
|
43
43
|
aria-current={option.current ? "true" : undefined}
|
|
44
44
|
class={menuRowClass}
|
|
45
|
-
href={
|
|
45
|
+
href={withMountedBase(option.href)}
|
|
46
46
|
hreflang={option.code}
|
|
47
47
|
lang={option.code}
|
|
48
48
|
>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
import {
|
|
2
|
+
import { withMountedBase } from "../islands/base-path.ts";
|
|
3
3
|
// A top-level navigation selector: a dropdown that switches
|
|
4
4
|
// between partitions of the site — a product, a version, or any grouped set of
|
|
5
5
|
// destinations (`navigation.selectors` in the config). Built on
|
|
@@ -73,7 +73,7 @@ const menuRowClass =
|
|
|
73
73
|
<a
|
|
74
74
|
aria-current={item.path === active?.path ? "true" : undefined}
|
|
75
75
|
class={menuRowClass}
|
|
76
|
-
href={
|
|
76
|
+
href={withMountedBase(item.path)}
|
|
77
77
|
>
|
|
78
78
|
{item.icon && <Icon class="mt-0.5" name={item.icon} size={16} />}
|
|
79
79
|
<span class="flex-1">
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
// delegate from `document`, so client-router swaps need no re-init.
|
|
11
11
|
import type { NavTab } from "../../core/types.ts";
|
|
12
12
|
import Icon from "../Icon.astro";
|
|
13
|
-
import {
|
|
13
|
+
import { withMountedBase } from "../islands/base-path.ts";
|
|
14
14
|
|
|
15
15
|
interface Props {
|
|
16
16
|
tab: NavTab;
|
|
@@ -60,7 +60,7 @@ const drawerRowClass =
|
|
|
60
60
|
<a
|
|
61
61
|
aria-current={itemCurrent(item.path)}
|
|
62
62
|
class={barRowClass}
|
|
63
|
-
href={
|
|
63
|
+
href={withMountedBase(item.path)}
|
|
64
64
|
>
|
|
65
65
|
{item.icon && <Icon class="mt-0.5" name={item.icon} size={16} />}
|
|
66
66
|
<span class="flex-1">
|
|
@@ -102,7 +102,7 @@ const drawerRowClass =
|
|
|
102
102
|
<a
|
|
103
103
|
aria-current={itemCurrent(item.path)}
|
|
104
104
|
class={drawerRowClass}
|
|
105
|
-
href={
|
|
105
|
+
href={withMountedBase(item.path)}
|
|
106
106
|
>
|
|
107
107
|
{item.icon && (
|
|
108
108
|
<Icon class="shrink-0" name={item.icon} size={14} />
|
|
@@ -4,7 +4,7 @@ import type { UIStrings } from "../../core/i18n-ui.ts";
|
|
|
4
4
|
import type { NavNode } from "../../core/types.ts";
|
|
5
5
|
import { methodColor } from "../colors.ts";
|
|
6
6
|
import Icon from "../Icon.astro";
|
|
7
|
-
import { withBase } from "../islands/base-path.ts";
|
|
7
|
+
import { withBase, withMountedBase } from "../islands/base-path.ts";
|
|
8
8
|
import Self from "./NavTree.astro";
|
|
9
9
|
import NavTreeCache from "./NavTreeCache.astro";
|
|
10
10
|
import NavTreeScript from "./NavTreeScript.astro";
|
|
@@ -82,6 +82,16 @@ const n = { ...EN_UI.nav, ...strings };
|
|
|
82
82
|
/** The DOM id of a drill-in panel, which its drill button controls. */
|
|
83
83
|
const navPanelId = (id: string): string => `blume-nav-panel-${id}`;
|
|
84
84
|
|
|
85
|
+
/**
|
|
86
|
+
* A page row's href. A row backed by a page links a route Blume generates, so
|
|
87
|
+
* the deployment base always goes on — even over a route that starts with the
|
|
88
|
+
* base's own name. A config `href` link (no backing page) is authored, and
|
|
89
|
+
* keeps a base written by hand. Group rows link their index page the same way
|
|
90
|
+
* a backed page row does.
|
|
91
|
+
*/
|
|
92
|
+
const pageHref = (item: Extract<NavNode, { kind: "page" }>): string =>
|
|
93
|
+
item.pageId ? withMountedBase(item.route) : withBase(item.route);
|
|
94
|
+
|
|
85
95
|
const badgeBase =
|
|
86
96
|
"shrink-0 rounded-full px-1.5 py-0.5 font-medium text-[0.65rem] leading-none";
|
|
87
97
|
// HTTP-method, AsyncAPI-action, and GraphQL operation-kind badges (from a
|
|
@@ -191,7 +201,7 @@ const initialId =
|
|
|
191
201
|
: undefined
|
|
192
202
|
}
|
|
193
203
|
class="flex-1 truncate rounded-[0.65rem] px-1 py-1 font-semibold text-foreground text-sm transition-colors hover:bg-muted"
|
|
194
|
-
href={
|
|
204
|
+
href={withMountedBase(panel.route)}
|
|
195
205
|
>
|
|
196
206
|
{panel.label}
|
|
197
207
|
</a>
|
|
@@ -257,7 +267,7 @@ const initialId =
|
|
|
257
267
|
<a
|
|
258
268
|
aria-current={current}
|
|
259
269
|
class="blume-nav-link truncate"
|
|
260
|
-
href={
|
|
270
|
+
href={pageHref(item)}
|
|
261
271
|
>
|
|
262
272
|
{item.label}
|
|
263
273
|
</a>
|
|
@@ -269,7 +279,7 @@ const initialId =
|
|
|
269
279
|
<a
|
|
270
280
|
aria-current={current}
|
|
271
281
|
class="blume-nav-link"
|
|
272
|
-
href={
|
|
282
|
+
href={pageHref(item)}
|
|
273
283
|
>
|
|
274
284
|
<span class="flex items-center gap-2">
|
|
275
285
|
{item.icon && (
|
|
@@ -348,7 +358,7 @@ const initialId =
|
|
|
348
358
|
: undefined
|
|
349
359
|
}
|
|
350
360
|
class="blume-nav-summary-link"
|
|
351
|
-
href={
|
|
361
|
+
href={withMountedBase(item.route)}
|
|
352
362
|
>
|
|
353
363
|
{item.icon && (
|
|
354
364
|
<Icon
|
|
@@ -432,7 +442,7 @@ const initialId =
|
|
|
432
442
|
isGroupRowCurrent(item, currentRoute) ? "page" : undefined
|
|
433
443
|
}
|
|
434
444
|
class="blume-nav-heading-link"
|
|
435
|
-
href={
|
|
445
|
+
href={withMountedBase(item.route)}
|
|
436
446
|
>
|
|
437
447
|
{item.icon && (
|
|
438
448
|
<Icon
|
|
@@ -262,7 +262,7 @@ const menuRowClass =
|
|
|
262
262
|
<script>
|
|
263
263
|
import { copyDeferredText, copyText, flashLabel } from "../copy-feedback.ts";
|
|
264
264
|
import { installDropdownDismiss } from "../dropdown-dismiss.ts";
|
|
265
|
-
import {
|
|
265
|
+
import { mountBase } from "../islands/base-path.ts";
|
|
266
266
|
import { rafThrottle } from "../raf-throttle.ts";
|
|
267
267
|
|
|
268
268
|
const CHAT_URLS: Record<string, (q: string) => string> = {
|
|
@@ -390,9 +390,10 @@ hr { border: 0; border-top: 1px solid #ddd; margin: 2em 0; }`;
|
|
|
390
390
|
|
|
391
391
|
// `data-md` is the base-less logical route; the raw-markdown endpoint is a
|
|
392
392
|
// generated page route, so it's served under the deployment base like any
|
|
393
|
-
// other page
|
|
393
|
+
// other page, even when it starts with the base's own name. Mount it at
|
|
394
|
+
// emit time (the Search-island pattern).
|
|
394
395
|
const mdRoute = root.getAttribute("data-md") ?? "";
|
|
395
|
-
const md =
|
|
396
|
+
const md = mountBase(import.meta.env.BASE_URL, mdRoute);
|
|
396
397
|
const copiedLabel = root.getAttribute("data-i18n-copied") || "Copied!";
|
|
397
398
|
const copyFailedLabel =
|
|
398
399
|
root.getAttribute("data-i18n-copy-failed") || "Copy failed";
|
|
@@ -39,7 +39,7 @@ import {
|
|
|
39
39
|
import { buildStructuredData } from "../../seo/jsonld.ts";
|
|
40
40
|
import { normalizeXHandle } from "../../seo/x-handle.ts";
|
|
41
41
|
import Icon from "../Icon.astro";
|
|
42
|
-
import { stripBase, withBase } from "../islands/base-path.ts";
|
|
42
|
+
import { stripBase, withBase, withMountedBase } from "../islands/base-path.ts";
|
|
43
43
|
import { pageDirection, pageLocale } from "./page-locale.ts";
|
|
44
44
|
import { searchLocaleFor } from "./search-locale.ts";
|
|
45
45
|
import "blume:theme";
|
|
@@ -219,7 +219,7 @@ const activeTab = currentTabForRoute(navigation.tabs, route, navigation.root);
|
|
|
219
219
|
// llms.txt index), and the homepage HTTP `Link` header already advertises it,
|
|
220
220
|
// so the head is its HTML counterpart on hosts that can't set that header.
|
|
221
221
|
// Advertising a mirror for any other custom route would 404.
|
|
222
|
-
const markdownMirror = route === "/" ?
|
|
222
|
+
const markdownMirror = route === "/" ? withMountedBase("/index.md") : null;
|
|
223
223
|
|
|
224
224
|
// Derive canonical + og:image from the site URL the same way the catch-all does
|
|
225
225
|
// for content pages, so a custom page gets both for free. The matching OG card
|
|
@@ -230,8 +230,9 @@ const markdownMirror = route === "/" ? withBase("/index.md") : null;
|
|
|
230
230
|
const ogSlug = route === "/" ? "index" : route.slice(1);
|
|
231
231
|
const ogCardGenerated = !Astro.routePattern.includes("[");
|
|
232
232
|
// Absolute URLs carry the deployment base too (`site + base + route`), since the
|
|
233
|
-
// page is served under it
|
|
234
|
-
|
|
233
|
+
// page is served under it — even when the route starts with the base's own
|
|
234
|
+
// name. `withMountedBase` handles a root base as a no-op.
|
|
235
|
+
const basedRoute = withMountedBase(route);
|
|
235
236
|
// The schema accepts a trailing-slash site URL (`https://docs.example.com/`);
|
|
236
237
|
// strip it before joining with the root-relative route so canonical/og URLs
|
|
237
238
|
// don't come out double-slashed — the catch-all strips it the same way.
|
|
@@ -253,7 +254,7 @@ const absolutizeOgImage = (value: string): string =>
|
|
|
253
254
|
const resolvedOgImage = ogImage
|
|
254
255
|
? absolutizeOgImage(ogImage)
|
|
255
256
|
: ogEnabled && ogCardGenerated && siteBase
|
|
256
|
-
? `${siteBase}${encodeURI(
|
|
257
|
+
? `${siteBase}${encodeURI(withMountedBase(`/og/${ogSlug}.png`))}`
|
|
257
258
|
: null;
|
|
258
259
|
// Only the generated card has a known size and format, so its dimensions are
|
|
259
260
|
// declared for crawlers; a user-supplied `ogImage` could be any image.
|
|
@@ -439,7 +440,7 @@ createIconSprite(Astro.locals);
|
|
|
439
440
|
<a
|
|
440
441
|
aria-current={tab === activeTab ? "page" : undefined}
|
|
441
442
|
class="flex items-center gap-2 rounded-[0.65rem] px-2.5 py-1.5 font-medium text-muted-foreground text-sm transition-colors hover:bg-muted hover:text-foreground aria-[current=page]:bg-muted aria-[current=page]:text-foreground"
|
|
442
|
-
href={
|
|
443
|
+
href={withMountedBase(tab.href ?? tab.path)}
|
|
443
444
|
>
|
|
444
445
|
{tab.icon && (
|
|
445
446
|
<Icon class="shrink-0" name={tab.icon} size={14} />
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
import {
|
|
2
|
+
import { withMountedBase } from "../islands/base-path.ts";
|
|
3
3
|
import { EN_UI } from "../../core/i18n-ui.ts";
|
|
4
4
|
import type { UIStrings } from "../../core/i18n-ui.ts";
|
|
5
5
|
import type { FlatPage } from "./nav-utils.ts";
|
|
@@ -31,7 +31,7 @@ const s = { ...EN_UI.page, ...strings };
|
|
|
31
31
|
{prev ? (
|
|
32
32
|
<a
|
|
33
33
|
class="flex max-w-[48%] flex-1 items-center gap-2 rounded-blume border border-border px-4 py-3 text-foreground transition-colors hover:border-foreground"
|
|
34
|
-
href={
|
|
34
|
+
href={withMountedBase(prev.route)}
|
|
35
35
|
>
|
|
36
36
|
<Icon class="rtl:-scale-x-100" name="arrow-left" size={16} />
|
|
37
37
|
<span class="min-w-0">
|
|
@@ -47,7 +47,7 @@ const s = { ...EN_UI.page, ...strings };
|
|
|
47
47
|
{next && (
|
|
48
48
|
<a
|
|
49
49
|
class="ms-auto flex max-w-[48%] flex-1 items-center justify-end gap-2 rounded-blume border border-border px-4 py-3 text-end text-foreground transition-colors hover:border-foreground"
|
|
50
|
-
href={
|
|
50
|
+
href={withMountedBase(next.route)}
|
|
51
51
|
>
|
|
52
52
|
<span class="min-w-0">
|
|
53
53
|
<span class="block text-muted-foreground text-xs">
|
|
@@ -39,7 +39,7 @@ import {
|
|
|
39
39
|
} from "../../og/dimensions.ts";
|
|
40
40
|
import { buildStructuredData, toIso } from "../../seo/jsonld.ts";
|
|
41
41
|
import { normalizeXHandle } from "../../seo/x-handle.ts";
|
|
42
|
-
import { withBase } from "../islands/base-path.ts";
|
|
42
|
+
import { withBase, withMountedBase } from "../islands/base-path.ts";
|
|
43
43
|
import { isExternalUrl } from "../../core/base-path.ts";
|
|
44
44
|
import { NEW_TAB_HINT_ID, newTabAttrs } from "../../core/new-tab.ts";
|
|
45
45
|
import Analytics from "./Analytics.astro";
|
|
@@ -401,12 +401,12 @@ const formattedLastModified =
|
|
|
401
401
|
// not a content route and has none.
|
|
402
402
|
const markdownMirror = isBare
|
|
403
403
|
? null
|
|
404
|
-
:
|
|
404
|
+
: withMountedBase(page.route === "/" ? "/index.md" : `${page.route}.md`);
|
|
405
405
|
|
|
406
406
|
// The hosted MCP server's absolute URL, used by the page-actions install menu.
|
|
407
407
|
// Needs a configured site to be useful, so the menu is hidden without one.
|
|
408
408
|
const mcpUrl =
|
|
409
|
-
mcp && siteUrl ? new URL(
|
|
409
|
+
mcp && siteUrl ? new URL(withMountedBase(mcp.route), siteUrl).href : null;
|
|
410
410
|
|
|
411
411
|
// Scope the sidebar (and the breadcrumbs/pagination derived from it) to the
|
|
412
412
|
// active tab's section, so a multi-section site drills each tab into its own
|
|
@@ -540,7 +540,7 @@ createIconSprite(Astro.locals);
|
|
|
540
540
|
{
|
|
541
541
|
feeds?.map((feed) => (
|
|
542
542
|
<link
|
|
543
|
-
href={
|
|
543
|
+
href={withMountedBase(feed.href)}
|
|
544
544
|
rel="alternate"
|
|
545
545
|
title={feed.title}
|
|
546
546
|
type="application/rss+xml"
|
|
@@ -689,7 +689,7 @@ createIconSprite(Astro.locals);
|
|
|
689
689
|
<a
|
|
690
690
|
aria-current={tab === activeTab ? "page" : undefined}
|
|
691
691
|
class="flex items-center gap-2 rounded-[0.65rem] px-2.5 py-1.5 font-medium text-muted-foreground text-sm transition-colors hover:bg-muted hover:text-foreground aria-[current=page]:bg-muted aria-[current=page]:text-foreground"
|
|
692
|
-
href={
|
|
692
|
+
href={withMountedBase(tab.href ?? tab.path)}
|
|
693
693
|
>
|
|
694
694
|
{tab.icon && (
|
|
695
695
|
<Icon class="shrink-0" name={tab.icon} size={14} />
|