@tenphi/renderer 0.19.0
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/LICENSE +21 -0
- package/README.md +23 -0
- package/dist/client/appearance.d.ts +12 -0
- package/dist/client/appearance.d.ts.map +1 -0
- package/dist/client/appearance.js +66 -0
- package/dist/client/appearance.js.map +1 -0
- package/dist/client/code-copy.d.ts +1 -0
- package/dist/client/code-copy.js +63 -0
- package/dist/client/code-copy.js.map +1 -0
- package/dist/client/heading-links.d.ts +6 -0
- package/dist/client/heading-links.d.ts.map +1 -0
- package/dist/client/heading-links.js +87 -0
- package/dist/client/heading-links.js.map +1 -0
- package/dist/client/mobile-toc.d.ts +1 -0
- package/dist/client/mobile-toc.js +28 -0
- package/dist/client/mobile-toc.js.map +1 -0
- package/dist/client/navigation.d.ts +1 -0
- package/dist/client/navigation.js +112 -0
- package/dist/client/navigation.js.map +1 -0
- package/dist/client/page-copy.d.ts +1 -0
- package/dist/client/page-copy.js +34 -0
- package/dist/client/page-copy.js.map +1 -0
- package/dist/client/search.d.ts +13 -0
- package/dist/client/search.d.ts.map +1 -0
- package/dist/client/search.js +87 -0
- package/dist/client/search.js.map +1 -0
- package/dist/client/sidebar.d.ts +1 -0
- package/dist/client/sidebar.js +93 -0
- package/dist/client/sidebar.js.map +1 -0
- package/dist/client/tabs.d.ts +6 -0
- package/dist/client/tabs.d.ts.map +1 -0
- package/dist/client/tabs.js +64 -0
- package/dist/client/tabs.js.map +1 -0
- package/dist/components/Callout.astro +15 -0
- package/dist/components/Card.astro +13 -0
- package/dist/components/CodeGroup.astro +47 -0
- package/dist/components/ContrastIcon.astro +29 -0
- package/dist/components/EditLink.astro +11 -0
- package/dist/components/GlobalStyles.js +1675 -0
- package/dist/components/HeaderLinks.astro +84 -0
- package/dist/components/Icon.astro +39 -0
- package/dist/components/LastUpdated.astro +17 -0
- package/dist/components/LayoutComponents.js +866 -0
- package/dist/components/Logo.astro +37 -0
- package/dist/components/MobileNavigationTabs.astro +79 -0
- package/dist/components/MobileTocList.astro +22 -0
- package/dist/components/PackageVersion.astro +25 -0
- package/dist/components/PageActions.astro +29 -0
- package/dist/components/Pagination.astro +29 -0
- package/dist/components/Preview.astro +34 -0
- package/dist/components/SidebarList.astro +122 -0
- package/dist/components/SiteLogo.astro +40 -0
- package/dist/components/SiteTitle.astro +7 -0
- package/dist/components/Steps.astro +6 -0
- package/dist/components/Tab.astro +10 -0
- package/dist/components/TableOfContents.astro +23 -0
- package/dist/components/Tabs.astro +16 -0
- package/dist/components/TastyComponents.js +255 -0
- package/dist/components/VersionSwitcher.astro +44 -0
- package/dist/components/appearance-preferences.test.ts +91 -0
- package/dist/components/appearance-preferences.ts +57 -0
- package/dist/components/component-styles.test.ts +129 -0
- package/dist/components/component-styles.ts +65 -0
- package/dist/components/customize-component.js +8 -0
- package/dist/components/props.d.ts +38 -0
- package/dist/components/props.d.ts.map +1 -0
- package/dist/components/props.js +1 -0
- package/dist/components/props.ts +30 -0
- package/dist/components/svg-icon.test.ts +11 -0
- package/dist/components/svg-icon.ts +11 -0
- package/dist/components/tasty-states.d.ts +2 -0
- package/dist/components/tasty-states.js +42 -0
- package/dist/components-public.d.ts +21 -0
- package/dist/components.d.ts +10 -0
- package/dist/components.js +9 -0
- package/dist/content.d.ts +11 -0
- package/dist/content.d.ts.map +1 -0
- package/dist/content.js +16 -0
- package/dist/content.js.map +1 -0
- package/dist/eslint-plugin.d.ts +32 -0
- package/dist/eslint-plugin.d.ts.map +1 -0
- package/dist/eslint-plugin.js +155 -0
- package/dist/eslint-plugin.js.map +1 -0
- package/dist/icons/arrow-left.svg +1 -0
- package/dist/icons/arrow-right.svg +1 -0
- package/dist/icons/check.svg +1 -0
- package/dist/icons/chevron-down.svg +1 -0
- package/dist/icons/chevron-right.svg +1 -0
- package/dist/icons/close.svg +1 -0
- package/dist/icons/copy.svg +1 -0
- package/dist/icons/device-desktop.svg +1 -0
- package/dist/icons/favicon.svg +11 -0
- package/dist/icons/menu.svg +1 -0
- package/dist/icons/moon.svg +1 -0
- package/dist/icons/palette.svg +1 -0
- package/dist/icons/search.svg +1 -0
- package/dist/icons/sun.svg +1 -0
- package/dist/index-BuX_Sb5c.d.ts +10 -0
- package/dist/index-BuX_Sb5c.d.ts.map +1 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1648 -0
- package/dist/index.js.map +1 -0
- package/dist/localization.d.ts +69 -0
- package/dist/localization.d.ts.map +1 -0
- package/dist/localization.js +195 -0
- package/dist/localization.js.map +1 -0
- package/dist/markdown/rendered-content.d.ts +6 -0
- package/dist/markdown/rendered-content.d.ts.map +1 -0
- package/dist/markdown/rendered-content.js +34 -0
- package/dist/markdown/rendered-content.js.map +1 -0
- package/dist/messages-B_3xUzUb.js +14 -0
- package/dist/messages-B_3xUzUb.js.map +1 -0
- package/dist/navigation.d.ts +31 -0
- package/dist/navigation.d.ts.map +1 -0
- package/dist/navigation.js +165 -0
- package/dist/navigation.js.map +1 -0
- package/dist/overrides/DraftContentNotice.astro +8 -0
- package/dist/overrides/EmptyFooter.astro +3 -0
- package/dist/overrides/Footer.astro +23 -0
- package/dist/overrides/Head.astro +59 -0
- package/dist/overrides/Header.astro +139 -0
- package/dist/overrides/Hero.astro +73 -0
- package/dist/overrides/LanguageSelect.astro +63 -0
- package/dist/overrides/MarkdownContent.astro +14 -0
- package/dist/overrides/MobileMenuFooter.astro +15 -0
- package/dist/overrides/MobileMenuToggle.astro +36 -0
- package/dist/overrides/MobileTableOfContents.astro +37 -0
- package/dist/overrides/PageFrame.astro +35 -0
- package/dist/overrides/Search.astro +64 -0
- package/dist/overrides/Sidebar.astro +89 -0
- package/dist/overrides/SocialIcons.astro +27 -0
- package/dist/overrides/ThemeSelect.astro +148 -0
- package/dist/page-metadata.d.ts +13 -0
- package/dist/page-metadata.d.ts.map +1 -0
- package/dist/page-metadata.js +109 -0
- package/dist/page-metadata.js.map +1 -0
- package/dist/route-context.d.ts +85 -0
- package/dist/route-context.d.ts.map +1 -0
- package/dist/route-context.js +116 -0
- package/dist/route-context.js.map +1 -0
- package/dist/routes/DocsPage.astro +91 -0
- package/dist/routes/NotFound.astro +12 -0
- package/dist/routes/Page.astro +120 -0
- package/dist/styling.d.ts +17 -0
- package/dist/styling.d.ts.map +1 -0
- package/dist/styling.js +17 -0
- package/dist/styling.js.map +1 -0
- package/dist/tasty-states-BDKIbfw2.js +65 -0
- package/dist/tasty-states-BDKIbfw2.js.map +1 -0
- package/dist/theme/defaults.d.ts +21 -0
- package/dist/theme/defaults.d.ts.map +1 -0
- package/dist/theme/defaults.js +93 -0
- package/dist/theme/defaults.js.map +1 -0
- package/dist/theme/fonts.ts +64 -0
- package/dist/theme/shiki-theme.d.ts +13 -0
- package/dist/theme/shiki-theme.d.ts.map +1 -0
- package/dist/theme/shiki-theme.js +328 -0
- package/dist/theme/shiki-theme.js.map +1 -0
- package/dist/theme/tasty-config.d.ts +13 -0
- package/dist/theme/tasty-config.d.ts.map +1 -0
- package/dist/theme/tasty-config.js +16 -0
- package/dist/theme/tasty-config.js.map +1 -0
- package/dist/ui.d.ts +6 -0
- package/dist/ui.d.ts.map +1 -0
- package/dist/ui.js +53 -0
- package/dist/ui.js.map +1 -0
- package/dist/versioning.d.ts +11 -0
- package/dist/versioning.d.ts.map +1 -0
- package/dist/versioning.js +38 -0
- package/dist/versioning.js.map +1 -0
- package/package.json +92 -0
- package/tasty.config.mjs +1 -0
|
@@ -0,0 +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 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 if (typeof item === \"string\")\n return !internal || available.has(translated!) ? [translated!] : [];\n if (\"items\" in item || \"autogenerate\" in item) {\n const { link: _link, ...group } = item;\n return [\n {\n ...group,\n label: label(group.label),\n ...(translated && (!internal || available.has(translated))\n ? { link: translated }\n : {}),\n ...(\"items\" in item\n ? { items: convert(item.items) }\n : {\n autogenerate: {\n directory: localePath(item.autogenerate.directory, options),\n },\n }),\n },\n ];\n }\n return !internal || available.has(translated!)\n ? [{ ...item, label: label(item.label), link: translated! }]\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 const ENGLISH_MESSAGES = {\n copyPage: \"Copy page\",\n viewMarkdown: \"Download Markdown\",\n pageCopied: \"Page copied\",\n pageCopyError: \"Could not copy. Download Markdown to read or copy the text.\",\n draftTitle: \"Draft\",\n draftNotice:\n \"This page is available by direct link and excluded from navigation and indexes.\",\n searchError: \"Search could not load. Close and try again.\",\n appearance: \"Appearance\",\n colorScheme: \"Color scheme\",\n contrast: \"Contrast\",\n normalContrast: \"Normal\",\n highContrast: \"High\",\n auto: \"Auto\",\n closeNavigation: \"Close navigation\",\n primary: \"Primary\",\n sections: \"Sections\",\n chooseSection: \"Choose section\",\n headerLinks: \"Header links\",\n more: \"More\",\n closeMore: \"Close more menu\",\n moreLinks: \"More links\",\n versions: \"Versions\",\n documentationVersion: \"Documentation version\",\n documentationVersions: \"Documentation versions\",\n version: \"Version\",\n home: \"Home\",\n generatedWith: \"Generated with\",\n viewSource: \"View source\",\n copyCode: \"Copy code\",\n codeCopied: \"Code copied\",\n codeCopyError: \"Could not copy code\",\n copyHeading: \"Copy link to “{heading}”\",\n linkCopied: \"Link copied\",\n linkCopyError: \"Could not copy link\",\n notFound: \"Page not found\",\n notFoundDescription: \"The page you requested could not be found.\",\n fallback: \"fallback\",\n} as const;\nexport type MessageKey = keyof typeof ENGLISH_MESSAGES;\nconst FRENCH_MESSAGES: Record<MessageKey, string> = {\n copyPage: \"Copier la page\",\n viewMarkdown: \"Télécharger le Markdown\",\n pageCopied: \"Page copiée\",\n pageCopyError:\n \"Copie impossible. Téléchargez le Markdown pour lire ou copier le texte.\",\n draftTitle: \"Brouillon\",\n draftNotice:\n \"Cette page est accessible par son lien direct et exclue de la navigation et des index.\",\n searchError: \"La recherche n’a pas pu se charger. Fermez et réessayez.\",\n appearance: \"Apparence\",\n colorScheme: \"Thème de couleur\",\n contrast: \"Contraste\",\n normalContrast: \"Normal\",\n highContrast: \"Élevé\",\n auto: \"Auto\",\n closeNavigation: \"Fermer la navigation\",\n primary: \"Navigation principale\",\n sections: \"Sections\",\n chooseSection: \"Choisir une section\",\n headerLinks: \"Liens d’en-tête\",\n more: \"Plus\",\n closeMore: \"Fermer le menu\",\n moreLinks: \"Autres liens\",\n versions: \"Versions\",\n documentationVersion: \"Version de la documentation\",\n documentationVersions: \"Versions de la documentation\",\n version: \"Version\",\n home: \"Accueil\",\n generatedWith: \"Créé avec\",\n viewSource: \"Voir le code source\",\n copyCode: \"Copier le code\",\n codeCopied: \"Code copié\",\n codeCopyError: \"Impossible de copier le code\",\n copyHeading: \"Copier le lien vers « {heading} »\",\n linkCopied: \"Lien copié\",\n linkCopyError: \"Impossible de copier le lien\",\n notFound: \"Page introuvable\",\n notFoundDescription: \"La page demandée est introuvable.\",\n fallback: \"langue de secours\",\n};\nexport function messages(\n lang: string,\n options: LocaleOptions = {},\n): Record<MessageKey, string> {\n const language = lang.split(\"-\")[0] ?? \"en\";\n return {\n ...ENGLISH_MESSAGES,\n ...(language === \"fr\" ? FRENCH_MESSAGES : {}),\n ...options.translations?.[language],\n ...options.translations?.[lang],\n };\n}\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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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
//#region src/markdown/rendered-content.d.ts
|
|
2
|
+
/** Wrap rendered headings with a visible, accessible permalink. */
|
|
3
|
+
declare function addHeadingPermalinks(html: string): string;
|
|
4
|
+
//#endregion
|
|
5
|
+
export { addHeadingPermalinks };
|
|
6
|
+
//# sourceMappingURL=rendered-content.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rendered-content.d.ts","names":[],"sources":["../../src/markdown/rendered-content.ts"],"mappings":";;iBAMgB,qBAAqB"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
//#region src/markdown/rendered-content.ts
|
|
2
|
+
const headingPattern = /<div\b[^>]*\bclass=["'][^"']*\bcookbook-heading-wrapper\b[^"']*["'][^>]*>[\s\S]*?<\/div>|<h([1-6])\b([^>]*)>([\s\S]*?)<\/h\1>/gi;
|
|
3
|
+
const idPattern = /\sid=(['"])(.*?)\1/i;
|
|
4
|
+
const tags = /<[^>]*>/g;
|
|
5
|
+
/** Wrap rendered headings with a visible, accessible permalink. */
|
|
6
|
+
function addHeadingPermalinks(html) {
|
|
7
|
+
return html.replace(headingPattern, (heading, level, attributes, content) => {
|
|
8
|
+
if (!level || attributes === void 0 || content === void 0) return heading;
|
|
9
|
+
const id = idPattern.exec(attributes)?.[2];
|
|
10
|
+
if (!id) return heading;
|
|
11
|
+
const title = escapeAttribute(decodeEntities(content.replace(tags, "").trim()));
|
|
12
|
+
return `<div class="cookbook-heading-wrapper level-h${level}">${heading}<a class="cookbook-anchor-link" href="#${escapeAttribute(id)}" aria-label="Permalink to “${title}”"><span class="cookbook-anchor-icon" aria-hidden="true">#</span></a></div>`;
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
function decodeEntities(value) {
|
|
16
|
+
const named = {
|
|
17
|
+
amp: "&",
|
|
18
|
+
apos: "'",
|
|
19
|
+
gt: ">",
|
|
20
|
+
lt: "<",
|
|
21
|
+
quot: "\""
|
|
22
|
+
};
|
|
23
|
+
return value.replace(/&(?:#(\d+)|#x([\da-f]+)|(amp|apos|gt|lt|quot));/gi, (entity, decimal, hexadecimal, name) => {
|
|
24
|
+
const point = decimal ? Number.parseInt(decimal, 10) : hexadecimal ? Number.parseInt(hexadecimal, 16) : void 0;
|
|
25
|
+
return point === void 0 ? named[name.toLowerCase()] ?? entity : String.fromCodePoint(point);
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
function escapeAttribute(value) {
|
|
29
|
+
return value.replaceAll("&", "&").replaceAll("\"", """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
30
|
+
}
|
|
31
|
+
//#endregion
|
|
32
|
+
export { addHeadingPermalinks };
|
|
33
|
+
|
|
34
|
+
//# sourceMappingURL=rendered-content.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rendered-content.js","names":[],"sources":["../../src/markdown/rendered-content.ts"],"sourcesContent":["const headingPattern =\n /<div\\b[^>]*\\bclass=[\"'][^\"']*\\bcookbook-heading-wrapper\\b[^\"']*[\"'][^>]*>[\\s\\S]*?<\\/div>|<h([1-6])\\b([^>]*)>([\\s\\S]*?)<\\/h\\1>/gi;\nconst idPattern = /\\sid=(['\"])(.*?)\\1/i;\nconst tags = /<[^>]*>/g;\n\n/** Wrap rendered headings with a visible, accessible permalink. */\nexport function addHeadingPermalinks(html: string): string {\n return html.replace(\n headingPattern,\n (\n heading,\n level: string | undefined,\n attributes: string | undefined,\n content: string | undefined,\n ) => {\n // Consume an existing heading wrapper unchanged so its inner heading\n // is not matched and wrapped a second time.\n if (!level || attributes === undefined || content === undefined) {\n return heading;\n }\n const id = idPattern.exec(attributes)?.[2];\n if (!id) return heading;\n const title = escapeAttribute(\n decodeEntities(content.replace(tags, \"\").trim()),\n );\n return `<div class=\"cookbook-heading-wrapper level-h${level}\">${heading}<a class=\"cookbook-anchor-link\" href=\"#${escapeAttribute(id)}\" aria-label=\"Permalink to “${title}”\"><span class=\"cookbook-anchor-icon\" aria-hidden=\"true\">#</span></a></div>`;\n },\n );\n}\n\nfunction decodeEntities(value: string): string {\n const named: Record<string, string> = {\n amp: \"&\",\n apos: \"'\",\n gt: \">\",\n lt: \"<\",\n quot: '\"',\n };\n return value.replace(\n /&(?:#(\\d+)|#x([\\da-f]+)|(amp|apos|gt|lt|quot));/gi,\n (entity, decimal: string, hexadecimal: string, name: string) => {\n const point = decimal\n ? Number.parseInt(decimal, 10)\n : hexadecimal\n ? Number.parseInt(hexadecimal, 16)\n : undefined;\n return point === undefined\n ? (named[name.toLowerCase()] ?? entity)\n : String.fromCodePoint(point);\n },\n );\n}\n\nfunction escapeAttribute(value: string): string {\n return value\n .replaceAll(\"&\", \"&\")\n .replaceAll('\"', \""\")\n .replaceAll(\"'\", \"'\")\n .replaceAll(\"<\", \"<\")\n .replaceAll(\">\", \">\");\n}\n"],"mappings":";AAAA,MAAM,iBACJ;AACF,MAAM,YAAY;AAClB,MAAM,OAAO;;AAGb,SAAgB,qBAAqB,MAAsB;CACzD,OAAO,KAAK,QACV,iBAEE,SACA,OACA,YACA,YACG;EAGH,IAAI,CAAC,SAAS,eAAe,KAAA,KAAa,YAAY,KAAA,GACpD,OAAO;EAET,MAAM,KAAK,UAAU,KAAK,UAAU,CAAC,GAAG;EACxC,IAAI,CAAC,IAAI,OAAO;EAChB,MAAM,QAAQ,gBACZ,eAAe,QAAQ,QAAQ,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,CACjD;EACA,OAAO,+CAA+C,MAAM,IAAI,QAAQ,yCAAyC,gBAAgB,EAAE,EAAE,8BAA8B,MAAM;CAC3K,CACF;AACF;AAEA,SAAS,eAAe,OAAuB;CAC7C,MAAM,QAAgC;EACpC,KAAK;EACL,MAAM;EACN,IAAI;EACJ,IAAI;EACJ,MAAM;CACR;CACA,OAAO,MAAM,QACX,sDACC,QAAQ,SAAiB,aAAqB,SAAiB;EAC9D,MAAM,QAAQ,UACV,OAAO,SAAS,SAAS,EAAE,IAC3B,cACE,OAAO,SAAS,aAAa,EAAE,IAC/B,KAAA;EACN,OAAO,UAAU,KAAA,IACZ,MAAM,KAAK,YAAY,MAAM,SAC9B,OAAO,cAAc,KAAK;CAChC,CACF;AACF;AAEA,SAAS,gBAAgB,OAAuB;CAC9C,OAAO,MACJ,WAAW,KAAK,OAAO,CAAC,CACxB,WAAW,MAAK,QAAQ,CAAC,CACzB,WAAW,KAAK,OAAO,CAAC,CACxB,WAAW,KAAK,MAAM,CAAC,CACvB,WAAW,KAAK,MAAM;AAC3B"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { ENGLISH_MESSAGES } from "./localization.js";
|
|
2
|
+
//#region src/client/messages.ts
|
|
3
|
+
function message(key) {
|
|
4
|
+
try {
|
|
5
|
+
const custom = JSON.parse(document.querySelector("meta[name=\"cookbook-messages\"]")?.getAttribute("content") ?? "{}");
|
|
6
|
+
return typeof custom[key] === "string" ? custom[key] : ENGLISH_MESSAGES[key];
|
|
7
|
+
} catch {
|
|
8
|
+
return ENGLISH_MESSAGES[key];
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
//#endregion
|
|
12
|
+
export { message as t };
|
|
13
|
+
|
|
14
|
+
//# sourceMappingURL=messages-B_3xUzUb.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"messages-B_3xUzUb.js","names":[],"sources":["../src/client/messages.ts"],"sourcesContent":["import { ENGLISH_MESSAGES, type MessageKey } from \"../localization.js\";\nexport function message(key: MessageKey): string {\n try {\n const custom = JSON.parse(\n document\n .querySelector('meta[name=\"cookbook-messages\"]')\n ?.getAttribute(\"content\") ?? \"{}\",\n );\n return typeof custom[key] === \"string\"\n ? custom[key]\n : ENGLISH_MESSAGES[key];\n } catch {\n return ENGLISH_MESSAGES[key];\n }\n}\n"],"mappings":";;AACA,SAAgB,QAAQ,KAAyB;CAC/C,IAAI;EACF,MAAM,SAAS,KAAK,MAClB,SACG,cAAc,kCAAgC,CAAC,EAC9C,aAAa,SAAS,KAAK,IACjC;EACA,OAAO,OAAO,OAAO,SAAS,WAC1B,OAAO,OACP,iBAAiB;CACvB,QAAQ;EACN,OAAO,iBAAiB;CAC1B;AACF"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { DocsConfig, DocsRoute, NavigationItem, NavigationTab } from "@tenphi/docs";
|
|
2
|
+
//#region src/navigation.d.ts
|
|
3
|
+
interface ResolvedNavigationTab extends NavigationTab {
|
|
4
|
+
/** Index of the tab's resolved sidebar group. */
|
|
5
|
+
sidebarGroup?: number;
|
|
6
|
+
}
|
|
7
|
+
interface ResolvedNavigationLayout {
|
|
8
|
+
fallbackSidebarGroup?: number;
|
|
9
|
+
items?: NavigationItem[];
|
|
10
|
+
tabs: ResolvedNavigationTab[];
|
|
11
|
+
sectioned: boolean;
|
|
12
|
+
}
|
|
13
|
+
type PageSidebarItem = {
|
|
14
|
+
label: string;
|
|
15
|
+
link: string;
|
|
16
|
+
attrs?: Record<string, string>;
|
|
17
|
+
} | {
|
|
18
|
+
label: string;
|
|
19
|
+
items: PageSidebarItem[];
|
|
20
|
+
};
|
|
21
|
+
declare function resolveNavigationLayout(navigation: DocsConfig["navigation"]): ResolvedNavigationLayout;
|
|
22
|
+
declare function navigationItemsForPath(layout: ResolvedNavigationLayout, pathname: string): NavigationItem[] | undefined;
|
|
23
|
+
/** Build a sidebar for graph-backed custom pages. */
|
|
24
|
+
declare function pageSidebar(layout: ResolvedNavigationLayout, routes: DocsRoute[]): PageSidebarItem[];
|
|
25
|
+
/** Pick one tab, preferring its own URL before routes owned by its sidebar. */
|
|
26
|
+
declare function activeNavigationTab(tabs: NavigationTab[], pathname: string): number;
|
|
27
|
+
declare function navigationPath(pathname: string, base?: string): string;
|
|
28
|
+
declare function normalizeNavigationPath(path: string): string;
|
|
29
|
+
//#endregion
|
|
30
|
+
export { PageSidebarItem, ResolvedNavigationLayout, ResolvedNavigationTab, activeNavigationTab, navigationItemsForPath, navigationPath, normalizeNavigationPath, pageSidebar, resolveNavigationLayout };
|
|
31
|
+
//# sourceMappingURL=navigation.d.ts.map
|
|
@@ -0,0 +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;EACN;EAAe;EAAc,QAAQ;;EACrC;EAAe,OAAO;;iBAEZ,wBACd,YAAY,2BACX;iBAoBa,uBACd,QAAQ,0BACR,mBACC;;iBAQa,YACd,QAAQ,0BACR,QAAQ,cACP;;iBA0Ia,oBACd,MAAM,iBACN;iBAoBc,eAAe,kBAAkB;iBAUjC,wBAAwB"}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
//#region src/navigation.ts
|
|
2
|
+
function resolveNavigationLayout(navigation) {
|
|
3
|
+
const items = Array.isArray(navigation) ? navigation : navigation?.items;
|
|
4
|
+
const configuredTabs = Array.isArray(navigation) ? [] : navigation?.tabs ?? [];
|
|
5
|
+
const fallbackSidebarGroup = items !== void 0 ? 0 : void 0;
|
|
6
|
+
let sidebarGroup = fallbackSidebarGroup === void 0 ? 0 : 1;
|
|
7
|
+
const tabs = configuredTabs.map((tab) => ({
|
|
8
|
+
...tab,
|
|
9
|
+
...tab.items !== void 0 ? { sidebarGroup: sidebarGroup++ } : {}
|
|
10
|
+
}));
|
|
11
|
+
return {
|
|
12
|
+
...fallbackSidebarGroup !== void 0 ? { fallbackSidebarGroup } : {},
|
|
13
|
+
...items !== void 0 ? { items } : {},
|
|
14
|
+
tabs,
|
|
15
|
+
sectioned: tabs.some((tab) => tab.sidebarGroup !== void 0)
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
function navigationItemsForPath(layout, pathname) {
|
|
19
|
+
const active = activeNavigationTab(layout.tabs, pathname);
|
|
20
|
+
return active >= 0 && layout.tabs[active]?.items !== void 0 ? layout.tabs[active].items : layout.items;
|
|
21
|
+
}
|
|
22
|
+
/** Build a sidebar for graph-backed custom pages. */
|
|
23
|
+
function pageSidebar(layout, routes) {
|
|
24
|
+
const visibleRoutes = routes.filter((route) => route.sidebar !== false && route.discoverable !== false).toSorted((left, right) => {
|
|
25
|
+
const leftOrder = typeof left.sidebar === "object" ? left.sidebar.order : void 0;
|
|
26
|
+
const rightOrder = typeof right.sidebar === "object" ? right.sidebar.order : void 0;
|
|
27
|
+
return (leftOrder ?? Number.POSITIVE_INFINITY) - (rightOrder ?? Number.POSITIVE_INFINITY) || left.route.localeCompare(right.route);
|
|
28
|
+
});
|
|
29
|
+
const titles = new Map(visibleRoutes.map((route) => [route.route, typeof route.sidebar === "object" && route.sidebar.label ? route.sidebar.label : route.title]));
|
|
30
|
+
const labelFor = (route) => titles.get(normalizeNavigationPath(route)) ?? normalizeNavigationPath(route).split("/").filter(Boolean).at(-1) ?? "Home";
|
|
31
|
+
const generatedItems = (directory) => {
|
|
32
|
+
const root = normalizeNavigationPath(directory);
|
|
33
|
+
return groupedRoutes(visibleRoutes.filter((route) => root === "/" || route.route === root || route.route.startsWith(`${root}/`)));
|
|
34
|
+
};
|
|
35
|
+
const convert = (item) => {
|
|
36
|
+
if (typeof item === "string") return {
|
|
37
|
+
label: labelFor(item),
|
|
38
|
+
link: item
|
|
39
|
+
};
|
|
40
|
+
if ("items" in item || "autogenerate" in item) {
|
|
41
|
+
let children = "items" in item ? item.items.map(convert) : generatedItems(item.autogenerate.directory);
|
|
42
|
+
if (item.link) {
|
|
43
|
+
children = withoutRoute(children, item.link);
|
|
44
|
+
if (!children.length) return {
|
|
45
|
+
label: item.label,
|
|
46
|
+
link: item.link
|
|
47
|
+
};
|
|
48
|
+
children.unshift({
|
|
49
|
+
label: item.label,
|
|
50
|
+
link: item.link,
|
|
51
|
+
attrs: { "data-cookbook-group-link": "" }
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
return {
|
|
55
|
+
label: item.label,
|
|
56
|
+
items: children
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
return item;
|
|
60
|
+
};
|
|
61
|
+
const fallback = layout.items?.length ? layout.items.map(convert) : groupedRoutes(visibleRoutes);
|
|
62
|
+
const sidebar = !layout.sectioned ? fallback : [...layout.fallbackSidebarGroup !== void 0 ? [{
|
|
63
|
+
label: "Documentation",
|
|
64
|
+
items: fallback
|
|
65
|
+
}] : [], ...layout.tabs.flatMap((tab) => tab.items !== void 0 ? [{
|
|
66
|
+
label: tab.label,
|
|
67
|
+
items: tab.items.map(convert)
|
|
68
|
+
}] : [])];
|
|
69
|
+
return routes.filter((route) => route.discoverable === false).reduce((items, route) => withoutRoute(items, route.route), sidebar);
|
|
70
|
+
}
|
|
71
|
+
function withoutRoute(items, route) {
|
|
72
|
+
const target = normalizeNavigationPath(route);
|
|
73
|
+
return items.flatMap((item) => {
|
|
74
|
+
if ("link" in item) return !/^(?:[a-z][a-z\d+.-]*:|\/\/|[?#])/i.test(item.link) && normalizeNavigationPath(item.link) === target ? [] : [item];
|
|
75
|
+
const children = withoutRoute(item.items, route);
|
|
76
|
+
const first = children[0];
|
|
77
|
+
if (children.length === 1 && first && "link" in first && first.attrs?.["data-cookbook-group-link"] !== void 0) return [{
|
|
78
|
+
label: item.label,
|
|
79
|
+
link: first.link
|
|
80
|
+
}];
|
|
81
|
+
return children.length ? [{
|
|
82
|
+
...item,
|
|
83
|
+
items: children
|
|
84
|
+
}] : [];
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
function groupedRoutes(routes) {
|
|
88
|
+
const items = [];
|
|
89
|
+
const groups = /* @__PURE__ */ new Map();
|
|
90
|
+
for (const route of routes) {
|
|
91
|
+
const item = {
|
|
92
|
+
label: typeof route.sidebar === "object" && route.sidebar.label ? route.sidebar.label : route.title,
|
|
93
|
+
link: route.route
|
|
94
|
+
};
|
|
95
|
+
const group = typeof route.sidebar === "object" ? route.sidebar.group : void 0;
|
|
96
|
+
if (!group) {
|
|
97
|
+
items.push(item);
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
const grouped = groups.get(group) ?? [];
|
|
101
|
+
grouped.push(item);
|
|
102
|
+
groups.set(group, grouped);
|
|
103
|
+
}
|
|
104
|
+
return [...items, ...Array.from(groups, ([label, grouped]) => ({
|
|
105
|
+
label,
|
|
106
|
+
items: grouped
|
|
107
|
+
}))];
|
|
108
|
+
}
|
|
109
|
+
/** Pick one tab, preferring its own URL before routes owned by its sidebar. */
|
|
110
|
+
function activeNavigationTab(tabs, pathname) {
|
|
111
|
+
const current = normalizeNavigationPath(pathname);
|
|
112
|
+
let winner = -1;
|
|
113
|
+
let winningScore = -1;
|
|
114
|
+
for (const [index, tab] of tabs.entries()) {
|
|
115
|
+
const score = Math.max(linkMatchScore(tab.link, current, 3e4), navigationMatchScore(tab.items ?? [], current));
|
|
116
|
+
if (score > winningScore) {
|
|
117
|
+
winner = index;
|
|
118
|
+
winningScore = score;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
return winningScore >= 0 ? winner : -1;
|
|
122
|
+
}
|
|
123
|
+
function navigationPath(pathname, base = "/") {
|
|
124
|
+
const normalizedBase = normalizeNavigationPath(base);
|
|
125
|
+
return normalizeNavigationPath(normalizedBase !== "/" && (pathname === normalizedBase || pathname.startsWith(`${normalizedBase}/`)) ? pathname.slice(normalizedBase.length) || "/" : pathname);
|
|
126
|
+
}
|
|
127
|
+
function normalizeNavigationPath(path) {
|
|
128
|
+
const normalized = `/${(path.split(/[?#]/, 1)[0]?.replace(/\\/g, "/") ?? "/").replace(/^\/+|\/+$/g, "")}`;
|
|
129
|
+
return normalized === "/" ? normalized : normalized.replace(/\/$/, "");
|
|
130
|
+
}
|
|
131
|
+
function navigationMatchScore(items, current) {
|
|
132
|
+
let score = -1;
|
|
133
|
+
for (const item of items) {
|
|
134
|
+
if (typeof item === "string") {
|
|
135
|
+
if (normalizeNavigationPath(item) === current) score = Math.max(score, 2e4);
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
if (item.link) score = Math.max(score, linkMatchScore(item.link, current, 2e4));
|
|
139
|
+
if ("items" in item) {
|
|
140
|
+
score = Math.max(score, navigationMatchScore(item.items, current));
|
|
141
|
+
continue;
|
|
142
|
+
}
|
|
143
|
+
if ("autogenerate" in item) {
|
|
144
|
+
score = Math.max(score, directoryMatchScore(item.autogenerate.directory, current));
|
|
145
|
+
continue;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return score;
|
|
149
|
+
}
|
|
150
|
+
function linkMatchScore(link, current, base) {
|
|
151
|
+
if (!link.startsWith("/")) return -1;
|
|
152
|
+
const target = normalizeNavigationPath(link);
|
|
153
|
+
if (target === current) return base + 1e3 + target.length;
|
|
154
|
+
if (target !== "/" && current.startsWith(`${target}/`)) return base + target.length;
|
|
155
|
+
return -1;
|
|
156
|
+
}
|
|
157
|
+
function directoryMatchScore(directory, current) {
|
|
158
|
+
const target = normalizeNavigationPath(directory);
|
|
159
|
+
if (target === "/") return 1e4;
|
|
160
|
+
return current === target || current.startsWith(`${target}/`) ? 1e4 + target.length : -1;
|
|
161
|
+
}
|
|
162
|
+
//#endregion
|
|
163
|
+
export { activeNavigationTab, navigationItemsForPath, navigationPath, normalizeNavigationPath, pageSidebar, resolveNavigationLayout };
|
|
164
|
+
|
|
165
|
+
//# sourceMappingURL=navigation.js.map
|
|
@@ -0,0 +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 =\n | { label: string; link: string; attrs?: Record<string, string> }\n | { label: string; items: PageSidebarItem[] };\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 titles = new Map(\n visibleRoutes.map((route) => [\n route.route,\n typeof route.sidebar === \"object\" && route.sidebar.label\n ? route.sidebar.label\n : route.title,\n ]),\n );\n const labelFor = (route: string) =>\n titles.get(normalizeNavigationPath(route)) ??\n normalizeNavigationPath(route).split(\"/\").filter(Boolean).at(-1) ??\n \"Home\";\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 if (typeof item === \"string\") {\n return { label: labelFor(item), link: item };\n }\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) return { label: item.label, link: item.link };\n children.unshift({\n label: item.label,\n link: item.link,\n attrs: { \"data-cookbook-group-link\": \"\" },\n });\n }\n return {\n label: item.label,\n items: children,\n };\n }\n return item;\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 [{ label: item.label, link: first.link }];\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 };\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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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
---
|
|
2
|
+
import Callout from "../components/Callout.astro";
|
|
3
|
+
import { messages } from "../localization.js";
|
|
4
|
+
import { content } from "virtual:cookbook/config";
|
|
5
|
+
const ui = messages(Astro.locals.cookbookRoute.lang, content);
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
<Callout title={ui.draftTitle}>{ui.draftNotice}</Callout>
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
---
|
|
2
|
+
import PageActions from "../components/PageActions.astro";
|
|
3
|
+
import { messages } from "../localization.js";
|
|
4
|
+
import { content } from "virtual:cookbook/config";
|
|
5
|
+
import EditLink from "virtual:cookbook/components/EditLink";
|
|
6
|
+
import LastUpdated from "virtual:cookbook/components/LastUpdated";
|
|
7
|
+
import Pagination from "virtual:cookbook/components/Pagination";
|
|
8
|
+
import { FooterRoot } from "../components/LayoutComponents.js";
|
|
9
|
+
const ui = messages(Astro.locals.cookbookRoute?.lang ?? "en", content);
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
<FooterRoot className="td-footer" data-tasty-anatomy="Footer">
|
|
13
|
+
<div class="td-footer__meta">
|
|
14
|
+
<EditLink />
|
|
15
|
+
<LastUpdated />
|
|
16
|
+
</div>
|
|
17
|
+
<PageActions />
|
|
18
|
+
<Pagination />
|
|
19
|
+
<p class="td-footer__credit">
|
|
20
|
+
{ui.generatedWith}{" "}
|
|
21
|
+
<a href="https://cookbook.tenphi.me/">Cookbook</a>.
|
|
22
|
+
</p>
|
|
23
|
+
</FooterRoot>
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { pageMetadata } from "../page-metadata.js";
|
|
3
|
+
import { content } from "virtual:cookbook/config";
|
|
4
|
+
import { localeAlternates, messages } from "../localization.js";
|
|
5
|
+
import { navigationPath } from "../navigation.js";
|
|
6
|
+
const current = navigationPath(Astro.url.pathname, content.base);
|
|
7
|
+
const entry = content.entries.find((entry) => entry.route === current);
|
|
8
|
+
const head = (
|
|
9
|
+
entry
|
|
10
|
+
? pageMetadata(entry, content, Astro.locals.cookbookRoute.head)
|
|
11
|
+
: [
|
|
12
|
+
...Astro.locals.cookbookRoute.head,
|
|
13
|
+
{ tag: "meta", attrs: { name: "robots", content: "noindex, follow" } },
|
|
14
|
+
]
|
|
15
|
+
).filter(
|
|
16
|
+
(tag) =>
|
|
17
|
+
(tag.tag !== "link" ||
|
|
18
|
+
tag.attrs?.rel !== "sitemap" ||
|
|
19
|
+
content.routes.some((route) => route.sitemap !== false)) &&
|
|
20
|
+
(!content.locales ||
|
|
21
|
+
tag.tag !== "link" ||
|
|
22
|
+
tag.attrs?.rel !== "alternate" ||
|
|
23
|
+
!tag.attrs?.hreflang),
|
|
24
|
+
);
|
|
25
|
+
const indexedRoutes = content.routes.filter((route) => route.sitemap !== false);
|
|
26
|
+
if (Astro.site && indexedRoutes.some((route) => route.route === current)) {
|
|
27
|
+
for (const { lang, route } of localeAlternates(
|
|
28
|
+
current,
|
|
29
|
+
indexedRoutes,
|
|
30
|
+
content,
|
|
31
|
+
))
|
|
32
|
+
head.push({
|
|
33
|
+
tag: "link",
|
|
34
|
+
attrs: {
|
|
35
|
+
rel: "alternate",
|
|
36
|
+
hreflang: lang,
|
|
37
|
+
href: new URL(
|
|
38
|
+
`${content.base.replace(/\/$/, "")}${route === "/" ? "/" : `${route}/`}`,
|
|
39
|
+
Astro.site,
|
|
40
|
+
).href,
|
|
41
|
+
},
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
const ui = messages(Astro.locals.cookbookRoute.lang, content);
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
{
|
|
48
|
+
!entry && (
|
|
49
|
+
<title>
|
|
50
|
+
{`${Astro.locals.cookbookRoute.entry.data.title} | ${content.site.title}`}
|
|
51
|
+
</title>
|
|
52
|
+
)
|
|
53
|
+
}
|
|
54
|
+
{
|
|
55
|
+
head.map(({ tag: Tag, attrs, content }) => (
|
|
56
|
+
<Tag {...attrs} set:html={content} />
|
|
57
|
+
))
|
|
58
|
+
}
|
|
59
|
+
<meta name="cookbook-messages" content={JSON.stringify(ui)} />
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
---
|
|
2
|
+
import {
|
|
3
|
+
localizedNavigation,
|
|
4
|
+
localePath,
|
|
5
|
+
localeHref,
|
|
6
|
+
} from "../localization.js";
|
|
7
|
+
import { messages } from "../localization.js";
|
|
8
|
+
import LanguageSelect from "virtual:cookbook/components/LanguageSelect";
|
|
9
|
+
import Search from "virtual:cookbook/components/Search";
|
|
10
|
+
import SiteTitle from "virtual:cookbook/components/SiteTitle";
|
|
11
|
+
import SocialIcons from "virtual:cookbook/components/SocialIcons";
|
|
12
|
+
import MobileMenuToggle from "virtual:cookbook/components/MobileMenuToggle";
|
|
13
|
+
import HeaderLinks from "../components/HeaderLinks.astro";
|
|
14
|
+
import ThemeSelect from "virtual:cookbook/components/ThemeSelect";
|
|
15
|
+
import { content } from "virtual:cookbook/config";
|
|
16
|
+
import { layout as configuredLayout } from "virtual:cookbook/layout";
|
|
17
|
+
import { activeNavigationTab, navigationPath } from "../navigation.js";
|
|
18
|
+
import GlobalStyles from "../components/GlobalStyles.js";
|
|
19
|
+
import Logo from "../components/SiteLogo.astro";
|
|
20
|
+
import PackageVersion from "../components/PackageVersion.astro";
|
|
21
|
+
import VersionSwitcher from "../components/VersionSwitcher.astro";
|
|
22
|
+
import {
|
|
23
|
+
HeaderRoot,
|
|
24
|
+
TopNavigationRoot,
|
|
25
|
+
} from "../components/LayoutComponents.js";
|
|
26
|
+
|
|
27
|
+
const shouldRenderSearch = content.search;
|
|
28
|
+
const base = import.meta.env.BASE_URL.replace(/\/$/, "");
|
|
29
|
+
const currentPath = navigationPath(Astro.url.pathname, base || "/");
|
|
30
|
+
const { layout } = localizedNavigation(
|
|
31
|
+
configuredLayout,
|
|
32
|
+
content.routes,
|
|
33
|
+
currentPath,
|
|
34
|
+
content,
|
|
35
|
+
);
|
|
36
|
+
const activeTab = activeNavigationTab(
|
|
37
|
+
layout.tabs,
|
|
38
|
+
localePath(currentPath, content),
|
|
39
|
+
);
|
|
40
|
+
Astro.locals.cookbookRoute.siteTitleHref = localeHref(
|
|
41
|
+
content.logo ? (content.logo.href ?? "/") : "/",
|
|
42
|
+
currentPath,
|
|
43
|
+
content.routes,
|
|
44
|
+
content,
|
|
45
|
+
base || "/",
|
|
46
|
+
);
|
|
47
|
+
const { siteTitle } = Astro.locals.cookbookRoute;
|
|
48
|
+
|
|
49
|
+
function tabHref(link: string): string {
|
|
50
|
+
return localeHref(link, currentPath, content.routes, content, base || "/");
|
|
51
|
+
}
|
|
52
|
+
const ui = messages(Astro.locals.cookbookRoute?.lang ?? "en", content);
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
<GlobalStyles />
|
|
56
|
+
<HeaderRoot
|
|
57
|
+
className={`td-header${layout.tabs.length ? " td-header--with-tabs" : ""}`}
|
|
58
|
+
data-tasty-anatomy="Header"
|
|
59
|
+
data-has-sidebar={Astro.locals.cookbookRoute.hasSidebar ? "" : undefined}
|
|
60
|
+
>
|
|
61
|
+
<div class="td-header__primary">
|
|
62
|
+
<div class="td-header__title">
|
|
63
|
+
{
|
|
64
|
+
content.logo !== false && (
|
|
65
|
+
<a
|
|
66
|
+
class="td-header__logo-link"
|
|
67
|
+
href={localeHref(
|
|
68
|
+
content.logo ? (content.logo.href ?? "/") : "/",
|
|
69
|
+
currentPath,
|
|
70
|
+
content.routes,
|
|
71
|
+
content,
|
|
72
|
+
base || "/",
|
|
73
|
+
)}
|
|
74
|
+
aria-label={
|
|
75
|
+
content.logo && !content.logo.decorative
|
|
76
|
+
? undefined
|
|
77
|
+
: `${siteTitle}: ${ui.home}`
|
|
78
|
+
}
|
|
79
|
+
>
|
|
80
|
+
<Logo class="td-header__logo" />
|
|
81
|
+
</a>
|
|
82
|
+
)
|
|
83
|
+
}
|
|
84
|
+
<SiteTitle />
|
|
85
|
+
{
|
|
86
|
+
!content.site.versions && (
|
|
87
|
+
<PackageVersion version={content.site.version} />
|
|
88
|
+
)
|
|
89
|
+
}
|
|
90
|
+
</div>
|
|
91
|
+
{
|
|
92
|
+
content.site.versions && (
|
|
93
|
+
<VersionSwitcher
|
|
94
|
+
versions={content.site.versions}
|
|
95
|
+
routes={content.routes}
|
|
96
|
+
currentPath={currentPath}
|
|
97
|
+
base={base || "/"}
|
|
98
|
+
/>
|
|
99
|
+
)
|
|
100
|
+
}
|
|
101
|
+
<div class="td-header__search cookbook-print-hidden">
|
|
102
|
+
{shouldRenderSearch && <Search />}
|
|
103
|
+
</div>
|
|
104
|
+
<HeaderLinks />
|
|
105
|
+
<div
|
|
106
|
+
class="td-header__mobile-theme md:cookbook-hidden cookbook-print-hidden"
|
|
107
|
+
>
|
|
108
|
+
<ThemeSelect />
|
|
109
|
+
</div>
|
|
110
|
+
<div
|
|
111
|
+
class="td-header__tools cookbook-hidden md:cookbook-flex cookbook-print-hidden"
|
|
112
|
+
>
|
|
113
|
+
<div class="td-header__social"><SocialIcons /></div>
|
|
114
|
+
<ThemeSelect />
|
|
115
|
+
<LanguageSelect />
|
|
116
|
+
</div>
|
|
117
|
+
</div>
|
|
118
|
+
{
|
|
119
|
+
layout.tabs.length > 0 && (
|
|
120
|
+
<TopNavigationRoot
|
|
121
|
+
className="td-top-tabs cookbook-print-hidden"
|
|
122
|
+
aria-label={ui.primary}
|
|
123
|
+
data-tasty-anatomy="TopNavigation"
|
|
124
|
+
>
|
|
125
|
+
{layout.tabs.map((tab, index) => (
|
|
126
|
+
<a
|
|
127
|
+
href={tabHref(tab.link)}
|
|
128
|
+
aria-current={index === activeTab ? "page" : undefined}
|
|
129
|
+
>
|
|
130
|
+
{tab.label}
|
|
131
|
+
</a>
|
|
132
|
+
))}
|
|
133
|
+
</TopNavigationRoot>
|
|
134
|
+
)
|
|
135
|
+
}
|
|
136
|
+
{Astro.locals.cookbookRoute.hasSidebar && <MobileMenuToggle />}
|
|
137
|
+
</HeaderRoot>
|
|
138
|
+
|
|
139
|
+
<script src="../client/code-copy.js"></script>
|