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.
- package/bin/lib/serve.ts +16 -2
- package/bin/lib/start.ts +12 -10
- package/bin/veslx.ts +1 -1
- package/dist/client/components/front-matter.js +2 -6
- package/dist/client/components/front-matter.js.map +1 -1
- package/dist/client/components/gallery/components/figure-caption.js +1 -1
- package/dist/client/components/gallery/components/figure-caption.js.map +1 -1
- package/dist/client/components/gallery/components/figure-header.js +1 -1
- package/dist/client/components/gallery/components/figure-header.js.map +1 -1
- package/dist/client/components/gallery/components/lightbox.js +1 -1
- package/dist/client/components/gallery/components/lightbox.js.map +1 -1
- package/dist/client/components/gallery/index.js +38 -8
- package/dist/client/components/gallery/index.js.map +1 -1
- package/dist/client/components/header.js +45 -21
- package/dist/client/components/header.js.map +1 -1
- package/dist/client/components/mdx-components.js +8 -0
- package/dist/client/components/mdx-components.js.map +1 -1
- package/dist/client/components/post-list.js +13 -11
- package/dist/client/components/post-list.js.map +1 -1
- package/dist/client/components/slides/figure-slide.js +14 -0
- package/dist/client/components/slides/figure-slide.js.map +1 -0
- package/dist/client/components/slides/hero-slide.js +21 -0
- package/dist/client/components/slides/hero-slide.js.map +1 -0
- package/dist/client/components/slides/slide-outline.js +28 -0
- package/dist/client/components/slides/slide-outline.js.map +1 -0
- package/dist/client/components/slides/text-slide.js +18 -0
- package/dist/client/components/slides/text-slide.js.map +1 -0
- package/dist/client/components/slides-renderer.js.map +1 -1
- package/dist/client/hooks/use-mdx-content.js +19 -6
- package/dist/client/hooks/use-mdx-content.js.map +1 -1
- package/dist/client/lib/content-classification.js +11 -2
- package/dist/client/lib/content-classification.js.map +1 -1
- package/dist/client/lib/frontmatter-context.js +17 -0
- package/dist/client/lib/frontmatter-context.js.map +1 -0
- package/dist/client/pages/content-router.js +4 -1
- package/dist/client/pages/content-router.js.map +1 -1
- package/dist/client/pages/home.js +2 -6
- package/dist/client/pages/home.js.map +1 -1
- package/dist/client/pages/post.js +2 -9
- package/dist/client/pages/post.js.map +1 -1
- package/dist/client/pages/slides.js +9 -12
- package/dist/client/pages/slides.js.map +1 -1
- package/dist/client/plugin/src/client.js +20 -2
- package/dist/client/plugin/src/client.js.map +1 -1
- package/index.html +13 -0
- package/package.json +1 -1
- package/plugin/src/client.tsx +28 -2
- package/plugin/src/plugin.ts +49 -4
- package/src/components/content-tabs.tsx +4 -4
- package/src/components/front-matter.tsx +3 -8
- package/src/components/gallery/components/figure-caption.tsx +1 -1
- package/src/components/gallery/components/figure-header.tsx +1 -1
- package/src/components/gallery/components/lightbox.tsx +1 -1
- package/src/components/gallery/index.tsx +68 -29
- package/src/components/header.tsx +44 -25
- package/src/components/mdx-components.tsx +12 -0
- package/src/components/post-list.tsx +14 -10
- package/src/components/slides/figure-slide.tsx +16 -0
- package/src/components/slides/hero-slide.tsx +34 -0
- package/src/components/slides/slide-outline.tsx +38 -0
- package/src/components/slides/text-slide.tsx +35 -0
- package/src/components/slides-renderer.tsx +1 -1
- package/src/hooks/use-mdx-content.ts +27 -6
- package/src/index.css +1 -2
- package/src/lib/content-classification.ts +13 -2
- package/src/lib/frontmatter-context.tsx +29 -0
- package/src/pages/content-router.tsx +7 -1
- package/src/pages/home.tsx +3 -3
- package/src/pages/post.tsx +6 -24
- package/src/pages/slides.tsx +14 -16
- package/vite.config.ts +4 -3
- package/dist/client/components/content-tabs.js +0 -50
- package/dist/client/components/content-tabs.js.map +0 -1
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
export function SlideOutline({
|
|
4
|
+
children,
|
|
5
|
+
className,
|
|
6
|
+
size="md"
|
|
7
|
+
}: {
|
|
8
|
+
children?: React.ReactNode;
|
|
9
|
+
className?: string;
|
|
10
|
+
size?: "sm" | "md" | "lg" | "xl" | "2xl" | "3xl" | "full";
|
|
11
|
+
}) {
|
|
12
|
+
|
|
13
|
+
const wClasses: Record<string, string> = {
|
|
14
|
+
sm: "max-w-lg",
|
|
15
|
+
md: "max-w-2xl",
|
|
16
|
+
lg: "max-w-5xl",
|
|
17
|
+
xl: "max-w-7xl",
|
|
18
|
+
full: "max-w-full",
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const wClassName = `${wClasses[size]} ${className ?? ""}`;
|
|
22
|
+
|
|
23
|
+
const hClasses: Record<string, string> = {
|
|
24
|
+
sm: "min-h-[300px]",
|
|
25
|
+
md: "min-h-[400px]",
|
|
26
|
+
lg: "min-h-[500px]",
|
|
27
|
+
xl: "min-h-[600px]",
|
|
28
|
+
full: "min-h-[600px]",
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const hClassName = `${hClasses[size]} ${className ?? ""}`;
|
|
32
|
+
|
|
33
|
+
return (
|
|
34
|
+
<div className={`border rounded relative left-1/2 -translate-x-1/2 w-screen ${wClassName} ${hClassName} ${className}`}>
|
|
35
|
+
{children}
|
|
36
|
+
</div>
|
|
37
|
+
);
|
|
38
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
|
|
2
|
+
export function TextSlide({
|
|
3
|
+
title,
|
|
4
|
+
subtitle,
|
|
5
|
+
children,
|
|
6
|
+
}: {
|
|
7
|
+
title?: string;
|
|
8
|
+
subtitle?: string;
|
|
9
|
+
children?: React.ReactNode;
|
|
10
|
+
}) {
|
|
11
|
+
return (
|
|
12
|
+
<div>
|
|
13
|
+
{(title || subtitle) && (
|
|
14
|
+
<header className="flex flex-col gap-2">
|
|
15
|
+
{title && (
|
|
16
|
+
<h2 className="text-[clamp(1.75rem,4vw,3rem)] font-semibold leading-tight tracking-[-0.02em] text-foreground">
|
|
17
|
+
{title}
|
|
18
|
+
</h2>
|
|
19
|
+
)}
|
|
20
|
+
{subtitle && (
|
|
21
|
+
<p className="text-[clamp(0.95rem,1.5vw,1.25rem)] text-muted-foreground">
|
|
22
|
+
{subtitle}
|
|
23
|
+
</p>
|
|
24
|
+
)}
|
|
25
|
+
</header>
|
|
26
|
+
)}
|
|
27
|
+
|
|
28
|
+
{children && (
|
|
29
|
+
<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">
|
|
30
|
+
{children}
|
|
31
|
+
</div>
|
|
32
|
+
)}
|
|
33
|
+
</div>
|
|
34
|
+
);
|
|
35
|
+
}
|
|
@@ -15,7 +15,7 @@ export const slidesMdxComponents = {
|
|
|
15
15
|
*/
|
|
16
16
|
export function SlideContent({ children }: { children: ReactNode }) {
|
|
17
17
|
return (
|
|
18
|
-
<div className="slide-content prose dark:prose-invert prose-headings:tracking-tight prose-p:leading-relaxed
|
|
18
|
+
<div className="slide-content prose dark:prose-invert prose-headings:tracking-tight prose-p:leading-relaxed">
|
|
19
19
|
{children}
|
|
20
20
|
</div>
|
|
21
21
|
)
|
|
@@ -123,9 +123,25 @@ export function useMDXContent(path: string) {
|
|
|
123
123
|
function findSlidesModule(modules: ModuleMap, path: string): ModuleLoader | null {
|
|
124
124
|
const keys = Object.keys(modules)
|
|
125
125
|
|
|
126
|
+
// Normalize path - remove leading slash if present
|
|
127
|
+
const normalizedPath = path.replace(/^\//, '')
|
|
128
|
+
|
|
126
129
|
// If path already ends with .mdx, match exactly
|
|
127
|
-
if (
|
|
128
|
-
|
|
130
|
+
if (normalizedPath.endsWith('.mdx')) {
|
|
131
|
+
// Try multiple matching strategies for different Vite glob formats
|
|
132
|
+
const matchingKey = keys.find(key => {
|
|
133
|
+
// Strategy 1: Key ends with /path (e.g., @content/docs/foo.slides.mdx matches docs/foo.slides.mdx)
|
|
134
|
+
if (key.endsWith(`/${normalizedPath}`)) return true
|
|
135
|
+
// Strategy 2: Key equals @content/path (alias form)
|
|
136
|
+
if (key === `@content/${normalizedPath}`) return true
|
|
137
|
+
// Strategy 3: Key equals /@content/path (with leading slash)
|
|
138
|
+
if (key === `/@content/${normalizedPath}`) return true
|
|
139
|
+
// Strategy 4: Key equals path directly
|
|
140
|
+
if (key === normalizedPath) return true
|
|
141
|
+
// Strategy 5: Key equals /path (with leading slash)
|
|
142
|
+
if (key === `/${normalizedPath}`) return true
|
|
143
|
+
return false
|
|
144
|
+
})
|
|
129
145
|
return matchingKey ? modules[matchingKey] : null
|
|
130
146
|
}
|
|
131
147
|
|
|
@@ -133,12 +149,17 @@ function findSlidesModule(modules: ModuleMap, path: string): ModuleLoader | null
|
|
|
133
149
|
// 1. folder/SLIDES.mdx (current convention)
|
|
134
150
|
// 2. folder/index.slides.mdx (alternative)
|
|
135
151
|
const candidates = [
|
|
136
|
-
|
|
137
|
-
|
|
152
|
+
`${normalizedPath}/SLIDES.mdx`,
|
|
153
|
+
`${normalizedPath}/index.slides.mdx`,
|
|
138
154
|
]
|
|
139
155
|
|
|
140
|
-
for (const
|
|
141
|
-
const matchingKey = keys.find(key =>
|
|
156
|
+
for (const candidate of candidates) {
|
|
157
|
+
const matchingKey = keys.find(key => {
|
|
158
|
+
if (key.endsWith(`/${candidate}`)) return true
|
|
159
|
+
if (key === `@content/${candidate}`) return true
|
|
160
|
+
if (key === candidate) return true
|
|
161
|
+
return false
|
|
162
|
+
})
|
|
142
163
|
if (matchingKey) {
|
|
143
164
|
return modules[matchingKey]
|
|
144
165
|
}
|
package/src/index.css
CHANGED
|
@@ -325,8 +325,7 @@
|
|
|
325
325
|
.slides-container > .running-bar,
|
|
326
326
|
.slides-container hr,
|
|
327
327
|
.slides-container > title,
|
|
328
|
-
header
|
|
329
|
-
[class*="print:hidden"] {
|
|
328
|
+
body > header {
|
|
330
329
|
display: none !important;
|
|
331
330
|
height: 0 !important;
|
|
332
331
|
width: 0 !important;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ContentView } from "../../plugin/src/types";
|
|
2
2
|
import type { DirectoryEntry, FileEntry } from "../../plugin/src/lib";
|
|
3
|
-
import { findReadme, findSlides, findMdxFiles } from "../../plugin/src/client";
|
|
3
|
+
import { findReadme, findSlides, findMdxFiles, findStandaloneSlides } from "../../plugin/src/client";
|
|
4
4
|
|
|
5
5
|
export type PostEntry = {
|
|
6
6
|
type: 'folder' | 'file';
|
|
@@ -39,6 +39,7 @@ export function getViewCounts(posts: PostEntry[]): { posts: number; docs: number
|
|
|
39
39
|
export function directoryToPostEntries(directory: DirectoryEntry): PostEntry[] {
|
|
40
40
|
const folders = directory.children.filter((c): c is DirectoryEntry => c.type === "directory");
|
|
41
41
|
const standaloneFiles = findMdxFiles(directory);
|
|
42
|
+
const standaloneSlidesFiles = findStandaloneSlides(directory);
|
|
42
43
|
|
|
43
44
|
const folderPosts: PostEntry[] = folders
|
|
44
45
|
.map((folder) => ({
|
|
@@ -60,7 +61,17 @@ export function directoryToPostEntries(directory: DirectoryEntry): PostEntry[] {
|
|
|
60
61
|
file,
|
|
61
62
|
}));
|
|
62
63
|
|
|
63
|
-
|
|
64
|
+
// Standalone slides files (e.g., getting-started.slides.mdx)
|
|
65
|
+
const slidesPosts: PostEntry[] = standaloneSlidesFiles.map((file) => ({
|
|
66
|
+
type: 'file' as const,
|
|
67
|
+
name: file.name.replace(/\.slides\.mdx?$/, ''),
|
|
68
|
+
path: file.path,
|
|
69
|
+
readme: null,
|
|
70
|
+
slides: file,
|
|
71
|
+
file: null,
|
|
72
|
+
}));
|
|
73
|
+
|
|
74
|
+
return [...folderPosts, ...filePosts, ...slidesPosts];
|
|
64
75
|
}
|
|
65
76
|
|
|
66
77
|
export function filterVisiblePosts(posts: PostEntry[]): PostEntry[] {
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { createContext, useContext, ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
export interface Frontmatter {
|
|
4
|
+
title?: string;
|
|
5
|
+
description?: string;
|
|
6
|
+
date?: string;
|
|
7
|
+
visibility?: string;
|
|
8
|
+
draft?: boolean;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const FrontmatterContext = createContext<Frontmatter | undefined>(undefined);
|
|
12
|
+
|
|
13
|
+
export function FrontmatterProvider({
|
|
14
|
+
frontmatter,
|
|
15
|
+
children
|
|
16
|
+
}: {
|
|
17
|
+
frontmatter: Frontmatter | undefined;
|
|
18
|
+
children: ReactNode
|
|
19
|
+
}) {
|
|
20
|
+
return (
|
|
21
|
+
<FrontmatterContext.Provider value={frontmatter}>
|
|
22
|
+
{children}
|
|
23
|
+
</FrontmatterContext.Provider>
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function useFrontmatter() {
|
|
28
|
+
return useContext(FrontmatterContext);
|
|
29
|
+
}
|
|
@@ -26,7 +26,13 @@ export function ContentRouter() {
|
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
// Check if this is a slides file
|
|
29
|
-
|
|
29
|
+
const filename = path.split('/').pop()?.toLowerCase() || ''
|
|
30
|
+
const isSlides =
|
|
31
|
+
path.endsWith('.slides.mdx') ||
|
|
32
|
+
path.endsWith('.slides.md') ||
|
|
33
|
+
filename === 'slides.mdx' ||
|
|
34
|
+
filename === 'slides.md'
|
|
35
|
+
if (isSlides) {
|
|
30
36
|
return <SlidesPage />
|
|
31
37
|
}
|
|
32
38
|
|
package/src/pages/home.tsx
CHANGED
|
@@ -68,12 +68,12 @@ export function Home({ view }: HomeProps) {
|
|
|
68
68
|
</div>
|
|
69
69
|
)}
|
|
70
70
|
|
|
71
|
-
<div className="">
|
|
72
|
-
{isRoot && directory && (
|
|
71
|
+
<div className="flex flex-col gap-2">
|
|
72
|
+
{/* {isRoot && directory && (
|
|
73
73
|
<div className="animate-fade-in">
|
|
74
74
|
<ContentTabs value={activeView} counts={counts} />
|
|
75
75
|
</div>
|
|
76
|
-
)}
|
|
76
|
+
)} */}
|
|
77
77
|
{directory && (
|
|
78
78
|
<div className="animate-fade-in">
|
|
79
79
|
<PostList directory={directory} view={isRoot ? activeView : 'all'} />
|
package/src/pages/post.tsx
CHANGED
|
@@ -6,7 +6,7 @@ import { RunningBar } from "@/components/running-bar";
|
|
|
6
6
|
import { Header } from "@/components/header";
|
|
7
7
|
import { useMDXContent } from "@/hooks/use-mdx-content";
|
|
8
8
|
import { mdxComponents } from "@/components/mdx-components";
|
|
9
|
-
import {
|
|
9
|
+
import { FrontmatterProvider } from "@/lib/frontmatter-context";
|
|
10
10
|
|
|
11
11
|
export function Post() {
|
|
12
12
|
const { "*": rawPath = "." } = useParams();
|
|
@@ -55,29 +55,11 @@ export function Post() {
|
|
|
55
55
|
)}
|
|
56
56
|
|
|
57
57
|
{Content && (
|
|
58
|
-
<
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
{frontmatter.title}
|
|
64
|
-
</h1>
|
|
65
|
-
{frontmatter?.date && (
|
|
66
|
-
<div className="flex flex-wrap items-center gap-3 text-muted-foreground">
|
|
67
|
-
<time className="font-mono text-xs bg-muted px-2 py-0.5 rounded">
|
|
68
|
-
{formatDate(new Date(frontmatter.date as string))}
|
|
69
|
-
</time>
|
|
70
|
-
</div>
|
|
71
|
-
)}
|
|
72
|
-
{frontmatter?.description && (
|
|
73
|
-
<div className="flex flex-wrap text-sm items-center gap-3 text-muted-foreground">
|
|
74
|
-
{frontmatter.description}
|
|
75
|
-
</div>
|
|
76
|
-
)}
|
|
77
|
-
</header>
|
|
78
|
-
)}
|
|
79
|
-
<Content components={mdxComponents} />
|
|
80
|
-
</article>
|
|
58
|
+
<FrontmatterProvider frontmatter={frontmatter}>
|
|
59
|
+
<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">
|
|
60
|
+
<Content components={mdxComponents} />
|
|
61
|
+
</article>
|
|
62
|
+
</FrontmatterProvider>
|
|
81
63
|
)}
|
|
82
64
|
</main>
|
|
83
65
|
</div>
|
package/src/pages/slides.tsx
CHANGED
|
@@ -6,6 +6,7 @@ import { RunningBar } from "@/components/running-bar";
|
|
|
6
6
|
import { Header } from "@/components/header";
|
|
7
7
|
import { useMDXSlides } from "@/hooks/use-mdx-content";
|
|
8
8
|
import { slidesMdxComponents } from "@/components/slides-renderer";
|
|
9
|
+
import { FrontmatterProvider } from "@/lib/frontmatter-context";
|
|
9
10
|
|
|
10
11
|
|
|
11
12
|
export function SlidesPage() {
|
|
@@ -18,8 +19,7 @@ export function SlidesPage() {
|
|
|
18
19
|
// Load the compiled MDX module (now includes slideCount export)
|
|
19
20
|
const { Content, frontmatter, slideCount, loading, error } = useMDXSlides(mdxPath);
|
|
20
21
|
|
|
21
|
-
|
|
22
|
-
const totalSlides = (slideCount || 0) + 1;
|
|
22
|
+
const totalSlides = slideCount || 0;
|
|
23
23
|
|
|
24
24
|
const [currentSlide, setCurrentSlide] = useState(0);
|
|
25
25
|
const titleSlideRef = useRef<HTMLDivElement>(null);
|
|
@@ -29,7 +29,7 @@ export function SlidesPage() {
|
|
|
29
29
|
useEffect(() => {
|
|
30
30
|
const slideParam = parseInt(searchParams.get("slide") || "0", 10);
|
|
31
31
|
if (slideParam > 0 && contentRef.current) {
|
|
32
|
-
const slideEl = contentRef.current.querySelector(`[data-slide-index="${slideParam
|
|
32
|
+
const slideEl = contentRef.current.querySelector(`[data-slide-index="${slideParam}"]`);
|
|
33
33
|
if (slideEl) {
|
|
34
34
|
slideEl.scrollIntoView({ behavior: "auto" });
|
|
35
35
|
}
|
|
@@ -44,7 +44,7 @@ export function SlidesPage() {
|
|
|
44
44
|
if (entry.isIntersecting) {
|
|
45
45
|
const index = entry.target.getAttribute("data-slide-index");
|
|
46
46
|
if (index !== null) {
|
|
47
|
-
const slideNum = index === "title" ? 0 : parseInt(index, 10)
|
|
47
|
+
const slideNum = index === "title" ? 0 : parseInt(index, 10);
|
|
48
48
|
setCurrentSlide(slideNum);
|
|
49
49
|
setSearchParams(slideNum > 0 ? { slide: String(slideNum) } : {}, { replace: true });
|
|
50
50
|
}
|
|
@@ -71,20 +71,16 @@ export function SlidesPage() {
|
|
|
71
71
|
// Keyboard/scroll navigation helpers
|
|
72
72
|
const goToPrevious = useCallback(() => {
|
|
73
73
|
const prev = Math.max(0, currentSlide - 1);
|
|
74
|
-
if (
|
|
75
|
-
|
|
76
|
-
} else if (contentRef.current) {
|
|
77
|
-
const slideEl = contentRef.current.querySelector(`[data-slide-index="${prev - 1}"]`);
|
|
74
|
+
if (contentRef.current) {
|
|
75
|
+
const slideEl = contentRef.current.querySelector(`[data-slide-index="${prev}"]`);
|
|
78
76
|
slideEl?.scrollIntoView({ behavior: "smooth" });
|
|
79
77
|
}
|
|
80
78
|
}, [currentSlide]);
|
|
81
79
|
|
|
82
80
|
const goToNext = useCallback(() => {
|
|
83
81
|
const next = Math.min(totalSlides - 1, currentSlide + 1);
|
|
84
|
-
if (
|
|
85
|
-
|
|
86
|
-
} else if (contentRef.current) {
|
|
87
|
-
const slideEl = contentRef.current.querySelector(`[data-slide-index="${next - 1}"]`);
|
|
82
|
+
if (contentRef.current) {
|
|
83
|
+
const slideEl = contentRef.current.querySelector(`[data-slide-index="${next}"]`);
|
|
88
84
|
slideEl?.scrollIntoView({ behavior: "smooth" });
|
|
89
85
|
}
|
|
90
86
|
}, [currentSlide, totalSlides]);
|
|
@@ -137,11 +133,13 @@ export function SlidesPage() {
|
|
|
137
133
|
onNext: goToNext,
|
|
138
134
|
}}
|
|
139
135
|
/>
|
|
140
|
-
<
|
|
141
|
-
<div
|
|
142
|
-
<
|
|
136
|
+
<FrontmatterProvider frontmatter={frontmatter}>
|
|
137
|
+
<div {...{[FULLSCREEN_DATA_ATTR]: "true"}}>
|
|
138
|
+
<div ref={contentRef}>
|
|
139
|
+
<Content components={slidesMdxComponents} />
|
|
140
|
+
</div>
|
|
143
141
|
</div>
|
|
144
|
-
</
|
|
142
|
+
</FrontmatterProvider>
|
|
145
143
|
</main>
|
|
146
144
|
)
|
|
147
145
|
}
|
package/vite.config.ts
CHANGED
|
@@ -80,10 +80,11 @@ export default defineConfig(({ command }) => {
|
|
|
80
80
|
reactResolverPlugin(),
|
|
81
81
|
tailwindcss(),
|
|
82
82
|
// MDX for slides - splits at --- into <Slide> components
|
|
83
|
+
// Matches: SLIDES.mdx, slides.mdx, *.slides.mdx
|
|
83
84
|
{
|
|
84
85
|
enforce: 'pre',
|
|
85
86
|
...mdx({
|
|
86
|
-
include: /SLIDES\.mdx
|
|
87
|
+
include: /SLIDES\.mdx$|slides\.mdx$/i,
|
|
87
88
|
remarkPlugins: [
|
|
88
89
|
...commonRemarkPlugins,
|
|
89
90
|
remarkSlides, // Transform --- into <Slide> wrappers
|
|
@@ -92,11 +93,11 @@ export default defineConfig(({ command }) => {
|
|
|
92
93
|
providerImportSource: '@mdx-js/react',
|
|
93
94
|
}),
|
|
94
95
|
},
|
|
95
|
-
// MDX for regular posts
|
|
96
|
+
// MDX for regular posts (excludes all slides files)
|
|
96
97
|
{
|
|
97
98
|
enforce: 'pre',
|
|
98
99
|
...mdx({
|
|
99
|
-
exclude: /SLIDES\.mdx
|
|
100
|
+
exclude: /SLIDES\.mdx$|slides\.mdx$/i,
|
|
100
101
|
remarkPlugins: commonRemarkPlugins,
|
|
101
102
|
rehypePlugins: [rehypeKatex],
|
|
102
103
|
providerImportSource: '@mdx-js/react',
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
import { jsx } from "react/jsx-runtime";
|
|
2
|
-
import { Link } from "react-router-dom";
|
|
3
|
-
import { cn } from "../lib/utils.js";
|
|
4
|
-
const views = [
|
|
5
|
-
{ key: "posts", label: "posts", path: "/posts" },
|
|
6
|
-
{ key: "docs", label: "docs", path: "/docs" },
|
|
7
|
-
{ key: "all", label: "all", path: "/all" }
|
|
8
|
-
];
|
|
9
|
-
function ContentTabs({ value, counts }) {
|
|
10
|
-
const hasOnlyPosts = counts.posts > 0 && counts.docs === 0;
|
|
11
|
-
const hasOnlyDocs = counts.docs > 0 && counts.posts === 0;
|
|
12
|
-
if (hasOnlyPosts || hasOnlyDocs) {
|
|
13
|
-
return null;
|
|
14
|
-
}
|
|
15
|
-
const isDisabled = (key) => {
|
|
16
|
-
if (key === "posts") return counts.posts === 0;
|
|
17
|
-
if (key === "docs") return counts.docs === 0;
|
|
18
|
-
return false;
|
|
19
|
-
};
|
|
20
|
-
return /* @__PURE__ */ jsx("nav", { className: "flex justify-end items-center gap-3 font-mono font-medium text-xs text-muted-foreground", children: views.map((view) => {
|
|
21
|
-
const disabled = isDisabled(view.key);
|
|
22
|
-
if (disabled) {
|
|
23
|
-
return /* @__PURE__ */ jsx(
|
|
24
|
-
"span",
|
|
25
|
-
{
|
|
26
|
-
className: "opacity-30 cursor-not-allowed",
|
|
27
|
-
children: view.label
|
|
28
|
-
},
|
|
29
|
-
view.key
|
|
30
|
-
);
|
|
31
|
-
}
|
|
32
|
-
return /* @__PURE__ */ jsx(
|
|
33
|
-
Link,
|
|
34
|
-
{
|
|
35
|
-
to: view.path,
|
|
36
|
-
className: cn(
|
|
37
|
-
"transition-colors duration-150",
|
|
38
|
-
"hover:text-foreground hover:underline hover:underline-offset-4 hover:decoration-primary/60",
|
|
39
|
-
value === view.key ? "text-foreground underline-offset-4 decoration-primary/60" : ""
|
|
40
|
-
),
|
|
41
|
-
children: view.label
|
|
42
|
-
},
|
|
43
|
-
view.key
|
|
44
|
-
);
|
|
45
|
-
}) });
|
|
46
|
-
}
|
|
47
|
-
export {
|
|
48
|
-
ContentTabs
|
|
49
|
-
};
|
|
50
|
-
//# sourceMappingURL=content-tabs.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"content-tabs.js","sources":["../../../src/components/content-tabs.tsx"],"sourcesContent":["import { Link } from \"react-router-dom\";\nimport { cn } from \"@/lib/utils\";\nimport type { ContentView } from \"@/lib/content-classification\";\n\ninterface ContentTabsProps {\n value: ContentView;\n counts: { posts: number; docs: number; all: number };\n}\n\nconst views: { key: ContentView; label: string; path: string }[] = [\n { key: \"posts\", label: \"posts\", path: \"/posts\" },\n { key: \"docs\", label: \"docs\", path: \"/docs\" },\n { key: \"all\", label: \"all\", path: \"/all\" },\n];\n\nexport function ContentTabs({ value, counts }: ContentTabsProps) {\n const hasOnlyPosts = counts.posts > 0 && counts.docs === 0;\n const hasOnlyDocs = counts.docs > 0 && counts.posts === 0;\n\n if (hasOnlyPosts || hasOnlyDocs) {\n return null;\n }\n\n const isDisabled = (key: ContentView) => {\n if (key === \"posts\") return counts.posts === 0;\n if (key === \"docs\") return counts.docs === 0;\n return false;\n };\n\n return (\n <nav className=\"flex justify-end items-center gap-3 font-mono font-medium text-xs text-muted-foreground\">\n {views.map((view) => {\n const disabled = isDisabled(view.key);\n\n if (disabled) {\n return (\n <span\n key={view.key}\n className=\"opacity-30 cursor-not-allowed\"\n >\n {view.label}\n </span>\n );\n }\n\n return (\n <Link\n key={view.key}\n to={view.path}\n className={cn(\n \"transition-colors duration-150\",\n \"hover:text-foreground hover:underline hover:underline-offset-4 hover:decoration-primary/60\",\n value === view.key\n ? \"text-foreground underline-offset-4 decoration-primary/60\"\n : \"\"\n )}\n >\n {view.label}\n </Link>\n );\n })}\n </nav>\n );\n}\n"],"names":[],"mappings":";;;AASA,MAAM,QAA6D;AAAA,EACjE,EAAE,KAAK,SAAS,OAAO,SAAS,MAAM,SAAA;AAAA,EACtC,EAAE,KAAK,QAAQ,OAAO,QAAQ,MAAM,QAAA;AAAA,EACpC,EAAE,KAAK,OAAO,OAAO,OAAO,MAAM,OAAA;AACpC;AAEO,SAAS,YAAY,EAAE,OAAO,UAA4B;AAC/D,QAAM,eAAe,OAAO,QAAQ,KAAK,OAAO,SAAS;AACzD,QAAM,cAAc,OAAO,OAAO,KAAK,OAAO,UAAU;AAExD,MAAI,gBAAgB,aAAa;AAC/B,WAAO;AAAA,EACT;AAEA,QAAM,aAAa,CAAC,QAAqB;AACvC,QAAI,QAAQ,QAAS,QAAO,OAAO,UAAU;AAC7C,QAAI,QAAQ,OAAQ,QAAO,OAAO,SAAS;AAC3C,WAAO;AAAA,EACT;AAEA,6BACG,OAAA,EAAI,WAAU,2FACZ,UAAA,MAAM,IAAI,CAAC,SAAS;AACnB,UAAM,WAAW,WAAW,KAAK,GAAG;AAEpC,QAAI,UAAU;AACZ,aACE;AAAA,QAAC;AAAA,QAAA;AAAA,UAEC,WAAU;AAAA,UAET,UAAA,KAAK;AAAA,QAAA;AAAA,QAHD,KAAK;AAAA,MAAA;AAAA,IAMhB;AAEA,WACE;AAAA,MAAC;AAAA,MAAA;AAAA,QAEC,IAAI,KAAK;AAAA,QACT,WAAW;AAAA,UACT;AAAA,UACA;AAAA,UACA,UAAU,KAAK,MACX,6DACA;AAAA,QAAA;AAAA,QAGL,UAAA,KAAK;AAAA,MAAA;AAAA,MAVD,KAAK;AAAA,IAAA;AAAA,EAahB,CAAC,EAAA,CACH;AAEJ;"}
|