@tenphi/renderer 0.25.0 → 0.25.1
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/dist/client/search.js +6 -1
- package/dist/client/search.js.map +1 -1
- package/dist/components/MarkdownTable.styles.js +7 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +63 -12
- package/dist/index.js.map +1 -1
- package/dist/localization.d.ts +3 -1
- package/dist/localization.d.ts.map +1 -1
- package/dist/localization.js +3 -2
- package/dist/localization.js.map +1 -1
- package/dist/navigation.d.ts.map +1 -1
- package/dist/navigation.js +2 -1
- package/dist/navigation.js.map +1 -1
- package/dist/overrides/Head.astro +2 -1
- package/dist/overrides/LanguageSelect.astro +2 -1
- package/dist/overrides/Search.astro +1 -2
- package/dist/page-metadata.d.ts +2 -1
- package/dist/page-metadata.d.ts.map +1 -1
- package/dist/page-metadata.js +5 -2
- package/dist/page-metadata.js.map +1 -1
- package/dist/route-context.d.ts +2 -1
- package/dist/route-context.d.ts.map +1 -1
- package/dist/route-context.js +2 -1
- package/dist/route-context.js.map +1 -1
- package/dist/routes/DocsPage.astro +5 -1
- package/dist/versioning.d.ts +4 -2
- package/dist/versioning.d.ts.map +1 -1
- package/dist/versioning.js +2 -3
- package/dist/versioning.js.map +1 -1
- package/package.json +2 -2
package/dist/localization.d.ts
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { ResolvedNavigationLayout } from "./navigation.js";
|
|
2
2
|
import { n as MessageKey, r as messages, t as ENGLISH_MESSAGES } from "./messages-ClTf2nFf.js";
|
|
3
|
-
import { DocsConfig, DocsRoute } from "@tenphi/docs";
|
|
3
|
+
import { DocsConfig, DocsRoute, TrailingSlash } from "@tenphi/docs";
|
|
4
4
|
//#region src/localization.d.ts
|
|
5
5
|
type LocaleOptions = {
|
|
6
6
|
locales?: DocsConfig["locales"] | undefined;
|
|
7
7
|
defaultLocale?: DocsConfig["defaultLocale"] | undefined;
|
|
8
8
|
translations?: DocsConfig["translations"] | undefined;
|
|
9
|
+
/** Which page URLs end with a slash, following the site's URL format. */
|
|
10
|
+
trailingSlash?: TrailingSlash | undefined;
|
|
9
11
|
};
|
|
10
12
|
declare function routeLocale(path: string, options: LocaleOptions): string;
|
|
11
13
|
/** Author components can render before the page initializes route locals. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"localization.d.ts","names":[],"sources":["../src/localization.ts"],"mappings":";;;;
|
|
1
|
+
{"version":3,"file":"localization.d.ts","names":[],"sources":["../src/localization.ts"],"mappings":";;;;KAYK;EACH,UAAU;EACV,gBAAgB;EAChB,eAAe;;EAEf,gBAAgB;;iBAGF,YAAY,cAAc,SAAS;;iBAMnC,gBACd,kBACA,cACA,SAAS;iBAWK,WAAW,cAAc,SAAS;iBAQlC,eACd,cACA,gBACA,SAAS;;iBASK,aACd,cACA,gBACA,QAAQ,aACR,SAAS;iBAoBK,WACd,cACA,qBACA,QAAQ,aACR,SAAS,eACT;;iBAiBc,oBACd,QAAQ,0BACR,QAAQ,aACR,qBACA,SAAS;EACN,QAAQ;EAA0B,QAAQ;;iBAuH/B,iBACd,cACA,QAAQ,aACR,SAAS,gBACR;EAAQ;EAAc"}
|
package/dist/localization.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { normalizeNavigationPath } from "./navigation.js";
|
|
2
2
|
import { n as messages, t as ENGLISH_MESSAGES } from "./messages-BqBGDIoP.js";
|
|
3
|
+
import { routePath } from "@tenphi/docs";
|
|
3
4
|
//#region src/localization.ts
|
|
4
5
|
function routeLocale(path, options) {
|
|
5
6
|
const first = normalizeNavigationPath(path).split("/")[1];
|
|
@@ -35,8 +36,8 @@ function localeHref(link, currentPath, routes, options, base = "/") {
|
|
|
35
36
|
if (!link.startsWith("/") || link.startsWith("//")) return link;
|
|
36
37
|
const suffix = /[?#].*$/.exec(link)?.[0] ?? "";
|
|
37
38
|
const path = suffix ? link.slice(0, -suffix.length) : link;
|
|
38
|
-
const
|
|
39
|
-
return `${base.replace(/\/$/, "")}${
|
|
39
|
+
const route = (options.locales ? localeTarget(path, routeLocale(currentPath, options), routes, options) : normalizeNavigationPath(path)) ?? normalizeNavigationPath(path);
|
|
40
|
+
return `${routes.some((page) => page.route === route) ? routePath(route, base, options.trailingSlash) : `${base.replace(/\/$/, "")}${route}` || "/"}${suffix}`;
|
|
40
41
|
}
|
|
41
42
|
/** Resolve navigation against the current locale's available routes. */
|
|
42
43
|
function localizedNavigation(layout, routes, currentPath, options) {
|
package/dist/localization.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"localization.js","names":[],"sources":["../src/localization.ts"],"sourcesContent":["import type { DocsConfig, DocsRoute, NavigationItem } from \"@tenphi/docs\";\nimport {\n normalizeNavigationPath,\n type ResolvedNavigationLayout,\n} from \"./navigation.js\";\n\ntype LocaleOptions = {\n locales?: DocsConfig[\"locales\"] | undefined;\n defaultLocale?: DocsConfig[\"defaultLocale\"] | undefined;\n translations?: DocsConfig[\"translations\"] | undefined;\n};\n\nexport function routeLocale(path: string, options: LocaleOptions): string {\n const first = normalizeNavigationPath(path).split(\"/\")[1];\n return first && first !== \"root\" && options.locales?.[first] ? first : \"root\";\n}\n\n/** Author components can render before the page initializes route locals. */\nexport function requestLanguage(\n pathname: string,\n base: string,\n options: LocaleOptions,\n): string {\n const prefix = base.replace(/\\/$/, \"\");\n const path =\n prefix && (pathname === prefix || pathname.startsWith(`${prefix}/`))\n ? pathname.slice(prefix.length)\n : pathname;\n const locale = routeLocale(path, options);\n return options.locales?.[locale]?.lang ?? (locale === \"root\" ? \"en\" : locale);\n}\n\nexport function localePath(path: string, options: LocaleOptions): string {\n const route = normalizeNavigationPath(path);\n const locale = routeLocale(route, options);\n return locale === \"root\"\n ? route\n : normalizeNavigationPath(route.slice(locale.length + 1));\n}\n\nexport function localizedRoute(\n path: string,\n locale: string,\n options: LocaleOptions,\n): string {\n const suffix = localePath(path, options);\n return normalizeNavigationPath(\n `${locale === \"root\" ? \"\" : `/${locale}`}${suffix}`,\n );\n}\n\n/** Missing translations use a real default-language page, then a real locale home. */\nexport function localeTarget(\n path: string,\n locale: string,\n routes: DocsRoute[],\n options: LocaleOptions,\n): string | undefined {\n const visible = new Set(\n routes\n .filter((route) => route.discoverable !== false)\n .map((route) => route.route),\n );\n const fallback =\n options.defaultLocale ??\n (options.locales?.root\n ? \"root\"\n : (Object.keys(options.locales ?? {})[0] ?? \"root\"));\n return [\n localizedRoute(path, locale, options),\n localizedRoute(path, fallback, options),\n localizedRoute(\"/\", locale, options),\n localizedRoute(\"/\", fallback, options),\n ].find((route) => visible.has(route));\n}\n\nexport function localeHref(\n link: string,\n currentPath: string,\n routes: DocsRoute[],\n options: LocaleOptions,\n base = \"/\",\n): string {\n if (!link.startsWith(\"/\") || link.startsWith(\"//\")) return link;\n const suffix = /[?#].*$/.exec(link)?.[0] ?? \"\";\n const path = suffix ? link.slice(0, -suffix.length) : link;\n const target = options.locales\n ? localeTarget(path, routeLocale(currentPath, options), routes, options)\n : normalizeNavigationPath(path);\n return (\n `${base.replace(/\\/$/, \"\")}${target ?? normalizeNavigationPath(path)}${suffix}` ||\n \"/\"\n );\n}\n\n/** Resolve navigation against the current locale's available routes. */\nexport function localizedNavigation(\n layout: ResolvedNavigationLayout,\n routes: DocsRoute[],\n currentPath: string,\n options: LocaleOptions,\n): { layout: ResolvedNavigationLayout; routes: DocsRoute[] } {\n if (!options.locales) return { layout, routes };\n const locale = routeLocale(currentPath, options);\n const language =\n options.locales[locale]?.lang ?? (locale === \"root\" ? \"en\" : locale);\n const label = (value: string) =>\n options.translations?.[language]?.[`navigation.${value}`] ??\n options.translations?.[language.split(\"-\")[0]!]?.[`navigation.${value}`] ??\n value;\n const localRoutes = routes\n .filter((route) => routeLocale(route.route, options) === locale)\n .map((route) => ({ ...route, route: localePath(route.route, options) }));\n const available = new Set(\n localRoutes\n .filter((route) => route.discoverable !== false)\n .map((route) => route.route),\n );\n const visibleRoutes = new Map(\n routes\n .filter((route) => route.discoverable !== false)\n .map((route) => [route.route, route]),\n );\n const fallbackLocale =\n options.defaultLocale ??\n (options.locales.root ? \"root\" : Object.keys(options.locales)[0]!);\n const convert = (items: NavigationItem[]): NavigationItem[] =>\n items.flatMap((item): NavigationItem[] => {\n const link = typeof item === \"string\" ? item : item.link;\n const internal = link?.startsWith(\"/\") && !link.startsWith(\"//\");\n const translated = internal ? localePath(link!, options) : link;\n const fallback = internal\n ? localizedRoute(link!, fallbackLocale, options)\n : undefined;\n const target =\n !internal || available.has(translated!)\n ? translated\n : fallback && visibleRoutes.has(fallback)\n ? fallback\n : undefined;\n if (typeof item === \"string\") {\n if (!target) return [];\n if (!internal || available.has(translated!)) return [target];\n const route = visibleRoutes.get(target)!;\n return [\n {\n label:\n typeof route.sidebar === \"object\" && route.sidebar.label\n ? route.sidebar.label\n : route.title,\n link: target,\n ...(typeof route.sidebar === \"object\" &&\n route.sidebar.badge !== undefined\n ? { badge: route.sidebar.badge }\n : {}),\n },\n ];\n }\n const sidebar =\n fallback && target === fallback\n ? visibleRoutes.get(fallback)?.sidebar\n : undefined;\n const badge =\n item.badge !== undefined\n ? label(item.badge)\n : typeof sidebar === \"object\"\n ? sidebar.badge\n : undefined;\n const presentation = badge !== undefined ? { badge } : {};\n if (\"items\" in item || \"autogenerate\" in item) {\n const { link: _link, ...group } = item;\n const children = \"items\" in item ? convert(item.items) : undefined;\n if (children?.length === 0 && !target) return [];\n return [\n {\n ...group,\n label: label(group.label),\n ...presentation,\n ...(target ? { link: target } : {}),\n ...(\"items\" in item\n ? { items: children! }\n : {\n autogenerate: {\n directory: localePath(item.autogenerate.directory, options),\n },\n }),\n },\n ];\n }\n return target\n ? [\n {\n ...item,\n label: label(item.label),\n link: target,\n ...presentation,\n },\n ]\n : [];\n });\n return {\n layout: {\n ...layout,\n ...(layout.items ? { items: convert(layout.items) } : {}),\n tabs: layout.tabs.map((tab) => ({\n ...tab,\n label: label(tab.label),\n link:\n tab.link.startsWith(\"/\") && !tab.link.startsWith(\"//\")\n ? localePath(tab.link, options)\n : tab.link,\n ...(tab.items ? { items: convert(tab.items) } : {}),\n })),\n },\n routes: localRoutes,\n };\n}\n\nexport { ENGLISH_MESSAGES, messages, type MessageKey } from \"./messages.js\";\n\nexport function localeAlternates(\n path: string,\n routes: DocsRoute[],\n options: LocaleOptions,\n): Array<{ lang: string; route: string }> {\n const available = new Set(\n routes\n .filter((route) => route.discoverable !== false)\n .map((route) => route.route),\n );\n if (!options.locales || !available.has(path)) return [];\n const alternates = Object.entries(options.locales).flatMap(\n ([locale, config]) => {\n const route = localizedRoute(path, locale, options);\n return available.has(route)\n ? [{ lang: config.lang ?? locale, route }]\n : [];\n },\n );\n const fallback = localizedRoute(\n path,\n options.defaultLocale ??\n (options.locales.root ? \"root\" : Object.keys(options.locales)[0]!),\n options,\n );\n if (available.has(fallback))\n alternates.push({ lang: \"x-default\", route: fallback });\n return alternates;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"localization.js","names":[],"sources":["../src/localization.ts"],"sourcesContent":["import {\n routePath,\n type DocsConfig,\n type DocsRoute,\n type NavigationItem,\n type TrailingSlash,\n} from \"@tenphi/docs\";\nimport {\n normalizeNavigationPath,\n type ResolvedNavigationLayout,\n} from \"./navigation.js\";\n\ntype LocaleOptions = {\n locales?: DocsConfig[\"locales\"] | undefined;\n defaultLocale?: DocsConfig[\"defaultLocale\"] | undefined;\n translations?: DocsConfig[\"translations\"] | undefined;\n /** Which page URLs end with a slash, following the site's URL format. */\n trailingSlash?: TrailingSlash | undefined;\n};\n\nexport function routeLocale(path: string, options: LocaleOptions): string {\n const first = normalizeNavigationPath(path).split(\"/\")[1];\n return first && first !== \"root\" && options.locales?.[first] ? first : \"root\";\n}\n\n/** Author components can render before the page initializes route locals. */\nexport function requestLanguage(\n pathname: string,\n base: string,\n options: LocaleOptions,\n): string {\n const prefix = base.replace(/\\/$/, \"\");\n const path =\n prefix && (pathname === prefix || pathname.startsWith(`${prefix}/`))\n ? pathname.slice(prefix.length)\n : pathname;\n const locale = routeLocale(path, options);\n return options.locales?.[locale]?.lang ?? (locale === \"root\" ? \"en\" : locale);\n}\n\nexport function localePath(path: string, options: LocaleOptions): string {\n const route = normalizeNavigationPath(path);\n const locale = routeLocale(route, options);\n return locale === \"root\"\n ? route\n : normalizeNavigationPath(route.slice(locale.length + 1));\n}\n\nexport function localizedRoute(\n path: string,\n locale: string,\n options: LocaleOptions,\n): string {\n const suffix = localePath(path, options);\n return normalizeNavigationPath(\n `${locale === \"root\" ? \"\" : `/${locale}`}${suffix}`,\n );\n}\n\n/** Missing translations use a real default-language page, then a real locale home. */\nexport function localeTarget(\n path: string,\n locale: string,\n routes: DocsRoute[],\n options: LocaleOptions,\n): string | undefined {\n const visible = new Set(\n routes\n .filter((route) => route.discoverable !== false)\n .map((route) => route.route),\n );\n const fallback =\n options.defaultLocale ??\n (options.locales?.root\n ? \"root\"\n : (Object.keys(options.locales ?? {})[0] ?? \"root\"));\n return [\n localizedRoute(path, locale, options),\n localizedRoute(path, fallback, options),\n localizedRoute(\"/\", locale, options),\n localizedRoute(\"/\", fallback, options),\n ].find((route) => visible.has(route));\n}\n\nexport function localeHref(\n link: string,\n currentPath: string,\n routes: DocsRoute[],\n options: LocaleOptions,\n base = \"/\",\n): string {\n if (!link.startsWith(\"/\") || link.startsWith(\"//\")) return link;\n const suffix = /[?#].*$/.exec(link)?.[0] ?? \"\";\n const path = suffix ? link.slice(0, -suffix.length) : link;\n const target = options.locales\n ? localeTarget(path, routeLocale(currentPath, options), routes, options)\n : normalizeNavigationPath(path);\n const route = target ?? normalizeNavigationPath(path);\n // Only page routes follow the site's URL format; other paths stay as written.\n const href = routes.some((page) => page.route === route)\n ? routePath(route, base, options.trailingSlash)\n : `${base.replace(/\\/$/, \"\")}${route}` || \"/\";\n return `${href}${suffix}`;\n}\n\n/** Resolve navigation against the current locale's available routes. */\nexport function localizedNavigation(\n layout: ResolvedNavigationLayout,\n routes: DocsRoute[],\n currentPath: string,\n options: LocaleOptions,\n): { layout: ResolvedNavigationLayout; routes: DocsRoute[] } {\n if (!options.locales) return { layout, routes };\n const locale = routeLocale(currentPath, options);\n const language =\n options.locales[locale]?.lang ?? (locale === \"root\" ? \"en\" : locale);\n const label = (value: string) =>\n options.translations?.[language]?.[`navigation.${value}`] ??\n options.translations?.[language.split(\"-\")[0]!]?.[`navigation.${value}`] ??\n value;\n const localRoutes = routes\n .filter((route) => routeLocale(route.route, options) === locale)\n .map((route) => ({ ...route, route: localePath(route.route, options) }));\n const available = new Set(\n localRoutes\n .filter((route) => route.discoverable !== false)\n .map((route) => route.route),\n );\n const visibleRoutes = new Map(\n routes\n .filter((route) => route.discoverable !== false)\n .map((route) => [route.route, route]),\n );\n const fallbackLocale =\n options.defaultLocale ??\n (options.locales.root ? \"root\" : Object.keys(options.locales)[0]!);\n const convert = (items: NavigationItem[]): NavigationItem[] =>\n items.flatMap((item): NavigationItem[] => {\n const link = typeof item === \"string\" ? item : item.link;\n const internal = link?.startsWith(\"/\") && !link.startsWith(\"//\");\n const translated = internal ? localePath(link!, options) : link;\n const fallback = internal\n ? localizedRoute(link!, fallbackLocale, options)\n : undefined;\n const target =\n !internal || available.has(translated!)\n ? translated\n : fallback && visibleRoutes.has(fallback)\n ? fallback\n : undefined;\n if (typeof item === \"string\") {\n if (!target) return [];\n if (!internal || available.has(translated!)) return [target];\n const route = visibleRoutes.get(target)!;\n return [\n {\n label:\n typeof route.sidebar === \"object\" && route.sidebar.label\n ? route.sidebar.label\n : route.title,\n link: target,\n ...(typeof route.sidebar === \"object\" &&\n route.sidebar.badge !== undefined\n ? { badge: route.sidebar.badge }\n : {}),\n },\n ];\n }\n const sidebar =\n fallback && target === fallback\n ? visibleRoutes.get(fallback)?.sidebar\n : undefined;\n const badge =\n item.badge !== undefined\n ? label(item.badge)\n : typeof sidebar === \"object\"\n ? sidebar.badge\n : undefined;\n const presentation = badge !== undefined ? { badge } : {};\n if (\"items\" in item || \"autogenerate\" in item) {\n const { link: _link, ...group } = item;\n const children = \"items\" in item ? convert(item.items) : undefined;\n if (children?.length === 0 && !target) return [];\n return [\n {\n ...group,\n label: label(group.label),\n ...presentation,\n ...(target ? { link: target } : {}),\n ...(\"items\" in item\n ? { items: children! }\n : {\n autogenerate: {\n directory: localePath(item.autogenerate.directory, options),\n },\n }),\n },\n ];\n }\n return target\n ? [\n {\n ...item,\n label: label(item.label),\n link: target,\n ...presentation,\n },\n ]\n : [];\n });\n return {\n layout: {\n ...layout,\n ...(layout.items ? { items: convert(layout.items) } : {}),\n tabs: layout.tabs.map((tab) => ({\n ...tab,\n label: label(tab.label),\n link:\n tab.link.startsWith(\"/\") && !tab.link.startsWith(\"//\")\n ? localePath(tab.link, options)\n : tab.link,\n ...(tab.items ? { items: convert(tab.items) } : {}),\n })),\n },\n routes: localRoutes,\n };\n}\n\nexport { ENGLISH_MESSAGES, messages, type MessageKey } from \"./messages.js\";\n\nexport function localeAlternates(\n path: string,\n routes: DocsRoute[],\n options: LocaleOptions,\n): Array<{ lang: string; route: string }> {\n const available = new Set(\n routes\n .filter((route) => route.discoverable !== false)\n .map((route) => route.route),\n );\n if (!options.locales || !available.has(path)) return [];\n const alternates = Object.entries(options.locales).flatMap(\n ([locale, config]) => {\n const route = localizedRoute(path, locale, options);\n return available.has(route)\n ? [{ lang: config.lang ?? locale, route }]\n : [];\n },\n );\n const fallback = localizedRoute(\n path,\n options.defaultLocale ??\n (options.locales.root ? \"root\" : Object.keys(options.locales)[0]!),\n options,\n );\n if (available.has(fallback))\n alternates.push({ lang: \"x-default\", route: fallback });\n return alternates;\n}\n"],"mappings":"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"}
|
package/dist/navigation.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"navigation.d.ts","names":[],"sources":["../src/navigation.ts"],"mappings":";;UAOiB,8BAA8B;;EAE7C;;UAGe;EACf;EACA,QAAQ;EACR,MAAM;EACN;;KAGU;EAAoB;;EAC1B;EAAe;EAAc,QAAQ;;EACrC;EAAe,OAAO;;iBAGZ,wBACd,YAAY,2BACX;iBAoBa,uBACd,QAAQ,0BACR,mBACC;;iBAQa,YACd,QAAQ,0BACR,QAAQ,cACP;;iBAmKa,oBACd,MAAM,iBACN;iBAoBc,eAAe,kBAAkB;
|
|
1
|
+
{"version":3,"file":"navigation.d.ts","names":[],"sources":["../src/navigation.ts"],"mappings":";;UAOiB,8BAA8B;;EAE7C;;UAGe;EACf;EACA,QAAQ;EACR,MAAM;EACN;;KAGU;EAAoB;;EAC1B;EAAe;EAAc,QAAQ;;EACrC;EAAe,OAAO;;iBAGZ,wBACd,YAAY,2BACX;iBAoBa,uBACd,QAAQ,0BACR,mBACC;;iBAQa,YACd,QAAQ,0BACR,QAAQ,cACP;;iBAmKa,oBACd,MAAM,iBACN;iBAoBc,eAAe,kBAAkB;iBAYjC,wBAAwB"}
|
package/dist/navigation.js
CHANGED
|
@@ -143,7 +143,8 @@ function activeNavigationTab(tabs, pathname) {
|
|
|
143
143
|
}
|
|
144
144
|
function navigationPath(pathname, base = "/") {
|
|
145
145
|
const normalizedBase = normalizeNavigationPath(base);
|
|
146
|
-
|
|
146
|
+
const page = pathname.replace(/(?:\/index)?\.html$/, "");
|
|
147
|
+
return normalizeNavigationPath(normalizedBase !== "/" && (page === normalizedBase || page.startsWith(`${normalizedBase}/`)) ? page.slice(normalizedBase.length) || "/" : page);
|
|
147
148
|
}
|
|
148
149
|
function normalizeNavigationPath(path) {
|
|
149
150
|
const normalized = `/${(path.split(/[?#]/, 1)[0]?.replace(/\\/g, "/") ?? "/").replace(/^\/+|\/+$/g, "")}`;
|
package/dist/navigation.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"navigation.js","names":[],"sources":["../src/navigation.ts"],"sourcesContent":["import type {\n DocsConfig,\n DocsRoute,\n NavigationItem,\n NavigationTab,\n} from \"@tenphi/docs\";\n\nexport interface ResolvedNavigationTab extends NavigationTab {\n /** Index of the tab's resolved sidebar group. */\n sidebarGroup?: number;\n}\n\nexport interface ResolvedNavigationLayout {\n fallbackSidebarGroup?: number;\n items?: NavigationItem[];\n tabs: ResolvedNavigationTab[];\n sectioned: boolean;\n}\n\nexport type PageSidebarItem = { badge?: string } & (\n | { label: string; link: string; attrs?: Record<string, string> }\n | { label: string; items: PageSidebarItem[] }\n);\n\nexport function resolveNavigationLayout(\n navigation: DocsConfig[\"navigation\"],\n): ResolvedNavigationLayout {\n const items = Array.isArray(navigation) ? navigation : navigation?.items;\n const configuredTabs = Array.isArray(navigation)\n ? []\n : (navigation?.tabs ?? []);\n const fallbackSidebarGroup = items !== undefined ? 0 : undefined;\n let sidebarGroup = fallbackSidebarGroup === undefined ? 0 : 1;\n const tabs = configuredTabs.map((tab) => ({\n ...tab,\n ...(tab.items !== undefined ? { sidebarGroup: sidebarGroup++ } : {}),\n }));\n\n return {\n ...(fallbackSidebarGroup !== undefined ? { fallbackSidebarGroup } : {}),\n ...(items !== undefined ? { items } : {}),\n tabs,\n sectioned: tabs.some((tab) => tab.sidebarGroup !== undefined),\n };\n}\n\nexport function navigationItemsForPath(\n layout: ResolvedNavigationLayout,\n pathname: string,\n): NavigationItem[] | undefined {\n const active = activeNavigationTab(layout.tabs, pathname);\n return active >= 0 && layout.tabs[active]?.items !== undefined\n ? layout.tabs[active].items\n : layout.items;\n}\n\n/** Build a sidebar for graph-backed custom pages. */\nexport function pageSidebar(\n layout: ResolvedNavigationLayout,\n routes: DocsRoute[],\n): PageSidebarItem[] {\n const visibleRoutes = routes\n .filter((route) => route.sidebar !== false && route.discoverable !== false)\n .toSorted((left, right) => {\n const leftOrder =\n typeof left.sidebar === \"object\" ? left.sidebar.order : undefined;\n const rightOrder =\n typeof right.sidebar === \"object\" ? right.sidebar.order : undefined;\n return (\n (leftOrder ?? Number.POSITIVE_INFINITY) -\n (rightOrder ?? Number.POSITIVE_INFINITY) ||\n left.route.localeCompare(right.route)\n );\n });\n const pages = new Map(visibleRoutes.map((route) => [route.route, route]));\n const badgeFor = (link: string) => {\n const sidebar = pages.get(normalizeNavigationPath(link))?.sidebar;\n return typeof sidebar === \"object\" ? sidebar.badge : undefined;\n };\n const labelFor = (link: string) => {\n const path = normalizeNavigationPath(link);\n const page = pages.get(path);\n return (\n (typeof page?.sidebar === \"object\" && page.sidebar.label\n ? page.sidebar.label\n : page?.title) ??\n path.split(\"/\").filter(Boolean).at(-1) ??\n \"Home\"\n );\n };\n const generatedItems = (directory: string) => {\n const root = normalizeNavigationPath(directory);\n return groupedRoutes(\n visibleRoutes.filter(\n (route) =>\n root === \"/\" ||\n route.route === root ||\n route.route.startsWith(`${root}/`),\n ),\n );\n };\n const convert = (item: NavigationItem): PageSidebarItem => {\n const link = typeof item === \"string\" ? item : item.link;\n const badge = link ? badgeFor(link) : undefined;\n if (typeof item === \"string\") {\n return {\n label: labelFor(item),\n link: item,\n ...(badge !== undefined ? { badge } : {}),\n };\n }\n const resolvedBadge = item.badge ?? badge;\n const presentation =\n resolvedBadge !== undefined ? { badge: resolvedBadge } : {};\n if (\"items\" in item || \"autogenerate\" in item) {\n let children =\n \"items\" in item\n ? item.items.map(convert)\n : generatedItems(item.autogenerate.directory);\n if (item.link) {\n children = withoutRoute(children, item.link);\n // Keep the parent in route resolution and pagination. The sidebar\n // promotes this marked entry into the group header.\n if (!children.length)\n return { label: item.label, link: item.link, ...presentation };\n children.unshift({\n label: item.label,\n link: item.link,\n attrs: { \"data-cookbook-group-link\": \"\" },\n ...presentation,\n });\n }\n return {\n label: item.label,\n items: children,\n ...presentation,\n };\n }\n return { ...item, ...presentation };\n };\n const fallback = layout.items?.length\n ? layout.items.map(convert)\n : groupedRoutes(visibleRoutes);\n const sidebar = !layout.sectioned\n ? fallback\n : [\n ...(layout.fallbackSidebarGroup !== undefined\n ? [{ label: \"Documentation\", items: fallback }]\n : []),\n ...layout.tabs.flatMap((tab) =>\n tab.items !== undefined\n ? [{ label: tab.label, items: tab.items.map(convert) }]\n : [],\n ),\n ];\n return routes\n .filter((route) => route.discoverable === false)\n .reduce((items, route) => withoutRoute(items, route.route), sidebar);\n}\n\nfunction withoutRoute(\n items: PageSidebarItem[],\n route: string,\n): PageSidebarItem[] {\n const target = normalizeNavigationPath(route);\n return items.flatMap((item): PageSidebarItem[] => {\n if (\"link\" in item) {\n return !/^(?:[a-z][a-z\\d+.-]*:|\\/\\/|[?#])/i.test(item.link) &&\n normalizeNavigationPath(item.link) === target\n ? []\n : [item];\n }\n const children = withoutRoute(item.items, route);\n const first = children[0];\n if (\n children.length === 1 &&\n first &&\n \"link\" in first &&\n first.attrs?.[\"data-cookbook-group-link\"] !== undefined\n ) {\n return [\n {\n label: item.label,\n link: first.link,\n ...(item.badge !== undefined ? { badge: item.badge } : {}),\n },\n ];\n }\n return children.length ? [{ ...item, items: children }] : [];\n });\n}\n\nfunction groupedRoutes(routes: DocsRoute[]): PageSidebarItem[] {\n const items: PageSidebarItem[] = [];\n const groups = new Map<string, PageSidebarItem[]>();\n for (const route of routes) {\n const item = {\n label:\n typeof route.sidebar === \"object\" && route.sidebar.label\n ? route.sidebar.label\n : route.title,\n link: route.route,\n ...(typeof route.sidebar === \"object\" && route.sidebar.badge !== undefined\n ? { badge: route.sidebar.badge }\n : {}),\n };\n const group =\n typeof route.sidebar === \"object\" ? route.sidebar.group : undefined;\n if (!group) {\n items.push(item);\n continue;\n }\n const grouped = groups.get(group) ?? [];\n grouped.push(item);\n groups.set(group, grouped);\n }\n return [\n ...items,\n ...Array.from(groups, ([label, grouped]) => ({ label, items: grouped })),\n ];\n}\n\n/** Pick one tab, preferring its own URL before routes owned by its sidebar. */\nexport function activeNavigationTab(\n tabs: NavigationTab[],\n pathname: string,\n): number {\n const current = normalizeNavigationPath(pathname);\n let winner = -1;\n let winningScore = -1;\n\n for (const [index, tab] of tabs.entries()) {\n const score = Math.max(\n linkMatchScore(tab.link, current, 30_000),\n navigationMatchScore(tab.items ?? [], current),\n );\n if (score > winningScore) {\n winner = index;\n winningScore = score;\n }\n }\n\n return winningScore >= 0 ? winner : -1;\n}\n\nexport function navigationPath(pathname: string, base = \"/\"): string {\n const normalizedBase = normalizeNavigationPath(base);\n const withoutBase =\n normalizedBase !== \"/\" &&\n (pathname === normalizedBase || pathname.startsWith(`${normalizedBase}/`))\n ? pathname.slice(normalizedBase.length) || \"/\"\n : pathname;\n return normalizeNavigationPath(withoutBase);\n}\n\nexport function normalizeNavigationPath(path: string): string {\n const clean = path.split(/[?#]/, 1)[0]?.replace(/\\\\/g, \"/\") ?? \"/\";\n const normalized = `/${clean.replace(/^\\/+|\\/+$/g, \"\")}`;\n return normalized === \"/\" ? normalized : normalized.replace(/\\/$/, \"\");\n}\n\nfunction navigationMatchScore(\n items: NavigationItem[],\n current: string,\n): number {\n let score = -1;\n for (const item of items) {\n if (typeof item === \"string\") {\n if (normalizeNavigationPath(item) === current)\n score = Math.max(score, 20_000);\n continue;\n }\n if (item.link) {\n score = Math.max(score, linkMatchScore(item.link, current, 20_000));\n }\n if (\"items\" in item) {\n score = Math.max(score, navigationMatchScore(item.items, current));\n continue;\n }\n if (\"autogenerate\" in item) {\n score = Math.max(\n score,\n directoryMatchScore(item.autogenerate.directory, current),\n );\n continue;\n }\n }\n return score;\n}\n\nfunction linkMatchScore(link: string, current: string, base: number): number {\n if (!link.startsWith(\"/\")) return -1;\n const target = normalizeNavigationPath(link);\n if (target === current) return base + 1_000 + target.length;\n if (target !== \"/\" && current.startsWith(`${target}/`)) {\n return base + target.length;\n }\n return -1;\n}\n\nfunction directoryMatchScore(directory: string, current: string): number {\n const target = normalizeNavigationPath(directory);\n if (target === \"/\") return 10_000;\n return current === target || current.startsWith(`${target}/`)\n ? 10_000 + target.length\n : -1;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"navigation.js","names":[],"sources":["../src/navigation.ts"],"sourcesContent":["import type {\n DocsConfig,\n DocsRoute,\n NavigationItem,\n NavigationTab,\n} from \"@tenphi/docs\";\n\nexport interface ResolvedNavigationTab extends NavigationTab {\n /** Index of the tab's resolved sidebar group. */\n sidebarGroup?: number;\n}\n\nexport interface ResolvedNavigationLayout {\n fallbackSidebarGroup?: number;\n items?: NavigationItem[];\n tabs: ResolvedNavigationTab[];\n sectioned: boolean;\n}\n\nexport type PageSidebarItem = { badge?: string } & (\n | { label: string; link: string; attrs?: Record<string, string> }\n | { label: string; items: PageSidebarItem[] }\n);\n\nexport function resolveNavigationLayout(\n navigation: DocsConfig[\"navigation\"],\n): ResolvedNavigationLayout {\n const items = Array.isArray(navigation) ? navigation : navigation?.items;\n const configuredTabs = Array.isArray(navigation)\n ? []\n : (navigation?.tabs ?? []);\n const fallbackSidebarGroup = items !== undefined ? 0 : undefined;\n let sidebarGroup = fallbackSidebarGroup === undefined ? 0 : 1;\n const tabs = configuredTabs.map((tab) => ({\n ...tab,\n ...(tab.items !== undefined ? { sidebarGroup: sidebarGroup++ } : {}),\n }));\n\n return {\n ...(fallbackSidebarGroup !== undefined ? { fallbackSidebarGroup } : {}),\n ...(items !== undefined ? { items } : {}),\n tabs,\n sectioned: tabs.some((tab) => tab.sidebarGroup !== undefined),\n };\n}\n\nexport function navigationItemsForPath(\n layout: ResolvedNavigationLayout,\n pathname: string,\n): NavigationItem[] | undefined {\n const active = activeNavigationTab(layout.tabs, pathname);\n return active >= 0 && layout.tabs[active]?.items !== undefined\n ? layout.tabs[active].items\n : layout.items;\n}\n\n/** Build a sidebar for graph-backed custom pages. */\nexport function pageSidebar(\n layout: ResolvedNavigationLayout,\n routes: DocsRoute[],\n): PageSidebarItem[] {\n const visibleRoutes = routes\n .filter((route) => route.sidebar !== false && route.discoverable !== false)\n .toSorted((left, right) => {\n const leftOrder =\n typeof left.sidebar === \"object\" ? left.sidebar.order : undefined;\n const rightOrder =\n typeof right.sidebar === \"object\" ? right.sidebar.order : undefined;\n return (\n (leftOrder ?? Number.POSITIVE_INFINITY) -\n (rightOrder ?? Number.POSITIVE_INFINITY) ||\n left.route.localeCompare(right.route)\n );\n });\n const pages = new Map(visibleRoutes.map((route) => [route.route, route]));\n const badgeFor = (link: string) => {\n const sidebar = pages.get(normalizeNavigationPath(link))?.sidebar;\n return typeof sidebar === \"object\" ? sidebar.badge : undefined;\n };\n const labelFor = (link: string) => {\n const path = normalizeNavigationPath(link);\n const page = pages.get(path);\n return (\n (typeof page?.sidebar === \"object\" && page.sidebar.label\n ? page.sidebar.label\n : page?.title) ??\n path.split(\"/\").filter(Boolean).at(-1) ??\n \"Home\"\n );\n };\n const generatedItems = (directory: string) => {\n const root = normalizeNavigationPath(directory);\n return groupedRoutes(\n visibleRoutes.filter(\n (route) =>\n root === \"/\" ||\n route.route === root ||\n route.route.startsWith(`${root}/`),\n ),\n );\n };\n const convert = (item: NavigationItem): PageSidebarItem => {\n const link = typeof item === \"string\" ? item : item.link;\n const badge = link ? badgeFor(link) : undefined;\n if (typeof item === \"string\") {\n return {\n label: labelFor(item),\n link: item,\n ...(badge !== undefined ? { badge } : {}),\n };\n }\n const resolvedBadge = item.badge ?? badge;\n const presentation =\n resolvedBadge !== undefined ? { badge: resolvedBadge } : {};\n if (\"items\" in item || \"autogenerate\" in item) {\n let children =\n \"items\" in item\n ? item.items.map(convert)\n : generatedItems(item.autogenerate.directory);\n if (item.link) {\n children = withoutRoute(children, item.link);\n // Keep the parent in route resolution and pagination. The sidebar\n // promotes this marked entry into the group header.\n if (!children.length)\n return { label: item.label, link: item.link, ...presentation };\n children.unshift({\n label: item.label,\n link: item.link,\n attrs: { \"data-cookbook-group-link\": \"\" },\n ...presentation,\n });\n }\n return {\n label: item.label,\n items: children,\n ...presentation,\n };\n }\n return { ...item, ...presentation };\n };\n const fallback = layout.items?.length\n ? layout.items.map(convert)\n : groupedRoutes(visibleRoutes);\n const sidebar = !layout.sectioned\n ? fallback\n : [\n ...(layout.fallbackSidebarGroup !== undefined\n ? [{ label: \"Documentation\", items: fallback }]\n : []),\n ...layout.tabs.flatMap((tab) =>\n tab.items !== undefined\n ? [{ label: tab.label, items: tab.items.map(convert) }]\n : [],\n ),\n ];\n return routes\n .filter((route) => route.discoverable === false)\n .reduce((items, route) => withoutRoute(items, route.route), sidebar);\n}\n\nfunction withoutRoute(\n items: PageSidebarItem[],\n route: string,\n): PageSidebarItem[] {\n const target = normalizeNavigationPath(route);\n return items.flatMap((item): PageSidebarItem[] => {\n if (\"link\" in item) {\n return !/^(?:[a-z][a-z\\d+.-]*:|\\/\\/|[?#])/i.test(item.link) &&\n normalizeNavigationPath(item.link) === target\n ? []\n : [item];\n }\n const children = withoutRoute(item.items, route);\n const first = children[0];\n if (\n children.length === 1 &&\n first &&\n \"link\" in first &&\n first.attrs?.[\"data-cookbook-group-link\"] !== undefined\n ) {\n return [\n {\n label: item.label,\n link: first.link,\n ...(item.badge !== undefined ? { badge: item.badge } : {}),\n },\n ];\n }\n return children.length ? [{ ...item, items: children }] : [];\n });\n}\n\nfunction groupedRoutes(routes: DocsRoute[]): PageSidebarItem[] {\n const items: PageSidebarItem[] = [];\n const groups = new Map<string, PageSidebarItem[]>();\n for (const route of routes) {\n const item = {\n label:\n typeof route.sidebar === \"object\" && route.sidebar.label\n ? route.sidebar.label\n : route.title,\n link: route.route,\n ...(typeof route.sidebar === \"object\" && route.sidebar.badge !== undefined\n ? { badge: route.sidebar.badge }\n : {}),\n };\n const group =\n typeof route.sidebar === \"object\" ? route.sidebar.group : undefined;\n if (!group) {\n items.push(item);\n continue;\n }\n const grouped = groups.get(group) ?? [];\n grouped.push(item);\n groups.set(group, grouped);\n }\n return [\n ...items,\n ...Array.from(groups, ([label, grouped]) => ({ label, items: grouped })),\n ];\n}\n\n/** Pick one tab, preferring its own URL before routes owned by its sidebar. */\nexport function activeNavigationTab(\n tabs: NavigationTab[],\n pathname: string,\n): number {\n const current = normalizeNavigationPath(pathname);\n let winner = -1;\n let winningScore = -1;\n\n for (const [index, tab] of tabs.entries()) {\n const score = Math.max(\n linkMatchScore(tab.link, current, 30_000),\n navigationMatchScore(tab.items ?? [], current),\n );\n if (score > winningScore) {\n winner = index;\n winningScore = score;\n }\n }\n\n return winningScore >= 0 ? winner : -1;\n}\n\nexport function navigationPath(pathname: string, base = \"/\"): string {\n const normalizedBase = normalizeNavigationPath(base);\n // Astro's file build format renders /guide and / as guide.html and index.html.\n const page = pathname.replace(/(?:\\/index)?\\.html$/, \"\");\n const withoutBase =\n normalizedBase !== \"/\" &&\n (page === normalizedBase || page.startsWith(`${normalizedBase}/`))\n ? page.slice(normalizedBase.length) || \"/\"\n : page;\n return normalizeNavigationPath(withoutBase);\n}\n\nexport function normalizeNavigationPath(path: string): string {\n const clean = path.split(/[?#]/, 1)[0]?.replace(/\\\\/g, \"/\") ?? \"/\";\n const normalized = `/${clean.replace(/^\\/+|\\/+$/g, \"\")}`;\n return normalized === \"/\" ? normalized : normalized.replace(/\\/$/, \"\");\n}\n\nfunction navigationMatchScore(\n items: NavigationItem[],\n current: string,\n): number {\n let score = -1;\n for (const item of items) {\n if (typeof item === \"string\") {\n if (normalizeNavigationPath(item) === current)\n score = Math.max(score, 20_000);\n continue;\n }\n if (item.link) {\n score = Math.max(score, linkMatchScore(item.link, current, 20_000));\n }\n if (\"items\" in item) {\n score = Math.max(score, navigationMatchScore(item.items, current));\n continue;\n }\n if (\"autogenerate\" in item) {\n score = Math.max(\n score,\n directoryMatchScore(item.autogenerate.directory, current),\n );\n continue;\n }\n }\n return score;\n}\n\nfunction linkMatchScore(link: string, current: string, base: number): number {\n if (!link.startsWith(\"/\")) return -1;\n const target = normalizeNavigationPath(link);\n if (target === current) return base + 1_000 + target.length;\n if (target !== \"/\" && current.startsWith(`${target}/`)) {\n return base + target.length;\n }\n return -1;\n}\n\nfunction directoryMatchScore(directory: string, current: string): number {\n const target = normalizeNavigationPath(directory);\n if (target === \"/\") return 10_000;\n return current === target || current.startsWith(`${target}/`)\n ? 10_000 + target.length\n : -1;\n}\n"],"mappings":"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"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
+
import { routePath } from "@tenphi/docs";
|
|
2
3
|
import { pageMetadata } from "../page-metadata.js";
|
|
3
4
|
import { content } from "virtual:cookbook/config";
|
|
4
5
|
import { localeAlternates, messages } from "../localization.js";
|
|
@@ -38,7 +39,7 @@ if (Astro.site && indexedRoutes.some((route) => route.route === current)) {
|
|
|
38
39
|
rel: "alternate",
|
|
39
40
|
hreflang: lang,
|
|
40
41
|
href: new URL(
|
|
41
|
-
|
|
42
|
+
routePath(route, content.base, content.trailingSlash),
|
|
42
43
|
Astro.site,
|
|
43
44
|
).href,
|
|
44
45
|
},
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
+
import { routePath } from "@tenphi/docs";
|
|
2
3
|
import { content } from "virtual:cookbook/config";
|
|
3
4
|
import { localeTarget, routeLocale, messages } from "../localization.js";
|
|
4
5
|
import { navigationPath } from "../navigation.js";
|
|
@@ -24,7 +25,7 @@ const options = Object.entries(content.locales ?? {}).flatMap(
|
|
|
24
25
|
label: config.label,
|
|
25
26
|
lang: config.lang ?? (locale === "root" ? "en" : locale),
|
|
26
27
|
fallback,
|
|
27
|
-
href:
|
|
28
|
+
href: routePath(target, content.base, content.trailingSlash),
|
|
28
29
|
},
|
|
29
30
|
]
|
|
30
31
|
: [];
|
|
@@ -21,8 +21,7 @@ const translations = {
|
|
|
21
21
|
data-search-key={`cookbook-search:${import.meta.env.BASE_URL}:${Astro.locals.cookbookRoute.lang}`}
|
|
22
22
|
data-search-base={import.meta.env.BASE_URL}
|
|
23
23
|
data-translations={JSON.stringify(translations)}
|
|
24
|
-
data-
|
|
25
|
-
undefined}
|
|
24
|
+
data-trailing-slash={content.trailingSlash}
|
|
26
25
|
>
|
|
27
26
|
<SearchButtonRoot
|
|
28
27
|
type="button"
|
package/dist/page-metadata.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { DocsConfig, DocsEntry, DocsRoute, HeadConfig, SiteConfig } from "@tenphi/docs";
|
|
1
|
+
import { DocsConfig, DocsEntry, DocsRoute, HeadConfig, SiteConfig, TrailingSlash } from "@tenphi/docs";
|
|
2
2
|
//#region src/page-metadata.d.ts
|
|
3
3
|
declare function pageMetadata(entry: DocsEntry, content: {
|
|
4
4
|
site: SiteConfig;
|
|
5
5
|
base: string;
|
|
6
|
+
trailingSlash?: TrailingSlash;
|
|
6
7
|
routes: DocsRoute[];
|
|
7
8
|
locales?: DocsConfig["locales"];
|
|
8
9
|
}, existing: HeadConfig[]): HeadConfig[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"page-metadata.d.ts","names":[],"sources":["../src/page-metadata.ts"],"mappings":";;
|
|
1
|
+
{"version":3,"file":"page-metadata.d.ts","names":[],"sources":["../src/page-metadata.ts"],"mappings":";;iBAagB,aACd,OAAO,WACP;EACE,MAAM;EACN;EACA,gBAAgB;EAChB,QAAQ;EACR,UAAU;GAEZ,UAAU,eACT;;iBAiIa,cAAc,eAAe"}
|
package/dist/page-metadata.js
CHANGED
|
@@ -7,7 +7,10 @@ function pageMetadata(entry, content, existing) {
|
|
|
7
7
|
const publishing = pagePublishing(entry, {
|
|
8
8
|
site: content.site,
|
|
9
9
|
...content.locales ? { locales: content.locales } : {},
|
|
10
|
-
build: {
|
|
10
|
+
build: {
|
|
11
|
+
base: content.base,
|
|
12
|
+
trailingSlash: content.trailingSlash
|
|
13
|
+
}
|
|
11
14
|
});
|
|
12
15
|
const { canonical, title, image, index } = publishing;
|
|
13
16
|
const owned = /* @__PURE__ */ new Set([
|
|
@@ -76,7 +79,7 @@ function pageMetadata(entry, content, existing) {
|
|
|
76
79
|
if (configured !== false && (configured || content.site.seo?.breadcrumbs) && /^https?:/.test(canonical)) {
|
|
77
80
|
const crumbs = configured ?? content.routes.filter((route) => (route.discoverable !== false || route.route === entry.route) && routeLocale(route.route, localeConfig) === routeLocale(entry.route, localeConfig) && (route.route === "/" || route.route === entry.route || entry.route.startsWith(`${route.route}/`))).sort((a, b) => a.route.length - b.route.length).map((route) => ({
|
|
78
81
|
name: route.title,
|
|
79
|
-
url: route.route === entry.route ? canonical : routeUrl(route.route, content.base, content.site.url)
|
|
82
|
+
url: route.route === entry.route ? canonical : routeUrl(route.route, content.base, content.site.url, content.trailingSlash)
|
|
80
83
|
}));
|
|
81
84
|
if (configured && crumbs.at(-1)?.url !== canonical) throw new Error(`seo.breadcrumbs in ${entry.sourcePath} must end with the page's canonical URL (${canonical}).`);
|
|
82
85
|
if (crumbs.length >= 2) head.push({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"page-metadata.js","names":[],"sources":["../src/page-metadata.ts"],"sourcesContent":["import { createHash } from \"node:crypto\";\nimport { routeLocale } from \"./localization.js\";\nimport {\n pagePublishing,\n routeUrl,\n type DocsEntry,\n type DocsRoute,\n type HeadConfig,\n type SiteConfig,\n type DocsConfig,\n} from \"@tenphi/docs\";\n\nexport function pageMetadata(\n entry: DocsEntry,\n content: {\n site: SiteConfig;\n base: string;\n routes: DocsRoute[];\n locales?: DocsConfig[\"locales\"];\n },\n existing: HeadConfig[],\n): HeadConfig[] {\n const localeConfig = content.locales ? { locales: content.locales } : {};\n const publishing = pagePublishing(entry, {\n site: content.site,\n ...(content.locales ? { locales: content.locales } : {}),\n build: { base: content.base },\n });\n const { canonical, title, image, index } = publishing;\n const owned = new Set([\n \"og:title\",\n \"og:url\",\n \"og:image\",\n \"og:image:alt\",\n \"og:image:width\",\n \"og:image:height\",\n \"twitter:card\",\n \"twitter:title\",\n \"twitter:image\",\n \"twitter:image:alt\",\n \"robots\",\n ]);\n const head = existing.filter(\n (tag) =>\n tag.tag !== \"title\" &&\n !(tag.tag === \"link\" && tag.attrs?.rel === \"canonical\") &&\n !(\n tag.tag === \"meta\" &&\n owned.has(String(tag.attrs?.name ?? tag.attrs?.property).toLowerCase())\n ),\n );\n const meta = (name: string, value: string, property = false) =>\n head.push({\n tag: \"meta\",\n attrs: { [property ? \"property\" : \"name\"]: name, content: value },\n });\n head.push({ tag: \"title\", content: escapeHtml(title) });\n if (/^https?:/.test(canonical)) {\n head.push({ tag: \"link\", attrs: { rel: \"canonical\", href: canonical } });\n meta(\"og:url\", canonical, true);\n }\n meta(\"og:title\", title, true);\n meta(\"twitter:title\", title);\n meta(\"twitter:card\", image ? \"summary_large_image\" : \"summary\");\n if (!index) meta(\"robots\", \"noindex, follow\");\n if (image) {\n const path = image.src.startsWith(\"/\")\n ? `${content.base.replace(/\\/$/, \"\")}${image.src}`\n : image.src;\n const url = content.site.url ? new URL(path, content.site.url).href : path;\n meta(\"og:image\", url, true);\n meta(\"og:image:alt\", image.alt, true);\n meta(\"twitter:image\", url);\n meta(\"twitter:image:alt\", image.alt);\n if (image.width && image.height) {\n meta(\"og:image:width\", String(image.width), true);\n meta(\"og:image:height\", String(image.height), true);\n }\n }\n meta(\"cookbook:source\", entry.sourcePath);\n if (publishing.version?.label ?? content.site.version)\n meta(\n \"cookbook:version\",\n publishing.version?.label ?? content.site.version!,\n );\n if (content.site.seo?.copyPage !== false && !entry.frontmatter.draft)\n head.push({\n tag: \"link\",\n attrs: {\n rel: \"alternate\",\n type: \"text/markdown\",\n title: \"Markdown\",\n href: agentPagePath(entry.route, content.base),\n },\n });\n const configured = entry.frontmatter.seo?.breadcrumbs;\n if (\n configured !== false &&\n (configured || content.site.seo?.breadcrumbs) &&\n /^https?:/.test(canonical)\n ) {\n const crumbs =\n configured ??\n content.routes\n .filter(\n (route) =>\n (route.discoverable !== false || route.route === entry.route) &&\n routeLocale(route.route, localeConfig) ===\n routeLocale(entry.route, localeConfig) &&\n (route.route === \"/\" ||\n route.route === entry.route ||\n entry.route.startsWith(`${route.route}/`)),\n )\n .sort((a, b) => a.route.length - b.route.length)\n .map((route) => ({\n name: route.title,\n url:\n route.route === entry.route\n ? canonical\n : routeUrl(route.route
|
|
1
|
+
{"version":3,"file":"page-metadata.js","names":[],"sources":["../src/page-metadata.ts"],"sourcesContent":["import { createHash } from \"node:crypto\";\nimport { routeLocale } from \"./localization.js\";\nimport {\n pagePublishing,\n routeUrl,\n type DocsEntry,\n type DocsRoute,\n type HeadConfig,\n type SiteConfig,\n type DocsConfig,\n type TrailingSlash,\n} from \"@tenphi/docs\";\n\nexport function pageMetadata(\n entry: DocsEntry,\n content: {\n site: SiteConfig;\n base: string;\n trailingSlash?: TrailingSlash;\n routes: DocsRoute[];\n locales?: DocsConfig[\"locales\"];\n },\n existing: HeadConfig[],\n): HeadConfig[] {\n const localeConfig = content.locales ? { locales: content.locales } : {};\n const publishing = pagePublishing(entry, {\n site: content.site,\n ...(content.locales ? { locales: content.locales } : {}),\n build: { base: content.base, trailingSlash: content.trailingSlash },\n });\n const { canonical, title, image, index } = publishing;\n const owned = new Set([\n \"og:title\",\n \"og:url\",\n \"og:image\",\n \"og:image:alt\",\n \"og:image:width\",\n \"og:image:height\",\n \"twitter:card\",\n \"twitter:title\",\n \"twitter:image\",\n \"twitter:image:alt\",\n \"robots\",\n ]);\n const head = existing.filter(\n (tag) =>\n tag.tag !== \"title\" &&\n !(tag.tag === \"link\" && tag.attrs?.rel === \"canonical\") &&\n !(\n tag.tag === \"meta\" &&\n owned.has(String(tag.attrs?.name ?? tag.attrs?.property).toLowerCase())\n ),\n );\n const meta = (name: string, value: string, property = false) =>\n head.push({\n tag: \"meta\",\n attrs: { [property ? \"property\" : \"name\"]: name, content: value },\n });\n head.push({ tag: \"title\", content: escapeHtml(title) });\n if (/^https?:/.test(canonical)) {\n head.push({ tag: \"link\", attrs: { rel: \"canonical\", href: canonical } });\n meta(\"og:url\", canonical, true);\n }\n meta(\"og:title\", title, true);\n meta(\"twitter:title\", title);\n meta(\"twitter:card\", image ? \"summary_large_image\" : \"summary\");\n if (!index) meta(\"robots\", \"noindex, follow\");\n if (image) {\n const path = image.src.startsWith(\"/\")\n ? `${content.base.replace(/\\/$/, \"\")}${image.src}`\n : image.src;\n const url = content.site.url ? new URL(path, content.site.url).href : path;\n meta(\"og:image\", url, true);\n meta(\"og:image:alt\", image.alt, true);\n meta(\"twitter:image\", url);\n meta(\"twitter:image:alt\", image.alt);\n if (image.width && image.height) {\n meta(\"og:image:width\", String(image.width), true);\n meta(\"og:image:height\", String(image.height), true);\n }\n }\n meta(\"cookbook:source\", entry.sourcePath);\n if (publishing.version?.label ?? content.site.version)\n meta(\n \"cookbook:version\",\n publishing.version?.label ?? content.site.version!,\n );\n if (content.site.seo?.copyPage !== false && !entry.frontmatter.draft)\n head.push({\n tag: \"link\",\n attrs: {\n rel: \"alternate\",\n type: \"text/markdown\",\n title: \"Markdown\",\n href: agentPagePath(entry.route, content.base),\n },\n });\n const configured = entry.frontmatter.seo?.breadcrumbs;\n if (\n configured !== false &&\n (configured || content.site.seo?.breadcrumbs) &&\n /^https?:/.test(canonical)\n ) {\n const crumbs =\n configured ??\n content.routes\n .filter(\n (route) =>\n (route.discoverable !== false || route.route === entry.route) &&\n routeLocale(route.route, localeConfig) ===\n routeLocale(entry.route, localeConfig) &&\n (route.route === \"/\" ||\n route.route === entry.route ||\n entry.route.startsWith(`${route.route}/`)),\n )\n .sort((a, b) => a.route.length - b.route.length)\n .map((route) => ({\n name: route.title,\n url:\n route.route === entry.route\n ? canonical\n : routeUrl(\n route.route,\n content.base,\n content.site.url,\n content.trailingSlash,\n ),\n }));\n if (configured && crumbs.at(-1)?.url !== canonical)\n throw new Error(\n `seo.breadcrumbs in ${entry.sourcePath} must end with the page's canonical URL (${canonical}).`,\n );\n if (crumbs.length >= 2)\n head.push({\n tag: \"script\",\n attrs: { type: \"application/ld+json\" },\n content: JSON.stringify({\n \"@context\": \"https://schema.org\",\n \"@type\": \"BreadcrumbList\",\n itemListElement: crumbs.map((crumb, index) => ({\n \"@type\": \"ListItem\",\n position: index + 1,\n name: crumb.name,\n item: crumb.url,\n })),\n }).replaceAll(\"<\", \"\\\\u003c\"),\n });\n }\n return head;\n}\n\n/** Stable short asset names also support deeply nested and non-ASCII routes. */\nexport function agentPagePath(route: string, base = \"/\"): string {\n return `${base.replace(/\\/$/, \"\")}/_cookbook/pages/${createHash(\"sha256\").update(route).digest(\"hex\").slice(0, 32)}.md`;\n}\n\nfunction escapeHtml(value: string): string {\n return value\n .replaceAll(\"&\", \"&\")\n .replaceAll(\"<\", \"<\")\n .replaceAll(\">\", \">\")\n .replaceAll('\"', \""\");\n}\n"],"mappings":"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"}
|
package/dist/route-context.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ResolvedNavigationLayout } from "./navigation.js";
|
|
2
|
-
import { DocsConfig, DocsHeading, DocsRoute, HeadConfig } from "@tenphi/docs";
|
|
2
|
+
import { DocsConfig, DocsHeading, DocsRoute, HeadConfig, TrailingSlash } from "@tenphi/docs";
|
|
3
3
|
//#region src/route-context.d.ts
|
|
4
4
|
type SidebarEntry = {
|
|
5
5
|
type: "link";
|
|
@@ -55,6 +55,7 @@ interface CookbookRoute {
|
|
|
55
55
|
type Content = {
|
|
56
56
|
routes: DocsRoute[];
|
|
57
57
|
base: string;
|
|
58
|
+
trailingSlash?: TrailingSlash;
|
|
58
59
|
site: {
|
|
59
60
|
title?: string;
|
|
60
61
|
description?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"route-context.d.ts","names":[],"sources":["../src/route-context.ts"],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"route-context.d.ts","names":[],"sources":["../src/route-context.ts"],"mappings":";;;KAsBY;EAEN;EACA;EACA;EACA;EACA,OAAO;EACP;;EAGA;EACA;EACA,SAAS;EACT;;UAGW;EACf;EACA;EACA,UAAU;;UAGK;EACf;EACA;EACA;EACA;EACA;EACA;EACA;IAAS,MAAM;;EACf;IAAa;IAAc;IAAoB;;EAC/C,SAAS;EACT;IACE;MAAS;MAAc;;IACvB;MAAS;MAAc;;;EAEzB;IAAQ,OAAO;;EACf,MAAM;EACN;EACA,cAAc;;KAGX;EACH,QAAQ;EACR;EACA,gBAAgB;EAChB;IAAQ;IAAgB;;EACxB,UAAU;EACV;EACA,eAAe;EACf,kBAAkB;EAClB,OAAO;;iBAGO,mBAAmB;EACjC;EACA,aAAa;EACb,UAAU;EACV,QAAQ;EACR,SAAS;IACP"}
|
package/dist/route-context.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { navigationPath, normalizeNavigationPath, pageSidebar } from "./navigation.js";
|
|
2
2
|
import { localeHref, localizedNavigation, requestLanguage, routeLocale } from "./localization.js";
|
|
3
|
+
import { routePath } from "@tenphi/docs";
|
|
3
4
|
//#region src/route-context.ts
|
|
4
5
|
function createRouteContext(input) {
|
|
5
6
|
const { pathname, frontmatter, headings, layout, content } = input;
|
|
@@ -35,7 +36,7 @@ function createRouteContext(input) {
|
|
|
35
36
|
dir,
|
|
36
37
|
hasSidebar: frontmatter.template !== "splash",
|
|
37
38
|
siteTitle: content.site.title ?? "Documentation",
|
|
38
|
-
siteTitleHref: content.base,
|
|
39
|
+
siteTitleHref: routePath("/", content.base, content.trailingSlash),
|
|
39
40
|
entry: { data: frontmatter },
|
|
40
41
|
entryMeta: {
|
|
41
42
|
lang,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"route-context.js","names":[],"sources":["../src/route-context.ts"],"sourcesContent":["import type {\n DocsConfig,\n DocsHeading,\n DocsRoute,\n HeadConfig,\n} from \"@tenphi/docs\";\nimport {\n localeHref,\n localizedNavigation,\n requestLanguage,\n routeLocale,\n} from \"./localization.js\";\nimport {\n navigationPath,\n normalizeNavigationPath,\n pageSidebar,\n type ResolvedNavigationLayout,\n type PageSidebarItem,\n} from \"./navigation.js\";\n\nexport type SidebarEntry =\n | {\n type: \"link\";\n label: string;\n href: string;\n isCurrent: boolean;\n attrs: Record<string, string>;\n badge?: string;\n }\n | {\n type: \"group\";\n label: string;\n entries: SidebarEntry[];\n badge?: string;\n };\n\nexport interface TocItem {\n slug: string;\n text: string;\n children: TocItem[];\n}\n\nexport interface CookbookRoute {\n id: string;\n lang: string;\n dir: \"ltr\" | \"rtl\";\n hasSidebar: boolean;\n siteTitle: string;\n siteTitleHref: string;\n entry: { data: Record<string, any> };\n entryMeta: { lang: string; dir: \"ltr\" | \"rtl\"; locale: string };\n sidebar: SidebarEntry[];\n pagination: {\n prev?: { href: string; label: string };\n next?: { href: string; label: string };\n };\n toc?: { items: TocItem[] };\n head: HeadConfig[];\n editUrl?: string;\n lastUpdated?: Date;\n}\n\ntype Content = {\n routes: DocsRoute[];\n base: string;\n site: { title?: string; description?: string };\n locales?: DocsConfig[\"locales\"];\n defaultLocale?: string;\n translations?: DocsConfig[\"translations\"];\n tableOfContents?: DocsConfig[\"tableOfContents\"];\n head?: HeadConfig[];\n};\n\nexport function createRouteContext(input: {\n pathname: string;\n frontmatter: Record<string, any>;\n headings: DocsHeading[];\n layout: ResolvedNavigationLayout;\n content: Content;\n}): CookbookRoute {\n const { pathname, frontmatter, headings, layout, content } = input;\n const currentPath = navigationPath(pathname, content.base);\n const locale = routeLocale(currentPath, content);\n const lang = requestLanguage(pathname, content.base, content);\n const dir = content.locales?.[locale]?.dir ?? \"ltr\";\n const localized = localizedNavigation(\n layout,\n content.routes,\n currentPath,\n content,\n );\n const sidebar = resolveSidebar(\n pageSidebar(localized.layout, localized.routes),\n currentPath,\n content,\n );\n const links = flattenLinks(sidebar);\n const currentIndex = links.findIndex((link) => link.isCurrent);\n const previous = resolvePaginationLink(\n frontmatter.prev,\n currentIndex >= 0 ? links[currentIndex - 1] : undefined,\n content,\n currentPath,\n );\n const next = resolvePaginationLink(\n frontmatter.next,\n currentIndex >= 0 ? links[currentIndex + 1] : undefined,\n content,\n currentPath,\n );\n const pagination = {\n ...(previous ? { prev: previous } : {}),\n ...(next ? { next } : {}),\n };\n const toc = resolveToc(headings, frontmatter, content);\n const head: HeadConfig[] = [\n ...(content.head ?? []),\n ...(frontmatter.head ?? []),\n ...(frontmatter.description || content.site.description\n ? [\n {\n tag: \"meta\",\n attrs: {\n name: \"description\",\n content: frontmatter.description ?? content.site.description,\n },\n },\n ]\n : []),\n ];\n return {\n id: currentPath,\n lang,\n dir,\n hasSidebar: frontmatter.template !== \"splash\",\n siteTitle: content.site.title ?? \"Documentation\",\n siteTitleHref: content.base,\n entry: { data: frontmatter },\n entryMeta: { lang, dir, locale },\n sidebar,\n pagination,\n ...(toc ? { toc } : {}),\n head,\n ...(typeof frontmatter.editUrl === \"string\"\n ? { editUrl: frontmatter.editUrl }\n : {}),\n ...(frontmatter.lastUpdated instanceof Date\n ? { lastUpdated: frontmatter.lastUpdated }\n : {}),\n };\n}\n\nfunction resolveSidebar(\n items: PageSidebarItem[],\n currentPath: string,\n content: Content,\n): SidebarEntry[] {\n return items.map((item): SidebarEntry => {\n if (\"link\" in item) {\n const href = localeHref(\n item.link,\n currentPath,\n content.routes,\n content,\n content.base,\n );\n return {\n type: \"link\",\n label: item.label,\n href,\n isCurrent:\n href.startsWith(\"/\") &&\n !href.startsWith(\"//\") &&\n navigationPath(\n new URL(href, \"https://cookbook.invalid\").pathname,\n content.base,\n ) === currentPath,\n attrs: item.attrs ?? {},\n ...(item.badge !== undefined ? { badge: item.badge } : {}),\n };\n }\n return {\n type: \"group\",\n label: item.label,\n entries: resolveSidebar(item.items, currentPath, content),\n ...(item.badge !== undefined ? { badge: item.badge } : {}),\n };\n });\n}\n\nfunction flattenLinks(\n items: SidebarEntry[],\n): Extract<SidebarEntry, { type: \"link\" }>[] {\n return items.flatMap((item) =>\n item.type === \"link\" ? [item] : flattenLinks(item.entries),\n );\n}\n\nfunction resolvePaginationLink(\n configured: unknown,\n automatic: Extract<SidebarEntry, { type: \"link\" }> | undefined,\n content: Content,\n currentPath: string,\n): { href: string; label: string } | undefined {\n if (configured === false) return undefined;\n if (configured === undefined)\n return automatic && { href: automatic.href, label: automatic.label };\n const link =\n typeof configured === \"string\"\n ? configured\n : configured &&\n typeof configured === \"object\" &&\n \"link\" in configured &&\n typeof configured.link === \"string\"\n ? configured.link\n : automatic?.href;\n if (!link) return undefined;\n const label =\n configured &&\n typeof configured === \"object\" &&\n \"label\" in configured &&\n typeof configured.label === \"string\"\n ? configured.label\n : (content.routes.find(\n (route) =>\n normalizeNavigationPath(route.route) ===\n normalizeNavigationPath(link),\n )?.title ??\n automatic?.label ??\n link);\n return {\n href: localeHref(link, currentPath, content.routes, content, content.base),\n label,\n };\n}\n\nfunction resolveToc(\n headings: DocsHeading[],\n frontmatter: Record<string, any>,\n content: Content,\n): { items: TocItem[] } | undefined {\n const option =\n frontmatter.tableOfContents ??\n (frontmatter.template === \"splash\" ? false : content.tableOfContents);\n if (option === false) return undefined;\n const min = typeof option === \"object\" ? (option.minHeadingLevel ?? 2) : 2;\n const max = typeof option === \"object\" ? (option.maxHeadingLevel ?? 3) : 3;\n const roots: TocItem[] = [];\n const stack: Array<{ depth: number; item: TocItem }> = [];\n for (const heading of headings) {\n if (heading.depth < min || heading.depth > max) continue;\n const item: TocItem = {\n slug: heading.slug,\n text: heading.text,\n children: [],\n };\n while (stack.length && stack[stack.length - 1]!.depth >= heading.depth)\n stack.pop();\n if (stack.length) stack[stack.length - 1]!.item.children.push(item);\n else roots.push(item);\n stack.push({ depth: heading.depth, item });\n }\n return roots.length ? { items: roots } : undefined;\n}\n"],"mappings":";;;AAyEA,SAAgB,mBAAmB,OAMjB;CAChB,MAAM,EAAE,UAAU,aAAa,UAAU,QAAQ,YAAY;CAC7D,MAAM,cAAc,eAAe,UAAU,QAAQ,IAAI;CACzD,MAAM,SAAS,YAAY,aAAa,OAAO;CAC/C,MAAM,OAAO,gBAAgB,UAAU,QAAQ,MAAM,OAAO;CAC5D,MAAM,MAAM,QAAQ,UAAU,OAAO,EAAE,OAAO;CAC9C,MAAM,YAAY,oBAChB,QACA,QAAQ,QACR,aACA,OACF;CACA,MAAM,UAAU,eACd,YAAY,UAAU,QAAQ,UAAU,MAAM,GAC9C,aACA,OACF;CACA,MAAM,QAAQ,aAAa,OAAO;CAClC,MAAM,eAAe,MAAM,WAAW,SAAS,KAAK,SAAS;CAC7D,MAAM,WAAW,sBACf,YAAY,MACZ,gBAAgB,IAAI,MAAM,eAAe,KAAK,KAAA,GAC9C,SACA,WACF;CACA,MAAM,OAAO,sBACX,YAAY,MACZ,gBAAgB,IAAI,MAAM,eAAe,KAAK,KAAA,GAC9C,SACA,WACF;CACA,MAAM,aAAa;EACjB,GAAI,WAAW,EAAE,MAAM,SAAS,IAAI,CAAC;EACrC,GAAI,OAAO,EAAE,KAAK,IAAI,CAAC;CACzB;CACA,MAAM,MAAM,WAAW,UAAU,aAAa,OAAO;CACrD,MAAM,OAAqB;EACzB,GAAI,QAAQ,QAAQ,CAAC;EACrB,GAAI,YAAY,QAAQ,CAAC;EACzB,GAAI,YAAY,eAAe,QAAQ,KAAK,cACxC,CACE;GACE,KAAK;GACL,OAAO;IACL,MAAM;IACN,SAAS,YAAY,eAAe,QAAQ,KAAK;GACnD;EACF,CACF,IACA,CAAC;CACP;CACA,OAAO;EACL,IAAI;EACJ;EACA;EACA,YAAY,YAAY,aAAa;EACrC,WAAW,QAAQ,KAAK,SAAS;EACjC,eAAe,QAAQ;EACvB,OAAO,EAAE,MAAM,YAAY;EAC3B,WAAW;GAAE;GAAM;GAAK;EAAO;EAC/B;EACA;EACA,GAAI,MAAM,EAAE,IAAI,IAAI,CAAC;EACrB;EACA,GAAI,OAAO,YAAY,YAAY,WAC/B,EAAE,SAAS,YAAY,QAAQ,IAC/B,CAAC;EACL,GAAI,YAAY,uBAAuB,OACnC,EAAE,aAAa,YAAY,YAAY,IACvC,CAAC;CACP;AACF;AAEA,SAAS,eACP,OACA,aACA,SACgB;CAChB,OAAO,MAAM,KAAK,SAAuB;EACvC,IAAI,UAAU,MAAM;GAClB,MAAM,OAAO,WACX,KAAK,MACL,aACA,QAAQ,QACR,SACA,QAAQ,IACV;GACA,OAAO;IACL,MAAM;IACN,OAAO,KAAK;IACZ;IACA,WACE,KAAK,WAAW,GAAG,KACnB,CAAC,KAAK,WAAW,IAAI,KACrB,eACE,IAAI,IAAI,MAAM,0BAA0B,CAAC,CAAC,UAC1C,QAAQ,IACV,MAAM;IACR,OAAO,KAAK,SAAS,CAAC;IACtB,GAAI,KAAK,UAAU,KAAA,IAAY,EAAE,OAAO,KAAK,MAAM,IAAI,CAAC;GAC1D;EACF;EACA,OAAO;GACL,MAAM;GACN,OAAO,KAAK;GACZ,SAAS,eAAe,KAAK,OAAO,aAAa,OAAO;GACxD,GAAI,KAAK,UAAU,KAAA,IAAY,EAAE,OAAO,KAAK,MAAM,IAAI,CAAC;EAC1D;CACF,CAAC;AACH;AAEA,SAAS,aACP,OAC2C;CAC3C,OAAO,MAAM,SAAS,SACpB,KAAK,SAAS,SAAS,CAAC,IAAI,IAAI,aAAa,KAAK,OAAO,CAC3D;AACF;AAEA,SAAS,sBACP,YACA,WACA,SACA,aAC6C;CAC7C,IAAI,eAAe,OAAO,OAAO,KAAA;CACjC,IAAI,eAAe,KAAA,GACjB,OAAO,aAAa;EAAE,MAAM,UAAU;EAAM,OAAO,UAAU;CAAM;CACrE,MAAM,OACJ,OAAO,eAAe,WAClB,aACA,cACE,OAAO,eAAe,YACtB,UAAU,cACV,OAAO,WAAW,SAAS,WAC3B,WAAW,OACX,WAAW;CACnB,IAAI,CAAC,MAAM,OAAO,KAAA;CAClB,MAAM,QACJ,cACA,OAAO,eAAe,YACtB,WAAW,cACX,OAAO,WAAW,UAAU,WACxB,WAAW,QACV,QAAQ,OAAO,MACb,UACC,wBAAwB,MAAM,KAAK,MACnC,wBAAwB,IAAI,CAChC,CAAC,EAAE,SACH,WAAW,SACX;CACN,OAAO;EACL,MAAM,WAAW,MAAM,aAAa,QAAQ,QAAQ,SAAS,QAAQ,IAAI;EACzE;CACF;AACF;AAEA,SAAS,WACP,UACA,aACA,SACkC;CAClC,MAAM,SACJ,YAAY,oBACX,YAAY,aAAa,WAAW,QAAQ,QAAQ;CACvD,IAAI,WAAW,OAAO,OAAO,KAAA;CAC7B,MAAM,MAAM,OAAO,WAAW,WAAY,OAAO,mBAAmB,IAAK;CACzE,MAAM,MAAM,OAAO,WAAW,WAAY,OAAO,mBAAmB,IAAK;CACzE,MAAM,QAAmB,CAAC;CAC1B,MAAM,QAAiD,CAAC;CACxD,KAAK,MAAM,WAAW,UAAU;EAC9B,IAAI,QAAQ,QAAQ,OAAO,QAAQ,QAAQ,KAAK;EAChD,MAAM,OAAgB;GACpB,MAAM,QAAQ;GACd,MAAM,QAAQ;GACd,UAAU,CAAC;EACb;EACA,OAAO,MAAM,UAAU,MAAM,MAAM,SAAS,EAAE,CAAE,SAAS,QAAQ,OAC/D,MAAM,IAAI;EACZ,IAAI,MAAM,QAAQ,MAAM,MAAM,SAAS,EAAE,CAAE,KAAK,SAAS,KAAK,IAAI;OAC7D,MAAM,KAAK,IAAI;EACpB,MAAM,KAAK;GAAE,OAAO,QAAQ;GAAO;EAAK,CAAC;CAC3C;CACA,OAAO,MAAM,SAAS,EAAE,OAAO,MAAM,IAAI,KAAA;AAC3C"}
|
|
1
|
+
{"version":3,"file":"route-context.js","names":[],"sources":["../src/route-context.ts"],"sourcesContent":["import {\n routePath,\n type DocsConfig,\n type DocsHeading,\n type DocsRoute,\n type HeadConfig,\n type TrailingSlash,\n} from \"@tenphi/docs\";\nimport {\n localeHref,\n localizedNavigation,\n requestLanguage,\n routeLocale,\n} from \"./localization.js\";\nimport {\n navigationPath,\n normalizeNavigationPath,\n pageSidebar,\n type ResolvedNavigationLayout,\n type PageSidebarItem,\n} from \"./navigation.js\";\n\nexport type SidebarEntry =\n | {\n type: \"link\";\n label: string;\n href: string;\n isCurrent: boolean;\n attrs: Record<string, string>;\n badge?: string;\n }\n | {\n type: \"group\";\n label: string;\n entries: SidebarEntry[];\n badge?: string;\n };\n\nexport interface TocItem {\n slug: string;\n text: string;\n children: TocItem[];\n}\n\nexport interface CookbookRoute {\n id: string;\n lang: string;\n dir: \"ltr\" | \"rtl\";\n hasSidebar: boolean;\n siteTitle: string;\n siteTitleHref: string;\n entry: { data: Record<string, any> };\n entryMeta: { lang: string; dir: \"ltr\" | \"rtl\"; locale: string };\n sidebar: SidebarEntry[];\n pagination: {\n prev?: { href: string; label: string };\n next?: { href: string; label: string };\n };\n toc?: { items: TocItem[] };\n head: HeadConfig[];\n editUrl?: string;\n lastUpdated?: Date;\n}\n\ntype Content = {\n routes: DocsRoute[];\n base: string;\n trailingSlash?: TrailingSlash;\n site: { title?: string; description?: string };\n locales?: DocsConfig[\"locales\"];\n defaultLocale?: string;\n translations?: DocsConfig[\"translations\"];\n tableOfContents?: DocsConfig[\"tableOfContents\"];\n head?: HeadConfig[];\n};\n\nexport function createRouteContext(input: {\n pathname: string;\n frontmatter: Record<string, any>;\n headings: DocsHeading[];\n layout: ResolvedNavigationLayout;\n content: Content;\n}): CookbookRoute {\n const { pathname, frontmatter, headings, layout, content } = input;\n const currentPath = navigationPath(pathname, content.base);\n const locale = routeLocale(currentPath, content);\n const lang = requestLanguage(pathname, content.base, content);\n const dir = content.locales?.[locale]?.dir ?? \"ltr\";\n const localized = localizedNavigation(\n layout,\n content.routes,\n currentPath,\n content,\n );\n const sidebar = resolveSidebar(\n pageSidebar(localized.layout, localized.routes),\n currentPath,\n content,\n );\n const links = flattenLinks(sidebar);\n const currentIndex = links.findIndex((link) => link.isCurrent);\n const previous = resolvePaginationLink(\n frontmatter.prev,\n currentIndex >= 0 ? links[currentIndex - 1] : undefined,\n content,\n currentPath,\n );\n const next = resolvePaginationLink(\n frontmatter.next,\n currentIndex >= 0 ? links[currentIndex + 1] : undefined,\n content,\n currentPath,\n );\n const pagination = {\n ...(previous ? { prev: previous } : {}),\n ...(next ? { next } : {}),\n };\n const toc = resolveToc(headings, frontmatter, content);\n const head: HeadConfig[] = [\n ...(content.head ?? []),\n ...(frontmatter.head ?? []),\n ...(frontmatter.description || content.site.description\n ? [\n {\n tag: \"meta\",\n attrs: {\n name: \"description\",\n content: frontmatter.description ?? content.site.description,\n },\n },\n ]\n : []),\n ];\n return {\n id: currentPath,\n lang,\n dir,\n hasSidebar: frontmatter.template !== \"splash\",\n siteTitle: content.site.title ?? \"Documentation\",\n siteTitleHref: routePath(\"/\", content.base, content.trailingSlash),\n entry: { data: frontmatter },\n entryMeta: { lang, dir, locale },\n sidebar,\n pagination,\n ...(toc ? { toc } : {}),\n head,\n ...(typeof frontmatter.editUrl === \"string\"\n ? { editUrl: frontmatter.editUrl }\n : {}),\n ...(frontmatter.lastUpdated instanceof Date\n ? { lastUpdated: frontmatter.lastUpdated }\n : {}),\n };\n}\n\nfunction resolveSidebar(\n items: PageSidebarItem[],\n currentPath: string,\n content: Content,\n): SidebarEntry[] {\n return items.map((item): SidebarEntry => {\n if (\"link\" in item) {\n const href = localeHref(\n item.link,\n currentPath,\n content.routes,\n content,\n content.base,\n );\n return {\n type: \"link\",\n label: item.label,\n href,\n isCurrent:\n href.startsWith(\"/\") &&\n !href.startsWith(\"//\") &&\n navigationPath(\n new URL(href, \"https://cookbook.invalid\").pathname,\n content.base,\n ) === currentPath,\n attrs: item.attrs ?? {},\n ...(item.badge !== undefined ? { badge: item.badge } : {}),\n };\n }\n return {\n type: \"group\",\n label: item.label,\n entries: resolveSidebar(item.items, currentPath, content),\n ...(item.badge !== undefined ? { badge: item.badge } : {}),\n };\n });\n}\n\nfunction flattenLinks(\n items: SidebarEntry[],\n): Extract<SidebarEntry, { type: \"link\" }>[] {\n return items.flatMap((item) =>\n item.type === \"link\" ? [item] : flattenLinks(item.entries),\n );\n}\n\nfunction resolvePaginationLink(\n configured: unknown,\n automatic: Extract<SidebarEntry, { type: \"link\" }> | undefined,\n content: Content,\n currentPath: string,\n): { href: string; label: string } | undefined {\n if (configured === false) return undefined;\n if (configured === undefined)\n return automatic && { href: automatic.href, label: automatic.label };\n const link =\n typeof configured === \"string\"\n ? configured\n : configured &&\n typeof configured === \"object\" &&\n \"link\" in configured &&\n typeof configured.link === \"string\"\n ? configured.link\n : automatic?.href;\n if (!link) return undefined;\n const label =\n configured &&\n typeof configured === \"object\" &&\n \"label\" in configured &&\n typeof configured.label === \"string\"\n ? configured.label\n : (content.routes.find(\n (route) =>\n normalizeNavigationPath(route.route) ===\n normalizeNavigationPath(link),\n )?.title ??\n automatic?.label ??\n link);\n return {\n href: localeHref(link, currentPath, content.routes, content, content.base),\n label,\n };\n}\n\nfunction resolveToc(\n headings: DocsHeading[],\n frontmatter: Record<string, any>,\n content: Content,\n): { items: TocItem[] } | undefined {\n const option =\n frontmatter.tableOfContents ??\n (frontmatter.template === \"splash\" ? false : content.tableOfContents);\n if (option === false) return undefined;\n const min = typeof option === \"object\" ? (option.minHeadingLevel ?? 2) : 2;\n const max = typeof option === \"object\" ? (option.maxHeadingLevel ?? 3) : 3;\n const roots: TocItem[] = [];\n const stack: Array<{ depth: number; item: TocItem }> = [];\n for (const heading of headings) {\n if (heading.depth < min || heading.depth > max) continue;\n const item: TocItem = {\n slug: heading.slug,\n text: heading.text,\n children: [],\n };\n while (stack.length && stack[stack.length - 1]!.depth >= heading.depth)\n stack.pop();\n if (stack.length) stack[stack.length - 1]!.item.children.push(item);\n else roots.push(item);\n stack.push({ depth: heading.depth, item });\n }\n return roots.length ? { items: roots } : undefined;\n}\n"],"mappings":"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"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
+
import { routePath } from "@tenphi/docs";
|
|
2
3
|
import Page from "./Page.astro";
|
|
3
4
|
import { content, mdxLoaders } from "virtual:cookbook/config";
|
|
4
5
|
|
|
@@ -27,7 +28,10 @@ export function getStaticPaths() {
|
|
|
27
28
|
|
|
28
29
|
const { entry, routes, redirect } = Astro.props;
|
|
29
30
|
if (redirect)
|
|
30
|
-
return Astro.redirect(
|
|
31
|
+
return Astro.redirect(
|
|
32
|
+
routePath(redirect, content.base, content.trailingSlash),
|
|
33
|
+
301,
|
|
34
|
+
);
|
|
31
35
|
const loadMdx = mdxLoaders[entry.route];
|
|
32
36
|
if (!entry.rendered && !loadMdx) {
|
|
33
37
|
throw new Error(`Cookbook did not render ${entry.sourcePath}.`);
|
package/dist/versioning.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import { DocsConfig, DocsRoute, SiteVersion } from "@tenphi/docs";
|
|
1
|
+
import { DocsConfig, DocsRoute, SiteVersion, TrailingSlash } from "@tenphi/docs";
|
|
2
2
|
//#region src/versioning.d.ts
|
|
3
|
-
declare function versionLinks(versions: SiteVersion[], routes: DocsRoute[], currentPath: string, base?: string, options?: Pick<DocsConfig, "locales" | "defaultLocale">
|
|
3
|
+
declare function versionLinks(versions: SiteVersion[], routes: DocsRoute[], currentPath: string, base?: string, options?: Pick<DocsConfig, "locales" | "defaultLocale"> & {
|
|
4
|
+
trailingSlash?: TrailingSlash;
|
|
5
|
+
}): {
|
|
4
6
|
current?: SiteVersion;
|
|
5
7
|
links: Array<SiteVersion & {
|
|
6
8
|
href: string;
|
package/dist/versioning.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"versioning.d.ts","names":[],"sources":["../src/versioning.ts"],"mappings":";;
|
|
1
|
+
{"version":3,"file":"versioning.d.ts","names":[],"sources":["../src/versioning.ts"],"mappings":";;iBAUgB,aACd,UAAU,eACV,QAAQ,aACR,qBACA,eACA,UAAS,KAAK;EACZ,gBAAgB;;EAEf,UAAU;EAAa,OAAO,MAAM;IAAgB"}
|
package/dist/versioning.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { normalizeNavigationPath } from "./navigation.js";
|
|
2
|
-
import { routeVersion } from "@tenphi/docs";
|
|
2
|
+
import { routePath, routeVersion } from "@tenphi/docs";
|
|
3
3
|
//#region src/versioning.ts
|
|
4
4
|
function versionLinks(versions, routes, currentPath, base = "/", options = {}) {
|
|
5
5
|
const path = normalizeNavigationPath(currentPath);
|
|
@@ -13,7 +13,6 @@ function versionLinks(versions, routes, currentPath, base = "/", options = {}) {
|
|
|
13
13
|
});
|
|
14
14
|
const suffix = current ? versionPath.slice(current.routeBase === "/" ? 0 : current.routeBase.length) : "";
|
|
15
15
|
const available = new Set(routes.filter((route) => route.discoverable !== false).map((route) => route.route));
|
|
16
|
-
const prefix = base.replace(/\/$/, "");
|
|
17
16
|
const locales = [
|
|
18
17
|
locale,
|
|
19
18
|
options.defaultLocale ?? (options.locales?.root ? "root" : Object.keys(options.locales ?? {})[0] ?? "root"),
|
|
@@ -27,7 +26,7 @@ function versionLinks(versions, routes, currentPath, base = "/", options = {}) {
|
|
|
27
26
|
const route = [...locales.slice(0, 2).map((lang) => normalizeNavigationPath(`${lang === "root" ? "" : `/${lang}`}${root}${suffix}`)), ...locales.map((lang) => normalizeNavigationPath(`${lang === "root" ? "" : `/${lang}`}${root}`))].find((route) => available.has(route));
|
|
28
27
|
return route ? [{
|
|
29
28
|
...version,
|
|
30
|
-
href:
|
|
29
|
+
href: routePath(route, base, options.trailingSlash)
|
|
31
30
|
}] : [];
|
|
32
31
|
})
|
|
33
32
|
};
|
package/dist/versioning.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"versioning.js","names":[],"sources":["../src/versioning.ts"],"sourcesContent":["import {\n routeVersion,\n type DocsConfig,\n type DocsRoute,\n type SiteVersion,\n} from \"@tenphi/docs\";\nimport { normalizeNavigationPath } from \"./navigation.js\";\n\nexport function versionLinks(\n versions: SiteVersion[],\n routes: DocsRoute[],\n currentPath: string,\n base = \"/\",\n options: Pick<DocsConfig, \"locales\" | \"defaultLocale\"> = {},\n): { current?: SiteVersion; links: Array<SiteVersion & { href: string }> } {\n const path = normalizeNavigationPath(currentPath);\n const first = path.split(\"/\")[1];\n const locale =\n first && first !== \"root\" && options.locales?.[first] ? first : \"root\";\n const localePrefix = locale === \"root\" ? \"\" : `/${locale}`;\n const versionPath = path.slice(localePrefix.length) || \"/\";\n const current = routeVersion(path, { site: { versions }, ...options });\n const suffix = current\n ? versionPath.slice(\n current.routeBase === \"/\" ? 0 : current.routeBase.length,\n )\n : \"\";\n const available = new Set(\n routes\n .filter((route) => route.discoverable !== false)\n .map((route) => route.route),\n );\n const
|
|
1
|
+
{"version":3,"file":"versioning.js","names":[],"sources":["../src/versioning.ts"],"sourcesContent":["import {\n routePath,\n routeVersion,\n type TrailingSlash,\n type DocsConfig,\n type DocsRoute,\n type SiteVersion,\n} from \"@tenphi/docs\";\nimport { normalizeNavigationPath } from \"./navigation.js\";\n\nexport function versionLinks(\n versions: SiteVersion[],\n routes: DocsRoute[],\n currentPath: string,\n base = \"/\",\n options: Pick<DocsConfig, \"locales\" | \"defaultLocale\"> & {\n trailingSlash?: TrailingSlash;\n } = {},\n): { current?: SiteVersion; links: Array<SiteVersion & { href: string }> } {\n const path = normalizeNavigationPath(currentPath);\n const first = path.split(\"/\")[1];\n const locale =\n first && first !== \"root\" && options.locales?.[first] ? first : \"root\";\n const localePrefix = locale === \"root\" ? \"\" : `/${locale}`;\n const versionPath = path.slice(localePrefix.length) || \"/\";\n const current = routeVersion(path, { site: { versions }, ...options });\n const suffix = current\n ? versionPath.slice(\n current.routeBase === \"/\" ? 0 : current.routeBase.length,\n )\n : \"\";\n const available = new Set(\n routes\n .filter((route) => route.discoverable !== false)\n .map((route) => route.route),\n );\n const defaultLocale =\n options.defaultLocale ??\n (options.locales?.root\n ? \"root\"\n : (Object.keys(options.locales ?? {})[0] ?? \"root\"));\n const locales = [\n locale,\n defaultLocale,\n \"root\",\n ...Object.keys(options.locales ?? {}),\n ];\n return {\n ...(current ? { current } : {}),\n links: versions.flatMap((version) => {\n const root = version.routeBase === \"/\" ? \"\" : version.routeBase;\n const candidates = [\n ...locales\n .slice(0, 2)\n .map((lang) =>\n normalizeNavigationPath(\n `${lang === \"root\" ? \"\" : `/${lang}`}${root}${suffix}`,\n ),\n ),\n ...locales.map((lang) =>\n normalizeNavigationPath(\n `${lang === \"root\" ? \"\" : `/${lang}`}${root}`,\n ),\n ),\n ];\n const route = candidates.find((route) => available.has(route));\n return route\n ? [{ ...version, href: routePath(route, base, options.trailingSlash) }]\n : [];\n }),\n };\n}\n"],"mappings":";;;AAUA,SAAgB,aACd,UACA,QACA,aACA,OAAO,KACP,UAEI,CAAC,GACoE;CACzE,MAAM,OAAO,wBAAwB,WAAW;CAChD,MAAM,QAAQ,KAAK,MAAM,GAAG,CAAC,CAAC;CAC9B,MAAM,SACJ,SAAS,UAAU,UAAU,QAAQ,UAAU,SAAS,QAAQ;CAClE,MAAM,eAAe,WAAW,SAAS,KAAK,IAAI;CAClD,MAAM,cAAc,KAAK,MAAM,aAAa,MAAM,KAAK;CACvD,MAAM,UAAU,aAAa,MAAM;EAAE,MAAM,EAAE,SAAS;EAAG,GAAG;CAAQ,CAAC;CACrE,MAAM,SAAS,UACX,YAAY,MACV,QAAQ,cAAc,MAAM,IAAI,QAAQ,UAAU,MACpD,IACA;CACJ,MAAM,YAAY,IAAI,IACpB,OACG,QAAQ,UAAU,MAAM,iBAAiB,KAAK,CAAC,CAC/C,KAAK,UAAU,MAAM,KAAK,CAC/B;CAMA,MAAM,UAAU;EACd;EALA,QAAQ,kBACP,QAAQ,SAAS,OACd,SACC,OAAO,KAAK,QAAQ,WAAW,CAAC,CAAC,CAAC,CAAC,MAAM;EAI9C;EACA,GAAG,OAAO,KAAK,QAAQ,WAAW,CAAC,CAAC;CACtC;CACA,OAAO;EACL,GAAI,UAAU,EAAE,QAAQ,IAAI,CAAC;EAC7B,OAAO,SAAS,SAAS,YAAY;GACnC,MAAM,OAAO,QAAQ,cAAc,MAAM,KAAK,QAAQ;GAetD,MAAM,QAAQ,CAbZ,GAAG,QACA,MAAM,GAAG,CAAC,CAAC,CACX,KAAK,SACJ,wBACE,GAAG,SAAS,SAAS,KAAK,IAAI,SAAS,OAAO,QAChD,CACF,GACF,GAAG,QAAQ,KAAK,SACd,wBACE,GAAG,SAAS,SAAS,KAAK,IAAI,SAAS,MACzC,CACF,CAEqB,CAAC,CAAC,MAAM,UAAU,UAAU,IAAI,KAAK,CAAC;GAC7D,OAAO,QACH,CAAC;IAAE,GAAG;IAAS,MAAM,UAAU,OAAO,MAAM,QAAQ,aAAa;GAAE,CAAC,IACpE,CAAC;EACP,CAAC;CACH;AACF"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tenphi/renderer",
|
|
3
|
-
"version": "0.25.
|
|
3
|
+
"version": "0.25.1",
|
|
4
4
|
"description": "Astro renderer and Tasty theme for Cookbook",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": [
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
"@fontsource-variable/jetbrains-mono": "^5.3.0",
|
|
62
62
|
"@fontsource-variable/onest": "^5.3.0",
|
|
63
63
|
"@pagefind/default-ui": "1.5.2",
|
|
64
|
-
"@tenphi/docs": "0.25.
|
|
64
|
+
"@tenphi/docs": "0.25.1",
|
|
65
65
|
"@tenphi/eslint-plugin-tasty": "1.6.0",
|
|
66
66
|
"@tenphi/glaze": "2.0.1",
|
|
67
67
|
"@tenphi/tasty": "3.9.10",
|