slidev-workspace 0.9.0 → 0.9.1
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/package.json +4 -2
- package/src/preview/components/SlideDeck.vue +227 -46
- package/src/preview/components/ui/drawer/Drawer.vue +22 -0
- package/src/preview/components/ui/drawer/DrawerClose.vue +12 -0
- package/src/preview/components/ui/drawer/DrawerContent.vue +44 -0
- package/src/preview/components/ui/drawer/DrawerDescription.vue +23 -0
- package/src/preview/components/ui/drawer/DrawerFooter.vue +17 -0
- package/src/preview/components/ui/drawer/DrawerHeader.vue +17 -0
- package/src/preview/components/ui/drawer/DrawerOverlay.vue +26 -0
- package/src/preview/components/ui/drawer/DrawerTitle.vue +23 -0
- package/src/preview/components/ui/drawer/DrawerTrigger.vue +12 -0
- package/src/preview/components/ui/drawer/index.ts +9 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "slidev-workspace",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.1",
|
|
4
4
|
"description": "A workspace tool for managing multiple Slidev presentations with API-based content management",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -37,14 +37,16 @@
|
|
|
37
37
|
"dependencies": {
|
|
38
38
|
"@tailwindcss/vite": "^4.1.11",
|
|
39
39
|
"@vitejs/plugin-vue": "^6.0.0",
|
|
40
|
-
"@vueuse/core": "^13.
|
|
40
|
+
"@vueuse/core": "^13.8.0",
|
|
41
41
|
"class-variance-authority": "^0.7.1",
|
|
42
42
|
"clsx": "^2.1.1",
|
|
43
43
|
"commander": "^14.0.0",
|
|
44
44
|
"lucide-vue-next": "^0.525.0",
|
|
45
|
+
"reka-ui": "^2.8.0",
|
|
45
46
|
"tailwind-merge": "^3.3.1",
|
|
46
47
|
"tw-animate-css": "^1.3.5",
|
|
47
48
|
"unhead": "^2.0.19",
|
|
49
|
+
"vaul-vue": "^0.4.1",
|
|
48
50
|
"vite": "npm:rolldown-vite@latest",
|
|
49
51
|
"vue": "^3.5.17",
|
|
50
52
|
"yaml": "^2.8.0"
|
|
@@ -1,14 +1,11 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div class="min-h-screen transition-colors">
|
|
3
|
-
<div
|
|
4
|
-
class="min-h-screen lg:grid lg:grid-cols-[minmax(0,1fr)_280px_minmax(0,3fr)_minmax(0,1fr)]"
|
|
5
|
-
>
|
|
6
|
-
<div class="hidden bg-[#F1F1F1] dark:bg-[#191919] lg:block" />
|
|
2
|
+
<div class="min-h-screen transition-colors sw-page">
|
|
3
|
+
<div class="min-h-screen sw-layout">
|
|
7
4
|
<aside
|
|
8
|
-
class="w-full border-r border-[#E8E8E8] bg-[#F1F1F1] text-sidebar-foreground dark:border-[#212121] dark:bg-[#191919]"
|
|
5
|
+
class="sw-sidebar w-full border-r border-[#E8E8E8] bg-[#F1F1F1] text-sidebar-foreground dark:border-[#212121] dark:bg-[#191919]"
|
|
9
6
|
>
|
|
10
7
|
<div
|
|
11
|
-
class="sticky top-0 flex h-screen flex-col px-6 py-10 text-sidebar-foreground"
|
|
8
|
+
class="sticky top-0 flex h-screen flex-col px-6 py-10 text-sidebar-foreground w-[270px]"
|
|
12
9
|
>
|
|
13
10
|
<div class="px-1 pb-4">
|
|
14
11
|
<h2 class="text-lg font-semibold tracking-tight">
|
|
@@ -84,65 +81,164 @@
|
|
|
84
81
|
</div>
|
|
85
82
|
</aside>
|
|
86
83
|
|
|
87
|
-
<
|
|
88
|
-
<div class="
|
|
89
|
-
<div
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
84
|
+
<header class="sw-header bg-[#F5F5F5] dark:bg-[#121212]">
|
|
85
|
+
<div class="max-w-[900px]">
|
|
86
|
+
<div class="px-6 py-8 lg:px-12 lg:py-10">
|
|
87
|
+
<Drawer direction="left">
|
|
88
|
+
<DrawerTrigger as-child>
|
|
89
|
+
<button
|
|
90
|
+
type="button"
|
|
91
|
+
class="sw-drawer-trigger mb-6 inline-flex items-center justify-center rounded-xl border border-border bg-background p-2 text-sm font-medium shadow-sm transition-colors hover:bg-accent hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
|
92
|
+
aria-label="Open sidebar"
|
|
93
|
+
>
|
|
94
|
+
<PanelLeft class="size-5" />
|
|
95
|
+
</button>
|
|
96
|
+
</DrawerTrigger>
|
|
97
|
+
<DrawerContent
|
|
98
|
+
class="bg-[#F1F1F1] text-sidebar-foreground dark:bg-[#191919]"
|
|
99
|
+
>
|
|
100
|
+
<div
|
|
101
|
+
class="flex h-full flex-col px-6 py-8 text-sidebar-foreground"
|
|
102
|
+
>
|
|
103
|
+
<div class="px-1 pb-4">
|
|
104
|
+
<h2 class="text-lg font-semibold tracking-tight">
|
|
105
|
+
{{ sidebar.title }}
|
|
106
|
+
</h2>
|
|
107
|
+
</div>
|
|
108
|
+
|
|
109
|
+
<div class="px-1 pb-6">
|
|
110
|
+
<div class="relative w-full">
|
|
111
|
+
<Input
|
|
112
|
+
class="pl-10 h-10 rounded-xl bg-background/70"
|
|
113
|
+
placeholder="Search slides..."
|
|
114
|
+
v-model="searchTerm"
|
|
115
|
+
/>
|
|
116
|
+
<span
|
|
117
|
+
class="absolute start-0 inset-y-0 flex items-center justify-center px-3"
|
|
118
|
+
>
|
|
119
|
+
<Search class="size-5 text-muted-foreground/50" />
|
|
120
|
+
</span>
|
|
121
|
+
</div>
|
|
122
|
+
</div>
|
|
123
|
+
|
|
124
|
+
<div class="px-1 pb-2">
|
|
125
|
+
<h3
|
|
126
|
+
class="text-xs font-semibold uppercase tracking-widest text-muted-foreground"
|
|
127
|
+
>
|
|
128
|
+
Categories
|
|
129
|
+
</h3>
|
|
130
|
+
</div>
|
|
131
|
+
|
|
132
|
+
<div class="px-0.5 space-y-1 flex-1 overflow-auto">
|
|
133
|
+
<button
|
|
134
|
+
v-for="category in categoryOptions"
|
|
135
|
+
:key="category.name"
|
|
136
|
+
type="button"
|
|
137
|
+
@click="selectedCategory = category.name"
|
|
138
|
+
class="w-full flex items-center justify-between rounded-xl px-3 py-2 text-left text-sm transition-colors"
|
|
139
|
+
:class="
|
|
140
|
+
selectedCategory === category.name
|
|
141
|
+
? 'bg-sidebar-accent text-sidebar-accent-foreground'
|
|
142
|
+
: 'hover:bg-sidebar-accent/70 text-sidebar-foreground'
|
|
143
|
+
"
|
|
144
|
+
>
|
|
145
|
+
<span class="truncate">{{ category.name }}</span>
|
|
146
|
+
<span class="text-xs text-muted-foreground">{{
|
|
147
|
+
category.count
|
|
148
|
+
}}</span>
|
|
149
|
+
</button>
|
|
150
|
+
</div>
|
|
151
|
+
|
|
152
|
+
<div
|
|
153
|
+
class="mt-auto flex items-center justify-between gap-3 pt-6"
|
|
154
|
+
>
|
|
155
|
+
<a
|
|
156
|
+
v-if="sidebar.githubUrl"
|
|
157
|
+
:href="sidebar.githubUrl"
|
|
158
|
+
target="_blank"
|
|
159
|
+
rel="noreferrer"
|
|
160
|
+
class="inline-flex items-center justify-center rounded-lg p-2 text-muted-foreground hover:bg-accent hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring transition-colors cursor-pointer"
|
|
161
|
+
aria-label="Open GitHub repository"
|
|
162
|
+
>
|
|
163
|
+
<Github class="size-5" />
|
|
164
|
+
</a>
|
|
165
|
+
<div v-else />
|
|
166
|
+
<button
|
|
167
|
+
@click="toggleDarkMode"
|
|
168
|
+
class="p-2 rounded-lg hover:bg-accent focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring transition-colors cursor-pointer"
|
|
169
|
+
aria-label="Toggle dark mode"
|
|
170
|
+
type="button"
|
|
171
|
+
>
|
|
172
|
+
<Moon v-if="!isDark" class="size-5" />
|
|
173
|
+
<Sun v-else class="size-5" />
|
|
174
|
+
</button>
|
|
175
|
+
</div>
|
|
176
|
+
</div>
|
|
177
|
+
</DrawerContent>
|
|
178
|
+
</Drawer>
|
|
179
|
+
|
|
180
|
+
<div
|
|
181
|
+
class="flex flex-col gap-4 md:flex-row md:items-start md:justify-between"
|
|
182
|
+
>
|
|
183
|
+
<div>
|
|
184
|
+
<h1 class="text-3xl font-semibold">{{ hero.title }}</h1>
|
|
185
|
+
<p class="mt-2 text-sm text-muted-foreground">
|
|
186
|
+
{{ hero.description }}
|
|
187
|
+
</p>
|
|
188
|
+
</div>
|
|
189
|
+
<div class="self-start" />
|
|
190
|
+
</div>
|
|
191
|
+
|
|
192
|
+
<div
|
|
193
|
+
class="flex flex-col gap-3 md:mt-6 md:flex-row md:items-center md:justify-between"
|
|
194
|
+
>
|
|
195
|
+
<p class="text-sm text-muted-foreground">
|
|
196
|
+
Found {{ filteredSlides.length }} of {{ slidesCount }} slides
|
|
197
|
+
<template v-if="searchTerm">
|
|
198
|
+
<span>
|
|
199
|
+
containing "
|
|
200
|
+
<span class="font-medium">{{ searchTerm }}</span>
|
|
201
|
+
"
|
|
202
|
+
</span>
|
|
203
|
+
</template>
|
|
96
204
|
</p>
|
|
205
|
+
<div />
|
|
97
206
|
</div>
|
|
98
|
-
<div class="self-start" />
|
|
99
207
|
</div>
|
|
208
|
+
</div>
|
|
209
|
+
</header>
|
|
100
210
|
|
|
211
|
+
<section class="sw-main bg-[#F5F5F5] dark:bg-[#121212]">
|
|
212
|
+
<div class="max-w-[900px]">
|
|
101
213
|
<div
|
|
102
|
-
class="
|
|
214
|
+
class="grid grid-cols-1 gap-6 px-6 pb-12 sm:grid-cols-2 xl:grid-cols-3 lg:px-12"
|
|
103
215
|
>
|
|
104
|
-
<
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
<div />
|
|
216
|
+
<SlideCard
|
|
217
|
+
v-for="slide in filteredSlides"
|
|
218
|
+
:key="slide.url"
|
|
219
|
+
:title="slide.title"
|
|
220
|
+
:image="slide.image"
|
|
221
|
+
:description="slide.description"
|
|
222
|
+
:url="slide.url"
|
|
223
|
+
:author="slide.author"
|
|
224
|
+
:date="slide.date"
|
|
225
|
+
/>
|
|
115
226
|
</div>
|
|
116
227
|
</div>
|
|
117
|
-
|
|
118
|
-
<div
|
|
119
|
-
class="grid grid-cols-1 gap-6 px-6 pb-12 sm:grid-cols-2 xl:grid-cols-3 lg:px-12"
|
|
120
|
-
>
|
|
121
|
-
<SlideCard
|
|
122
|
-
v-for="slide in filteredSlides"
|
|
123
|
-
:key="slide.url"
|
|
124
|
-
:title="slide.title"
|
|
125
|
-
:image="slide.image"
|
|
126
|
-
:description="slide.description"
|
|
127
|
-
:url="slide.url"
|
|
128
|
-
:author="slide.author"
|
|
129
|
-
:date="slide.date"
|
|
130
|
-
/>
|
|
131
|
-
</div>
|
|
132
228
|
</section>
|
|
133
|
-
<div class="hidden bg-[#F5F5F5] dark:bg-[#121212] lg:block" />
|
|
134
229
|
</div>
|
|
135
230
|
</div>
|
|
136
231
|
</template>
|
|
137
232
|
|
|
138
233
|
<script setup lang="ts">
|
|
139
234
|
import { ref, computed, watch } from "vue";
|
|
140
|
-
import { Search, Moon, Sun, Github } from "lucide-vue-next";
|
|
235
|
+
import { Search, Moon, Sun, Github, PanelLeft } from "lucide-vue-next";
|
|
141
236
|
|
|
142
237
|
import { useSlides } from "../composables/useSlides";
|
|
143
238
|
import { useConfig } from "../composables/useConfig";
|
|
144
239
|
import { useDarkMode } from "../composables/useDarkMode";
|
|
145
240
|
import { Input } from "../components/ui/input";
|
|
241
|
+
import { Drawer, DrawerContent, DrawerTrigger } from "../components/ui/drawer";
|
|
146
242
|
import SlideCard from "./SlideCard.vue";
|
|
147
243
|
|
|
148
244
|
const searchTerm = ref("");
|
|
@@ -213,3 +309,88 @@ const filteredSlides = computed(() => {
|
|
|
213
309
|
);
|
|
214
310
|
});
|
|
215
311
|
</script>
|
|
312
|
+
|
|
313
|
+
<style scoped>
|
|
314
|
+
.sw-layout {
|
|
315
|
+
display: grid;
|
|
316
|
+
width: 100%;
|
|
317
|
+
max-width: var(--sw-layout-width, 97rem);
|
|
318
|
+
margin: 0 auto;
|
|
319
|
+
grid-template-columns: var(--sw-sidebar-width, 270px) minmax(0, 1fr);
|
|
320
|
+
grid-template-rows: auto auto 1fr;
|
|
321
|
+
grid-template-areas:
|
|
322
|
+
"sidebar header"
|
|
323
|
+
"sidebar main"
|
|
324
|
+
"sidebar main";
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
.sw-sidebar {
|
|
328
|
+
grid-area: sidebar;
|
|
329
|
+
position: relative;
|
|
330
|
+
display: flex;
|
|
331
|
+
justify-content: flex-end;
|
|
332
|
+
background: var(--sw-sidebar-bg);
|
|
333
|
+
z-index: 0;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
.sw-sidebar::before {
|
|
337
|
+
content: "";
|
|
338
|
+
position: absolute;
|
|
339
|
+
inset: 0;
|
|
340
|
+
left: -100vw;
|
|
341
|
+
background: var(--sw-sidebar-bg);
|
|
342
|
+
z-index: -1;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
.sw-header {
|
|
346
|
+
grid-area: header;
|
|
347
|
+
display: flex;
|
|
348
|
+
justify-content: flex-start;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
.sw-main {
|
|
352
|
+
grid-area: main;
|
|
353
|
+
display: flex;
|
|
354
|
+
justify-content: flex-start;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
.sw-drawer-trigger {
|
|
358
|
+
display: inline-flex;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
.sw-page {
|
|
362
|
+
--sw-sidebar-bg: #f1f1f1;
|
|
363
|
+
--sw-main-bg: #f5f5f5;
|
|
364
|
+
background: var(--sw-main-bg);
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
:global(.dark) .sw-page {
|
|
368
|
+
--sw-sidebar-bg: #191919;
|
|
369
|
+
--sw-main-bg: #121212;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
@media (max-width: 1024px) {
|
|
373
|
+
.sw-layout {
|
|
374
|
+
grid-template-columns: 1fr;
|
|
375
|
+
grid-template-rows: auto auto 1fr;
|
|
376
|
+
grid-template-areas:
|
|
377
|
+
"sidebar"
|
|
378
|
+
"header"
|
|
379
|
+
"main";
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
.sw-sidebar {
|
|
383
|
+
display: none;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
.sw-drawer-trigger {
|
|
387
|
+
display: inline-flex;
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
@media (min-width: 1024px) {
|
|
392
|
+
.sw-drawer-trigger {
|
|
393
|
+
display: none;
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
</style>
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
import type { DrawerRootEmits, DrawerRootProps } from "vaul-vue";
|
|
3
|
+
import { useForwardPropsEmits } from "reka-ui";
|
|
4
|
+
import { DrawerRoot } from "vaul-vue";
|
|
5
|
+
|
|
6
|
+
const props = withDefaults(defineProps<DrawerRootProps>(), {
|
|
7
|
+
shouldScaleBackground: true,
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
const emits = defineEmits<DrawerRootEmits>();
|
|
11
|
+
|
|
12
|
+
const forwarded = useForwardPropsEmits<DrawerRootProps, keyof DrawerRootEmits>(
|
|
13
|
+
props,
|
|
14
|
+
emits,
|
|
15
|
+
);
|
|
16
|
+
</script>
|
|
17
|
+
|
|
18
|
+
<template>
|
|
19
|
+
<DrawerRoot v-slot="slotProps" data-slot="drawer" v-bind="forwarded">
|
|
20
|
+
<slot v-bind="slotProps" />
|
|
21
|
+
</DrawerRoot>
|
|
22
|
+
</template>
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
import type { DrawerCloseProps } from "vaul-vue";
|
|
3
|
+
import { DrawerClose } from "vaul-vue";
|
|
4
|
+
|
|
5
|
+
const props = defineProps<DrawerCloseProps>();
|
|
6
|
+
</script>
|
|
7
|
+
|
|
8
|
+
<template>
|
|
9
|
+
<DrawerClose data-slot="drawer-close" v-bind="props">
|
|
10
|
+
<slot />
|
|
11
|
+
</DrawerClose>
|
|
12
|
+
</template>
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
import type { DialogContentEmits, DialogContentProps } from "reka-ui";
|
|
3
|
+
import type { HTMLAttributes } from "vue";
|
|
4
|
+
import { useForwardPropsEmits } from "reka-ui";
|
|
5
|
+
import { DrawerContent, DrawerPortal } from "vaul-vue";
|
|
6
|
+
import { cn } from "@/lib/utils";
|
|
7
|
+
import DrawerOverlay from "./DrawerOverlay.vue";
|
|
8
|
+
|
|
9
|
+
defineOptions({
|
|
10
|
+
inheritAttrs: false,
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
const props = defineProps<
|
|
14
|
+
DialogContentProps & { class?: HTMLAttributes["class"] }
|
|
15
|
+
>();
|
|
16
|
+
const emits = defineEmits<DialogContentEmits>();
|
|
17
|
+
|
|
18
|
+
const forwarded = useForwardPropsEmits(props, emits);
|
|
19
|
+
</script>
|
|
20
|
+
|
|
21
|
+
<template>
|
|
22
|
+
<DrawerPortal>
|
|
23
|
+
<DrawerOverlay />
|
|
24
|
+
<DrawerContent
|
|
25
|
+
data-slot="drawer-content"
|
|
26
|
+
v-bind="{ ...$attrs, ...forwarded }"
|
|
27
|
+
:class="
|
|
28
|
+
cn(
|
|
29
|
+
'group/drawer-content bg-background fixed z-50 flex h-auto flex-col',
|
|
30
|
+
'data-[vaul-drawer-direction=top]:inset-x-0 data-[vaul-drawer-direction=top]:top-0 data-[vaul-drawer-direction=top]:mb-24 data-[vaul-drawer-direction=top]:max-h-[80vh] data-[vaul-drawer-direction=top]:rounded-b-lg',
|
|
31
|
+
'data-[vaul-drawer-direction=bottom]:inset-x-0 data-[vaul-drawer-direction=bottom]:bottom-0 data-[vaul-drawer-direction=bottom]:mt-24 data-[vaul-drawer-direction=bottom]:max-h-[80vh] data-[vaul-drawer-direction=bottom]:rounded-t-lg',
|
|
32
|
+
'data-[vaul-drawer-direction=right]:inset-y-0 data-[vaul-drawer-direction=right]:right-0 data-[vaul-drawer-direction=right]:w-3/4 data-[vaul-drawer-direction=right]:sm:max-w-sm',
|
|
33
|
+
'data-[vaul-drawer-direction=left]:inset-y-0 data-[vaul-drawer-direction=left]:left-0 data-[vaul-drawer-direction=left]:w-3/4 data-[vaul-drawer-direction=left]:sm:max-w-sm',
|
|
34
|
+
props.class,
|
|
35
|
+
)
|
|
36
|
+
"
|
|
37
|
+
>
|
|
38
|
+
<div
|
|
39
|
+
class="bg-muted mx-auto mt-4 hidden h-2 w-[100px] shrink-0 rounded-full group-data-[vaul-drawer-direction=bottom]/drawer-content:block"
|
|
40
|
+
/>
|
|
41
|
+
<slot />
|
|
42
|
+
</DrawerContent>
|
|
43
|
+
</DrawerPortal>
|
|
44
|
+
</template>
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
import type { DrawerDescriptionProps } from "vaul-vue";
|
|
3
|
+
import type { HTMLAttributes } from "vue";
|
|
4
|
+
import { reactiveOmit } from "@vueuse/core";
|
|
5
|
+
import { DrawerDescription } from "vaul-vue";
|
|
6
|
+
import { cn } from "@/lib/utils";
|
|
7
|
+
|
|
8
|
+
const props = defineProps<
|
|
9
|
+
DrawerDescriptionProps & { class?: HTMLAttributes["class"] }
|
|
10
|
+
>();
|
|
11
|
+
|
|
12
|
+
const delegatedProps = reactiveOmit(props, "class");
|
|
13
|
+
</script>
|
|
14
|
+
|
|
15
|
+
<template>
|
|
16
|
+
<DrawerDescription
|
|
17
|
+
data-slot="drawer-description"
|
|
18
|
+
v-bind="delegatedProps"
|
|
19
|
+
:class="cn('text-muted-foreground text-sm', props.class)"
|
|
20
|
+
>
|
|
21
|
+
<slot />
|
|
22
|
+
</DrawerDescription>
|
|
23
|
+
</template>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
import type { HTMLAttributes } from "vue";
|
|
3
|
+
import { cn } from "@/lib/utils";
|
|
4
|
+
|
|
5
|
+
const props = defineProps<{
|
|
6
|
+
class?: HTMLAttributes["class"];
|
|
7
|
+
}>();
|
|
8
|
+
</script>
|
|
9
|
+
|
|
10
|
+
<template>
|
|
11
|
+
<div
|
|
12
|
+
data-slot="drawer-footer"
|
|
13
|
+
:class="cn('mt-auto flex flex-col gap-2 p-4', props.class)"
|
|
14
|
+
>
|
|
15
|
+
<slot />
|
|
16
|
+
</div>
|
|
17
|
+
</template>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
import type { HTMLAttributes } from "vue";
|
|
3
|
+
import { cn } from "@/lib/utils";
|
|
4
|
+
|
|
5
|
+
const props = defineProps<{
|
|
6
|
+
class?: HTMLAttributes["class"];
|
|
7
|
+
}>();
|
|
8
|
+
</script>
|
|
9
|
+
|
|
10
|
+
<template>
|
|
11
|
+
<div
|
|
12
|
+
data-slot="drawer-header"
|
|
13
|
+
:class="cn('flex flex-col gap-1.5 p-4', props.class)"
|
|
14
|
+
>
|
|
15
|
+
<slot />
|
|
16
|
+
</div>
|
|
17
|
+
</template>
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
import type { DialogOverlayProps } from "reka-ui";
|
|
3
|
+
import type { HTMLAttributes } from "vue";
|
|
4
|
+
import { reactiveOmit } from "@vueuse/core";
|
|
5
|
+
import { DrawerOverlay } from "vaul-vue";
|
|
6
|
+
import { cn } from "@/lib/utils";
|
|
7
|
+
|
|
8
|
+
const props = defineProps<
|
|
9
|
+
DialogOverlayProps & { class?: HTMLAttributes["class"] }
|
|
10
|
+
>();
|
|
11
|
+
|
|
12
|
+
const delegatedProps = reactiveOmit(props, "class");
|
|
13
|
+
</script>
|
|
14
|
+
|
|
15
|
+
<template>
|
|
16
|
+
<DrawerOverlay
|
|
17
|
+
data-slot="drawer-overlay"
|
|
18
|
+
v-bind="delegatedProps"
|
|
19
|
+
:class="
|
|
20
|
+
cn(
|
|
21
|
+
'data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/80',
|
|
22
|
+
props.class,
|
|
23
|
+
)
|
|
24
|
+
"
|
|
25
|
+
/>
|
|
26
|
+
</template>
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
import type { DrawerTitleProps } from "vaul-vue";
|
|
3
|
+
import type { HTMLAttributes } from "vue";
|
|
4
|
+
import { reactiveOmit } from "@vueuse/core";
|
|
5
|
+
import { DrawerTitle } from "vaul-vue";
|
|
6
|
+
import { cn } from "@/lib/utils";
|
|
7
|
+
|
|
8
|
+
const props = defineProps<
|
|
9
|
+
DrawerTitleProps & { class?: HTMLAttributes["class"] }
|
|
10
|
+
>();
|
|
11
|
+
|
|
12
|
+
const delegatedProps = reactiveOmit(props, "class");
|
|
13
|
+
</script>
|
|
14
|
+
|
|
15
|
+
<template>
|
|
16
|
+
<DrawerTitle
|
|
17
|
+
data-slot="drawer-title"
|
|
18
|
+
v-bind="delegatedProps"
|
|
19
|
+
:class="cn('text-foreground font-semibold', props.class)"
|
|
20
|
+
>
|
|
21
|
+
<slot />
|
|
22
|
+
</DrawerTitle>
|
|
23
|
+
</template>
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
import type { DrawerTriggerProps } from "vaul-vue";
|
|
3
|
+
import { DrawerTrigger } from "vaul-vue";
|
|
4
|
+
|
|
5
|
+
const props = defineProps<DrawerTriggerProps>();
|
|
6
|
+
</script>
|
|
7
|
+
|
|
8
|
+
<template>
|
|
9
|
+
<DrawerTrigger data-slot="drawer-trigger" v-bind="props">
|
|
10
|
+
<slot />
|
|
11
|
+
</DrawerTrigger>
|
|
12
|
+
</template>
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export { default as Drawer } from "./Drawer.vue";
|
|
2
|
+
export { default as DrawerClose } from "./DrawerClose.vue";
|
|
3
|
+
export { default as DrawerContent } from "./DrawerContent.vue";
|
|
4
|
+
export { default as DrawerDescription } from "./DrawerDescription.vue";
|
|
5
|
+
export { default as DrawerFooter } from "./DrawerFooter.vue";
|
|
6
|
+
export { default as DrawerHeader } from "./DrawerHeader.vue";
|
|
7
|
+
export { default as DrawerOverlay } from "./DrawerOverlay.vue";
|
|
8
|
+
export { default as DrawerTitle } from "./DrawerTitle.vue";
|
|
9
|
+
export { default as DrawerTrigger } from "./DrawerTrigger.vue";
|