veslx 0.1.21 → 0.1.23

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.
Files changed (73) hide show
  1. package/bin/lib/serve.ts +16 -2
  2. package/bin/lib/start.ts +12 -10
  3. package/bin/veslx.ts +1 -1
  4. package/dist/client/components/front-matter.js +2 -6
  5. package/dist/client/components/front-matter.js.map +1 -1
  6. package/dist/client/components/gallery/components/figure-caption.js +1 -1
  7. package/dist/client/components/gallery/components/figure-caption.js.map +1 -1
  8. package/dist/client/components/gallery/components/figure-header.js +1 -1
  9. package/dist/client/components/gallery/components/figure-header.js.map +1 -1
  10. package/dist/client/components/gallery/components/lightbox.js +1 -1
  11. package/dist/client/components/gallery/components/lightbox.js.map +1 -1
  12. package/dist/client/components/gallery/index.js +38 -8
  13. package/dist/client/components/gallery/index.js.map +1 -1
  14. package/dist/client/components/header.js +45 -21
  15. package/dist/client/components/header.js.map +1 -1
  16. package/dist/client/components/mdx-components.js +8 -0
  17. package/dist/client/components/mdx-components.js.map +1 -1
  18. package/dist/client/components/post-list.js +13 -11
  19. package/dist/client/components/post-list.js.map +1 -1
  20. package/dist/client/components/slides/figure-slide.js +14 -0
  21. package/dist/client/components/slides/figure-slide.js.map +1 -0
  22. package/dist/client/components/slides/hero-slide.js +21 -0
  23. package/dist/client/components/slides/hero-slide.js.map +1 -0
  24. package/dist/client/components/slides/slide-outline.js +28 -0
  25. package/dist/client/components/slides/slide-outline.js.map +1 -0
  26. package/dist/client/components/slides/text-slide.js +18 -0
  27. package/dist/client/components/slides/text-slide.js.map +1 -0
  28. package/dist/client/components/slides-renderer.js.map +1 -1
  29. package/dist/client/hooks/use-mdx-content.js +19 -6
  30. package/dist/client/hooks/use-mdx-content.js.map +1 -1
  31. package/dist/client/lib/content-classification.js +11 -2
  32. package/dist/client/lib/content-classification.js.map +1 -1
  33. package/dist/client/lib/frontmatter-context.js +17 -0
  34. package/dist/client/lib/frontmatter-context.js.map +1 -0
  35. package/dist/client/pages/content-router.js +4 -1
  36. package/dist/client/pages/content-router.js.map +1 -1
  37. package/dist/client/pages/home.js +2 -6
  38. package/dist/client/pages/home.js.map +1 -1
  39. package/dist/client/pages/post.js +2 -9
  40. package/dist/client/pages/post.js.map +1 -1
  41. package/dist/client/pages/slides.js +9 -12
  42. package/dist/client/pages/slides.js.map +1 -1
  43. package/dist/client/plugin/src/client.js +20 -2
  44. package/dist/client/plugin/src/client.js.map +1 -1
  45. package/index.html +13 -0
  46. package/package.json +1 -1
  47. package/plugin/src/client.tsx +28 -2
  48. package/plugin/src/plugin.ts +49 -4
  49. package/src/components/content-tabs.tsx +4 -4
  50. package/src/components/front-matter.tsx +3 -8
  51. package/src/components/gallery/components/figure-caption.tsx +1 -1
  52. package/src/components/gallery/components/figure-header.tsx +1 -1
  53. package/src/components/gallery/components/lightbox.tsx +1 -1
  54. package/src/components/gallery/index.tsx +68 -29
  55. package/src/components/header.tsx +44 -25
  56. package/src/components/mdx-components.tsx +12 -0
  57. package/src/components/post-list.tsx +14 -10
  58. package/src/components/slides/figure-slide.tsx +16 -0
  59. package/src/components/slides/hero-slide.tsx +34 -0
  60. package/src/components/slides/slide-outline.tsx +38 -0
  61. package/src/components/slides/text-slide.tsx +35 -0
  62. package/src/components/slides-renderer.tsx +1 -1
  63. package/src/hooks/use-mdx-content.ts +27 -6
  64. package/src/index.css +1 -2
  65. package/src/lib/content-classification.ts +13 -2
  66. package/src/lib/frontmatter-context.tsx +29 -0
  67. package/src/pages/content-router.tsx +7 -1
  68. package/src/pages/home.tsx +3 -3
  69. package/src/pages/post.tsx +6 -24
  70. package/src/pages/slides.tsx +14 -16
  71. package/vite.config.ts +4 -3
  72. package/dist/client/components/content-tabs.js +0 -50
  73. package/dist/client/components/content-tabs.js.map +0 -1
@@ -0,0 +1,14 @@
1
+ import { jsxs, jsx } from "react/jsx-runtime";
2
+ function FigureSlide({
3
+ title,
4
+ src
5
+ }) {
6
+ return /* @__PURE__ */ jsxs("div", { className: "figure-slide", children: [
7
+ /* @__PURE__ */ jsx("h2", { children: title }),
8
+ /* @__PURE__ */ jsx("img", { src, alt: title })
9
+ ] });
10
+ }
11
+ export {
12
+ FigureSlide
13
+ };
14
+ //# sourceMappingURL=figure-slide.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"figure-slide.js","sources":["../../../../src/components/slides/figure-slide.tsx"],"sourcesContent":["\n\nexport function FigureSlide({\n title,\n src,\n}: {\n title: string;\n src: string;\n}) {\n return (\n <div className=\"figure-slide\">\n <h2>{title}</h2>\n <img src={src} alt={title} />\n </div>\n );\n}"],"names":[],"mappings":";AAEO,SAAS,YAAY;AAAA,EAC1B;AAAA,EACA;AACF,GAGG;AACD,SACE,qBAAC,OAAA,EAAI,WAAU,gBACb,UAAA;AAAA,IAAA,oBAAC,QAAI,UAAA,MAAA,CAAM;AAAA,IACX,oBAAC,OAAA,EAAI,KAAU,KAAK,MAAA,CAAO;AAAA,EAAA,GAC7B;AAEJ;"}
@@ -0,0 +1,21 @@
1
+ import { jsxs, jsx } from "react/jsx-runtime";
2
+ function HeroSlide({
3
+ title,
4
+ subtitle,
5
+ author,
6
+ date
7
+ }) {
8
+ return /* @__PURE__ */ jsxs("div", { children: [
9
+ /* @__PURE__ */ jsx("h1", { className: "text-[clamp(2.5rem,6vw,5rem)] font-semibold leading-[1.1] tracking-[-0.02em] text-foreground text-balance", children: title }),
10
+ subtitle && /* @__PURE__ */ jsx("p", { className: "text-[clamp(1rem,2vw,1.5rem)] text-muted-foreground max-w-[50ch] leading-relaxed", children: subtitle }),
11
+ (author || date) && /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap gap-x-4 gap-y-1 text-sm text-muted-foreground mt-4", children: [
12
+ author && /* @__PURE__ */ jsx("span", { children: author }),
13
+ author && date && /* @__PURE__ */ jsx("span", { className: "text-border", children: "·" }),
14
+ date && /* @__PURE__ */ jsx("span", { children: date })
15
+ ] })
16
+ ] });
17
+ }
18
+ export {
19
+ HeroSlide
20
+ };
21
+ //# sourceMappingURL=hero-slide.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hero-slide.js","sources":["../../../../src/components/slides/hero-slide.tsx"],"sourcesContent":["\nexport function HeroSlide({\n title,\n subtitle,\n author,\n date,\n}: {\n title: string;\n subtitle?: string;\n author?: string;\n date?: string;\n}) {\n return (\n <div>\n <h1 className=\"text-[clamp(2.5rem,6vw,5rem)] font-semibold leading-[1.1] tracking-[-0.02em] text-foreground text-balance\">\n {title}\n </h1>\n\n {subtitle && (\n <p className=\"text-[clamp(1rem,2vw,1.5rem)] text-muted-foreground max-w-[50ch] leading-relaxed\">\n {subtitle}\n </p>\n )}\n\n {(author || date) && (\n <div className=\"flex flex-wrap gap-x-4 gap-y-1 text-sm text-muted-foreground mt-4\">\n {author && <span>{author}</span>}\n {author && date && <span className=\"text-border\">·</span>}\n {date && <span>{date}</span>}\n </div>\n )}\n </div>\n );\n}\n"],"names":[],"mappings":";AACO,SAAS,UAAU;AAAA,EACxB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAKG;AACD,8BACG,OAAA,EACC,UAAA;AAAA,IAAA,oBAAC,MAAA,EAAG,WAAU,6GACX,UAAA,OACH;AAAA,IAEC,YACC,oBAAC,KAAA,EAAE,WAAU,oFACV,UAAA,UACH;AAAA,KAGA,UAAU,SACV,qBAAC,OAAA,EAAI,WAAU,qEACZ,UAAA;AAAA,MAAA,UAAU,oBAAC,UAAM,UAAA,OAAA,CAAO;AAAA,MACxB,UAAU,QAAQ,oBAAC,QAAA,EAAK,WAAU,eAAc,UAAA,KAAC;AAAA,MACjD,QAAQ,oBAAC,QAAA,EAAM,UAAA,KAAA,CAAK;AAAA,IAAA,EAAA,CACvB;AAAA,EAAA,GAEJ;AAEJ;"}
@@ -0,0 +1,28 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ function SlideOutline({
3
+ children,
4
+ className,
5
+ size = "md"
6
+ }) {
7
+ const wClasses = {
8
+ sm: "max-w-lg",
9
+ md: "max-w-2xl",
10
+ lg: "max-w-5xl",
11
+ xl: "max-w-7xl",
12
+ full: "max-w-full"
13
+ };
14
+ const wClassName = `${wClasses[size]} ${className ?? ""}`;
15
+ const hClasses = {
16
+ sm: "min-h-[300px]",
17
+ md: "min-h-[400px]",
18
+ lg: "min-h-[500px]",
19
+ xl: "min-h-[600px]",
20
+ full: "min-h-[600px]"
21
+ };
22
+ const hClassName = `${hClasses[size]} ${className ?? ""}`;
23
+ return /* @__PURE__ */ jsx("div", { className: `border rounded relative left-1/2 -translate-x-1/2 w-screen ${wClassName} ${hClassName} ${className}`, children });
24
+ }
25
+ export {
26
+ SlideOutline
27
+ };
28
+ //# sourceMappingURL=slide-outline.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"slide-outline.js","sources":["../../../../src/components/slides/slide-outline.tsx"],"sourcesContent":["\n\nexport function SlideOutline({\n children,\n className,\n size=\"md\"\n}: {\n children?: React.ReactNode;\n className?: string;\n size?: \"sm\" | \"md\" | \"lg\" | \"xl\" | \"2xl\" | \"3xl\" | \"full\";\n}) {\n\n const wClasses: Record<string, string> = {\n sm: \"max-w-lg\",\n md: \"max-w-2xl\",\n lg: \"max-w-5xl\",\n xl: \"max-w-7xl\",\n full: \"max-w-full\",\n };\n\n const wClassName = `${wClasses[size]} ${className ?? \"\"}`;\n\n const hClasses: Record<string, string> = {\n sm: \"min-h-[300px]\",\n md: \"min-h-[400px]\",\n lg: \"min-h-[500px]\",\n xl: \"min-h-[600px]\",\n full: \"min-h-[600px]\",\n };\n\n const hClassName = `${hClasses[size]} ${className ?? \"\"}`;\n\n return (\n <div className={`border rounded relative left-1/2 -translate-x-1/2 w-screen ${wClassName} ${hClassName} ${className}`}>\n {children}\n </div>\n );\n}"],"names":[],"mappings":";AAEO,SAAS,aAAa;AAAA,EAC3B;AAAA,EACA;AAAA,EACA,OAAK;AACP,GAIG;AAED,QAAM,WAAmC;AAAA,IACvC,IAAI;AAAA,IACJ,IAAI;AAAA,IACJ,IAAI;AAAA,IACJ,IAAI;AAAA,IACJ,MAAM;AAAA,EAAA;AAGR,QAAM,aAAa,GAAG,SAAS,IAAI,CAAC,IAAI,aAAa,EAAE;AAEvD,QAAM,WAAmC;AAAA,IACvC,IAAI;AAAA,IACJ,IAAI;AAAA,IACJ,IAAI;AAAA,IACJ,IAAI;AAAA,IACJ,MAAM;AAAA,EAAA;AAGR,QAAM,aAAa,GAAG,SAAS,IAAI,CAAC,IAAI,aAAa,EAAE;AAEvD,SACE,oBAAC,OAAA,EAAI,WAAW,8DAA8D,UAAU,IAAI,UAAU,IAAI,SAAS,IAChH,SAAA,CACH;AAEJ;"}
@@ -0,0 +1,18 @@
1
+ import { jsxs, jsx } from "react/jsx-runtime";
2
+ function TextSlide({
3
+ title,
4
+ subtitle,
5
+ children
6
+ }) {
7
+ return /* @__PURE__ */ jsxs("div", { children: [
8
+ (title || subtitle) && /* @__PURE__ */ jsxs("header", { className: "flex flex-col gap-2", children: [
9
+ title && /* @__PURE__ */ jsx("h2", { className: "text-[clamp(1.75rem,4vw,3rem)] font-semibold leading-tight tracking-[-0.02em] text-foreground", children: title }),
10
+ subtitle && /* @__PURE__ */ jsx("p", { className: "text-[clamp(0.95rem,1.5vw,1.25rem)] text-muted-foreground", children: subtitle })
11
+ ] }),
12
+ children && /* @__PURE__ */ jsx("div", { className: "text-[clamp(1rem,1.8vw,1.35rem)] leading-[1.6] text-foreground/90 space-y-4 [&>ul]:space-y-2 [&>ul]:list-disc [&>ul]:pl-6 [&>ol]:space-y-2 [&>ol]:list-decimal [&>ol]:pl-6", children })
13
+ ] });
14
+ }
15
+ export {
16
+ TextSlide
17
+ };
18
+ //# sourceMappingURL=text-slide.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"text-slide.js","sources":["../../../../src/components/slides/text-slide.tsx"],"sourcesContent":["\nexport function TextSlide({\n title,\n subtitle,\n children,\n}: {\n title?: string;\n subtitle?: string;\n children?: React.ReactNode;\n}) {\n return (\n <div>\n {(title || subtitle) && (\n <header className=\"flex flex-col gap-2\">\n {title && (\n <h2 className=\"text-[clamp(1.75rem,4vw,3rem)] font-semibold leading-tight tracking-[-0.02em] text-foreground\">\n {title}\n </h2>\n )}\n {subtitle && (\n <p className=\"text-[clamp(0.95rem,1.5vw,1.25rem)] text-muted-foreground\">\n {subtitle}\n </p>\n )}\n </header>\n )}\n\n {children && (\n <div className=\"text-[clamp(1rem,1.8vw,1.35rem)] leading-[1.6] text-foreground/90 space-y-4 [&>ul]:space-y-2 [&>ul]:list-disc [&>ul]:pl-6 [&>ol]:space-y-2 [&>ol]:list-decimal [&>ol]:pl-6\">\n {children}\n </div>\n )}\n </div>\n );\n}\n"],"names":[],"mappings":";AACO,SAAS,UAAU;AAAA,EACxB;AAAA,EACA;AAAA,EACA;AACF,GAIG;AACD,8BACG,OAAA,EACG,UAAA;AAAA,KAAA,SAAS,aACT,qBAAC,UAAA,EAAO,WAAU,uBACf,UAAA;AAAA,MAAA,SACC,oBAAC,MAAA,EAAG,WAAU,iGACX,UAAA,OACH;AAAA,MAED,YACC,oBAAC,KAAA,EAAE,WAAU,6DACV,UAAA,SAAA,CACH;AAAA,IAAA,GAEJ;AAAA,IAGD,YACC,oBAAC,OAAA,EAAI,WAAU,8KACZ,SAAA,CACH;AAAA,EAAA,GAEJ;AAEJ;"}
@@ -1 +1 @@
1
- {"version":3,"file":"slides-renderer.js","sources":["../../../src/components/slides-renderer.tsx"],"sourcesContent":["import { ReactNode } from 'react'\nimport { mdxComponents } from '@/components/mdx-components'\nimport { Slide } from '@/components/slide'\n\n/**\n * MDX components for slides - includes the Slide component\n */\nexport const slidesMdxComponents = {\n ...mdxComponents,\n Slide,\n}\n\n/**\n * Renders a single slide's content\n */\nexport function SlideContent({ children }: { children: ReactNode }) {\n return (\n <div className=\"slide-content prose dark:prose-invert prose-headings:tracking-tight prose-p:leading-relaxed max-w-xl\">\n {children}\n </div>\n )\n}\n"],"names":[],"mappings":";;;AAOO,MAAM,sBAAsB;AAAA,EACjC,GAAG;AAAA,EACH;AACF;"}
1
+ {"version":3,"file":"slides-renderer.js","sources":["../../../src/components/slides-renderer.tsx"],"sourcesContent":["import { ReactNode } from 'react'\nimport { mdxComponents } from '@/components/mdx-components'\nimport { Slide } from '@/components/slide'\n\n/**\n * MDX components for slides - includes the Slide component\n */\nexport const slidesMdxComponents = {\n ...mdxComponents,\n Slide,\n}\n\n/**\n * Renders a single slide's content\n */\nexport function SlideContent({ children }: { children: ReactNode }) {\n return (\n <div className=\"slide-content prose dark:prose-invert prose-headings:tracking-tight prose-p:leading-relaxed\">\n {children}\n </div>\n )\n}\n"],"names":[],"mappings":";;;AAOO,MAAM,sBAAsB;AAAA,EACjC,GAAG;AAAA,EACH;AACF;"}
@@ -66,16 +66,29 @@ function useMDXContent(path) {
66
66
  }
