slidev-workspace 0.1.6 → 0.1.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +1 -2
- package/dist/index.d.ts +7 -38
- package/dist/index.js +2 -157
- package/dist/plugin-slides.d.ts +6 -0
- package/dist/plugin-slides.js +153 -0
- package/package.json +11 -15
- package/src/preview/assets/main.css +1 -1
- package/src/preview/components/SlideCard.vue +41 -20
- package/src/preview/components/SlideDeck.vue +11 -20
- package/src/preview/components/ui/button/Button.vue +2 -2
- package/src/preview/components/ui/button/index.ts +1 -1
- package/src/preview/components/ui/card/Card.vue +4 -4
- package/src/preview/components/ui/card/CardAction.vue +10 -5
- package/src/preview/components/ui/card/CardContent.vue +5 -8
- package/src/preview/components/ui/card/CardDescription.vue +4 -4
- package/src/preview/components/ui/card/CardFooter.vue +4 -4
- package/src/preview/components/ui/card/CardHeader.vue +8 -5
- package/src/preview/components/ui/card/CardTitle.vue +4 -4
- package/src/preview/components/ui/card/index.ts +7 -7
- package/src/preview/components/ui/input/Input.vue +20 -18
- package/src/preview/components/ui/input/index.ts +1 -1
- package/src/preview/composables/useSlides.ts +5 -17
- package/src/preview/index.html +11 -11
- package/src/preview/lib/utils.ts +3 -3
- package/src/preview/main.ts +4 -4
- package/vite.config.ts +1 -1
- package/src/preview/components/SlideDetail.vue +0 -160
- package/src/preview/dist/assets/index-Cbywrv7-.css +0 -2
- package/src/preview/dist/assets/index-LGnZwLzS.js +0 -24
- package/src/preview/dist/index.html +0 -13
- package/src/preview/utils/getSlides.ts +0 -65
package/dist/cli.js
CHANGED
|
@@ -7,7 +7,6 @@ import tailwindcss from "@tailwindcss/vite";
|
|
|
7
7
|
import { existsSync, readFileSync, readdirSync, watch } from "fs";
|
|
8
8
|
import { basename, join as join$1, resolve as resolve$1 } from "path";
|
|
9
9
|
import { parse } from "yaml";
|
|
10
|
-
import "vue";
|
|
11
10
|
|
|
12
11
|
//#region src/scripts/config.ts
|
|
13
12
|
const DEFAULT_CONFIG = {
|
|
@@ -112,7 +111,7 @@ if (import.meta.url === `file://${process.argv[1]}`) {
|
|
|
112
111
|
}
|
|
113
112
|
|
|
114
113
|
//#endregion
|
|
115
|
-
//#region src/
|
|
114
|
+
//#region src/vite/plugin-slides.ts
|
|
116
115
|
function slidesPlugin() {
|
|
117
116
|
return {
|
|
118
117
|
name: "vite-plugin-slides",
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import * as vue0 from "vue";
|
|
2
|
-
import { Plugin } from "vite";
|
|
3
2
|
|
|
4
3
|
//#region src/types/slide.d.ts
|
|
5
4
|
interface SlideFrontmatter {
|
|
@@ -20,7 +19,6 @@ interface SlideFrontmatter {
|
|
|
20
19
|
};
|
|
21
20
|
author?: string;
|
|
22
21
|
date?: string;
|
|
23
|
-
[key: string]: any;
|
|
24
22
|
}
|
|
25
23
|
interface SlideInfo {
|
|
26
24
|
id: string;
|
|
@@ -31,7 +29,6 @@ interface SlideInfo {
|
|
|
31
29
|
content: string;
|
|
32
30
|
}
|
|
33
31
|
interface SlideData {
|
|
34
|
-
id: string;
|
|
35
32
|
title: string;
|
|
36
33
|
url: string;
|
|
37
34
|
description: string;
|
|
@@ -41,20 +38,14 @@ interface SlideData {
|
|
|
41
38
|
theme?: string;
|
|
42
39
|
transition?: string;
|
|
43
40
|
class?: string;
|
|
44
|
-
sourceDir: string;
|
|
45
|
-
path: string;
|
|
46
|
-
fullPath: string;
|
|
47
|
-
frontmatter: SlideFrontmatter;
|
|
48
|
-
content: string;
|
|
49
41
|
}
|
|
50
42
|
//#endregion
|
|
51
|
-
//#region src/
|
|
52
|
-
declare function
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
declare function slidesPlugin(): Plugin;
|
|
43
|
+
//#region src/preview/composables/useSlides.d.ts
|
|
44
|
+
declare function useSlides(): {
|
|
45
|
+
slides: vue0.ComputedRef<SlideData[]>;
|
|
46
|
+
slidesCount: vue0.ComputedRef<number>;
|
|
47
|
+
loadSlidesData: () => Promise<void>;
|
|
48
|
+
};
|
|
58
49
|
//#endregion
|
|
59
50
|
//#region src/types/config.d.ts
|
|
60
51
|
interface SlidevWorkspaceConfig {
|
|
@@ -64,26 +55,4 @@ interface SlidevWorkspaceConfig {
|
|
|
64
55
|
exclude: string[];
|
|
65
56
|
}
|
|
66
57
|
//#endregion
|
|
67
|
-
|
|
68
|
-
declare function loadConfig(workingDir?: string): SlidevWorkspaceConfig;
|
|
69
|
-
declare function resolveSlidesDirs(config: SlidevWorkspaceConfig, workingDir?: string): string[];
|
|
70
|
-
//#endregion
|
|
71
|
-
//#region src/preview/composables/useSlides.d.ts
|
|
72
|
-
interface SlideData$1 {
|
|
73
|
-
title: string;
|
|
74
|
-
url: string;
|
|
75
|
-
description: string;
|
|
76
|
-
image: string;
|
|
77
|
-
author: string;
|
|
78
|
-
date: string;
|
|
79
|
-
theme?: string;
|
|
80
|
-
transition?: string;
|
|
81
|
-
class?: string;
|
|
82
|
-
}
|
|
83
|
-
declare function useSlides(): {
|
|
84
|
-
slides: vue0.ComputedRef<SlideData$1[]>;
|
|
85
|
-
slidesCount: vue0.ComputedRef<number>;
|
|
86
|
-
loadSlidesData: () => Promise<void>;
|
|
87
|
-
};
|
|
88
|
-
//#endregion
|
|
89
|
-
export { type SlideData, type SlideFrontmatter, type SlideInfo, type SlidevWorkspaceConfig, getAllSlidesFrontmatter, getSlideFrontmatter, getSlideFrontmatterByPath, loadConfig, resolveSlidesDirs, slidesPlugin, useSlides };
|
|
58
|
+
export { type SlideData, type SlideFrontmatter, type SlideInfo, type SlidevWorkspaceConfig, useSlides };
|
package/dist/index.js
CHANGED
|
@@ -1,167 +1,12 @@
|
|
|
1
|
-
import { existsSync, readFileSync, readdirSync, watch } from "fs";
|
|
2
|
-
import { basename, join, resolve } from "path";
|
|
3
|
-
import { parse } from "yaml";
|
|
4
1
|
import { computed, ref } from "vue";
|
|
5
2
|
|
|
6
|
-
//#region src/scripts/config.ts
|
|
7
|
-
const DEFAULT_CONFIG = {
|
|
8
|
-
slidesDir: ["./slides"],
|
|
9
|
-
outputDir: "./dist",
|
|
10
|
-
baseUrl: "/",
|
|
11
|
-
exclude: ["node_modules", ".git"]
|
|
12
|
-
};
|
|
13
|
-
function loadConfig(workingDir) {
|
|
14
|
-
const configPaths = [
|
|
15
|
-
"slidev-workspace.config.js",
|
|
16
|
-
"slidev-workspace.config.ts",
|
|
17
|
-
"slidev-workspace.yml",
|
|
18
|
-
"slidev-workspace.yaml"
|
|
19
|
-
];
|
|
20
|
-
const projectRoot = workingDir || process.env.SLIDEV_WORKSPACE_CWD || process.cwd();
|
|
21
|
-
for (const configPath of configPaths) {
|
|
22
|
-
const fullPath = join(projectRoot, configPath);
|
|
23
|
-
if (existsSync(fullPath)) try {
|
|
24
|
-
if (configPath.endsWith(".yml") || configPath.endsWith(".yaml")) {
|
|
25
|
-
const content = readFileSync(fullPath, "utf8");
|
|
26
|
-
const config = parse(content);
|
|
27
|
-
return {
|
|
28
|
-
...DEFAULT_CONFIG,
|
|
29
|
-
...config
|
|
30
|
-
};
|
|
31
|
-
}
|
|
32
|
-
} catch (error) {
|
|
33
|
-
console.warn(`Failed to load config from ${fullPath}:`, error);
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
return DEFAULT_CONFIG;
|
|
37
|
-
}
|
|
38
|
-
function resolveSlidesDirs(config, workingDir) {
|
|
39
|
-
const projectRoot = workingDir || process.env.SLIDEV_WORKSPACE_CWD || process.cwd();
|
|
40
|
-
const resolvedDirs = (config.slidesDir || []).map((dir) => {
|
|
41
|
-
if (resolve(dir) === dir) return dir;
|
|
42
|
-
else return resolve(projectRoot, dir);
|
|
43
|
-
}).filter((dir) => {
|
|
44
|
-
const exists = existsSync(dir);
|
|
45
|
-
return exists;
|
|
46
|
-
});
|
|
47
|
-
return resolvedDirs;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
//#endregion
|
|
51
|
-
//#region src/scripts/getSlideFrontmatter.ts
|
|
52
|
-
function getSlideFrontmatter(slideId) {
|
|
53
|
-
const allSlides = getAllSlidesFrontmatter();
|
|
54
|
-
return allSlides.find((slide) => slide.id === slideId) || null;
|
|
55
|
-
}
|
|
56
|
-
function getSlideFrontmatterByPath(slideDir, slideName) {
|
|
57
|
-
try {
|
|
58
|
-
const fullPath = join(slideDir, slideName, "slides.md");
|
|
59
|
-
if (!existsSync(fullPath)) {
|
|
60
|
-
console.warn(`File not found: ${fullPath}`);
|
|
61
|
-
return null;
|
|
62
|
-
}
|
|
63
|
-
const content = readFileSync(fullPath, "utf8");
|
|
64
|
-
const frontmatterMatch = content.match(/^---\s*\n([\s\S]*?)\n---\s*\n/);
|
|
65
|
-
if (!frontmatterMatch) {
|
|
66
|
-
console.warn(`Frontmatter not found in ${fullPath}`);
|
|
67
|
-
return null;
|
|
68
|
-
}
|
|
69
|
-
const frontmatterYaml = frontmatterMatch[1];
|
|
70
|
-
const frontmatter = parse(frontmatterYaml);
|
|
71
|
-
const sourceBasename = basename(slideDir);
|
|
72
|
-
const slideId = `${sourceBasename}/${slideName}`;
|
|
73
|
-
return {
|
|
74
|
-
id: slideId,
|
|
75
|
-
path: slideName,
|
|
76
|
-
fullPath,
|
|
77
|
-
sourceDir: slideDir,
|
|
78
|
-
frontmatter,
|
|
79
|
-
content: content.replace(frontmatterMatch[0], "")
|
|
80
|
-
};
|
|
81
|
-
} catch (error) {
|
|
82
|
-
console.error(`Error parsing frontmatter for ${slideName} in ${slideDir}:`, error);
|
|
83
|
-
return null;
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
function getAllSlidesFrontmatter() {
|
|
87
|
-
const config = loadConfig();
|
|
88
|
-
const slidesDirs = resolveSlidesDirs(config);
|
|
89
|
-
const slides = [];
|
|
90
|
-
for (const slidesDir of slidesDirs) {
|
|
91
|
-
if (!existsSync(slidesDir)) {
|
|
92
|
-
console.warn(`Slides directory not found: ${slidesDir}`);
|
|
93
|
-
continue;
|
|
94
|
-
}
|
|
95
|
-
try {
|
|
96
|
-
const slideDirs = readdirSync(slidesDir, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).filter((dirent) => !(config.exclude || []).includes(dirent.name)).map((dirent) => dirent.name);
|
|
97
|
-
for (const slideDir of slideDirs) {
|
|
98
|
-
const slideInfo = getSlideFrontmatterByPath(slidesDir, slideDir);
|
|
99
|
-
if (slideInfo) slides.push(slideInfo);
|
|
100
|
-
}
|
|
101
|
-
} catch (error) {
|
|
102
|
-
console.error(`Error reading slides directory ${slidesDir}:`, error);
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
return slides;
|
|
106
|
-
}
|
|
107
|
-
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
108
|
-
const slides = getAllSlidesFrontmatter();
|
|
109
|
-
console.log(JSON.stringify(slides, null, 2));
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
//#endregion
|
|
113
|
-
//#region src/scripts/vite-plugin-slides.ts
|
|
114
|
-
function slidesPlugin() {
|
|
115
|
-
return {
|
|
116
|
-
name: "vite-plugin-slides",
|
|
117
|
-
configureServer(server) {
|
|
118
|
-
const watchers = [];
|
|
119
|
-
const config = loadConfig();
|
|
120
|
-
const slidesDirs = resolveSlidesDirs(config);
|
|
121
|
-
slidesDirs.forEach((slidesDir) => {
|
|
122
|
-
const watcher = watch(slidesDir, { recursive: true }, (eventType, filename) => {
|
|
123
|
-
if (filename && filename.endsWith("slides.md")) try {
|
|
124
|
-
const slides = getAllSlidesFrontmatter();
|
|
125
|
-
server.ws.send({
|
|
126
|
-
type: "custom",
|
|
127
|
-
event: "slides-updated",
|
|
128
|
-
data: slides
|
|
129
|
-
});
|
|
130
|
-
} catch (error) {
|
|
131
|
-
console.error("❌ Error reading slides frontmatter:", error);
|
|
132
|
-
}
|
|
133
|
-
});
|
|
134
|
-
watchers.push(watcher);
|
|
135
|
-
});
|
|
136
|
-
server.httpServer?.once("close", () => {
|
|
137
|
-
watchers.forEach((watcher) => watcher.close());
|
|
138
|
-
});
|
|
139
|
-
},
|
|
140
|
-
resolveId(id) {
|
|
141
|
-
if (id === "slidev:content") return id;
|
|
142
|
-
},
|
|
143
|
-
load(id) {
|
|
144
|
-
if (id === "slidev:content") try {
|
|
145
|
-
const slides = getAllSlidesFrontmatter();
|
|
146
|
-
return `export const slidesData = ${JSON.stringify(slides, null, 2)};
|
|
147
|
-
export default slidesData;`;
|
|
148
|
-
} catch (error) {
|
|
149
|
-
console.error("Error loading slides data:", error);
|
|
150
|
-
return `export const slidesData = [];
|
|
151
|
-
export default slidesData;`;
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
};
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
//#endregion
|
|
158
3
|
//#region src/preview/composables/useSlides.ts
|
|
159
4
|
function useSlides() {
|
|
160
5
|
const slidesData = ref([]);
|
|
161
6
|
const loadSlidesData = async () => {
|
|
162
7
|
try {
|
|
163
8
|
const module = await import("slidev:content");
|
|
164
|
-
slidesData.value = module.default ||
|
|
9
|
+
slidesData.value = module.default || [];
|
|
165
10
|
} catch (error) {
|
|
166
11
|
console.warn("Failed to load slides data:", error);
|
|
167
12
|
slidesData.value = [];
|
|
@@ -191,4 +36,4 @@ function useSlides() {
|
|
|
191
36
|
}
|
|
192
37
|
|
|
193
38
|
//#endregion
|
|
194
|
-
export {
|
|
39
|
+
export { useSlides };
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { existsSync, readFileSync, readdirSync, watch } from "fs";
|
|
2
|
+
import { basename, join, resolve } from "path";
|
|
3
|
+
import { parse } from "yaml";
|
|
4
|
+
|
|
5
|
+
//#region src/scripts/config.ts
|
|
6
|
+
const DEFAULT_CONFIG = {
|
|
7
|
+
slidesDir: ["./slides"],
|
|
8
|
+
outputDir: "./dist",
|
|
9
|
+
baseUrl: "/",
|
|
10
|
+
exclude: ["node_modules", ".git"]
|
|
11
|
+
};
|
|
12
|
+
function loadConfig(workingDir) {
|
|
13
|
+
const configPaths = [
|
|
14
|
+
"slidev-workspace.config.js",
|
|
15
|
+
"slidev-workspace.config.ts",
|
|
16
|
+
"slidev-workspace.yml",
|
|
17
|
+
"slidev-workspace.yaml"
|
|
18
|
+
];
|
|
19
|
+
const projectRoot = workingDir || process.env.SLIDEV_WORKSPACE_CWD || process.cwd();
|
|
20
|
+
for (const configPath of configPaths) {
|
|
21
|
+
const fullPath = join(projectRoot, configPath);
|
|
22
|
+
if (existsSync(fullPath)) try {
|
|
23
|
+
if (configPath.endsWith(".yml") || configPath.endsWith(".yaml")) {
|
|
24
|
+
const content = readFileSync(fullPath, "utf8");
|
|
25
|
+
const config = parse(content);
|
|
26
|
+
return {
|
|
27
|
+
...DEFAULT_CONFIG,
|
|
28
|
+
...config
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
} catch (error) {
|
|
32
|
+
console.warn(`Failed to load config from ${fullPath}:`, error);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return DEFAULT_CONFIG;
|
|
36
|
+
}
|
|
37
|
+
function resolveSlidesDirs(config, workingDir) {
|
|
38
|
+
const projectRoot = workingDir || process.env.SLIDEV_WORKSPACE_CWD || process.cwd();
|
|
39
|
+
const resolvedDirs = (config.slidesDir || []).map((dir) => {
|
|
40
|
+
if (resolve(dir) === dir) return dir;
|
|
41
|
+
else return resolve(projectRoot, dir);
|
|
42
|
+
}).filter((dir) => {
|
|
43
|
+
const exists = existsSync(dir);
|
|
44
|
+
return exists;
|
|
45
|
+
});
|
|
46
|
+
return resolvedDirs;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
//#endregion
|
|
50
|
+
//#region src/scripts/getSlideFrontmatter.ts
|
|
51
|
+
function getSlideFrontmatterByPath(slideDir, slideName) {
|
|
52
|
+
try {
|
|
53
|
+
const fullPath = join(slideDir, slideName, "slides.md");
|
|
54
|
+
if (!existsSync(fullPath)) {
|
|
55
|
+
console.warn(`File not found: ${fullPath}`);
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
const content = readFileSync(fullPath, "utf8");
|
|
59
|
+
const frontmatterMatch = content.match(/^---\s*\n([\s\S]*?)\n---\s*\n/);
|
|
60
|
+
if (!frontmatterMatch) {
|
|
61
|
+
console.warn(`Frontmatter not found in ${fullPath}`);
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
const frontmatterYaml = frontmatterMatch[1];
|
|
65
|
+
const frontmatter = parse(frontmatterYaml);
|
|
66
|
+
const sourceBasename = basename(slideDir);
|
|
67
|
+
const slideId = `${sourceBasename}/${slideName}`;
|
|
68
|
+
return {
|
|
69
|
+
id: slideId,
|
|
70
|
+
path: slideName,
|
|
71
|
+
fullPath,
|
|
72
|
+
sourceDir: slideDir,
|
|
73
|
+
frontmatter,
|
|
74
|
+
content: content.replace(frontmatterMatch[0], "")
|
|
75
|
+
};
|
|
76
|
+
} catch (error) {
|
|
77
|
+
console.error(`Error parsing frontmatter for ${slideName} in ${slideDir}:`, error);
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
function getAllSlidesFrontmatter() {
|
|
82
|
+
const config = loadConfig();
|
|
83
|
+
const slidesDirs = resolveSlidesDirs(config);
|
|
84
|
+
const slides = [];
|
|
85
|
+
for (const slidesDir of slidesDirs) {
|
|
86
|
+
if (!existsSync(slidesDir)) {
|
|
87
|
+
console.warn(`Slides directory not found: ${slidesDir}`);
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
try {
|
|
91
|
+
const slideDirs = readdirSync(slidesDir, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).filter((dirent) => !(config.exclude || []).includes(dirent.name)).map((dirent) => dirent.name);
|
|
92
|
+
for (const slideDir of slideDirs) {
|
|
93
|
+
const slideInfo = getSlideFrontmatterByPath(slidesDir, slideDir);
|
|
94
|
+
if (slideInfo) slides.push(slideInfo);
|
|
95
|
+
}
|
|
96
|
+
} catch (error) {
|
|
97
|
+
console.error(`Error reading slides directory ${slidesDir}:`, error);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return slides;
|
|
101
|
+
}
|
|
102
|
+
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
103
|
+
const slides = getAllSlidesFrontmatter();
|
|
104
|
+
console.log(JSON.stringify(slides, null, 2));
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
//#endregion
|
|
108
|
+
//#region src/vite/plugin-slides.ts
|
|
109
|
+
function slidesPlugin() {
|
|
110
|
+
return {
|
|
111
|
+
name: "vite-plugin-slides",
|
|
112
|
+
configureServer(server) {
|
|
113
|
+
const watchers = [];
|
|
114
|
+
const config = loadConfig();
|
|
115
|
+
const slidesDirs = resolveSlidesDirs(config);
|
|
116
|
+
slidesDirs.forEach((slidesDir) => {
|
|
117
|
+
const watcher = watch(slidesDir, { recursive: true }, (eventType, filename) => {
|
|
118
|
+
if (filename && filename.endsWith("slides.md")) try {
|
|
119
|
+
const slides = getAllSlidesFrontmatter();
|
|
120
|
+
server.ws.send({
|
|
121
|
+
type: "custom",
|
|
122
|
+
event: "slides-updated",
|
|
123
|
+
data: slides
|
|
124
|
+
});
|
|
125
|
+
} catch (error) {
|
|
126
|
+
console.error("❌ Error reading slides frontmatter:", error);
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
watchers.push(watcher);
|
|
130
|
+
});
|
|
131
|
+
server.httpServer?.once("close", () => {
|
|
132
|
+
watchers.forEach((watcher) => watcher.close());
|
|
133
|
+
});
|
|
134
|
+
},
|
|
135
|
+
resolveId(id) {
|
|
136
|
+
if (id === "slidev:content") return id;
|
|
137
|
+
},
|
|
138
|
+
load(id) {
|
|
139
|
+
if (id === "slidev:content") try {
|
|
140
|
+
const slides = getAllSlidesFrontmatter();
|
|
141
|
+
return `export const slidesData = ${JSON.stringify(slides, null, 2)};
|
|
142
|
+
export default slidesData;`;
|
|
143
|
+
} catch (error) {
|
|
144
|
+
console.error("Error loading slides data:", error);
|
|
145
|
+
return `export const slidesData = [];
|
|
146
|
+
export default slidesData;`;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
//#endregion
|
|
153
|
+
export { slidesPlugin };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "slidev-workspace",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.8",
|
|
4
4
|
"description": "A workspace tool for managing multiple Slidev presentations with API-based content management",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -27,6 +27,7 @@
|
|
|
27
27
|
"types": "./dist/index.d.ts",
|
|
28
28
|
"exports": {
|
|
29
29
|
".": "./dist/index.js",
|
|
30
|
+
"./vite": "./dist/plugin-slides.js",
|
|
30
31
|
"./package.json": "./package.json",
|
|
31
32
|
"./scripts": "./scripts"
|
|
32
33
|
},
|
|
@@ -34,7 +35,7 @@
|
|
|
34
35
|
"access": "public"
|
|
35
36
|
},
|
|
36
37
|
"dependencies": {
|
|
37
|
-
"
|
|
38
|
+
"@tailwindcss/vite": "^4.1.11",
|
|
38
39
|
"@vitejs/plugin-vue": "^6.0.0",
|
|
39
40
|
"@vueuse/core": "^13.5.0",
|
|
40
41
|
"class-variance-authority": "^0.7.1",
|
|
@@ -44,29 +45,24 @@
|
|
|
44
45
|
"tw-animate-css": "^1.3.5",
|
|
45
46
|
"vite": "npm:rolldown-vite@latest",
|
|
46
47
|
"vue": "^3.5.17",
|
|
47
|
-
"
|
|
48
|
+
"yaml": "^2.8.0"
|
|
48
49
|
},
|
|
49
50
|
"devDependencies": {
|
|
50
|
-
"
|
|
51
|
-
"typescript": "^5.8.3",
|
|
52
|
-
"vitest": "^3.1.3",
|
|
53
|
-
"vue-tsc": "^3.0.3",
|
|
51
|
+
"@prettier/plugin-oxc": "^0.0.4",
|
|
54
52
|
"@tsconfig/node22": "^22.0.2",
|
|
55
53
|
"@types/node": "^22.15.32",
|
|
56
|
-
"@vue/eslint-config-prettier": "^10.2.0",
|
|
57
|
-
"@vue/eslint-config-typescript": "^14.5.1",
|
|
58
54
|
"@vue/tsconfig": "^0.7.0",
|
|
59
|
-
"autoprefixer": "^10.4.21",
|
|
60
|
-
"eslint": "^9.29.0",
|
|
61
|
-
"eslint-plugin-oxlint": "~1.1.0",
|
|
62
|
-
"eslint-plugin-vue": "~10.2.0",
|
|
63
55
|
"jiti": "^2.4.2",
|
|
64
56
|
"npm-run-all2": "^8.0.4",
|
|
65
57
|
"oxlint": "~1.1.0",
|
|
66
58
|
"postcss": "^8.5.6",
|
|
67
59
|
"prettier": "3.5.3",
|
|
68
60
|
"tailwindcss": "^4.1.11",
|
|
69
|
-
"
|
|
61
|
+
"tsdown": "^0.11.9",
|
|
62
|
+
"typescript": "^5.8.3",
|
|
63
|
+
"vite-plugin-vue-devtools": "^7.7.7",
|
|
64
|
+
"vitest": "^3.1.3",
|
|
65
|
+
"vue-tsc": "^3.0.3"
|
|
70
66
|
},
|
|
71
67
|
"scripts": {
|
|
72
68
|
"build": "tsdown",
|
|
@@ -74,7 +70,7 @@
|
|
|
74
70
|
"dev:watch": "tsdown --watch",
|
|
75
71
|
"test": "vitest",
|
|
76
72
|
"typecheck": "vue-tsc --noEmit",
|
|
77
|
-
"lint": "
|
|
73
|
+
"lint": "oxlint",
|
|
78
74
|
"format": "prettier --write src/"
|
|
79
75
|
}
|
|
80
76
|
}
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<Card
|
|
2
|
+
<Card
|
|
3
|
+
class="group hover:shadow-lg transition-all duration-200 cursor-pointer"
|
|
4
|
+
@click="$emit('click')"
|
|
5
|
+
>
|
|
3
6
|
<div class="relative overflow-hidden rounded-t-lg">
|
|
4
7
|
<img
|
|
5
8
|
:src="image || '/placeholder.svg'"
|
|
@@ -9,24 +12,36 @@
|
|
|
9
12
|
</div>
|
|
10
13
|
|
|
11
14
|
<CardHeader class="pb-2">
|
|
12
|
-
<CardTitle
|
|
15
|
+
<CardTitle
|
|
16
|
+
class="text-lg line-clamp-2 group-hover:text-primary transition-colors"
|
|
17
|
+
>
|
|
13
18
|
{{ title }}
|
|
14
19
|
</CardTitle>
|
|
15
20
|
</CardHeader>
|
|
16
21
|
|
|
17
22
|
<CardContent class="space-y-3">
|
|
18
|
-
<CardDescription class="line-clamp-3 text-sm h-[40px]">{{
|
|
23
|
+
<CardDescription class="line-clamp-3 text-sm h-[40px]">{{
|
|
24
|
+
description
|
|
25
|
+
}}</CardDescription>
|
|
19
26
|
|
|
20
27
|
<div class="flex flex-wrap gap-1 mb-2">
|
|
21
|
-
<span
|
|
28
|
+
<span
|
|
29
|
+
v-if="theme"
|
|
30
|
+
class="inline-flex items-center px-2 py-1 rounded-full text-xs bg-blue-100 text-blue-800"
|
|
31
|
+
>
|
|
22
32
|
{{ theme }}
|
|
23
33
|
</span>
|
|
24
|
-
<span
|
|
25
|
-
|
|
34
|
+
<span
|
|
35
|
+
v-if="sourceDir"
|
|
36
|
+
class="inline-flex items-center px-2 py-1 rounded-full text-xs bg-green-100 text-green-800"
|
|
37
|
+
>
|
|
38
|
+
{{ sourceDir.split("/").pop() }}
|
|
26
39
|
</span>
|
|
27
40
|
</div>
|
|
28
41
|
|
|
29
|
-
<div
|
|
42
|
+
<div
|
|
43
|
+
class="flex items-center justify-between text-xs text-muted-foreground pt-2 border-t"
|
|
44
|
+
>
|
|
30
45
|
<div class="flex items-center gap-1">
|
|
31
46
|
<User class="h-3 w-3" />
|
|
32
47
|
<span>{{ author }}</span>
|
|
@@ -41,22 +56,28 @@
|
|
|
41
56
|
</template>
|
|
42
57
|
|
|
43
58
|
<script setup lang="ts">
|
|
44
|
-
import { Calendar, User } from
|
|
59
|
+
import { Calendar, User } from "lucide-vue-next";
|
|
45
60
|
|
|
46
|
-
import {
|
|
61
|
+
import {
|
|
62
|
+
Card,
|
|
63
|
+
CardContent,
|
|
64
|
+
CardDescription,
|
|
65
|
+
CardHeader,
|
|
66
|
+
CardTitle,
|
|
67
|
+
} from "@/components/ui/card";
|
|
47
68
|
|
|
48
69
|
defineProps<{
|
|
49
|
-
title: string
|
|
50
|
-
image?: string
|
|
51
|
-
description?: string
|
|
52
|
-
url: string
|
|
53
|
-
author: string
|
|
54
|
-
date: string
|
|
55
|
-
theme?: string
|
|
56
|
-
sourceDir?: string
|
|
57
|
-
}>()
|
|
70
|
+
title: string;
|
|
71
|
+
image?: string;
|
|
72
|
+
description?: string;
|
|
73
|
+
url: string;
|
|
74
|
+
author: string;
|
|
75
|
+
date: string;
|
|
76
|
+
theme?: string;
|
|
77
|
+
sourceDir?: string;
|
|
78
|
+
}>();
|
|
58
79
|
|
|
59
80
|
defineEmits<{
|
|
60
|
-
click: []
|
|
61
|
-
}>()
|
|
81
|
+
click: [];
|
|
82
|
+
}>();
|
|
62
83
|
</script>
|
|
@@ -47,13 +47,6 @@
|
|
|
47
47
|
/>
|
|
48
48
|
</div>
|
|
49
49
|
</div>
|
|
50
|
-
|
|
51
|
-
<!-- Slide Detail Modal -->
|
|
52
|
-
<SlideDetail
|
|
53
|
-
v-if="selectedSlide"
|
|
54
|
-
:slide="selectedSlide"
|
|
55
|
-
@close="closeSlide"
|
|
56
|
-
/>
|
|
57
50
|
</div>
|
|
58
51
|
</template>
|
|
59
52
|
|
|
@@ -62,27 +55,25 @@ import { ref, computed } from "vue";
|
|
|
62
55
|
import { useSlides } from "../composables/useSlides";
|
|
63
56
|
import { Input } from "../components/ui/input";
|
|
64
57
|
import SlideCard from "./SlideCard.vue";
|
|
65
|
-
import
|
|
58
|
+
import type { SlideData } from "../../types/slide";
|
|
66
59
|
|
|
67
60
|
const searchTerm = ref("");
|
|
68
61
|
const { slides, slidesCount } = useSlides();
|
|
69
62
|
|
|
70
63
|
const filteredSlides = computed(() => {
|
|
71
64
|
if (!searchTerm.value) return slides.value;
|
|
72
|
-
return slides.value.filter(
|
|
73
|
-
slide
|
|
74
|
-
|
|
75
|
-
|
|
65
|
+
return slides.value.filter(
|
|
66
|
+
(slide) =>
|
|
67
|
+
slide.title.toLowerCase().includes(searchTerm.value.toLowerCase()) ||
|
|
68
|
+
slide.description
|
|
69
|
+
.toLowerCase()
|
|
70
|
+
.includes(searchTerm.value.toLowerCase()) ||
|
|
71
|
+
slide.author.toLowerCase().includes(searchTerm.value.toLowerCase()),
|
|
76
72
|
);
|
|
77
73
|
});
|
|
78
74
|
|
|
79
|
-
const
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
selectedSlide.value = slide;
|
|
83
|
-
};
|
|
84
|
-
|
|
85
|
-
const closeSlide = () => {
|
|
86
|
-
selectedSlide.value = null;
|
|
75
|
+
const openSlide = (slide: SlideData) => {
|
|
76
|
+
const url = `${window.location.href}/${slide.url}`;
|
|
77
|
+
window.open(url, "_blank");
|
|
87
78
|
};
|
|
88
79
|
</script>
|
|
@@ -14,8 +14,8 @@ import type { VariantProps } from "class-variance-authority";
|
|
|
14
14
|
|
|
15
15
|
interface Props {
|
|
16
16
|
as?: string;
|
|
17
|
-
variant?: VariantProps<typeof buttonVariants>[
|
|
18
|
-
size?: VariantProps<typeof buttonVariants>[
|
|
17
|
+
variant?: VariantProps<typeof buttonVariants>["variant"];
|
|
18
|
+
size?: VariantProps<typeof buttonVariants>["size"];
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
const props = withDefaults(defineProps<Props>(), {
|