@f5xc-salesdemos/docs-theme 2.0.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.
@@ -0,0 +1,69 @@
1
+ import { defineRouteMiddleware } from '@astrojs/starlight/route-data';
2
+ import type { StarlightRouteData } from '@astrojs/starlight/route-data';
3
+
4
+ type SidebarEntry = StarlightRouteData['sidebar'][number];
5
+
6
+ function isIndexPage(filePath: string | undefined): boolean {
7
+ if (!filePath) return false;
8
+ return /(?:^|[\\/])index\.mdx?$/.test(filePath);
9
+ }
10
+
11
+ function hrefToSlug(href: string): string {
12
+ const base = import.meta.env.BASE_URL.replace(/\/$/, '');
13
+ let s = href;
14
+ if (base && s.startsWith(base)) s = s.slice(base.length);
15
+ s = s.replace(/^\/+|\/+$/g, '');
16
+ if (s.endsWith('.html')) s = s.slice(0, -5);
17
+ if (s === 'index') s = '';
18
+ return s;
19
+ }
20
+
21
+ // Discover all index pages at build time via Vite glob — no astro:content needed
22
+ const indexPaths = Object.keys(
23
+ import.meta.glob(
24
+ ['/src/content/docs/**/index.md', '/src/content/docs/**/index.mdx'],
25
+ { eager: false }
26
+ )
27
+ );
28
+
29
+ const indexSlugs = new Set<string>(
30
+ indexPaths.map((p) =>
31
+ p.replace(/^\/src\/content\/docs\//, '').replace(/\/?index\.mdx?$/, '')
32
+ )
33
+ );
34
+
35
+ function filterIndexPages(
36
+ entries: SidebarEntry[],
37
+ slugs: Set<string>
38
+ ): SidebarEntry[] {
39
+ return entries.reduce<SidebarEntry[]>((acc, entry) => {
40
+ if (entry.type === 'link') {
41
+ const slug = hrefToSlug(entry.href);
42
+ if (!slugs.has(slug)) {
43
+ acc.push(entry);
44
+ }
45
+ } else {
46
+ acc.push({
47
+ ...entry,
48
+ entries: filterIndexPages(entry.entries, slugs),
49
+ });
50
+ }
51
+ return acc;
52
+ }, []);
53
+ }
54
+
55
+ export const onRequest = defineRouteMiddleware(async (context, next) => {
56
+ const route = context.locals.starlightRoute;
57
+ const entry = route.entry;
58
+
59
+ if (isIndexPage(entry.filePath)) {
60
+ // Unconditionally hide TOC on index pages
61
+ route.toc = undefined;
62
+ }
63
+
64
+ if (indexSlugs.size > 0) {
65
+ route.sidebar = filterIndexPages(route.sidebar, indexSlugs);
66
+ }
67
+
68
+ await next();
69
+ });
@@ -0,0 +1,7 @@
1
+ import { defineCollection } from 'astro:content';
2
+ import { docsLoader } from '@astrojs/starlight/loaders';
3
+ import { docsSchema } from '@astrojs/starlight/schema';
4
+
5
+ export const collections = {
6
+ docs: defineCollection({ loader: docsLoader(), schema: docsSchema() }),
7
+ };
@@ -0,0 +1,24 @@
1
+ import { visit } from 'unist-util-visit';
2
+
3
+ export default function remarkMermaid() {
4
+ return (tree) => {
5
+ visit(tree, 'code', (node, index, parent) => {
6
+ if (node.lang !== 'mermaid') return;
7
+ if (index === undefined || !parent) return;
8
+
9
+ const escaped = node.value
10
+ .replace(/&/g, '&amp;')
11
+ .replace(/</g, '&lt;')
12
+ .replace(/>/g, '&gt;')
13
+ .replace(/"/g, '&quot;');
14
+
15
+ parent.children[index] = {
16
+ type: 'html',
17
+ value: `<div class="mermaid-container" data-mermaid-src="${escaped}"><pre class="mermaid">${escaped}</pre></div>`,
18
+ };
19
+ });
20
+
21
+ // Note: Mermaid CDN script is loaded via Starlight head config in astro.config.mjs.
22
+ // Script injection via remark HTML nodes is stripped by MDX/Astro for security.
23
+ };
24
+ }
@@ -0,0 +1,69 @@
1
+ import { createRequire } from 'module';
2
+
3
+ const require = createRequire(import.meta.url);
4
+
5
+ /**
6
+ * Returns true if the SVG body contains explicit color fills (hex, CSS vars,
7
+ * gradient refs, named colors) — i.e. anything other than "none" or "currentColor".
8
+ */
9
+ export function hasExplicitColors(body: string): boolean {
10
+ const fills = body.match(/fill="([^"]*)"/g) || [];
11
+ return fills.some(f => f !== 'fill="none"' && f !== 'fill="currentColor"');
12
+ }
13
+
14
+ /**
15
+ * Resolves a `prefix:name` icon identifier to a complete SVG string
16
+ * using the installed Iconify JSON packages. Designed for synchronous
17
+ * use at module scope (e.g. in config.ts default values).
18
+ */
19
+ export function resolveIcon(name: string): string {
20
+ const colonIndex = name.indexOf(':');
21
+ if (colonIndex === -1) {
22
+ throw new Error(`Invalid icon name "${name}". Expected "prefix:name" format.`);
23
+ }
24
+ const prefix = name.slice(0, colonIndex);
25
+ const iconName = name.slice(colonIndex + 1);
26
+
27
+ let iconData: any;
28
+ switch (prefix) {
29
+ case 'lucide':
30
+ iconData = require('@iconify-json/lucide/icons.json');
31
+ break;
32
+ case 'carbon':
33
+ iconData = require('@iconify-json/carbon/icons.json');
34
+ break;
35
+ case 'mdi':
36
+ iconData = require('@iconify-json/mdi/icons.json');
37
+ break;
38
+ case 'phosphor':
39
+ iconData = require('@iconify-json/ph/icons.json');
40
+ break;
41
+ case 'tabler':
42
+ iconData = require('@iconify-json/tabler/icons.json');
43
+ break;
44
+ case 'f5-brand':
45
+ iconData = require('@f5xc-salesdemos/icons-f5-brand/icons.json');
46
+ break;
47
+ case 'f5xc':
48
+ iconData = require('@f5xc-salesdemos/icons-f5xc/icons.json');
49
+ break;
50
+ case 'hashicorp-flight':
51
+ iconData = require('@f5xc-salesdemos/icons-hashicorp-flight/icons.json');
52
+ break;
53
+ default:
54
+ throw new Error(
55
+ `Unknown icon prefix "${prefix}". Available: lucide, carbon, mdi, phosphor, tabler, f5-brand, f5xc, hashicorp-flight`
56
+ );
57
+ }
58
+
59
+ const icon = iconData.icons?.[iconName];
60
+ if (!icon) {
61
+ throw new Error(`Icon "${iconName}" not found in "${prefix}" icon set.`);
62
+ }
63
+
64
+ const w = icon.width ?? iconData.width ?? 24;
65
+ const h = icon.height ?? iconData.height ?? 24;
66
+ const isPalette = iconData.info?.palette === true || hasExplicitColors(icon.body);
67
+ const fillAttr = isPalette ? '' : ' fill="currentColor"';
68
+ return `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 ${w} ${h}"${fillAttr}>${icon.body}</svg>`;
69
+ }