67
67
  function findSlidesModule(modules, path) {
68
68
  const keys = Object.keys(modules);
69
- if (path.endsWith(".mdx")) {
70
- const matchingKey = keys.find((key) => key.endsWith(`/${path}`));
69
+ const normalizedPath = path.replace(/^\//, "");
70
+ if (normalizedPath.endsWith(".mdx")) {
71
+ const matchingKey = keys.find((key) => {
72
+ if (key.endsWith(`/${normalizedPath}`)) return true;
73
+ if (key === `@content/${normalizedPath}`) return true;
74
+ if (key === `/@content/${normalizedPath}`) return true;
75
+ if (key === normalizedPath) return true;
76
+ if (key === `/${normalizedPath}`) return true;
77
+ return false;
78
+ });
71
79
  return matchingKey ? modules[matchingKey] : null;
72
80
  }
73
81
  const candidates = [
74
- `/${path}/SLIDES.mdx`,
75
- `/${path}/index.slides.mdx`
82
+ `${normalizedPath}/SLIDES.mdx`,
83
+ `${normalizedPath}/index.slides.mdx`
76
84
  ];
77
- for (const suffix of candidates) {
78
- const matchingKey = keys.find((key) => key.endsWith(suffix));
85
+ for (const candidate of candidates) {
86
+ const matchingKey = keys.find((key) => {
87
+ if (key.endsWith(`/${candidate}`)) return true;
88
+ if (key === `@content/${candidate}`) return true;
89
+ if (key === candidate) return true;
90
+ return false;
91
+ });
79
92
  if (matchingKey) {
80
93
  return modules[matchingKey];
81
94
  }
@@ -1 +1 @@
1
- {"version":3,"file":"use-mdx-content.js","sources":["../../../src/hooks/use-mdx-content.ts"],"sourcesContent":["import { useState, useEffect } from 'react'\nimport type { ComponentType } from 'react'\n\ninterface MDXModule {\n default: ComponentType<{ components?: Record<string, ComponentType> }>\n frontmatter?: {\n title?: string\n description?: string\n date?: string\n visibility?: string\n draft?: boolean\n }\n slideCount?: number // Exported by remark-slides plugin for SLIDES.mdx files\n}\n\ntype ModuleLoader = () => Promise<MDXModule>\ntype ModuleMap = Record<string, ModuleLoader>\n\n/**\n * Find MDX module by path. Supports:\n * - Full path: \"docs/intro.mdx\" -> matches exactly\n * - Folder path: \"docs\" -> matches \"docs/index.mdx\", \"docs/README.mdx\", or \"docs.mdx\"\n */\nfunction findMdxModule(modules: ModuleMap, path: string): ModuleLoader | null {\n const keys = Object.keys(modules)\n\n // Normalize path - remove leading slash if present\n const normalizedPath = path.replace(/^\\//, '')\n\n // If path already ends with .mdx, match exactly\n if (normalizedPath.endsWith('.mdx')) {\n // Try multiple matching strategies for different Vite glob formats\n const matchingKey = keys.find(key => {\n // Strategy 1: Key ends with /path (e.g., @content/docs/foo.mdx matches docs/foo.mdx)\n if (key.endsWith(`/${normalizedPath}`)) return true\n // Strategy 2: Key equals @content/path (alias form)\n if (key === `@content/${normalizedPath}`) return true\n // Strategy 3: Key equals /@content/path (with leading slash)\n if (key === `/@content/${normalizedPath}`) return true\n // Strategy 4: Key equals path directly\n if (key === normalizedPath) return true\n // Strategy 5: Key equals /path (with leading slash)\n if (key === `/${normalizedPath}`) return true\n return false\n })\n return matchingKey ? modules[matchingKey] : null\n }\n\n // Otherwise, try folder conventions in order of preference:\n // 1. folder/index.mdx (modern convention)\n // 2. folder/README.mdx (current convention)\n // 3. folder.mdx (file alongside folders)\n const candidates = [\n `${normalizedPath}/index.mdx`,\n `${normalizedPath}/README.mdx`,\n `${normalizedPath}.mdx`,\n ]\n\n for (const candidate of candidates) {\n const matchingKey = keys.find(key => {\n if (key.endsWith(`/${candidate}`)) return true\n if (key === `@content/${candidate}`) return true\n if (key === candidate) return true\n return false\n })\n if (matchingKey) {\n return modules[matchingKey]\n }\n }\n\n return null\n}\n\nexport function useMDXContent(path: string) {\n const [Content, setContent] = useState<MDXModule['default'] | null>(null)\n const [frontmatter, setFrontmatter] = useState<MDXModule['frontmatter']>(undefined)\n const [loading, setLoading] = useState(true)\n const [error, setError] = useState<Error | null>(null)\n\n useEffect(() => {\n let cancelled = false\n setLoading(true)\n setError(null)\n\n // Dynamic import to avoid pre-bundling issues\n import('virtual:content-modules')\n .then(({ modules }) => {\n const loader = findMdxModule(modules as ModuleMap, path)\n\n if (!loader) {\n throw new Error(`MDX module not found for path: ${path}`)\n }\n\n return loader()\n })\n .then((mod) => {\n if (!cancelled) {\n setContent(() => mod.default)\n setFrontmatter(mod.frontmatter)\n setLoading(false)\n }\n })\n .catch((err) => {\n if (!cancelled) {\n setError(err)\n setLoading(false)\n }\n })\n\n return () => {\n cancelled = true\n }\n }, [path])\n\n return { Content, frontmatter, loading, error }\n}\n\n/**\n * Find slides module by path. Supports:\n * - Full path: \"docs/intro.slides.mdx\" or \"docs/SLIDES.mdx\" -> matches exactly\n * - Folder path: \"docs\" -> matches \"docs/SLIDES.mdx\" or \"docs/index.slides.mdx\"\n */\nfunction findSlidesModule(modules: ModuleMap, path: string): ModuleLoader | null {\n const keys = Object.keys(modules)\n\n // If path already ends with .mdx, match exactly\n if (path.endsWith('.mdx')) {\n const matchingKey = keys.find(key => key.endsWith(`/${path}`))\n return matchingKey ? modules[matchingKey] : null\n }\n\n // Otherwise, try folder conventions:\n // 1. folder/SLIDES.mdx (current convention)\n // 2. folder/index.slides.mdx (alternative)\n const candidates = [\n `/${path}/SLIDES.mdx`,\n `/${path}/index.slides.mdx`,\n ]\n\n for (const suffix of candidates) {\n const matchingKey = keys.find(key => key.endsWith(suffix))\n if (matchingKey) {\n return modules[matchingKey]\n }\n }\n\n return null\n}\n\nexport function useMDXSlides(path: string) {\n const [Content, setContent] = useState<MDXModule['default'] | null>(null)\n const [frontmatter, setFrontmatter] = useState<MDXModule['frontmatter']>(undefined)\n const [slideCount, setSlideCount] = useState<number | undefined>(undefined)\n const [loading, setLoading] = useState(true)\n const [error, setError] = useState<Error | null>(null)\n\n useEffect(() => {\n let cancelled = false\n setLoading(true)\n setError(null)\n\n // Dynamic import to avoid pre-bundling issues\n import('virtual:content-modules')\n .then(({ slides }) => {\n const loader = findSlidesModule(slides as ModuleMap, path)\n\n if (!loader) {\n throw new Error(`Slides module not found for path: ${path}`)\n }\n\n return loader()\n })\n .then((mod) => {\n if (!cancelled) {\n setContent(() => mod.default)\n setFrontmatter(mod.frontmatter)\n setSlideCount(mod.slideCount)\n setLoading(false)\n }\n })\n .catch((err) => {\n if (!cancelled) {\n setError(err)\n setLoading(false)\n }\n })\n\n return () => {\n cancelled = true\n }\n }, [path])\n\n return { Content, frontmatter, slideCount, loading, error }\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"use-mdx-content.js","sources":["../../../src/hooks/use-mdx-content.ts"],"sourcesContent":["import { useState, useEffect } from 'react'\nimport type { ComponentType } from 'react'\n\ninterface MDXModule {\n default: ComponentType<{ components?: Record<string, ComponentType> }>\n frontmatter?: {\n title?: string\n description?: string\n date?: string\n visibility?: string\n draft?: boolean\n }\n slideCount?: number // Exported by remark-slides plugin for SLIDES.mdx files\n}\n\ntype ModuleLoader = () => Promise<MDXModule>\ntype ModuleMap = Record<string, ModuleLoader>\n\n/**\n * Find MDX module by path. Supports:\n * - Full path: \"docs/intro.mdx\" -> matches exactly\n * - Folder path: \"docs\" -> matches \"docs/index.mdx\", \"docs/README.mdx\", or \"docs.mdx\"\n */\nfunction findMdxModule(modules: ModuleMap, path: string): ModuleLoader | null {\n const keys = Object.keys(modules)\n\n // Normalize path - remove leading slash if present\n const normalizedPath = path.replace(/^\\//, '')\n\n // If path already ends with .mdx, match exactly\n if (normalizedPath.endsWith('.mdx')) {\n // Try multiple matching strategies for different Vite glob formats\n const matchingKey = keys.find(key => {\n // Strategy 1: Key ends with /path (e.g., @content/docs/foo.mdx matches docs/foo.mdx)\n if (key.endsWith(`/${normalizedPath}`)) return true\n // Strategy 2: Key equals @content/path (alias form)\n if (key === `@content/${normalizedPath}`) return true\n // Strategy 3: Key equals /@content/path (with leading slash)\n if (key === `/@content/${normalizedPath}`) return true\n // Strategy 4: Key equals path directly\n if (key === normalizedPath) return true\n // Strategy 5: Key equals /path (with leading slash)\n if (key === `/${normalizedPath}`) return true\n return false\n })\n return matchingKey ? modules[matchingKey] : null\n }\n\n // Otherwise, try folder conventions in order of preference:\n // 1. folder/index.mdx (modern convention)\n // 2. folder/README.mdx (current convention)\n // 3. folder.mdx (file alongside folders)\n const candidates = [\n `${normalizedPath}/index.mdx`,\n `${normalizedPath}/README.mdx`,\n `${normalizedPath}.mdx`,\n ]\n\n for (const candidate of candidates) {\n const matchingKey = keys.find(key => {\n if (key.endsWith(`/${candidate}`)) return true\n if (key === `@content/${candidate}`) return true\n if (key === candidate) return true\n return false\n })\n if (matchingKey) {\n return modules[matchingKey]\n }\n }\n\n return null\n}\n\nexport function useMDXContent(path: string) {\n const [Content, setContent] = useState<MDXModule['default'] | null>(null)\n const [frontmatter, setFrontmatter] = useState<MDXModule['frontmatter']>(undefined)\n const [loading, setLoading] = useState(true)\n const [error, setError] = useState<Error | null>(null)\n\n useEffect(() => {\n let cancelled = false\n setLoading(true)\n setError(null)\n\n // Dynamic import to avoid pre-bundling issues\n import('virtual:content-modules')\n .then(({ modules }) => {\n const loader = findMdxModule(modules as ModuleMap, path)\n\n if (!loader) {\n throw new Error(`MDX module not found for path: ${path}`)\n }\n\n return loader()\n })\n .then((mod) => {\n if (!cancelled) {\n setContent(() => mod.default)\n setFrontmatter(mod.frontmatter)\n setLoading(false)\n }\n })\n .catch((err) => {\n if (!cancelled) {\n setError(err)\n setLoading(false)\n }\n })\n\n return () => {\n cancelled = true\n }\n }, [path])\n\n return { Content, frontmatter, loading, error }\n}\n\n/**\n * Find slides module by path. Supports:\n * - Full path: \"docs/intro.slides.mdx\" or \"docs/SLIDES.mdx\" -> matches exactly\n * - Folder path: \"docs\" -> matches \"docs/SLIDES.mdx\" or \"docs/index.slides.mdx\"\n */\nfunction findSlidesModule(modules: ModuleMap, path: string): ModuleLoader | null {\n const keys = Object.keys(modules)\n\n // Normalize path - remove leading slash if present\n const normalizedPath = path.replace(/^\\//, '')\n\n // If path already ends with .mdx, match exactly\n if (normalizedPath.endsWith('.mdx')) {\n // Try multiple matching strategies for different Vite glob formats\n const matchingKey = keys.find(key => {\n // Strategy 1: Key ends with /path (e.g., @content/docs/foo.slides.mdx matches docs/foo.slides.mdx)\n if (key.endsWith(`/${normalizedPath}`)) return true\n // Strategy 2: Key equals @content/path (alias form)\n if (key === `@content/${normalizedPath}`) return true\n // Strategy 3: Key equals /@content/path (with leading slash)\n if (key === `/@content/${normalizedPath}`) return true\n // Strategy 4: Key equals path directly\n if (key === normalizedPath) return true\n // Strategy 5: Key equals /path (with leading slash)\n if (key === `/${normalizedPath}`) return true\n return false\n })\n return matchingKey ? modules[matchingKey] : null\n }\n\n // Otherwise, try folder conventions:\n // 1. folder/SLIDES.mdx (current convention)\n // 2. folder/index.slides.mdx (alternative)\n const candidates = [\n `${normalizedPath}/SLIDES.mdx`,\n `${normalizedPath}/index.slides.mdx`,\n ]\n\n for (const candidate of candidates) {\n const matchingKey = keys.find(key => {\n if (key.endsWith(`/${candidate}`)) return true\n if (key === `@content/${candidate}`) return true\n if (key === candidate) return true\n return false\n })\n if (matchingKey) {\n return modules[matchingKey]\n }\n }\n\n return null\n}\n\nexport function useMDXSlides(path: string) {\n const [Content, setContent] = useState<MDXModule['default'] | null>(null)\n const [frontmatter, setFrontmatter] = useState<MDXModule['frontmatter']>(undefined)\n const [slideCount, setSlideCount] = useState<number | undefined>(undefined)\n const [loading, setLoading] = useState(true)\n const [error, setError] = useState<Error | null>(null)\n\n useEffect(() => {\n let cancelled = false\n setLoading(true)\n setError(null)\n\n // Dynamic import to avoid pre-bundling issues\n import('virtual:content-modules')\n .then(({ slides }) => {\n const loader = findSlidesModule(slides as ModuleMap, path)\n\n if (!loader) {\n throw new Error(`Slides module not found for path: ${path}`)\n }\n\n return loader()\n })\n .then((mod) => {\n if (!cancelled) {\n setContent(() => mod.default)\n setFrontmatter(mod.frontmatter)\n setSlideCount(mod.slideCount)\n setLoading(false)\n }\n })\n .catch((err) => {\n if (!cancelled) {\n setError(err)\n setLoading(false)\n }\n })\n\n return () => {\n cancelled = true\n }\n }, [path])\n\n return { Content, frontmatter, slideCount, loading, error }\n}\n"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { findMdxFiles, findSlides, findReadme } from "../plugin/src/client.js";
1
+ import { findMdxFiles, findStandaloneSlides, findSlides, findReadme } from "../plugin/src/client.js";
2
2
  function getFrontmatter(post) {
3
3
  var _a, _b, _c;
4
4
  return ((_a = post.readme) == null ? void 0 : _a.frontmatter) || ((_b = post.file) == null ? void 0 : _b.frontmatter) || ((_c = post.slides) == null ? void 0 : _c.frontmatter);
@@ -24,6 +24,7 @@ function getViewCounts(posts) {
24
24
  function directoryToPostEntries(directory) {
25
25
  const folders = directory.children.filter((c) => c.type === "directory");
26
26
  const standaloneFiles = findMdxFiles(directory);
27
+ const standaloneSlidesFiles = findStandaloneSlides(directory);
27
28
  const folderPosts = folders.map((folder) => ({
28
29
  type: "folder",
29
30
  name: folder.name,
@@ -40,7 +41,15 @@ function directoryToPostEntries(directory) {
40
41
  slides: null,
41
42
  file
42
43
  }));
43
- return [...folderPosts, ...filePosts];
44
+ const slidesPosts = standaloneSlidesFiles.map((file) => ({
45
+ type: "file",
46
+ name: file.name.replace(/\.slides\.mdx?$/, ""),
47
+ path: file.path,
48
+ readme: null,
49
+ slides: file,
50
+ file: null
51
+ }));
52
+ return [...folderPosts, ...filePosts, ...slidesPosts];
44
53
  }
45
54
  function filterVisiblePosts(posts) {
46
55
  return posts.filter((post) => {
@@ -1 +1 @@
1
- {"version":3,"file":"content-classification.js","sources":["../../../src/lib/content-classification.ts"],"sourcesContent":["import type { ContentView } from \"../../plugin/src/types\";\nimport type { DirectoryEntry, FileEntry } from \"../../plugin/src/lib\";\nimport { findReadme, findSlides, findMdxFiles } from \"../../plugin/src/client\";\n\nexport type PostEntry = {\n type: 'folder' | 'file';\n name: string;\n path: string;\n readme: FileEntry | null;\n slides: FileEntry | null;\n file: FileEntry | null;\n};\n\nexport function getFrontmatter(post: PostEntry) {\n return post.readme?.frontmatter || post.file?.frontmatter || post.slides?.frontmatter;\n}\n\nexport function hasDate(post: PostEntry): boolean {\n const frontmatter = getFrontmatter(post);\n return frontmatter?.date !== undefined && frontmatter.date !== null && frontmatter.date !== '';\n}\n\nexport function filterByView(posts: PostEntry[], view: ContentView): PostEntry[] {\n if (view === 'all') return posts;\n if (view === 'posts') return posts.filter(hasDate);\n if (view === 'docs') return posts.filter(post => !hasDate(post));\n return posts;\n}\n\nexport function getViewCounts(posts: PostEntry[]): { posts: number; docs: number; all: number } {\n const dated = posts.filter(hasDate).length;\n return {\n posts: dated,\n docs: posts.length - dated,\n all: posts.length,\n };\n}\n\nexport function directoryToPostEntries(directory: DirectoryEntry): PostEntry[] {\n const folders = directory.children.filter((c): c is DirectoryEntry => c.type === \"directory\");\n const standaloneFiles = findMdxFiles(directory);\n\n const folderPosts: PostEntry[] = folders\n .map((folder) => ({\n type: 'folder' as const,\n name: folder.name,\n path: folder.path,\n readme: findReadme(folder),\n slides: findSlides(folder),\n file: null,\n }))\n .filter((post) => post.readme || post.slides); // Only include folders with content\n\n const filePosts: PostEntry[] = standaloneFiles.map((file) => ({\n type: 'file' as const,\n name: file.name.replace(/\\.mdx?$/, ''),\n path: file.path,\n readme: null,\n slides: null,\n file,\n }));\n\n return [...folderPosts, ...filePosts];\n}\n\nexport function filterVisiblePosts(posts: PostEntry[]): PostEntry[] {\n return posts.filter((post) => {\n const frontmatter = getFrontmatter(post);\n return frontmatter?.visibility !== \"hidden\" && frontmatter?.draft !== true;\n });\n}\n\nexport type { ContentView };\n"],"names":[],"mappings":";AAaO,SAAS,eAAe,MAAiB;;AAC9C,WAAO,UAAK,WAAL,mBAAa,kBAAe,UAAK,SAAL,mBAAW,kBAAe,UAAK,WAAL,mBAAa;AAC5E;AAEO,SAAS,QAAQ,MAA0B;AAChD,QAAM,cAAc,eAAe,IAAI;AACvC,UAAO,2CAAa,UAAS,UAAa,YAAY,SAAS,QAAQ,YAAY,SAAS;AAC9F;AAEO,SAAS,aAAa,OAAoB,MAAgC;AAC/E,MAAI,SAAS,MAAO,QAAO;AAC3B,MAAI,SAAS,QAAS,QAAO,MAAM,OAAO,OAAO;AACjD,MAAI,SAAS,OAAQ,QAAO,MAAM,OAAO,CAAA,SAAQ,CAAC,QAAQ,IAAI,CAAC;AAC/D,SAAO;AACT;AAEO,SAAS,cAAc,OAAkE;AAC9F,QAAM,QAAQ,MAAM,OAAO,OAAO,EAAE;AACpC,SAAO;AAAA,IACL,OAAO;AAAA,IACP,MAAM,MAAM,SAAS;AAAA,IACrB,KAAK,MAAM;AAAA,EAAA;AAEf;AAEO,SAAS,uBAAuB,WAAwC;AAC7E,QAAM,UAAU,UAAU,SAAS,OAAO,CAAC,MAA2B,EAAE,SAAS,WAAW;AAC5F,QAAM,kBAAkB,aAAa,SAAS;AAE9C,QAAM,cAA2B,QAC9B,IAAI,CAAC,YAAY;AAAA,IAChB,MAAM;AAAA,IACN,MAAM,OAAO;AAAA,IACb,MAAM,OAAO;AAAA,IACb,QAAQ,WAAW,MAAM;AAAA,IACzB,QAAQ,WAAW,MAAM;AAAA,IACzB,MAAM;AAAA,EAAA,EACN,EACD,OAAO,CAAC,SAAS,KAAK,UAAU,KAAK,MAAM;AAE9C,QAAM,YAAyB,gBAAgB,IAAI,CAAC,UAAU;AAAA,IAC5D,MAAM;AAAA,IACN,MAAM,KAAK,KAAK,QAAQ,WAAW,EAAE;AAAA,IACrC,MAAM,KAAK;AAAA,IACX,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR;AAAA,EAAA,EACA;AAEF,SAAO,CAAC,GAAG,aAAa,GAAG,SAAS;AACtC;AAEO,SAAS,mBAAmB,OAAiC;AAClE,SAAO,MAAM,OAAO,CAAC,SAAS;AAC5B,UAAM,cAAc,eAAe,IAAI;AACvC,YAAO,2CAAa,gBAAe,aAAY,2CAAa,WAAU;AAAA,EACxE,CAAC;AACH;"}
1
+ {"version":3,"file":"content-classification.js","sources":["../../../src/lib/content-classification.ts"],"sourcesContent":["import type { ContentView } from \"../../plugin/src/types\";\nimport type { DirectoryEntry, FileEntry } from \"../../plugin/src/lib\";\nimport { findReadme, findSlides, findMdxFiles, findStandaloneSlides } from \"../../plugin/src/client\";\n\nexport type PostEntry = {\n type: 'folder' | 'file';\n name: string;\n path: string;\n readme: FileEntry | null;\n slides: FileEntry | null;\n file: FileEntry | null;\n};\n\nexport function getFrontmatter(post: PostEntry) {\n return post.readme?.frontmatter || post.file?.frontmatter || post.slides?.frontmatter;\n}\n\nexport function hasDate(post: PostEntry): boolean {\n const frontmatter = getFrontmatter(post);\n return frontmatter?.date !== undefined && frontmatter.date !== null && frontmatter.date !== '';\n}\n\nexport function filterByView(posts: PostEntry[], view: ContentView): PostEntry[] {\n if (view === 'all') return posts;\n if (view === 'posts') return posts.filter(hasDate);\n if (view === 'docs') return posts.filter(post => !hasDate(post));\n return posts;\n}\n\nexport function getViewCounts(posts: PostEntry[]): { posts: number; docs: number; all: number } {\n const dated = posts.filter(hasDate).length;\n return {\n posts: dated,\n docs: posts.length - dated,\n all: posts.length,\n };\n}\n\nexport function directoryToPostEntries(directory: DirectoryEntry): PostEntry[] {\n const folders = directory.children.filter((c): c is DirectoryEntry => c.type === \"directory\");\n const standaloneFiles = findMdxFiles(directory);\n const standaloneSlidesFiles = findStandaloneSlides(directory);\n\n const folderPosts: PostEntry[] = folders\n .map((folder) => ({\n type: 'folder' as const,\n name: folder.name,\n path: folder.path,\n readme: findReadme(folder),\n slides: findSlides(folder),\n file: null,\n }))\n .filter((post) => post.readme || post.slides); // Only include folders with content\n\n const filePosts: PostEntry[] = standaloneFiles.map((file) => ({\n type: 'file' as const,\n name: file.name.replace(/\\.mdx?$/, ''),\n path: file.path,\n readme: null,\n slides: null,\n file,\n }));\n\n // Standalone slides files (e.g., getting-started.slides.mdx)\n const slidesPosts: PostEntry[] = standaloneSlidesFiles.map((file) => ({\n type: 'file' as const,\n name: file.name.replace(/\\.slides\\.mdx?$/, ''),\n path: file.path,\n readme: null,\n slides: file,\n file: null,\n }));\n\n return [...folderPosts, ...filePosts, ...slidesPosts];\n}\n\nexport function filterVisiblePosts(posts: PostEntry[]): PostEntry[] {\n return posts.filter((post) => {\n const frontmatter = getFrontmatter(post);\n return frontmatter?.visibility !== \"hidden\" && frontmatter?.draft !== true;\n });\n}\n\nexport type { ContentView };\n"],"names":[],"mappings":";AAaO,SAAS,eAAe,MAAiB;;AAC9C,WAAO,UAAK,WAAL,mBAAa,kBAAe,UAAK,SAAL,mBAAW,kBAAe,UAAK,WAAL,mBAAa;AAC5E;AAEO,SAAS,QAAQ,MAA0B;AAChD,QAAM,cAAc,eAAe,IAAI;AACvC,UAAO,2CAAa,UAAS,UAAa,YAAY,SAAS,QAAQ,YAAY,SAAS;AAC9F;AAEO,SAAS,aAAa,OAAoB,MAAgC;AAC/E,MAAI,SAAS,MAAO,QAAO;AAC3B,MAAI,SAAS,QAAS,QAAO,MAAM,OAAO,OAAO;AACjD,MAAI,SAAS,OAAQ,QAAO,MAAM,OAAO,CAAA,SAAQ,CAAC,QAAQ,IAAI,CAAC;AAC/D,SAAO;AACT;AAEO,SAAS,cAAc,OAAkE;AAC9F,QAAM,QAAQ,MAAM,OAAO,OAAO,EAAE;AACpC,SAAO;AAAA,IACL,OAAO;AAAA,IACP,MAAM,MAAM,SAAS;AAAA,IACrB,KAAK,MAAM;AAAA,EAAA;AAEf;AAEO,SAAS,uBAAuB,WAAwC;AAC7E,QAAM,UAAU,UAAU,SAAS,OAAO,CAAC,MAA2B,EAAE,SAAS,WAAW;AAC5F,QAAM,kBAAkB,aAAa,SAAS;AAC9C,QAAM,wBAAwB,qBAAqB,SAAS;AAE5D,QAAM,cAA2B,QAC9B,IAAI,CAAC,YAAY;AAAA,IAChB,MAAM;AAAA,IACN,MAAM,OAAO;AAAA,IACb,MAAM,OAAO;AAAA,IACb,QAAQ,WAAW,MAAM;AAAA,IACzB,QAAQ,WAAW,MAAM;AAAA,IACzB,MAAM;AAAA,EAAA,EACN,EACD,OAAO,CAAC,SAAS,KAAK,UAAU,KAAK,MAAM;AAE9C,QAAM,YAAyB,gBAAgB,IAAI,CAAC,UAAU;AAAA,IAC5D,MAAM;AAAA,IACN,MAAM,KAAK,KAAK,QAAQ,WAAW,EAAE;AAAA,IACrC,MAAM,KAAK;AAAA,IACX,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR;AAAA,EAAA,EACA;AAGF,QAAM,cAA2B,sBAAsB,IAAI,CAAC,UAAU;AAAA,IACpE,MAAM;AAAA,IACN,MAAM,KAAK,KAAK,QAAQ,mBAAmB,EAAE;AAAA,IAC7C,MAAM,KAAK;AAAA,IACX,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,MAAM;AAAA,EAAA,EACN;AAEF,SAAO,CAAC,GAAG,aAAa,GAAG,WAAW,GAAG,WAAW;AACtD;AAEO,SAAS,mBAAmB,OAAiC;AAClE,SAAO,MAAM,OAAO,CAAC,SAAS;AAC5B,UAAM,cAAc,eAAe,IAAI;AACvC,YAAO,2CAAa,gBAAe,aAAY,2CAAa,WAAU;AAAA,EACxE,CAAC;AACH;"}
@@ -0,0 +1,17 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import { createContext, useContext } from "react";
3
+ const FrontmatterContext = createContext(void 0);
4
+ function FrontmatterProvider({
5
+ frontmatter,
6
+ children
7
+ }) {
8
+ return /* @__PURE__ */ jsx(FrontmatterContext.Provider, { value: frontmatter, children });
9
+ }
10
+ function useFrontmatter() {
11
+ return useContext(FrontmatterContext);
12
+ }
13
+ export {
14
+ FrontmatterProvider,
15
+ useFrontmatter
16
+ };
17
+ //# sourceMappingURL=frontmatter-context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"frontmatter-context.js","sources":["../../../src/lib/frontmatter-context.tsx"],"sourcesContent":["import { createContext, useContext, ReactNode } from 'react';\n\nexport interface Frontmatter {\n title?: string;\n description?: string;\n date?: string;\n visibility?: string;\n draft?: boolean;\n}\n\nconst FrontmatterContext = createContext<Frontmatter | undefined>(undefined);\n\nexport function FrontmatterProvider({\n frontmatter,\n children\n}: {\n frontmatter: Frontmatter | undefined;\n children: ReactNode\n}) {\n return (\n <FrontmatterContext.Provider value={frontmatter}>\n {children}\n </FrontmatterContext.Provider>\n );\n}\n\nexport function useFrontmatter() {\n return useContext(FrontmatterContext);\n}\n"],"names":[],"mappings":";;AAUA,MAAM,qBAAqB,cAAuC,MAAS;AAEpE,SAAS,oBAAoB;AAAA,EAClC;AAAA,EACA;AACF,GAGG;AACD,6BACG,mBAAmB,UAAnB,EAA4B,OAAO,aACjC,UACH;AAEJ;AAEO,SAAS,iBAAiB;AAC/B,SAAO,WAAW,kBAAkB;AACtC;"}
@@ -4,6 +4,7 @@ import { Home } from "./home.js";
4
4
  import { Post } from "./post.js";
5
5
  import { SlidesPage } from "./slides.js";
6
6
  function ContentRouter() {
7
+ var _a;
7
8
  const { "*": path = "" } = useParams();
8
9
  if (path === "posts") {
9
10
  return /* @__PURE__ */ jsx(Home, { view: "posts" });
@@ -14,7 +15,9 @@ function ContentRouter() {
14
15
  if (path === "all") {
15
16
  return /* @__PURE__ */ jsx(Home, { view: "all" });
16
17
  }
17
- if (path.endsWith(".slides.mdx") || path.endsWith("SLIDES.mdx")) {
18
+ const filename = ((_a = path.split("/").pop()) == null ? void 0 : _a.toLowerCase()) || "";
19
+ const isSlides = path.endsWith(".slides.mdx") || path.endsWith(".slides.md") || filename === "slides.mdx" || filename === "slides.md";
20
+ if (isSlides) {
18
21
  return /* @__PURE__ */ jsx(SlidesPage, {});
19
22
  }
20
23
  if (path.endsWith(".mdx") || path.endsWith(".md")) {
@@ -1 +1 @@
1
- {"version":3,"file":"content-router.js","sources":["../../../src/pages/content-router.tsx"],"sourcesContent":["import { useParams } from \"react-router-dom\"\nimport { Home } from \"./home\"\nimport { Post } from \"./post\"\nimport { SlidesPage } from \"./slides\"\n\n/**\n * Routes to the appropriate page based on the URL path:\n * - /posts → Home with posts view\n * - /docs → Home with docs view\n * - *.slides.mdx or *SLIDES.mdx → SlidesPage\n * - *.mdx → Post\n * - everything else → Home (directory listing)\n */\nexport function ContentRouter() {\n const { \"*\": path = \"\" } = useParams()\n\n // Check for content view routes\n if (path === 'posts') {\n return <Home view=\"posts\" />\n }\n if (path === 'docs') {\n return <Home view=\"docs\" />\n }\n if (path === 'all') {\n return <Home view=\"all\" />\n }\n\n // Check if this is a slides file\n if (path.endsWith('.slides.mdx') || path.endsWith('SLIDES.mdx')) {\n return <SlidesPage />\n }\n\n // Check if this is any MDX file\n if (path.endsWith('.mdx') || path.endsWith('.md')) {\n return <Post />\n }\n\n // Otherwise show directory listing\n return <Home />\n}\n"],"names":[],"mappings":";;;;;AAaO,SAAS,gBAAgB;AAC9B,QAAM,EAAE,KAAK,OAAO,GAAA,IAAO,UAAA;AAG3B,MAAI,SAAS,SAAS;AACpB,WAAO,oBAAC,MAAA,EAAK,MAAK,QAAA,CAAQ;AAAA,EAC5B;AACA,MAAI,SAAS,QAAQ;AACnB,WAAO,oBAAC,MAAA,EAAK,MAAK,OAAA,CAAO;AAAA,EAC3B;AACA,MAAI,SAAS,OAAO;AAClB,WAAO,oBAAC,MAAA,EAAK,MAAK,MAAA,CAAM;AAAA,EAC1B;AAGA,MAAI,KAAK,SAAS,aAAa,KAAK,KAAK,SAAS,YAAY,GAAG;AAC/D,+BAAQ,YAAA,EAAW;AAAA,EACrB;AAGA,MAAI,KAAK,SAAS,MAAM,KAAK,KAAK,SAAS,KAAK,GAAG;AACjD,+BAAQ,MAAA,EAAK;AAAA,EACf;AAGA,6BAAQ,MAAA,EAAK;AACf;"}
1
+ {"version":3,"file":"content-router.js","sources":["../../../src/pages/content-router.tsx"],"sourcesContent":["import { useParams } from \"react-router-dom\"\nimport { Home } from \"./home\"\nimport { Post } from \"./post\"\nimport { SlidesPage } from \"./slides\"\n\n/**\n * Routes to the appropriate page based on the URL path:\n * - /posts → Home with posts view\n * - /docs → Home with docs view\n * - *.slides.mdx or *SLIDES.mdx → SlidesPage\n * - *.mdx → Post\n * - everything else → Home (directory listing)\n */\nexport function ContentRouter() {\n const { \"*\": path = \"\" } = useParams()\n\n // Check for content view routes\n if (path === 'posts') {\n return <Home view=\"posts\" />\n }\n if (path === 'docs') {\n return <Home view=\"docs\" />\n }\n if (path === 'all') {\n return <Home view=\"all\" />\n }\n\n // Check if this is a slides file\n const filename = path.split('/').pop()?.toLowerCase() || ''\n const isSlides =\n path.endsWith('.slides.mdx') ||\n path.endsWith('.slides.md') ||\n filename === 'slides.mdx' ||\n filename === 'slides.md'\n if (isSlides) {\n return <SlidesPage />\n }\n\n // Check if this is any MDX file\n if (path.endsWith('.mdx') || path.endsWith('.md')) {\n return <Post />\n }\n\n // Otherwise show directory listing\n return <Home />\n}\n"],"names":[],"mappings":";;;;;AAaO,SAAS,gBAAgB;;AAC9B,QAAM,EAAE,KAAK,OAAO,GAAA,IAAO,UAAA;AAG3B,MAAI,SAAS,SAAS;AACpB,WAAO,oBAAC,MAAA,EAAK,MAAK,QAAA,CAAQ;AAAA,EAC5B;AACA,MAAI,SAAS,QAAQ;AACnB,WAAO,oBAAC,MAAA,EAAK,MAAK,OAAA,CAAO;AAAA,EAC3B;AACA,MAAI,SAAS,OAAO;AAClB,WAAO,oBAAC,MAAA,EAAK,MAAK,MAAA,CAAM;AAAA,EAC1B;AAGA,QAAM,aAAW,UAAK,MAAM,GAAG,EAAE,IAAA,MAAhB,mBAAuB,kBAAiB;AACzD,QAAM,WACJ,KAAK,SAAS,aAAa,KAC3B,KAAK,SAAS,YAAY,KAC1B,aAAa,gBACb,aAAa;AACf,MAAI,UAAU;AACZ,+BAAQ,YAAA,EAAW;AAAA,EACrB;AAGA,MAAI,KAAK,SAAS,MAAM,KAAK,KAAK,SAAS,KAAK,GAAG;AACjD,+BAAQ,MAAA,EAAK;AAAA,EACf;AAGA,6BAAQ,MAAA,EAAK;AACf;"}
@@ -5,7 +5,6 @@ import PostList from "../components/post-list.js";
5
5
  import { ErrorDisplay } from "../components/page-error.js";
6
6
  import { RunningBar } from "../components/running-bar.js";
7
7
  import { Header } from "../components/header.js";
8
- import { ContentTabs } from "../components/content-tabs.js";
9
8
  import { getViewCounts, filterVisiblePosts, directoryToPostEntries } from "../lib/content-classification.js";
10
9
  import siteConfig from "virtual:veslx-config";
11
10
  function Home({ view }) {
@@ -16,7 +15,7 @@ function Home({ view }) {
16
15
  const { directory, error } = useDirectory(directoryPath);
17
16
  const activeView = view ?? config.defaultView;
18
17
  const isRoot = path === "." || path === "" || isViewRoute;
19
- const counts = directory ? getViewCounts(filterVisiblePosts(directoryToPostEntries(directory))) : { posts: 0, docs: 0, all: 0 };
18
+ directory ? getViewCounts(filterVisiblePosts(directoryToPostEntries(directory))) : {};
20
19
  if (error) {
21
20
  return /* @__PURE__ */ jsx(ErrorDisplay, { error, path });
22
21
  }
@@ -30,10 +29,7 @@ function Home({ view }) {
30
29
  /* @__PURE__ */ jsx("h1", { className: "text-2xl md:text-3xl font-semibold tracking-tight text-foreground", children: config.name }),
31
30
  config.description && /* @__PURE__ */ jsx("p", { className: "mt-2 text-muted-foreground", children: config.description })
32
31
  ] }),
33
- /* @__PURE__ */ jsxs("div", { className: "", children: [
34
- isRoot && directory && /* @__PURE__ */ jsx("div", { className: "animate-fade-in", children: /* @__PURE__ */ jsx(ContentTabs, { value: activeView, counts }) }),
35
- directory && /* @__PURE__ */ jsx("div", { className: "animate-fade-in", children: /* @__PURE__ */ jsx(PostList, { directory, view: isRoot ? activeView : "all" }) })
36
- ] })
32
+ /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-2", children: directory && /* @__PURE__ */ jsx("div", { className: "animate-fade-in", children: /* @__PURE__ */ jsx(PostList, { directory, view: isRoot ? activeView : "all" }) }) })
37
33
  ] })
38
34
  ] })
39
35
  ] });
@@ -1 +1 @@
1
- {"version":3,"file":"home.js","sources":["../../../src/pages/home.tsx"],"sourcesContent":["import { useParams } from \"react-router-dom\"\nimport { useDirectory } from \"../../plugin/src/client\";\nimport Loading from \"@/components/loading\";\nimport PostList from \"@/components/post-list\";\nimport { ErrorDisplay } from \"@/components/page-error\";\nimport { RunningBar } from \"@/components/running-bar\";\nimport { Header } from \"@/components/header\";\nimport { ContentTabs } from \"@/components/content-tabs\";\nimport {\n type ContentView,\n directoryToPostEntries,\n filterVisiblePosts,\n getViewCounts,\n} from \"@/lib/content-classification\";\nimport siteConfig from \"virtual:veslx-config\";\n\ninterface HomeProps {\n view?: ContentView;\n}\n\nexport function Home({ view }: HomeProps) {\n const { \"*\": path = \".\" } = useParams();\n const config = siteConfig;\n\n // Normalize path - \"posts\", \"docs\", and \"all\" are view routes, not directories\n const isViewRoute = path === \"posts\" || path === \"docs\" || path === \"all\";\n const directoryPath = isViewRoute ? \".\" : path;\n\n const { directory, loading, error } = useDirectory(directoryPath)\n\n // Use prop view, fallback to config default\n const activeView = view ?? config.defaultView;\n\n const isRoot = path === \".\" || path === \"\" || isViewRoute;\n\n // Calculate counts for tabs (only meaningful on root)\n const counts = directory\n ? getViewCounts(filterVisiblePosts(directoryToPostEntries(directory)))\n : { posts: 0, docs: 0, all: 0 };\n\n if (error) {\n return <ErrorDisplay error={error} path={path} />;\n }\n\n if (loading) {\n return (\n <Loading />\n )\n }\n\n return (\n <div className=\"flex min-h-screen flex-col bg-background noise-overlay\">\n <RunningBar />\n <Header />\n <main className=\"flex-1 mx-auto w-full max-w-[var(--content-width)] px-[var(--page-padding)]\">\n <title>{isRoot ? config.name : `${config.name} - ${path}`}</title>\n <main className=\"flex flex-col gap-8 mb-32 mt-32\">\n {isRoot && (\n <div className=\"animate-fade-in\">\n <h1 className=\"text-2xl md:text-3xl font-semibold tracking-tight text-foreground\">\n {config.name}\n </h1>\n {config.description && (\n <p className=\"mt-2 text-muted-foreground\">\n {config.description}\n </p>\n )}\n </div>\n )}\n\n <div className=\"\">\n {isRoot && directory && (\n <div className=\"animate-fade-in\">\n <ContentTabs value={activeView} counts={counts} />\n </div>\n )}\n {directory && (\n <div className=\"animate-fade-in\">\n <PostList directory={directory} view={isRoot ? activeView : 'all'} />\n </div>\n )}\n </div>\n </main>\n </main>\n </div>\n )\n}\n"],"names":[],"mappings":";;;;;;;;;;AAoBO,SAAS,KAAK,EAAE,QAAmB;AACxC,QAAM,EAAE,KAAK,OAAO,IAAA,IAAQ,UAAA;AAC5B,QAAM,SAAS;AAGf,QAAM,cAAc,SAAS,WAAW,SAAS,UAAU,SAAS;AACpE,QAAM,gBAAgB,cAAc,MAAM;AAE1C,QAAM,EAAE,WAAoB,UAAU,aAAa,aAAa;AAGhE,QAAM,aAAa,QAAQ,OAAO;AAElC,QAAM,SAAS,SAAS,OAAO,SAAS,MAAM;AAG9C,QAAM,SAAS,YACX,cAAc,mBAAmB,uBAAuB,SAAS,CAAC,CAAC,IACnE,EAAE,OAAO,GAAG,MAAM,GAAG,KAAK,EAAA;AAE9B,MAAI,OAAO;AACT,WAAO,oBAAC,cAAA,EAAa,OAAc,KAAA,CAAY;AAAA,EACjD;AAQA,SACE,qBAAC,OAAA,EAAI,WAAU,0DACb,UAAA;AAAA,IAAA,oBAAC,YAAA,EAAW;AAAA,wBACX,QAAA,EAAO;AAAA,IACR,qBAAC,QAAA,EAAK,WAAU,+EACd,UAAA;AAAA,MAAA,oBAAC,SAAA,EAAO,mBAAS,OAAO,OAAO,GAAG,OAAO,IAAI,MAAM,IAAI,GAAA,CAAG;AAAA,MAC1D,qBAAC,QAAA,EAAK,WAAU,mCACb,UAAA;AAAA,QAAA,UACC,qBAAC,OAAA,EAAI,WAAU,mBACb,UAAA;AAAA,UAAA,oBAAC,MAAA,EAAG,WAAU,qEACX,UAAA,OAAO,MACV;AAAA,UACC,OAAO,eACN,oBAAC,OAAE,WAAU,8BACV,iBAAO,YAAA,CACV;AAAA,QAAA,GAEJ;AAAA,QAGF,qBAAC,OAAA,EAAI,WAAU,IACZ,UAAA;AAAA,UAAA,UAAU,aACT,oBAAC,OAAA,EAAI,WAAU,mBACb,8BAAC,aAAA,EAAY,OAAO,YAAY,OAAA,CAAgB,EAAA,CAClD;AAAA,UAED,aACC,oBAAC,OAAA,EAAI,WAAU,mBACb,UAAA,oBAAC,UAAA,EAAS,WAAsB,MAAM,SAAS,aAAa,MAAA,CAAO,EAAA,CACrE;AAAA,QAAA,EAAA,CAEJ;AAAA,MAAA,EAAA,CACF;AAAA,IAAA,EAAA,CACF;AAAA,EAAA,GACF;AAEJ;"}
1
+ {"version":3,"file":"home.js","sources":["../../../src/pages/home.tsx"],"sourcesContent":["import { useParams } from \"react-router-dom\"\nimport { useDirectory } from \"../../plugin/src/client\";\nimport Loading from \"@/components/loading\";\nimport PostList from \"@/components/post-list\";\nimport { ErrorDisplay } from \"@/components/page-error\";\nimport { RunningBar } from \"@/components/running-bar\";\nimport { Header } from \"@/components/header\";\nimport { ContentTabs } from \"@/components/content-tabs\";\nimport {\n type ContentView,\n directoryToPostEntries,\n filterVisiblePosts,\n getViewCounts,\n} from \"@/lib/content-classification\";\nimport siteConfig from \"virtual:veslx-config\";\n\ninterface HomeProps {\n view?: ContentView;\n}\n\nexport function Home({ view }: HomeProps) {\n const { \"*\": path = \".\" } = useParams();\n const config = siteConfig;\n\n // Normalize path - \"posts\", \"docs\", and \"all\" are view routes, not directories\n const isViewRoute = path === \"posts\" || path === \"docs\" || path === \"all\";\n const directoryPath = isViewRoute ? \".\" : path;\n\n const { directory, loading, error } = useDirectory(directoryPath)\n\n // Use prop view, fallback to config default\n const activeView = view ?? config.defaultView;\n\n const isRoot = path === \".\" || path === \"\" || isViewRoute;\n\n // Calculate counts for tabs (only meaningful on root)\n const counts = directory\n ? getViewCounts(filterVisiblePosts(directoryToPostEntries(directory)))\n : { posts: 0, docs: 0, all: 0 };\n\n if (error) {\n return <ErrorDisplay error={error} path={path} />;\n }\n\n if (loading) {\n return (\n <Loading />\n )\n }\n\n return (\n <div className=\"flex min-h-screen flex-col bg-background noise-overlay\">\n <RunningBar />\n <Header />\n <main className=\"flex-1 mx-auto w-full max-w-[var(--content-width)] px-[var(--page-padding)]\">\n <title>{isRoot ? config.name : `${config.name} - ${path}`}</title>\n <main className=\"flex flex-col gap-8 mb-32 mt-32\">\n {isRoot && (\n <div className=\"animate-fade-in\">\n <h1 className=\"text-2xl md:text-3xl font-semibold tracking-tight text-foreground\">\n {config.name}\n </h1>\n {config.description && (\n <p className=\"mt-2 text-muted-foreground\">\n {config.description}\n </p>\n )}\n </div>\n )}\n\n <div className=\"flex flex-col gap-2\">\n {/* {isRoot && directory && (\n <div className=\"animate-fade-in\">\n <ContentTabs value={activeView} counts={counts} />\n </div>\n )} */}\n {directory && (\n <div className=\"animate-fade-in\">\n <PostList directory={directory} view={isRoot ? activeView : 'all'} />\n </div>\n )}\n </div>\n </main>\n </main>\n </div>\n )\n}\n"],"names":[],"mappings":";;;;;;;;;AAoBO,SAAS,KAAK,EAAE,QAAmB;AACxC,QAAM,EAAE,KAAK,OAAO,IAAA,IAAQ,UAAA;AAC5B,QAAM,SAAS;AAGf,QAAM,cAAc,SAAS,WAAW,SAAS,UAAU,SAAS;AACpE,QAAM,gBAAgB,cAAc,MAAM;AAE1C,QAAM,EAAE,WAAoB,UAAU,aAAa,aAAa;AAGhE,QAAM,aAAa,QAAQ,OAAO;AAElC,QAAM,SAAS,SAAS,OAAO,SAAS,MAAM;AAG/B,cACX,cAAc,mBAAmB,uBAAuB,SAAS,CAAC,CAAC,IACnE,CAA4B;AAEhC,MAAI,OAAO;AACT,WAAO,oBAAC,cAAA,EAAa,OAAc,KAAA,CAAY;AAAA,EACjD;AAQA,SACE,qBAAC,OAAA,EAAI,WAAU,0DACb,UAAA;AAAA,IAAA,oBAAC,YAAA,EAAW;AAAA,wBACX,QAAA,EAAO;AAAA,IACR,qBAAC,QAAA,EAAK,WAAU,+EACd,UAAA;AAAA,MAAA,oBAAC,SAAA,EAAO,mBAAS,OAAO,OAAO,GAAG,OAAO,IAAI,MAAM,IAAI,GAAA,CAAG;AAAA,MAC1D,qBAAC,QAAA,EAAK,WAAU,mCACb,UAAA;AAAA,QAAA,UACC,qBAAC,OAAA,EAAI,WAAU,mBACb,UAAA;AAAA,UAAA,oBAAC,MAAA,EAAG,WAAU,qEACX,UAAA,OAAO,MACV;AAAA,UACC,OAAO,eACN,oBAAC,OAAE,WAAU,8BACV,iBAAO,YAAA,CACV;AAAA,QAAA,GAEJ;AAAA,4BAGD,OAAA,EAAI,WAAU,uBAMZ,UAAA,iCACE,OAAA,EAAI,WAAU,mBACb,UAAA,oBAAC,YAAS,WAAsB,MAAM,SAAS,aAAa,OAAO,GACrE,EAAA,CAEJ;AAAA,MAAA,EAAA,CACF;AAAA,IAAA,EAAA,CACF;AAAA,EAAA,GACF;AAEJ;"}
@@ -6,7 +6,7 @@ import { RunningBar } from "../components/running-bar.js";
6
6
  import { Header } from "../components/header.js";
7
7
  import { useMDXContent } from "../hooks/use-mdx-content.js";
8
8
  import { mdxComponents } from "../components/mdx-components.js";
9
- import { formatDate } from "../lib/format-date.js";
9
+ import { FrontmatterProvider } from "../lib/frontmatter-context.js";
10
10
  function Post() {
11
11
  const { "*": rawPath = "." } = useParams();
12
12
  const mdxPath = rawPath;
@@ -32,14 +32,7 @@ function Post() {
32
32
  /* @__PURE__ */ jsx("span", { className: "uppercase tracking-widest", children: "simulation running" }),
33
33
  /* @__PURE__ */ jsx("span", { className: "text-primary-foreground/60", children: "Page will auto-refresh on completion" })
34
34
  ] }) }),
35
- Content && /* @__PURE__ */ jsxs("article", { className: "my-24 prose dark:prose-invert prose-headings:tracking-tight prose-p:leading-relaxed prose-a:text-primary prose-a:no-underline hover:prose-a:underline max-w-[var(--prose-width)] animate-fade-in", children: [
36
- (frontmatter == null ? void 0 : frontmatter.title) && /* @__PURE__ */ jsxs("header", { className: "not-prose flex flex-col gap-2 mb-8 pt-4", children: [
37
- /* @__PURE__ */ jsx("h1", { className: "text-2xl md:text-3xl font-semibold tracking-tight text-foreground mb-3", children: frontmatter.title }),
38
- (frontmatter == null ? void 0 : frontmatter.date) && /* @__PURE__ */ jsx("div", { className: "flex flex-wrap items-center gap-3 text-muted-foreground", children: /* @__PURE__ */ jsx("time", { className: "font-mono text-xs bg-muted px-2 py-0.5 rounded", children: formatDate(new Date(frontmatter.date)) }) }),
39
- (frontmatter == null ? void 0 : frontmatter.description) && /* @__PURE__ */ jsx("div", { className: "flex flex-wrap text-sm items-center gap-3 text-muted-foreground", children: frontmatter.description })
40
- ] }),
41
- /* @__PURE__ */ jsx(Content, { components: mdxComponents })
42
- ] })
35
+ Content && /* @__PURE__ */ jsx(FrontmatterProvider, { frontmatter, children: /* @__PURE__ */ jsx("article", { className: "my-24 prose dark:prose-invert prose-headings:tracking-tight prose-p:leading-relaxed prose-a:text-primary prose-a:no-underline hover:prose-a:underline max-w-[var(--prose-width)] animate-fade-in", children: /* @__PURE__ */ jsx(Content, { components: mdxComponents }) }) })
43
36
  ] })
44
37
  ] });
45
38
  }
