slidev-workspace 0.1.7 → 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/index.d.ts +7 -25
- package/package.json +10 -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 +1 -13
- package/src/preview/index.html +11 -11
- package/src/preview/lib/utils.ts +3 -3
- package/src/preview/main.ts +4 -4
- package/src/preview/components/SlideDetail.vue +0 -165
- package/src/preview/utils/getSlides.ts +0 -65
package/dist/index.d.ts
CHANGED
|
@@ -1,23 +1,5 @@
|
|
|
1
1
|
import * as vue0 from "vue";
|
|
2
2
|
|
|
3
|
-
//#region src/preview/composables/useSlides.d.ts
|
|
4
|
-
interface SlideData$1 {
|
|
5
|
-
title: string;
|
|
6
|
-
url: string;
|
|
7
|
-
description: string;
|
|
8
|
-
image: string;
|
|
9
|
-
author: string;
|
|
10
|
-
date: string;
|
|
11
|
-
theme?: string;
|
|
12
|
-
transition?: string;
|
|
13
|
-
class?: string;
|
|
14
|
-
}
|
|
15
|
-
declare function useSlides(): {
|
|
16
|
-
slides: vue0.ComputedRef<SlideData$1[]>;
|
|
17
|
-
slidesCount: vue0.ComputedRef<number>;
|
|
18
|
-
loadSlidesData: () => Promise<void>;
|
|
19
|
-
};
|
|
20
|
-
//#endregion
|
|
21
3
|
//#region src/types/slide.d.ts
|
|
22
4
|
interface SlideFrontmatter {
|
|
23
5
|
theme?: string;
|
|
@@ -37,7 +19,6 @@ interface SlideFrontmatter {
|
|
|
37
19
|
};
|
|
38
20
|
author?: string;
|
|
39
21
|
date?: string;
|
|
40
|
-
[key: string]: any;
|
|
41
22
|
}
|
|
42
23
|
interface SlideInfo {
|
|
43
24
|
id: string;
|
|
@@ -48,7 +29,6 @@ interface SlideInfo {
|
|
|
48
29
|
content: string;
|
|
49
30
|
}
|
|
50
31
|
interface SlideData {
|
|
51
|
-
id: string;
|
|
52
32
|
title: string;
|
|
53
33
|
url: string;
|
|
54
34
|
description: string;
|
|
@@ -58,13 +38,15 @@ interface SlideData {
|
|
|
58
38
|
theme?: string;
|
|
59
39
|
transition?: string;
|
|
60
40
|
class?: string;
|
|
61
|
-
sourceDir: string;
|
|
62
|
-
path: string;
|
|
63
|
-
fullPath: string;
|
|
64
|
-
frontmatter: SlideFrontmatter;
|
|
65
|
-
content: string;
|
|
66
41
|
}
|
|
67
42
|
//#endregion
|
|
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
|
+
};
|
|
49
|
+
//#endregion
|
|
68
50
|
//#region src/types/config.d.ts
|
|
69
51
|
interface SlidevWorkspaceConfig {
|
|
70
52
|
slidesDir: string[];
|
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",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"access": "public"
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"
|
|
38
|
+
"@tailwindcss/vite": "^4.1.11",
|
|
39
39
|
"@vitejs/plugin-vue": "^6.0.0",
|
|
40
40
|
"@vueuse/core": "^13.5.0",
|
|
41
41
|
"class-variance-authority": "^0.7.1",
|
|
@@ -45,29 +45,24 @@
|
|
|
45
45
|
"tw-animate-css": "^1.3.5",
|
|
46
46
|
"vite": "npm:rolldown-vite@latest",
|
|
47
47
|
"vue": "^3.5.17",
|
|
48
|
-
"
|
|
48
|
+
"yaml": "^2.8.0"
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|
|
51
|
-
"
|
|
52
|
-
"typescript": "^5.8.3",
|
|
53
|
-
"vitest": "^3.1.3",
|
|
54
|
-
"vue-tsc": "^3.0.3",
|
|
51
|
+
"@prettier/plugin-oxc": "^0.0.4",
|
|
55
52
|
"@tsconfig/node22": "^22.0.2",
|
|
56
53
|
"@types/node": "^22.15.32",
|
|
57
|
-
"@vue/eslint-config-prettier": "^10.2.0",
|
|
58
|
-
"@vue/eslint-config-typescript": "^14.5.1",
|
|
59
54
|
"@vue/tsconfig": "^0.7.0",
|
|
60
|
-
"autoprefixer": "^10.4.21",
|
|
61
|
-
"eslint": "^9.29.0",
|
|
62
|
-
"eslint-plugin-oxlint": "~1.1.0",
|
|
63
|
-
"eslint-plugin-vue": "~10.2.0",
|
|
64
55
|
"jiti": "^2.4.2",
|
|
65
56
|
"npm-run-all2": "^8.0.4",
|
|
66
57
|
"oxlint": "~1.1.0",
|
|
67
58
|
"postcss": "^8.5.6",
|
|
68
59
|
"prettier": "3.5.3",
|
|
69
60
|
"tailwindcss": "^4.1.11",
|
|
70
|
-
"
|
|
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"
|
|
71
66
|
},
|
|
72
67
|
"scripts": {
|
|
73
68
|
"build": "tsdown",
|
|
@@ -75,7 +70,7 @@
|
|
|
75
70
|
"dev:watch": "tsdown --watch",
|
|
76
71
|
"test": "vitest",
|
|
77
72
|
"typecheck": "vue-tsc --noEmit",
|
|
78
|
-
"lint": "
|
|
73
|
+
"lint": "oxlint",
|
|
79
74
|
"format": "prettier --write src/"
|
|
80
75
|
}
|
|
81
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>(), {
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import type { HTMLAttributes } from
|
|
3
|
-
import { cn } from
|
|
2
|
+
import type { HTMLAttributes } from "vue";
|
|
3
|
+
import { cn } from "@/lib/utils";
|
|
4
4
|
|
|
5
5
|
const props = defineProps<{
|
|
6
|
-
class?: HTMLAttributes[
|
|
7
|
-
}>()
|
|
6
|
+
class?: HTMLAttributes["class"];
|
|
7
|
+
}>();
|
|
8
8
|
</script>
|
|
9
9
|
|
|
10
10
|
<template>
|
|
@@ -1,16 +1,21 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import type { HTMLAttributes } from
|
|
3
|
-
import { cn } from
|
|
2
|
+
import type { HTMLAttributes } from "vue";
|
|
3
|
+
import { cn } from "@/lib/utils";
|
|
4
4
|
|
|
5
5
|
const props = defineProps<{
|
|
6
|
-
class?: HTMLAttributes[
|
|
7
|
-
}>()
|
|
6
|
+
class?: HTMLAttributes["class"];
|
|
7
|
+
}>();
|
|
8
8
|
</script>
|
|
9
9
|
|
|
10
10
|
<template>
|
|
11
11
|
<div
|
|
12
12
|
data-slot="card-action"
|
|
13
|
-
:class="
|
|
13
|
+
:class="
|
|
14
|
+
cn(
|
|
15
|
+
'col-start-2 row-span-2 row-start-1 self-start justify-self-end',
|
|
16
|
+
props.class,
|
|
17
|
+
)
|
|
18
|
+
"
|
|
14
19
|
>
|
|
15
20
|
<slot />
|
|
16
21
|
</div>
|
|
@@ -1,17 +1,14 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import type { HTMLAttributes } from
|
|
3
|
-
import { cn } from
|
|
2
|
+
import type { HTMLAttributes } from "vue";
|
|
3
|
+
import { cn } from "@/lib/utils";
|
|
4
4
|
|
|
5
5
|
const props = defineProps<{
|
|
6
|
-
class?: HTMLAttributes[
|
|
7
|
-
}>()
|
|
6
|
+
class?: HTMLAttributes["class"];
|
|
7
|
+
}>();
|
|
8
8
|
</script>
|
|
9
9
|
|
|
10
10
|
<template>
|
|
11
|
-
<div
|
|
12
|
-
data-slot="card-content"
|
|
13
|
-
:class="cn('px-6 pb-6', props.class)"
|
|
14
|
-
>
|
|
11
|
+
<div data-slot="card-content" :class="cn('px-6 pb-6', props.class)">
|
|
15
12
|
<slot />
|
|
16
13
|
</div>
|
|
17
14
|
</template>
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import type { HTMLAttributes } from
|
|
3
|
-
import { cn } from
|
|
2
|
+
import type { HTMLAttributes } from "vue";
|
|
3
|
+
import { cn } from "@/lib/utils";
|
|
4
4
|
|
|
5
5
|
const props = defineProps<{
|
|
6
|
-
class?: HTMLAttributes[
|
|
7
|
-
}>()
|
|
6
|
+
class?: HTMLAttributes["class"];
|
|
7
|
+
}>();
|
|
8
8
|
</script>
|
|
9
9
|
|
|
10
10
|
<template>
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import type { HTMLAttributes } from
|
|
3
|
-
import { cn } from
|
|
2
|
+
import type { HTMLAttributes } from "vue";
|
|
3
|
+
import { cn } from "@/lib/utils";
|
|
4
4
|
|
|
5
5
|
const props = defineProps<{
|
|
6
|
-
class?: HTMLAttributes[
|
|
7
|
-
}>()
|
|
6
|
+
class?: HTMLAttributes["class"];
|
|
7
|
+
}>();
|
|
8
8
|
</script>
|
|
9
9
|
|
|
10
10
|
<template>
|
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import type { HTMLAttributes } from
|
|
3
|
-
import { cn } from
|
|
2
|
+
import type { HTMLAttributes } from "vue";
|
|
3
|
+
import { cn } from "@/lib/utils";
|
|
4
4
|
|
|
5
5
|
const props = defineProps<{
|
|
6
|
-
class?: HTMLAttributes[
|
|
7
|
-
}>()
|
|
6
|
+
class?: HTMLAttributes["class"];
|
|
7
|
+
}>();
|
|
8
8
|
</script>
|
|
9
9
|
|
|
10
10
|
<template>
|
|
11
|
-
<div
|
|
11
|
+
<div
|
|
12
|
+
data-slot="card-header"
|
|
13
|
+
:class="cn('@container/card-header gap-1.5 pt-6 px-6', props.class)"
|
|
14
|
+
>
|
|
12
15
|
<slot />
|
|
13
16
|
</div>
|
|
14
17
|
</template>
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import type { HTMLAttributes } from
|
|
3
|
-
import { cn } from
|
|
2
|
+
import type { HTMLAttributes } from "vue";
|
|
3
|
+
import { cn } from "@/lib/utils";
|
|
4
4
|
|
|
5
5
|
const props = defineProps<{
|
|
6
|
-
class?: HTMLAttributes[
|
|
7
|
-
}>()
|
|
6
|
+
class?: HTMLAttributes["class"];
|
|
7
|
+
}>();
|
|
8
8
|
</script>
|
|
9
9
|
|
|
10
10
|
<template>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
export { default as Card } from
|
|
2
|
-
export { default as CardAction } from
|
|
3
|
-
export { default as CardContent } from
|
|
4
|
-
export { default as CardDescription } from
|
|
5
|
-
export { default as CardFooter } from
|
|
6
|
-
export { default as CardHeader } from
|
|
7
|
-
export { default as CardTitle } from
|
|
1
|
+
export { default as Card } from "./Card.vue";
|
|
2
|
+
export { default as CardAction } from "./CardAction.vue";
|
|
3
|
+
export { default as CardContent } from "./CardContent.vue";
|
|
4
|
+
export { default as CardDescription } from "./CardDescription.vue";
|
|
5
|
+
export { default as CardFooter } from "./CardFooter.vue";
|
|
6
|
+
export { default as CardHeader } from "./CardHeader.vue";
|
|
7
|
+
export { default as CardTitle } from "./CardTitle.vue";
|
|
@@ -1,33 +1,35 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import type { HTMLAttributes } from
|
|
3
|
-
import { useVModel } from
|
|
4
|
-
import { cn } from
|
|
2
|
+
import type { HTMLAttributes } from "vue";
|
|
3
|
+
import { useVModel } from "@vueuse/core";
|
|
4
|
+
import { cn } from "@/lib/utils";
|
|
5
5
|
|
|
6
6
|
const props = defineProps<{
|
|
7
|
-
defaultValue?: string | number
|
|
8
|
-
modelValue?: string | number
|
|
9
|
-
class?: HTMLAttributes[
|
|
10
|
-
}>()
|
|
7
|
+
defaultValue?: string | number;
|
|
8
|
+
modelValue?: string | number;
|
|
9
|
+
class?: HTMLAttributes["class"];
|
|
10
|
+
}>();
|
|
11
11
|
|
|
12
12
|
const emits = defineEmits<{
|
|
13
|
-
(e:
|
|
14
|
-
}>()
|
|
13
|
+
(e: "update:modelValue", payload: string | number): void;
|
|
14
|
+
}>();
|
|
15
15
|
|
|
16
|
-
const modelValue = useVModel(props,
|
|
16
|
+
const modelValue = useVModel(props, "modelValue", emits, {
|
|
17
17
|
passive: true,
|
|
18
18
|
defaultValue: props.defaultValue,
|
|
19
|
-
})
|
|
19
|
+
});
|
|
20
20
|
</script>
|
|
21
21
|
|
|
22
22
|
<template>
|
|
23
23
|
<input
|
|
24
24
|
v-model="modelValue"
|
|
25
25
|
data-slot="input"
|
|
26
|
-
:class="
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
26
|
+
:class="
|
|
27
|
+
cn(
|
|
28
|
+
'file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground dark:bg-input/30 border-input flex h-9 w-full min-w-0 rounded-md border bg-transparent px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm',
|
|
29
|
+
'focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]',
|
|
30
|
+
'aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive',
|
|
31
|
+
props.class,
|
|
32
|
+
)
|
|
33
|
+
"
|
|
34
|
+
/>
|
|
33
35
|
</template>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export { default as Input } from
|
|
1
|
+
export { default as Input } from "./Input.vue";
|
|
@@ -1,17 +1,5 @@
|
|
|
1
1
|
import { computed, ref } from "vue";
|
|
2
|
-
import type { SlideInfo } from "../../types/slide.js";
|
|
3
|
-
|
|
4
|
-
export interface SlideData {
|
|
5
|
-
title: string;
|
|
6
|
-
url: string;
|
|
7
|
-
description: string;
|
|
8
|
-
image: string;
|
|
9
|
-
author: string;
|
|
10
|
-
date: string;
|
|
11
|
-
theme?: string;
|
|
12
|
-
transition?: string;
|
|
13
|
-
class?: string;
|
|
14
|
-
}
|
|
2
|
+
import type { SlideData, SlideInfo } from "../../types/slide.js";
|
|
15
3
|
|
|
16
4
|
export function useSlides() {
|
|
17
5
|
const slidesData = ref<SlideInfo[]>([]);
|
package/src/preview/index.html
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
<!
|
|
1
|
+
<!doctype html>
|
|
2
2
|
<html lang="en">
|
|
3
|
-
<head>
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
</head>
|
|
8
|
-
<body>
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
</body>
|
|
12
|
-
</html>
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<title>Slidev Workspace</title>
|
|
7
|
+
</head>
|
|
8
|
+
<body>
|
|
9
|
+
<div id="app"></div>
|
|
10
|
+
<script type="module" src="/main.ts"></script>
|
|
11
|
+
</body>
|
|
12
|
+
</html>
|
package/src/preview/lib/utils.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { type ClassValue, clsx } from
|
|
2
|
-
import { twMerge } from
|
|
1
|
+
import { type ClassValue, clsx } from "clsx";
|
|
2
|
+
import { twMerge } from "tailwind-merge";
|
|
3
3
|
|
|
4
4
|
export function cn(...inputs: ClassValue[]) {
|
|
5
|
-
return twMerge(clsx(inputs))
|
|
5
|
+
return twMerge(clsx(inputs));
|
|
6
6
|
}
|
package/src/preview/main.ts
CHANGED
|
@@ -1,165 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<div
|
|
3
|
-
class="fixed inset-0 bg-black/50 flex items-center justify-center z-50 p-4"
|
|
4
|
-
@click="$emit('close')"
|
|
5
|
-
>
|
|
6
|
-
<div
|
|
7
|
-
class="bg-white rounded-lg max-w-4xl w-full max-h-[90vh] overflow-y-auto"
|
|
8
|
-
@click.stop
|
|
9
|
-
>
|
|
10
|
-
<div class="p-6">
|
|
11
|
-
<div class="flex items-start justify-between mb-6">
|
|
12
|
-
<div class="flex-1">
|
|
13
|
-
<h1 class="text-2xl font-bold mb-2">{{ slide.title }}</h1>
|
|
14
|
-
<div class="flex items-center gap-4 text-sm text-muted-foreground">
|
|
15
|
-
<div class="flex items-center gap-1">
|
|
16
|
-
<User class="h-4 w-4" />
|
|
17
|
-
<span>{{ slide.author }}</span>
|
|
18
|
-
</div>
|
|
19
|
-
<div class="flex items-center gap-1">
|
|
20
|
-
<Calendar class="h-4 w-4" />
|
|
21
|
-
<span>{{ slide.date }}</span>
|
|
22
|
-
</div>
|
|
23
|
-
<div v-if="slide.theme" class="flex items-center gap-1">
|
|
24
|
-
<Palette class="h-4 w-4" />
|
|
25
|
-
<span>{{ slide.theme }}</span>
|
|
26
|
-
</div>
|
|
27
|
-
</div>
|
|
28
|
-
</div>
|
|
29
|
-
<Button variant="ghost" size="sm" @click="$emit('close')">
|
|
30
|
-
<X class="h-4 w-4" />
|
|
31
|
-
</Button>
|
|
32
|
-
</div>
|
|
33
|
-
|
|
34
|
-
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
|
35
|
-
<!-- Preview Image -->
|
|
36
|
-
<div class="space-y-4">
|
|
37
|
-
<div
|
|
38
|
-
class="aspect-video bg-gradient-to-br from-gray-100 to-gray-200 rounded-lg overflow-hidden"
|
|
39
|
-
>
|
|
40
|
-
<img
|
|
41
|
-
:src="slide.image"
|
|
42
|
-
:alt="slide.title"
|
|
43
|
-
class="w-full h-full object-cover"
|
|
44
|
-
@error="handleImageError"
|
|
45
|
-
/>
|
|
46
|
-
</div>
|
|
47
|
-
|
|
48
|
-
<!-- Slide Actions -->
|
|
49
|
-
<div class="flex gap-2">
|
|
50
|
-
<Button @click="openInSlidev" class="flex-1">
|
|
51
|
-
<ExternalLink class="h-4 w-4 mr-2" />
|
|
52
|
-
Open in Slidev
|
|
53
|
-
</Button>
|
|
54
|
-
<Button variant="outline" @click="copyPath">
|
|
55
|
-
<Copy class="h-4 w-4 mr-2" />
|
|
56
|
-
Copy Path
|
|
57
|
-
</Button>
|
|
58
|
-
</div>
|
|
59
|
-
</div>
|
|
60
|
-
|
|
61
|
-
<!-- Slide Information -->
|
|
62
|
-
<div class="space-y-6">
|
|
63
|
-
<div>
|
|
64
|
-
<h3 class="font-semibold mb-2">Description</h3>
|
|
65
|
-
<p class="text-muted-foreground">{{ slide.description }}</p>
|
|
66
|
-
</div>
|
|
67
|
-
|
|
68
|
-
<div>
|
|
69
|
-
<h3 class="font-semibold mb-2">Frontmatter</h3>
|
|
70
|
-
<div class="bg-gray-50 rounded-lg p-4">
|
|
71
|
-
<pre class="text-sm overflow-x-auto">{{
|
|
72
|
-
formatFrontmatter(slide.frontmatter)
|
|
73
|
-
}}</pre>
|
|
74
|
-
</div>
|
|
75
|
-
</div>
|
|
76
|
-
|
|
77
|
-
<div>
|
|
78
|
-
<h3 class="font-semibold mb-2">File Information</h3>
|
|
79
|
-
<div class="space-y-2 text-sm">
|
|
80
|
-
<div class="flex justify-between">
|
|
81
|
-
<span class="text-muted-foreground">ID:</span>
|
|
82
|
-
<code class="bg-gray-100 px-2 py-1 rounded">{{
|
|
83
|
-
slide.id
|
|
84
|
-
}}</code>
|
|
85
|
-
</div>
|
|
86
|
-
<div class="flex justify-between">
|
|
87
|
-
<span class="text-muted-foreground">Path:</span>
|
|
88
|
-
<code class="bg-gray-100 px-2 py-1 rounded">{{
|
|
89
|
-
slide.path
|
|
90
|
-
}}</code>
|
|
91
|
-
</div>
|
|
92
|
-
<div class="flex justify-between">
|
|
93
|
-
<span class="text-muted-foreground">Source:</span>
|
|
94
|
-
<span>{{
|
|
95
|
-
slide.sourceDir?.split("/").pop() || "Unknown"
|
|
96
|
-
}}</span>
|
|
97
|
-
</div>
|
|
98
|
-
<div class="flex justify-between">
|
|
99
|
-
<span class="text-muted-foreground">Full Path:</span>
|
|
100
|
-
<code class="bg-gray-100 px-2 py-1 rounded text-xs">{{
|
|
101
|
-
slide.fullPath
|
|
102
|
-
}}</code>
|
|
103
|
-
</div>
|
|
104
|
-
</div>
|
|
105
|
-
</div>
|
|
106
|
-
|
|
107
|
-
<div v-if="slide.content">
|
|
108
|
-
<h3 class="font-semibold mb-2">Content Preview</h3>
|
|
109
|
-
<div class="bg-gray-50 rounded-lg p-4 max-h-60 overflow-y-auto">
|
|
110
|
-
<pre class="text-sm whitespace-pre-wrap"
|
|
111
|
-
>{{ slide.content.substring(0, 500)
|
|
112
|
-
}}{{ slide.content.length > 500 ? "..." : "" }}</pre
|
|
113
|
-
>
|
|
114
|
-
</div>
|
|
115
|
-
</div>
|
|
116
|
-
</div>
|
|
117
|
-
</div>
|
|
118
|
-
</div>
|
|
119
|
-
</div>
|
|
120
|
-
</div>
|
|
121
|
-
</template>
|
|
122
|
-
|
|
123
|
-
<script setup lang="ts">
|
|
124
|
-
import {
|
|
125
|
-
X,
|
|
126
|
-
User,
|
|
127
|
-
Calendar,
|
|
128
|
-
Palette,
|
|
129
|
-
ExternalLink,
|
|
130
|
-
Copy,
|
|
131
|
-
} from "lucide-vue-next";
|
|
132
|
-
import { computed } from "vue";
|
|
133
|
-
import { Button } from "@/components/ui/button";
|
|
134
|
-
import type { SlideData } from "../../types/slide";
|
|
135
|
-
|
|
136
|
-
const props = defineProps<{
|
|
137
|
-
slide: SlideData;
|
|
138
|
-
}>();
|
|
139
|
-
|
|
140
|
-
defineEmits<{
|
|
141
|
-
close: [];
|
|
142
|
-
}>();
|
|
143
|
-
|
|
144
|
-
const slidevUrl = computed(() => {
|
|
145
|
-
return `${window.location.href}/${props.slide.url}`;
|
|
146
|
-
});
|
|
147
|
-
|
|
148
|
-
const formatFrontmatter = (frontmatter: any) => {
|
|
149
|
-
return JSON.stringify(frontmatter, null, 2);
|
|
150
|
-
};
|
|
151
|
-
|
|
152
|
-
const handleImageError = (event: Event) => {
|
|
153
|
-
const target = event.target as HTMLImageElement;
|
|
154
|
-
target.src = "https://cover.sli.dev";
|
|
155
|
-
};
|
|
156
|
-
|
|
157
|
-
const openInSlidev = () => {
|
|
158
|
-
window.open(slidevUrl.value, "_blank");
|
|
159
|
-
};
|
|
160
|
-
|
|
161
|
-
const copyPath = () => {
|
|
162
|
-
navigator.clipboard.writeText(slidevUrl.value);
|
|
163
|
-
// You could add a toast notification here
|
|
164
|
-
};
|
|
165
|
-
</script>
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
import slidesData from "slidev:content";
|
|
2
|
-
import type { SlideData, SlideInfo } from "../../types/slide.js";
|
|
3
|
-
|
|
4
|
-
export function getSlides(): SlideData[] {
|
|
5
|
-
try {
|
|
6
|
-
if (slidesData && slidesData.length > 0) {
|
|
7
|
-
return (slidesData as SlideInfo[]).map((slide) => ({
|
|
8
|
-
id: slide.id,
|
|
9
|
-
title: slide.frontmatter.title || slide.path,
|
|
10
|
-
url: slide.path,
|
|
11
|
-
description:
|
|
12
|
-
slide.frontmatter.info ||
|
|
13
|
-
slide.frontmatter.seoMeta?.ogDescription ||
|
|
14
|
-
"No description available",
|
|
15
|
-
image:
|
|
16
|
-
slide.frontmatter.background ||
|
|
17
|
-
slide.frontmatter.seoMeta?.ogImage ||
|
|
18
|
-
"https://cover.sli.dev",
|
|
19
|
-
author: slide.frontmatter.author || "Unknown Author",
|
|
20
|
-
date: slide.frontmatter.date || new Date().toISOString().split("T")[0],
|
|
21
|
-
theme: slide.frontmatter.theme,
|
|
22
|
-
transition: slide.frontmatter.transition,
|
|
23
|
-
class: slide.frontmatter.class,
|
|
24
|
-
sourceDir: slide.sourceDir,
|
|
25
|
-
path: slide.path,
|
|
26
|
-
fullPath: slide.fullPath,
|
|
27
|
-
frontmatter: slide.frontmatter,
|
|
28
|
-
content: slide.content,
|
|
29
|
-
}));
|
|
30
|
-
}
|
|
31
|
-
} catch (error) {
|
|
32
|
-
console.error("Error reading slides frontmatter:", error);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
return [];
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export function getSlideById(id: string): SlideData | null {
|
|
39
|
-
const slides = getSlides();
|
|
40
|
-
return slides.find((slide) => slide.id === id) || null;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
export function getSlidesBySourceDir(sourceDir: string): SlideData[] {
|
|
44
|
-
const slides = getSlides();
|
|
45
|
-
return slides.filter((slide) => slide.sourceDir === sourceDir);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
export function searchSlides(query: string): SlideData[] {
|
|
49
|
-
const slides = getSlides();
|
|
50
|
-
const lowerQuery = query.toLowerCase();
|
|
51
|
-
|
|
52
|
-
return slides.filter(
|
|
53
|
-
(slide) =>
|
|
54
|
-
slide.title.toLowerCase().includes(lowerQuery) ||
|
|
55
|
-
slide.description.toLowerCase().includes(lowerQuery) ||
|
|
56
|
-
slide.author.toLowerCase().includes(lowerQuery) ||
|
|
57
|
-
(slide.theme && slide.theme.toLowerCase().includes(lowerQuery))
|
|
58
|
-
);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
if (import.meta.hot) {
|
|
62
|
-
import.meta.hot.accept("slidev:content", (_newSlidesData: any) => {
|
|
63
|
-
console.log("Slides data updated");
|
|
64
|
-
});
|
|
65
|
-
}
|