slidev-workspace 0.9.0 → 0.9.2
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 +230 -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.2",
|
|
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-
|
|
5
|
+
class="sw-sidebar w-full border-r border-border text-sidebar-foreground"
|
|
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,162 @@
|
|
|
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">
|
|
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 class="sw-drawer text-sidebar-foreground">
|
|
98
|
+
<div
|
|
99
|
+
class="flex h-full flex-col px-6 py-8 text-sidebar-foreground"
|
|
100
|
+
>
|
|
101
|
+
<div class="px-1 pb-4">
|
|
102
|
+
<h2 class="text-lg font-semibold tracking-tight">
|
|
103
|
+
{{ sidebar.title }}
|
|
104
|
+
</h2>
|
|
105
|
+
</div>
|
|
106
|
+
|
|
107
|
+
<div class="px-1 pb-6">
|
|
108
|
+
<div class="relative w-full">
|
|
109
|
+
<Input
|
|
110
|
+
class="pl-10 h-10 rounded-xl bg-background/70"
|
|
111
|
+
placeholder="Search slides..."
|
|
112
|
+
v-model="searchTerm"
|
|
113
|
+
/>
|
|
114
|
+
<span
|
|
115
|
+
class="absolute start-0 inset-y-0 flex items-center justify-center px-3"
|
|
116
|
+
>
|
|
117
|
+
<Search class="size-5 text-muted-foreground/50" />
|
|
118
|
+
</span>
|
|
119
|
+
</div>
|
|
120
|
+
</div>
|
|
121
|
+
|
|
122
|
+
<div class="px-1 pb-2">
|
|
123
|
+
<h3
|
|
124
|
+
class="text-xs font-semibold uppercase tracking-widest text-muted-foreground"
|
|
125
|
+
>
|
|
126
|
+
Categories
|
|
127
|
+
</h3>
|
|
128
|
+
</div>
|
|
129
|
+
|
|
130
|
+
<div class="px-0.5 space-y-1 flex-1 overflow-auto">
|
|
131
|
+
<button
|
|
132
|
+
v-for="category in categoryOptions"
|
|
133
|
+
:key="category.name"
|
|
134
|
+
type="button"
|
|
135
|
+
@click="selectedCategory = category.name"
|
|
136
|
+
class="w-full flex items-center justify-between rounded-xl px-3 py-2 text-left text-sm transition-colors"
|
|
137
|
+
:class="
|
|
138
|
+
selectedCategory === category.name
|
|
139
|
+
? 'bg-sidebar-accent text-sidebar-accent-foreground'
|
|
140
|
+
: 'hover:bg-sidebar-accent/70 text-sidebar-foreground'
|
|
141
|
+
"
|
|
142
|
+
>
|
|
143
|
+
<span class="truncate">{{ category.name }}</span>
|
|
144
|
+
<span class="text-xs text-muted-foreground">{{
|
|
145
|
+
category.count
|
|
146
|
+
}}</span>
|
|
147
|
+
</button>
|
|
148
|
+
</div>
|
|
149
|
+
|
|
150
|
+
<div
|
|
151
|
+
class="mt-auto flex items-center justify-between gap-3 pt-6"
|
|
152
|
+
>
|
|
153
|
+
<a
|
|
154
|
+
v-if="sidebar.githubUrl"
|
|
155
|
+
:href="sidebar.githubUrl"
|
|
156
|
+
target="_blank"
|
|
157
|
+
rel="noreferrer"
|
|
158
|
+
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"
|
|
159
|
+
aria-label="Open GitHub repository"
|
|
160
|
+
>
|
|
161
|
+
<Github class="size-5" />
|
|
162
|
+
</a>
|
|
163
|
+
<div v-else />
|
|
164
|
+
<button
|
|
165
|
+
@click="toggleDarkMode"
|
|
166
|
+
class="p-2 rounded-lg hover:bg-accent focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring transition-colors cursor-pointer"
|
|
167
|
+
aria-label="Toggle dark mode"
|
|
168
|
+
type="button"
|
|
169
|
+
>
|
|
170
|
+
<Moon v-if="!isDark" class="size-5" />
|
|
171
|
+
<Sun v-else class="size-5" />
|
|
172
|
+
</button>
|
|
173
|
+
</div>
|
|
174
|
+
</div>
|
|
175
|
+
</DrawerContent>
|
|
176
|
+
</Drawer>
|
|
177
|
+
|
|
178
|
+
<div
|
|
179
|
+
class="flex flex-col gap-4 md:flex-row md:items-start md:justify-between"
|
|
180
|
+
>
|
|
181
|
+
<div>
|
|
182
|
+
<h1 class="text-3xl font-semibold">{{ hero.title }}</h1>
|
|
183
|
+
<p class="mt-2 text-sm text-muted-foreground">
|
|
184
|
+
{{ hero.description }}
|
|
185
|
+
</p>
|
|
186
|
+
</div>
|
|
187
|
+
<div class="self-start" />
|
|
188
|
+
</div>
|
|
189
|
+
|
|
190
|
+
<div
|
|
191
|
+
class="flex flex-col gap-3 md:mt-6 md:flex-row md:items-center md:justify-between"
|
|
192
|
+
>
|
|
193
|
+
<p class="text-sm text-muted-foreground">
|
|
194
|
+
Found {{ filteredSlides.length }} of {{ slidesCount }} slides
|
|
195
|
+
<template v-if="searchTerm">
|
|
196
|
+
<span>
|
|
197
|
+
containing "
|
|
198
|
+
<span class="font-medium">{{ searchTerm }}</span>
|
|
199
|
+
"
|
|
200
|
+
</span>
|
|
201
|
+
</template>
|
|
96
202
|
</p>
|
|
203
|
+
<div />
|
|
97
204
|
</div>
|
|
98
|
-
<div class="self-start" />
|
|
99
205
|
</div>
|
|
206
|
+
</div>
|
|
207
|
+
</header>
|
|
100
208
|
|
|
209
|
+
<section class="sw-main">
|
|
210
|
+
<div class="max-w-[900px]">
|
|
101
211
|
<div
|
|
102
|
-
class="
|
|
212
|
+
class="grid grid-cols-1 gap-6 px-6 pb-12 sm:grid-cols-2 xl:grid-cols-3 lg:px-12"
|
|
103
213
|
>
|
|
104
|
-
<
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
<div />
|
|
214
|
+
<SlideCard
|
|
215
|
+
v-for="slide in filteredSlides"
|
|
216
|
+
:key="slide.url"
|
|
217
|
+
:title="slide.title"
|
|
218
|
+
:image="slide.image"
|
|
219
|
+
:description="slide.description"
|
|
220
|
+
:url="slide.url"
|
|
221
|
+
:author="slide.author"
|
|
222
|
+
:date="slide.date"
|
|
223
|
+
/>
|
|
115
224
|
</div>
|
|
116
225
|
</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
226
|
</section>
|
|
133
|
-
<div class="hidden bg-[#F5F5F5] dark:bg-[#121212] lg:block" />
|
|
134
227
|
</div>
|
|
135
228
|
</div>
|
|
136
229
|
</template>
|
|
137
230
|
|
|
138
231
|
<script setup lang="ts">
|
|
139
232
|
import { ref, computed, watch } from "vue";
|
|
140
|
-
import { Search, Moon, Sun, Github } from "lucide-vue-next";
|
|
233
|
+
import { Search, Moon, Sun, Github, PanelLeft } from "lucide-vue-next";
|
|
141
234
|
|
|
142
235
|
import { useSlides } from "../composables/useSlides";
|
|
143
236
|
import { useConfig } from "../composables/useConfig";
|
|
144
237
|
import { useDarkMode } from "../composables/useDarkMode";
|
|
145
238
|
import { Input } from "../components/ui/input";
|
|
239
|
+
import { Drawer, DrawerContent, DrawerTrigger } from "../components/ui/drawer";
|
|
146
240
|
import SlideCard from "./SlideCard.vue";
|
|
147
241
|
|
|
148
242
|
const searchTerm = ref("");
|
|
@@ -213,3 +307,93 @@ const filteredSlides = computed(() => {
|
|
|
213
307
|
);
|
|
214
308
|
});
|
|
215
309
|
</script>
|
|
310
|
+
|
|
311
|
+
<style scoped>
|
|
312
|
+
.sw-layout {
|
|
313
|
+
display: grid;
|
|
314
|
+
width: 100%;
|
|
315
|
+
max-width: var(--sw-layout-width, 97rem);
|
|
316
|
+
margin: 0 auto;
|
|
317
|
+
grid-template-columns: var(--sw-sidebar-width, 270px) minmax(0, 1fr);
|
|
318
|
+
grid-template-rows: auto auto 1fr;
|
|
319
|
+
grid-template-areas:
|
|
320
|
+
"sidebar header"
|
|
321
|
+
"sidebar main"
|
|
322
|
+
"sidebar main";
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
.sw-sidebar {
|
|
326
|
+
grid-area: sidebar;
|
|
327
|
+
position: relative;
|
|
328
|
+
display: flex;
|
|
329
|
+
justify-content: flex-end;
|
|
330
|
+
background: var(--sw-sidebar-bg);
|
|
331
|
+
z-index: 0;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
.sw-sidebar::before {
|
|
335
|
+
content: "";
|
|
336
|
+
position: absolute;
|
|
337
|
+
inset: 0;
|
|
338
|
+
left: -100vw;
|
|
339
|
+
background: var(--sw-sidebar-bg);
|
|
340
|
+
z-index: -1;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
.sw-header {
|
|
344
|
+
grid-area: header;
|
|
345
|
+
display: flex;
|
|
346
|
+
justify-content: flex-start;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
.sw-main {
|
|
350
|
+
grid-area: main;
|
|
351
|
+
display: flex;
|
|
352
|
+
justify-content: flex-start;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
.sw-drawer-trigger {
|
|
356
|
+
display: inline-flex;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
.sw-page {
|
|
360
|
+
background: var(--sw-main-bg);
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
:global(:root) {
|
|
364
|
+
--sw-sidebar-bg: #f1f1f1;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
:global(.dark) {
|
|
368
|
+
--sw-sidebar-bg: #191919;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
:global(.sw-drawer) {
|
|
372
|
+
background: var(--sw-sidebar-bg);
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
@media (max-width: 1024px) {
|
|
376
|
+
.sw-layout {
|
|
377
|
+
grid-template-columns: 1fr;
|
|
378
|
+
grid-template-rows: auto auto 1fr;
|
|
379
|
+
grid-template-areas:
|
|
380
|
+
"sidebar"
|
|
381
|
+
"header"
|
|
382
|
+
"main";
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
.sw-sidebar {
|
|
386
|
+
display: none;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
.sw-drawer-trigger {
|
|
390
|
+
display: inline-flex;
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
@media (min-width: 1024px) {
|
|
395
|
+
.sw-drawer-trigger {
|
|
396
|
+
display: none;
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
</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";
|