@@ -1 +1 @@
1
- {"version":3,"file":"post.js","sources":["../../../src/pages/post.tsx"],"sourcesContent":["import { useParams } from \"react-router-dom\";\nimport { findSlides, isSimulationRunning, useDirectory } from \"../../plugin/src/client\";\nimport Loading from \"@/components/loading\";\nimport { FileEntry } from \"plugin/src/lib\";\nimport { RunningBar } from \"@/components/running-bar\";\nimport { Header } from \"@/components/header\";\nimport { useMDXContent } from \"@/hooks/use-mdx-content\";\nimport { mdxComponents } from \"@/components/mdx-components\";\nimport { formatDate } from \"@/lib/format-date\";\n\nexport function Post() {\n const { \"*\": rawPath = \".\" } = useParams();\n\n // The path includes the .mdx extension from the route\n const mdxPath = rawPath;\n\n // Extract directory path for finding sibling files (slides, etc.)\n const dirPath = mdxPath.replace(/\\/[^/]+\\.mdx$/, '') || '.';\n\n const { directory, loading: dirLoading } = useDirectory(dirPath)\n const { Content, frontmatter, loading: mdxLoading, error } = useMDXContent(mdxPath);\n const isRunning = isSimulationRunning();\n\n let slides: FileEntry | null = null;\n if (directory) {\n slides = findSlides(directory);\n }\n\n const loading = dirLoading || mdxLoading;\n\n if (loading) return <Loading />\n\n if (error) {\n return (\n <main className=\"min-h-screen bg-background container mx-auto max-w-4xl py-12\">\n <p className=\"text-center text-red-600\">{error.message}</p>\n </main>\n )\n }\n\n return (\n <div className=\"flex min-h-screen flex-col bg-background noise-overlay\">\n <title>{frontmatter?.title}</title>\n <RunningBar />\n <Header />\n <main className=\"flex-1 mx-auto w-full max-w-[var(--content-width)] px-[var(--page-padding)]\">\n {isRunning && (\n <div className=\"sticky top-0 z-50 px-[var(--page-padding)] py-2 bg-red-500 text-primary-foreground font-mono text-xs text-center tracking-wide\">\n <span className=\"inline-flex items-center gap-3\">\n <span className=\"h-1.5 w-1.5 rounded-full bg-current animate-pulse\" />\n <span className=\"uppercase tracking-widest\">simulation running</span>\n <span className=\"text-primary-foreground/60\">Page will auto-refresh on completion</span>\n </span>\n </div>\n )}\n\n {Content && (\n <article className=\"my-24 prose dark:prose-invert prose-headings:tracking-tight prose-p:leading-relaxed prose-a:text-primary prose-a:no-underline hover:prose-a:underline max-w-[var(--prose-width)] animate-fade-in\">\n {/* Render frontmatter header */}\n {frontmatter?.title && (\n <header className=\"not-prose flex flex-col gap-2 mb-8 pt-4\">\n <h1 className=\"text-2xl md:text-3xl font-semibold tracking-tight text-foreground mb-3\">\n {frontmatter.title}\n </h1>\n {frontmatter?.date && (\n <div className=\"flex flex-wrap items-center gap-3 text-muted-foreground\">\n <time className=\"font-mono text-xs bg-muted px-2 py-0.5 rounded\">\n {formatDate(new Date(frontmatter.date as string))}\n </time>\n </div>\n )}\n {frontmatter?.description && (\n <div className=\"flex flex-wrap text-sm items-center gap-3 text-muted-foreground\">\n {frontmatter.description}\n </div>\n )}\n </header>\n )}\n <Content components={mdxComponents} />\n </article>\n )}\n </main>\n </div>\n )\n}\n"],"names":[],"mappings":";;;;;;;;;AAUO,SAAS,OAAO;AACrB,QAAM,EAAE,KAAK,UAAU,IAAA,IAAQ,UAAA;AAG/B,QAAM,UAAU;AAGhB,QAAM,UAAU,QAAQ,QAAQ,iBAAiB,EAAE,KAAK;AAExD,QAAM,EAAE,UAA+B,IAAI,aAAa,OAAO;AAC/D,QAAM,EAAE,SAAS,aAAa,SAAS,YAAY,MAAA,IAAU,cAAc,OAAO;AAClF,QAAM,YAAY,oBAAA;AAGlB,MAAI,WAAW;AACJ,eAAW,SAAS;AAAA,EAC/B;AAEA,QAAM,UAAwB;AAE9B,MAAI,QAAS,QAAO,oBAAC,SAAA,CAAA,CAAQ;AAE7B,MAAI,OAAO;AACT,WACE,oBAAC,QAAA,EAAK,WAAU,gEACd,UAAA,oBAAC,OAAE,WAAU,4BAA4B,UAAA,MAAM,QAAA,CAAQ,GACzD;AAAA,EAEJ;AAEA,SACE,qBAAC,OAAA,EAAI,WAAU,0DACb,UAAA;AAAA,IAAA,oBAAC,SAAA,EAAO,qDAAa,MAAA,CAAM;AAAA,wBAC1B,YAAA,EAAW;AAAA,wBACX,QAAA,EAAO;AAAA,IACR,qBAAC,QAAA,EAAK,WAAU,+EACb,UAAA;AAAA,MAAA,iCACE,OAAA,EAAI,WAAU,kIACb,UAAA,qBAAC,QAAA,EAAK,WAAU,kCACd,UAAA;AAAA,QAAA,oBAAC,QAAA,EAAK,WAAU,oDAAA,CAAoD;AAAA,QACpE,oBAAC,QAAA,EAAK,WAAU,6BAA4B,UAAA,sBAAkB;AAAA,QAC9D,oBAAC,QAAA,EAAK,WAAU,8BAA6B,UAAA,uCAAA,CAAoC;AAAA,MAAA,EAAA,CACnF,EAAA,CACF;AAAA,MAGD,WACC,qBAAC,WAAA,EAAQ,WAAU,oMAEhB,UAAA;AAAA,SAAA,2CAAa,UACZ,qBAAC,UAAA,EAAO,WAAU,2CAChB,UAAA;AAAA,UAAA,oBAAC,MAAA,EAAG,WAAU,0EACX,UAAA,YAAY,OACf;AAAA,WACC,2CAAa,SACZ,oBAAC,OAAA,EAAI,WAAU,2DACb,UAAA,oBAAC,QAAA,EAAK,WAAU,kDACb,qBAAW,IAAI,KAAK,YAAY,IAAc,CAAC,GAClD,GACF;AAAA,WAED,2CAAa,gBACZ,oBAAC,SAAI,WAAU,mEACZ,sBAAY,YAAA,CACf;AAAA,QAAA,GAEJ;AAAA,QAEF,oBAAC,SAAA,EAAQ,YAAY,cAAA,CAAe;AAAA,MAAA,EAAA,CACtC;AAAA,IAAA,EAAA,CAEJ;AAAA,EAAA,GACF;AAEJ;"}
1
+ {"version":3,"file":"post.js","sources":["../../../src/pages/post.tsx"],"sourcesContent":["import { useParams } from \"react-router-dom\";\nimport { findSlides, isSimulationRunning, useDirectory } from \"../../plugin/src/client\";\nimport Loading from \"@/components/loading\";\nimport { FileEntry } from \"plugin/src/lib\";\nimport { RunningBar } from \"@/components/running-bar\";\nimport { Header } from \"@/components/header\";\nimport { useMDXContent } from \"@/hooks/use-mdx-content\";\nimport { mdxComponents } from \"@/components/mdx-components\";\nimport { FrontmatterProvider } from \"@/lib/frontmatter-context\";\n\nexport function Post() {\n const { \"*\": rawPath = \".\" } = useParams();\n\n // The path includes the .mdx extension from the route\n const mdxPath = rawPath;\n\n // Extract directory path for finding sibling files (slides, etc.)\n const dirPath = mdxPath.replace(/\\/[^/]+\\.mdx$/, '') || '.';\n\n const { directory, loading: dirLoading } = useDirectory(dirPath)\n const { Content, frontmatter, loading: mdxLoading, error } = useMDXContent(mdxPath);\n const isRunning = isSimulationRunning();\n\n let slides: FileEntry | null = null;\n if (directory) {\n slides = findSlides(directory);\n }\n\n const loading = dirLoading || mdxLoading;\n\n if (loading) return <Loading />\n\n if (error) {\n return (\n <main className=\"min-h-screen bg-background container mx-auto max-w-4xl py-12\">\n <p className=\"text-center text-red-600\">{error.message}</p>\n </main>\n )\n }\n\n return (\n <div className=\"flex min-h-screen flex-col bg-background noise-overlay\">\n <title>{frontmatter?.title}</title>\n <RunningBar />\n <Header />\n <main className=\"flex-1 mx-auto w-full max-w-[var(--content-width)] px-[var(--page-padding)]\">\n {isRunning && (\n <div className=\"sticky top-0 z-50 px-[var(--page-padding)] py-2 bg-red-500 text-primary-foreground font-mono text-xs text-center tracking-wide\">\n <span className=\"inline-flex items-center gap-3\">\n <span className=\"h-1.5 w-1.5 rounded-full bg-current animate-pulse\" />\n <span className=\"uppercase tracking-widest\">simulation running</span>\n <span className=\"text-primary-foreground/60\">Page will auto-refresh on completion</span>\n </span>\n </div>\n )}\n\n {Content && (\n <FrontmatterProvider frontmatter={frontmatter}>\n <article className=\"my-24 prose dark:prose-invert prose-headings:tracking-tight prose-p:leading-relaxed prose-a:text-primary prose-a:no-underline hover:prose-a:underline max-w-[var(--prose-width)] animate-fade-in\">\n <Content components={mdxComponents} />\n </article>\n </FrontmatterProvider>\n )}\n </main>\n </div>\n )\n}\n"],"names":[],"mappings":";;;;;;;;;AAUO,SAAS,OAAO;AACrB,QAAM,EAAE,KAAK,UAAU,IAAA,IAAQ,UAAA;AAG/B,QAAM,UAAU;AAGhB,QAAM,UAAU,QAAQ,QAAQ,iBAAiB,EAAE,KAAK;AAExD,QAAM,EAAE,UAA+B,IAAI,aAAa,OAAO;AAC/D,QAAM,EAAE,SAAS,aAAa,SAAS,YAAY,MAAA,IAAU,cAAc,OAAO;AAClF,QAAM,YAAY,oBAAA;AAGlB,MAAI,WAAW;AACJ,eAAW,SAAS;AAAA,EAC/B;AAEA,QAAM,UAAwB;AAE9B,MAAI,QAAS,QAAO,oBAAC,SAAA,CAAA,CAAQ;AAE7B,MAAI,OAAO;AACT,WACE,oBAAC,QAAA,EAAK,WAAU,gEACd,UAAA,oBAAC,OAAE,WAAU,4BAA4B,UAAA,MAAM,QAAA,CAAQ,GACzD;AAAA,EAEJ;AAEA,SACE,qBAAC,OAAA,EAAI,WAAU,0DACb,UAAA;AAAA,IAAA,oBAAC,SAAA,EAAO,qDAAa,MAAA,CAAM;AAAA,wBAC1B,YAAA,EAAW;AAAA,wBACX,QAAA,EAAO;AAAA,IACR,qBAAC,QAAA,EAAK,WAAU,+EACb,UAAA;AAAA,MAAA,iCACE,OAAA,EAAI,WAAU,kIACb,UAAA,qBAAC,QAAA,EAAK,WAAU,kCACd,UAAA;AAAA,QAAA,oBAAC,QAAA,EAAK,WAAU,oDAAA,CAAoD;AAAA,QACpE,oBAAC,QAAA,EAAK,WAAU,6BAA4B,UAAA,sBAAkB;AAAA,QAC9D,oBAAC,QAAA,EAAK,WAAU,8BAA6B,UAAA,uCAAA,CAAoC;AAAA,MAAA,EAAA,CACnF,EAAA,CACF;AAAA,MAGD,WACC,oBAAC,qBAAA,EAAoB,aACnB,UAAA,oBAAC,WAAA,EAAQ,WAAU,oMACjB,UAAA,oBAAC,SAAA,EAAQ,YAAY,cAAA,CAAe,GACtC,EAAA,CACF;AAAA,IAAA,EAAA,CAEJ;AAAA,EAAA,GACF;AAEJ;"}
@@ -7,19 +7,20 @@ import { RunningBar } from "../components/running-bar.js";
7
7
  import { Header } from "../components/header.js";
8
8
  import { useMDXSlides } from "../hooks/use-mdx-content.js";
9
9
  import { slidesMdxComponents } from "../components/slides-renderer.js";
10
+ import { FrontmatterProvider } from "../lib/frontmatter-context.js";
10
11
  function SlidesPage() {
11
12
  const { "*": rawPath = "." } = useParams();
12
13
  const [searchParams, setSearchParams] = useSearchParams();
13
14
  const mdxPath = rawPath;
14
15
  const { Content, frontmatter, slideCount, loading, error } = useMDXSlides(mdxPath);
15
- const totalSlides = (slideCount || 0) + 1;
16
+ const totalSlides = slideCount || 0;
16
17
  const [currentSlide, setCurrentSlide] = useState(0);
17
18
  const titleSlideRef = useRef(null);
18
19
  const contentRef = useRef(null);
19
20
  useEffect(() => {
20
21
  const slideParam = parseInt(searchParams.get("slide") || "0", 10);
21
22
  if (slideParam > 0 && contentRef.current) {
22
- const slideEl = contentRef.current.querySelector(`[data-slide-index="${slideParam - 1}"]`);
23
+ const slideEl = contentRef.current.querySelector(`[data-slide-index="${slideParam}"]`);
23
24
  if (slideEl) {
24
25
  slideEl.scrollIntoView({ behavior: "auto" });
25
26
  }
@@ -32,7 +33,7 @@ function SlidesPage() {
32
33
  if (entry.isIntersecting) {
33
34
  const index = entry.target.getAttribute("data-slide-index");
34
35
  if (index !== null) {
35
- const slideNum = index === "title" ? 0 : parseInt(index, 10) + 1;
36
+ const slideNum = index === "title" ? 0 : parseInt(index, 10);
36
37
  setCurrentSlide(slideNum);
37
38
  setSearchParams(slideNum > 0 ? { slide: String(slideNum) } : {}, { replace: true });
38
39
  }
@@ -52,19 +53,15 @@ function SlidesPage() {
52
53
  }, [Content, setSearchParams]);
53
54
  const goToPrevious = useCallback(() => {
54
55
  const prev = Math.max(0, currentSlide - 1);
55
- if (prev === 0 && titleSlideRef.current) {
56
- titleSlideRef.current.scrollIntoView({ behavior: "smooth" });
57
- } else if (contentRef.current) {
58
- const slideEl = contentRef.current.querySelector(`[data-slide-index="${prev - 1}"]`);
56
+ if (contentRef.current) {
57
+ const slideEl = contentRef.current.querySelector(`[data-slide-index="${prev}"]`);
59
58
  slideEl == null ? void 0 : slideEl.scrollIntoView({ behavior: "smooth" });
60
59
  }
61
60
  }, [currentSlide]);
62
61
  const goToNext = useCallback(() => {
63
62
  const next = Math.min(totalSlides - 1, currentSlide + 1);
64
- if (next === 0 && titleSlideRef.current) {
65
- titleSlideRef.current.scrollIntoView({ behavior: "smooth" });
66
- } else if (contentRef.current) {
67
- const slideEl = contentRef.current.querySelector(`[data-slide-index="${next - 1}"]`);
63
+ if (contentRef.current) {
64
+ const slideEl = contentRef.current.querySelector(`[data-slide-index="${next}"]`);
68
65
  slideEl == null ? void 0 : slideEl.scrollIntoView({ behavior: "smooth" });
69
66
  }
70
67
  }, [currentSlide, totalSlides]);
@@ -104,7 +101,7 @@ function SlidesPage() {
104
101
  }
105
102
  }
106
103
  ),
107
- /* @__PURE__ */ jsx("div", { ...{ [FULLSCREEN_DATA_ATTR]: "true" }, children: /* @__PURE__ */ jsx("div", { ref: contentRef, children: /* @__PURE__ */ jsx(Content, { components: slidesMdxComponents }) }) })
104
+ /* @__PURE__ */ jsx(FrontmatterProvider, { frontmatter, children: /* @__PURE__ */ jsx("div", { ...{ [FULLSCREEN_DATA_ATTR]: "true" }, children: /* @__PURE__ */ jsx("div", { ref: contentRef, children: /* @__PURE__ */ jsx(Content, { components: slidesMdxComponents }) }) }) })
108
105
  ] });
109
106
  }
110
107
  export {
@@ -1 +1 @@
1
- {"version":3,"file":"slides.js","sources":["../../../src/pages/slides.tsx"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from \"react\";\nimport { FULLSCREEN_DATA_ATTR } from \"@/lib/constants\";\nimport { useParams, useSearchParams } from \"react-router-dom\"\nimport Loading from \"@/components/loading\";\nimport { RunningBar } from \"@/components/running-bar\";\nimport { Header } from \"@/components/header\";\nimport { useMDXSlides } from \"@/hooks/use-mdx-content\";\nimport { slidesMdxComponents } from \"@/components/slides-renderer\";\n\n\nexport function SlidesPage() {\n const { \"*\": rawPath = \".\" } = useParams();\n const [searchParams, setSearchParams] = useSearchParams();\n\n // The path includes the .mdx extension from the route\n const mdxPath = rawPath;\n\n // Load the compiled MDX module (now includes slideCount export)\n const { Content, frontmatter, slideCount, loading, error } = useMDXSlides(mdxPath);\n\n // Total slides = 1 (title) + content slides\n const totalSlides = (slideCount || 0) + 1;\n\n const [currentSlide, setCurrentSlide] = useState(0);\n const titleSlideRef = useRef<HTMLDivElement>(null);\n const contentRef = useRef<HTMLDivElement>(null);\n\n // Scroll to slide on initial load if query param is set\n useEffect(() => {\n const slideParam = parseInt(searchParams.get(\"slide\") || \"0\", 10);\n if (slideParam > 0 && contentRef.current) {\n const slideEl = contentRef.current.querySelector(`[data-slide-index=\"${slideParam - 1}\"]`);\n if (slideEl) {\n slideEl.scrollIntoView({ behavior: \"auto\" });\n }\n }\n }, [searchParams, Content]);\n\n // Track current slide based on scroll position\n useEffect(() => {\n const observer = new IntersectionObserver(\n (entries) => {\n for (const entry of entries) {\n if (entry.isIntersecting) {\n const index = entry.target.getAttribute(\"data-slide-index\");\n if (index !== null) {\n const slideNum = index === \"title\" ? 0 : parseInt(index, 10) + 1;\n setCurrentSlide(slideNum);\n setSearchParams(slideNum > 0 ? { slide: String(slideNum) } : {}, { replace: true });\n }\n }\n }\n },\n { threshold: 0.5 }\n );\n\n // Observe title slide\n if (titleSlideRef.current) {\n observer.observe(titleSlideRef.current);\n }\n\n // Observe content slides\n if (contentRef.current) {\n const slides = contentRef.current.querySelectorAll(\"[data-slide-index]\");\n slides.forEach((slide) => observer.observe(slide));\n }\n\n return () => observer.disconnect();\n }, [Content, setSearchParams]);\n\n // Keyboard/scroll navigation helpers\n const goToPrevious = useCallback(() => {\n const prev = Math.max(0, currentSlide - 1);\n if (prev === 0 && titleSlideRef.current) {\n titleSlideRef.current.scrollIntoView({ behavior: \"smooth\" });\n } else if (contentRef.current) {\n const slideEl = contentRef.current.querySelector(`[data-slide-index=\"${prev - 1}\"]`);\n slideEl?.scrollIntoView({ behavior: \"smooth\" });\n }\n }, [currentSlide]);\n\n const goToNext = useCallback(() => {\n const next = Math.min(totalSlides - 1, currentSlide + 1);\n if (next === 0 && titleSlideRef.current) {\n titleSlideRef.current.scrollIntoView({ behavior: \"smooth\" });\n } else if (contentRef.current) {\n const slideEl = contentRef.current.querySelector(`[data-slide-index=\"${next - 1}\"]`);\n slideEl?.scrollIntoView({ behavior: \"smooth\" });\n }\n }, [currentSlide, totalSlides]);\n\n // Keyboard navigation\n useEffect(() => {\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.key === \"ArrowUp\" || e.key === \"ArrowLeft\" || e.key === \"k\") {\n e.preventDefault();\n goToPrevious();\n } else if (e.key === \"ArrowDown\" || e.key === \"ArrowRight\" || e.key === \"j\") {\n e.preventDefault();\n goToNext();\n }\n };\n\n window.addEventListener(\"keydown\", handleKeyDown);\n return () => window.removeEventListener(\"keydown\", handleKeyDown);\n }, [goToPrevious, goToNext]);\n\n if (loading) {\n return <Loading />\n }\n\n if (error) {\n return (\n <main className=\"min-h-screen bg-background container mx-auto max-w-4xl py-12\">\n <p className=\"text-center text-red-600\">{error.message}</p>\n </main>\n )\n }\n\n if (!Content) {\n return (\n <div className=\"flex items-center justify-center p-12 text-muted-foreground font-mono text-sm\">\n no slides found — use \"---\" to separate slides\n </div>\n );\n }\n\n return (\n <main className=\"slides-container\">\n <title>{frontmatter?.title}</title>\n <RunningBar />\n <Header\n slideControls={{\n current: currentSlide,\n total: totalSlides,\n onPrevious: goToPrevious,\n onNext: goToNext,\n }}\n />\n <div {...{[FULLSCREEN_DATA_ATTR]: \"true\"}}>\n <div ref={contentRef}>\n <Content components={slidesMdxComponents} />\n </div>\n </div>\n </main>\n )\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"slides.js","sources":["../../../src/pages/slides.tsx"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from \"react\";\nimport { FULLSCREEN_DATA_ATTR } from \"@/lib/constants\";\nimport { useParams, useSearchParams } from \"react-router-dom\"\nimport Loading from \"@/components/loading\";\nimport { RunningBar } from \"@/components/running-bar\";\nimport { Header } from \"@/components/header\";\nimport { useMDXSlides } from \"@/hooks/use-mdx-content\";\nimport { slidesMdxComponents } from \"@/components/slides-renderer\";\nimport { FrontmatterProvider } from \"@/lib/frontmatter-context\";\n\n\nexport function SlidesPage() {\n const { \"*\": rawPath = \".\" } = useParams();\n const [searchParams, setSearchParams] = useSearchParams();\n\n // The path includes the .mdx extension from the route\n const mdxPath = rawPath;\n\n // Load the compiled MDX module (now includes slideCount export)\n const { Content, frontmatter, slideCount, loading, error } = useMDXSlides(mdxPath);\n\n const totalSlides = slideCount || 0;\n\n const [currentSlide, setCurrentSlide] = useState(0);\n const titleSlideRef = useRef<HTMLDivElement>(null);\n const contentRef = useRef<HTMLDivElement>(null);\n\n // Scroll to slide on initial load if query param is set\n useEffect(() => {\n const slideParam = parseInt(searchParams.get(\"slide\") || \"0\", 10);\n if (slideParam > 0 && contentRef.current) {\n const slideEl = contentRef.current.querySelector(`[data-slide-index=\"${slideParam}\"]`);\n if (slideEl) {\n slideEl.scrollIntoView({ behavior: \"auto\" });\n }\n }\n }, [searchParams, Content]);\n\n // Track current slide based on scroll position\n useEffect(() => {\n const observer = new IntersectionObserver(\n (entries) => {\n for (const entry of entries) {\n if (entry.isIntersecting) {\n const index = entry.target.getAttribute(\"data-slide-index\");\n if (index !== null) {\n const slideNum = index === \"title\" ? 0 : parseInt(index, 10);\n setCurrentSlide(slideNum);\n setSearchParams(slideNum > 0 ? { slide: String(slideNum) } : {}, { replace: true });\n }\n }\n }\n },\n { threshold: 0.5 }\n );\n\n // Observe title slide\n if (titleSlideRef.current) {\n observer.observe(titleSlideRef.current);\n }\n\n // Observe content slides\n if (contentRef.current) {\n const slides = contentRef.current.querySelectorAll(\"[data-slide-index]\");\n slides.forEach((slide) => observer.observe(slide));\n }\n\n return () => observer.disconnect();\n }, [Content, setSearchParams]);\n\n // Keyboard/scroll navigation helpers\n const goToPrevious = useCallback(() => {\n const prev = Math.max(0, currentSlide - 1);\n if (contentRef.current) {\n const slideEl = contentRef.current.querySelector(`[data-slide-index=\"${prev}\"]`);\n slideEl?.scrollIntoView({ behavior: \"smooth\" });\n }\n }, [currentSlide]);\n\n const goToNext = useCallback(() => {\n const next = Math.min(totalSlides - 1, currentSlide + 1);\n if (contentRef.current) {\n const slideEl = contentRef.current.querySelector(`[data-slide-index=\"${next}\"]`);\n slideEl?.scrollIntoView({ behavior: \"smooth\" });\n }\n }, [currentSlide, totalSlides]);\n\n // Keyboard navigation\n useEffect(() => {\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.key === \"ArrowUp\" || e.key === \"ArrowLeft\" || e.key === \"k\") {\n e.preventDefault();\n goToPrevious();\n } else if (e.key === \"ArrowDown\" || e.key === \"ArrowRight\" || e.key === \"j\") {\n e.preventDefault();\n goToNext();\n }\n };\n\n window.addEventListener(\"keydown\", handleKeyDown);\n return () => window.removeEventListener(\"keydown\", handleKeyDown);\n }, [goToPrevious, goToNext]);\n\n if (loading) {\n return <Loading />\n }\n\n if (error) {\n return (\n <main className=\"min-h-screen bg-background container mx-auto max-w-4xl py-12\">\n <p className=\"text-center text-red-600\">{error.message}</p>\n </main>\n )\n }\n\n if (!Content) {\n return (\n <div className=\"flex items-center justify-center p-12 text-muted-foreground font-mono text-sm\">\n no slides found — use \"---\" to separate slides\n </div>\n );\n }\n\n return (\n <main className=\"slides-container\">\n <title>{frontmatter?.title}</title>\n <RunningBar />\n <Header\n slideControls={{\n current: currentSlide,\n total: totalSlides,\n onPrevious: goToPrevious,\n onNext: goToNext,\n }}\n />\n <FrontmatterProvider frontmatter={frontmatter}>\n <div {...{[FULLSCREEN_DATA_ATTR]: \"true\"}}>\n <div ref={contentRef}>\n <Content components={slidesMdxComponents} />\n </div>\n </div>\n </FrontmatterProvider>\n </main>\n )\n}\n"],"names":[],"mappings":";;;;;;;;;;AAWO,SAAS,aAAa;AAC3B,QAAM,EAAE,KAAK,UAAU,IAAA,IAAQ,UAAA;AAC/B,QAAM,CAAC,cAAc,eAAe,IAAI,gBAAA;AAGxC,QAAM,UAAU;AAGhB,QAAM,EAAE,SAAS,aAAa,YAAY,SAAS,MAAA,IAAU,aAAa,OAAO;AAEjF,QAAM,cAAc,cAAc;AAElC,QAAM,CAAC,cAAc,eAAe,IAAI,SAAS,CAAC;AAClD,QAAM,gBAAgB,OAAuB,IAAI;AACjD,QAAM,aAAa,OAAuB,IAAI;AAG9C,YAAU,MAAM;AACd,UAAM,aAAa,SAAS,aAAa,IAAI,OAAO,KAAK,KAAK,EAAE;AAChE,QAAI,aAAa,KAAK,WAAW,SAAS;AACxC,YAAM,UAAU,WAAW,QAAQ,cAAc,sBAAsB,UAAU,IAAI;AACrF,UAAI,SAAS;AACX,gBAAQ,eAAe,EAAE,UAAU,OAAA,CAAQ;AAAA,MAC7C;AAAA,IACF;AAAA,EACF,GAAG,CAAC,cAAc,OAAO,CAAC;AAG1B,YAAU,MAAM;AACd,UAAM,WAAW,IAAI;AAAA,MACnB,CAAC,YAAY;AACX,mBAAW,SAAS,SAAS;AAC3B,cAAI,MAAM,gBAAgB;AACxB,kBAAM,QAAQ,MAAM,OAAO,aAAa,kBAAkB;AAC1D,gBAAI,UAAU,MAAM;AAClB,oBAAM,WAAW,UAAU,UAAU,IAAI,SAAS,OAAO,EAAE;AAC3D,8BAAgB,QAAQ;AACxB,8BAAgB,WAAW,IAAI,EAAE,OAAO,OAAO,QAAQ,EAAA,IAAM,CAAA,GAAI,EAAE,SAAS,MAAM;AAAA,YACpF;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,MACA,EAAE,WAAW,IAAA;AAAA,IAAI;AAInB,QAAI,cAAc,SAAS;AACzB,eAAS,QAAQ,cAAc,OAAO;AAAA,IACxC;AAGA,QAAI,WAAW,SAAS;AACtB,YAAM,SAAS,WAAW,QAAQ,iBAAiB,oBAAoB;AACvE,aAAO,QAAQ,CAAC,UAAU,SAAS,QAAQ,KAAK,CAAC;AAAA,IACnD;AAEA,WAAO,MAAM,SAAS,WAAA;AAAA,EACxB,GAAG,CAAC,SAAS,eAAe,CAAC;AAG7B,QAAM,eAAe,YAAY,MAAM;AACrC,UAAM,OAAO,KAAK,IAAI,GAAG,eAAe,CAAC;AACzC,QAAI,WAAW,SAAS;AACtB,YAAM,UAAU,WAAW,QAAQ,cAAc,sBAAsB,IAAI,IAAI;AAC/E,yCAAS,eAAe,EAAE,UAAU,SAAA;AAAA,IACtC;AAAA,EACF,GAAG,CAAC,YAAY,CAAC;AAEjB,QAAM,WAAW,YAAY,MAAM;AACjC,UAAM,OAAO,KAAK,IAAI,cAAc,GAAG,eAAe,CAAC;AACvD,QAAI,WAAW,SAAS;AACtB,YAAM,UAAU,WAAW,QAAQ,cAAc,sBAAsB,IAAI,IAAI;AAC/E,yCAAS,eAAe,EAAE,UAAU,SAAA;AAAA,IACtC;AAAA,EACF,GAAG,CAAC,cAAc,WAAW,CAAC;AAG9B,YAAU,MAAM;AACd,UAAM,gBAAgB,CAAC,MAAqB;AAC1C,UAAI,EAAE,QAAQ,aAAa,EAAE,QAAQ,eAAe,EAAE,QAAQ,KAAK;AACjE,UAAE,eAAA;AACF,qBAAA;AAAA,MACF,WAAW,EAAE,QAAQ,eAAe,EAAE,QAAQ,gBAAgB,EAAE,QAAQ,KAAK;AAC3E,UAAE,eAAA;AACF,iBAAA;AAAA,MACF;AAAA,IACF;AAEA,WAAO,iBAAiB,WAAW,aAAa;AAChD,WAAO,MAAM,OAAO,oBAAoB,WAAW,aAAa;AAAA,EAClE,GAAG,CAAC,cAAc,QAAQ,CAAC;AAE3B,MAAI,SAAS;AACX,+BAAQ,SAAA,EAAQ;AAAA,EAClB;AAEA,MAAI,OAAO;AACT,WACE,oBAAC,QAAA,EAAK,WAAU,gEACd,UAAA,oBAAC,OAAE,WAAU,4BAA4B,UAAA,MAAM,QAAA,CAAQ,GACzD;AAAA,EAEJ;AAEA,MAAI,CAAC,SAAS;AACZ,WACE,oBAAC,OAAA,EAAI,WAAU,iFAAgF,UAAA,kDAE/F;AAAA,EAEJ;AAEA,SACE,qBAAC,QAAA,EAAK,WAAU,oBACd,UAAA;AAAA,IAAA,oBAAC,SAAA,EAAO,qDAAa,MAAA,CAAM;AAAA,wBAC1B,YAAA,EAAW;AAAA,IACZ;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,eAAe;AAAA,UACb,SAAS;AAAA,UACT,OAAO;AAAA,UACP,YAAY;AAAA,UACZ,QAAQ;AAAA,QAAA;AAAA,MACV;AAAA,IAAA;AAAA,IAEF,oBAAC,uBAAoB,aACnB,UAAA,oBAAC,SAAK,GAAG,EAAC,CAAC,oBAAoB,GAAG,OAAA,GAChC,UAAA,oBAAC,OAAA,EAAI,KAAK,YACR,UAAA,oBAAC,WAAQ,YAAY,oBAAA,CAAqB,EAAA,CAC5C,EAAA,CACF,EAAA,CACF;AAAA,EAAA,GACF;AAEJ;"}
@@ -45,7 +45,7 @@ function findMdxFiles(directory) {
45
45
  );
46
46
  }
47
47
  function findSlides(directory) {
48
- const readme = directory.children.find(
48
+ const standardSlides = directory.children.find(
49
49
  (child) => child.type === "file" && [
50
50
  "SLIDES.md",
51
51
  "Slides.md",
@@ -55,7 +55,24 @@ function findSlides(directory) {
55
55
  "slides.mdx"
56
56
  ].includes(child.name)
57
57
  );
58
- return readme || null;
58
+ if (standardSlides) return standardSlides;
59
+ const dotSlides = directory.children.find(
60
+ (child) => child.type === "file" && (child.name.endsWith(".slides.mdx") || child.name.endsWith(".slides.md"))
61
+ );
62
+ return dotSlides || null;
63
+ }
64
+ function findStandaloneSlides(directory) {
65
+ const standardSlideFiles = [
66
+ "SLIDES.mdx",
67
+ "Slides.mdx",
68
+ "slides.mdx",
69
+ "SLIDES.md",
70
+ "Slides.md",
71
+ "slides.md"
72
+ ];
73
+ return directory.children.filter(
74
+ (child) => child.type === "file" && (child.name.endsWith(".slides.mdx") || child.name.endsWith(".slides.md")) && !standardSlideFiles.includes(child.name)
75
+ );
59
76
  }
60
77
  const directoryTree = buildDirectoryTree(Object.keys(files), frontmatters);
61
78
  function useDirectory(path = ".") {
@@ -140,6 +157,7 @@ export {
140
157
  findMdxFiles,
141
158
  findReadme,
142
159
  findSlides,
160
+ findStandaloneSlides,
143
161
  isSimulationRunning,
144
162
  useDirectory,
145
163
  useFileContent