fulldev-ui 0.11.1 → 0.13.0

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.
Files changed (166) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/package.json +29 -21
  3. package/public/r/accordion.json +2 -2
  4. package/public/r/alert-dialog.json +2 -2
  5. package/public/r/aspect-ratio.json +23 -0
  6. package/public/r/attachment.json +66 -0
  7. package/public/r/banner.json +0 -4
  8. package/public/r/blocks-1.json +1 -1
  9. package/public/r/button-group.json +41 -0
  10. package/public/r/button.json +1 -1
  11. package/public/r/carousel.json +8 -8
  12. package/public/r/collapsible.json +2 -2
  13. package/public/r/combobox.json +6 -5
  14. package/public/r/command.json +5 -4
  15. package/public/r/components.json +8 -0
  16. package/public/r/dialog.json +2 -2
  17. package/public/r/doc-1.json +1 -1
  18. package/public/r/drawer.json +109 -0
  19. package/public/r/dropdown-menu.json +4 -4
  20. package/public/r/hover-card.json +4 -4
  21. package/public/r/init.json +1 -1
  22. package/public/r/input-group.json +0 -1
  23. package/public/r/layout.json +3 -0
  24. package/public/r/navigation-menu.json +3 -3
  25. package/public/r/pagination.json +59 -0
  26. package/public/r/popover.json +3 -3
  27. package/public/r/radio-group.json +2 -2
  28. package/public/r/registry.json +418 -28
  29. package/public/r/resizable.json +36 -0
  30. package/public/r/reviews-3.json +1 -1
  31. package/public/r/select.json +3 -3
  32. package/public/r/sheet.json +2 -2
  33. package/public/r/sidebar-1.json +1 -1
  34. package/public/r/sidebar.json +1 -1
  35. package/public/r/slider.json +2 -2
  36. package/public/r/switch.json +2 -2
  37. package/public/r/tabs.json +4 -4
  38. package/public/r/toast.json +80 -0
  39. package/public/r/toggle-group.json +34 -0
  40. package/public/r/toggle.json +2 -2
  41. package/public/r/tooltip.json +3 -3
  42. package/public/r/typography.json +21 -16
  43. package/registry/init/global.css +2 -0
  44. package/registry.json +384 -23
  45. package/src/components/blocks/blocks-1.astro +23 -23
  46. package/src/components/blocks/doc-1.astro +116 -26
  47. package/src/components/blocks/reviews-3.astro +1 -1
  48. package/src/components/blocks/sidebar-1.astro +46 -44
  49. package/src/components/ui/accordion/accordion.astro +8 -2
  50. package/src/components/ui/alert-dialog/alert-dialog.astro +8 -2
  51. package/src/components/ui/aspect-ratio/aspect-ratio.astro +25 -0
  52. package/src/components/ui/aspect-ratio/index.ts +1 -0
  53. package/src/components/ui/attachment/attachment-action.astro +20 -0
  54. package/src/components/ui/attachment/attachment-actions.astro +20 -0
  55. package/src/components/ui/attachment/attachment-content.astro +20 -0
  56. package/src/components/ui/attachment/attachment-description.astro +20 -0
  57. package/src/components/ui/attachment/attachment-group.astro +20 -0
  58. package/src/components/ui/attachment/attachment-media.astro +36 -0
  59. package/src/components/ui/attachment/attachment-title.astro +20 -0
  60. package/src/components/ui/attachment/attachment-trigger.astro +24 -0
  61. package/src/components/ui/attachment/attachment.astro +52 -0
  62. package/src/components/ui/attachment/index.ts +9 -0
  63. package/src/components/ui/button/button.astro +4 -1
  64. package/src/components/ui/button-group/button-group-separator.astro +29 -0
  65. package/src/components/ui/button-group/button-group-text.astro +20 -0
  66. package/src/components/ui/button-group/button-group-variants.ts +20 -0
  67. package/src/components/ui/button-group/button-group.astro +30 -0
  68. package/src/components/ui/button-group/index.ts +7 -0
  69. package/src/components/ui/carousel/carousel-content.astro +11 -13
  70. package/src/components/ui/carousel/carousel-item.astro +2 -5
  71. package/src/components/ui/carousel/carousel-next.astro +0 -3
  72. package/src/components/ui/carousel/carousel-previous.astro +0 -3
  73. package/src/components/ui/carousel/carousel.astro +19 -219
  74. package/src/components/ui/carousel/index.ts +1 -5
  75. package/src/components/ui/collapsible/collapsible.astro +8 -2
  76. package/src/components/ui/combobox/combobox-content.astro +1 -1
  77. package/src/components/ui/combobox/combobox-input.astro +11 -4
  78. package/src/components/ui/combobox/combobox-trigger.astro +7 -7
  79. package/src/components/ui/combobox/combobox.astro +9 -17
  80. package/src/components/ui/command/command-dialog.astro +1 -0
  81. package/src/components/ui/command/command.astro +40 -25
  82. package/src/components/ui/dialog/dialog.astro +8 -2
  83. package/src/components/ui/drawer/drawer-close.astro +13 -0
  84. package/src/components/ui/drawer/drawer-content.astro +43 -0
  85. package/src/components/ui/drawer/drawer-description.astro +17 -0
  86. package/src/components/ui/drawer/drawer-footer.astro +17 -0
  87. package/src/components/ui/drawer/drawer-header.astro +17 -0
  88. package/src/components/ui/drawer/drawer-indent-background.astro +11 -0
  89. package/src/components/ui/drawer/drawer-indent.astro +11 -0
  90. package/src/components/ui/drawer/drawer-overlay.astro +21 -0
  91. package/src/components/ui/drawer/drawer-popup.astro +36 -0
  92. package/src/components/ui/drawer/drawer-portal.astro +27 -0
  93. package/src/components/ui/drawer/drawer-provider.astro +11 -0
  94. package/src/components/ui/drawer/drawer-swipe-handle.astro +20 -0
  95. package/src/components/ui/drawer/drawer-title.astro +17 -0
  96. package/src/components/ui/drawer/drawer-trigger.astro +21 -0
  97. package/src/components/ui/drawer/drawer-viewport.astro +21 -0
  98. package/src/components/ui/drawer/drawer-virtual-keyboard-provider.astro +11 -0
  99. package/src/components/ui/drawer/drawer.astro +60 -0
  100. package/src/components/ui/drawer/index.ts +28 -0
  101. package/src/components/ui/dropdown-menu/dropdown-menu-content.astro +1 -1
  102. package/src/components/ui/dropdown-menu/dropdown-menu-item.astro +40 -9
  103. package/src/components/ui/dropdown-menu/dropdown-menu.astro +8 -2
  104. package/src/components/ui/hover-card/hover-card-content.astro +1 -1
  105. package/src/components/ui/hover-card/hover-card.astro +15 -4
  106. package/src/components/ui/navigation-menu/navigation-menu-positioner.astro +1 -1
  107. package/src/components/ui/navigation-menu/navigation-menu.astro +13 -4
  108. package/src/components/ui/pagination/index.ts +7 -0
  109. package/src/components/ui/pagination/pagination-content.astro +17 -0
  110. package/src/components/ui/pagination/pagination-ellipsis.astro +22 -0
  111. package/src/components/ui/pagination/pagination-item.astro +11 -0
  112. package/src/components/ui/pagination/pagination-link.astro +41 -0
  113. package/src/components/ui/pagination/pagination-next.astro +27 -0
  114. package/src/components/ui/pagination/pagination-previous.astro +27 -0
  115. package/src/components/ui/pagination/pagination.astro +19 -0
  116. package/src/components/ui/popover/popover-content.astro +2 -1
  117. package/src/components/ui/popover/popover.astro +9 -2
  118. package/src/components/ui/radio-group/radio-group.astro +8 -2
  119. package/src/components/ui/resizable/index.ts +4 -0
  120. package/src/components/ui/resizable/resizable-handle.astro +32 -0
  121. package/src/components/ui/resizable/resizable-panel.astro +36 -0
  122. package/src/components/ui/resizable/resizable.astro +43 -0
  123. package/src/components/ui/select/select-content.astro +2 -2
  124. package/src/components/ui/select/select.astro +11 -7
  125. package/src/components/ui/sheet/sheet.astro +8 -2
  126. package/src/components/ui/slider/slider.astro +9 -3
  127. package/src/components/ui/switch/switch.astro +8 -2
  128. package/src/components/ui/tabs/tabs-content.astro +1 -1
  129. package/src/components/ui/tabs/tabs-trigger.astro +3 -2
  130. package/src/components/ui/tabs/tabs.astro +8 -2
  131. package/src/components/ui/toast/index.ts +26 -0
  132. package/src/components/ui/toast/toast-action.astro +25 -0
  133. package/src/components/ui/toast/toast-close.astro +27 -0
  134. package/src/components/ui/toast/toast-content.astro +20 -0
  135. package/src/components/ui/toast/toast-description.astro +18 -0
  136. package/src/components/ui/toast/toast-icon.astro +37 -0
  137. package/src/components/ui/toast/toast-item.astro +28 -0
  138. package/src/components/ui/toast/toast-template.astro +11 -0
  139. package/src/components/ui/toast/toast-title.astro +17 -0
  140. package/src/components/ui/toast/toast-viewport.astro +20 -0
  141. package/src/components/ui/toast/toast.astro +51 -0
  142. package/src/components/ui/toast/toaster.astro +37 -0
  143. package/src/components/ui/toggle/toggle.astro +8 -2
  144. package/src/components/ui/toggle-group/index.ts +2 -0
  145. package/src/components/ui/toggle-group/toggle-group-item.astro +44 -0
  146. package/src/components/ui/toggle-group/toggle-group.astro +74 -0
  147. package/src/components/ui/tooltip/tooltip-content.astro +1 -1
  148. package/src/components/ui/tooltip/tooltip.astro +11 -2
  149. package/src/components/ui/typography/typeset.css +441 -0
  150. package/src/components/ui/typography/typography-a.astro +13 -22
  151. package/src/components/ui/typography/typography-blockquote.astro +4 -23
  152. package/src/components/ui/typography/typography-h1.astro +13 -26
  153. package/src/components/ui/typography/typography-h2.astro +13 -31
  154. package/src/components/ui/typography/typography-h3.astro +9 -26
  155. package/src/components/ui/typography/typography-h4.astro +9 -26
  156. package/src/components/ui/typography/typography-inline-code.astro +8 -27
  157. package/src/components/ui/typography/typography-lead.astro +4 -26
  158. package/src/components/ui/typography/typography-list-item.astro +4 -24
  159. package/src/components/ui/typography/typography-list.astro +10 -40
  160. package/src/components/ui/typography/typography-p.astro +9 -28
  161. package/src/components/ui/typography/typography-table-cell.astro +9 -40
  162. package/src/components/ui/typography/typography-table-head.astro +9 -35
  163. package/src/components/ui/typography/typography-table-row.astro +4 -23
  164. package/src/components/ui/typography/typography-table.astro +8 -28
  165. package/src/components/ui/typography/typography.astro +10 -283
  166. package/src/styles/global.css +2 -0
@@ -15,6 +15,7 @@ import { buttonVariants } from "@/components/ui/button/button-variants"
15
15
  import {
16
16
  DropdownMenu,
17
17
  DropdownMenuContent,
18
+ DropdownMenuItem,
18
19
  DropdownMenuTrigger,
19
20
  } from "@/components/ui/dropdown-menu"
20
21
  import { SectionContainer } from "@/components/ui/section"
@@ -129,6 +130,7 @@ const openLinks = markdownUrl
129
130
  variant="outline"
130
131
  size="xs"
131
132
  data-source={copyButton?.source}
133
+ data-blocks-copy
132
134
  aria-label={labels.copyMarkdown}
133
135
  >
134
136
  <Copy class="blocks-copy-icon size-3.5" />
@@ -148,11 +150,10 @@ const openLinks = markdownUrl
148
150
  </DropdownMenuTrigger>
149
151
  <DropdownMenuContent align="end" sideOffset={6} class="w-56">
150
152
  {openLinks.map((link) => (
151
- <a
153
+ <DropdownMenuItem
152
154
  href={link.href}
153
155
  target="_blank"
154
156
  rel="noreferrer noopener"
155
- class="hover:bg-accent hover:text-accent-foreground flex items-center gap-2 rounded-sm px-2 py-1.5 text-sm transition-colors outline-none"
156
157
  >
157
158
  {link.icon === "markdown" && <Markdown class="size-4" />}
158
159
  {link.icon === "chatgpt" && (
@@ -170,7 +171,7 @@ const openLinks = markdownUrl
170
171
  {link.icon === "cursor" && <Cursor class="size-4" />}
171
172
  <span>{link.label}</span>
172
173
  <ExternalLink class="text-muted-foreground ml-auto size-3.5" />
173
- </a>
174
+ </DropdownMenuItem>
174
175
  ))}
175
176
  </DropdownMenuContent>
176
177
  </DropdownMenu>
@@ -224,27 +225,26 @@ const openLinks = markdownUrl
224
225
  </div>
225
226
  </SectionContainer>
226
227
 
227
- <script is:inline define:vars={{ copyButtonId: copyButton?.id }}>
228
- const button = copyButtonId ? document.getElementById(copyButtonId) : null
228
+ <script>
229
+ document.addEventListener("click", async (event) => {
230
+ if (!(event.target instanceof Element)) return
231
+ const button = event.target.closest("[data-blocks-copy]")
232
+ if (!(button instanceof HTMLButtonElement)) return
229
233
 
230
- if (button instanceof HTMLButtonElement) {
231
- button.addEventListener("click", async () => {
232
- const source = button.dataset.source
234
+ const source = button.dataset.source
235
+ if (!source) return
233
236
 
234
- if (!source) return
237
+ try {
238
+ await navigator.clipboard.writeText(source)
239
+ button.querySelector(".blocks-copy-icon")?.classList.add("hidden")
240
+ button.querySelector(".blocks-check-icon")?.classList.remove("hidden")
235
241
 
236
- try {
237
- await navigator.clipboard.writeText(source)
238
- button.querySelector(".blocks-copy-icon")?.classList.add("hidden")
239
- button.querySelector(".blocks-check-icon")?.classList.remove("hidden")
240
-
241
- window.setTimeout(() => {
242
- button.querySelector(".blocks-copy-icon")?.classList.remove("hidden")
243
- button.querySelector(".blocks-check-icon")?.classList.add("hidden")
244
- }, 1200)
245
- } catch {
246
- // Ignore clipboard failures; the button remains available for retry.
247
- }
248
- })
249
- }
242
+ window.setTimeout(() => {
243
+ button.querySelector(".blocks-copy-icon")?.classList.remove("hidden")
244
+ button.querySelector(".blocks-check-icon")?.classList.add("hidden")
245
+ }, 1200)
246
+ } catch {
247
+ // Keep the copy state unchanged so the action can be retried.
248
+ }
249
+ })
250
250
  </script>
@@ -21,6 +21,7 @@ import {
21
21
  import {
22
22
  DropdownMenu,
23
23
  DropdownMenuContent,
24
+ DropdownMenuItem,
24
25
  DropdownMenuTrigger,
25
26
  } from "@/components/ui/dropdown-menu"
26
27
  import { SectionContainer } from "@/components/ui/section"
@@ -180,11 +181,10 @@ const openLinks = markdownUrl
180
181
  </DropdownMenuTrigger>
181
182
  <DropdownMenuContent align="end" sideOffset={6} class="w-56">
182
183
  {openLinks.map((link) => (
183
- <a
184
+ <DropdownMenuItem
184
185
  href={link.href}
185
186
  target="_blank"
186
187
  rel="noreferrer noopener"
187
- class="hover:bg-accent hover:text-accent-foreground flex items-center gap-2 rounded-sm px-2 py-1.5 text-sm transition-colors outline-none"
188
188
  >
189
189
  {link.icon === "markdown" && <Markdown class="size-4" />}
190
190
  {link.icon === "chatgpt" && (
@@ -202,7 +202,7 @@ const openLinks = markdownUrl
202
202
  {link.icon === "cursor" && <Cursor class="size-4" />}
203
203
  <span>{link.label}</span>
204
204
  <ExternalLink class="text-muted-foreground ml-auto size-3.5" />
205
- </a>
205
+ </DropdownMenuItem>
206
206
  ))}
207
207
  </DropdownMenuContent>
208
208
  </DropdownMenu>
@@ -299,38 +299,128 @@ const openLinks = markdownUrl
299
299
  }
300
300
  </SectionContainer>
301
301
 
302
- <script is:inline>
302
+ <style is:global>
303
+ .docs-code-block {
304
+ position: relative;
305
+ overflow: hidden;
306
+ margin-block-start: var(--typeset-flow);
307
+ border: 1px solid var(--color-border);
308
+ border-radius: var(--radius-xl);
309
+ background: color-mix(in oklab, var(--color-muted) 60%, transparent);
310
+ }
311
+
312
+ .docs-code-block > pre,
313
+ .docs-code-block > pre.astro-code {
314
+ margin: 0;
315
+ overflow-x: auto;
316
+ border: 0;
317
+ border-radius: 0;
318
+ background: transparent !important;
319
+ padding: 1rem 3.5rem 1rem 1rem;
320
+ font-family: var(--font-mono);
321
+ font-size: var(--text-sm);
322
+ line-height: var(--text-sm--line-height);
323
+ }
324
+
325
+ .docs-code-block > pre.astro-code code {
326
+ color: var(--shiki-light, var(--color-foreground)) !important;
327
+ font: inherit;
328
+ }
329
+
330
+ .dark .docs-code-block > pre.astro-code code {
331
+ color: var(--shiki-dark, var(--color-foreground)) !important;
332
+ }
333
+
334
+ .dark .docs-code-block > pre.astro-code span[style*="--shiki-dark"] {
335
+ color: var(--shiki-dark) !important;
336
+ font-style: var(--shiki-dark-font-style, inherit) !important;
337
+ font-weight: var(--shiki-dark-font-weight, inherit) !important;
338
+ text-decoration: var(--shiki-dark-text-decoration, inherit) !important;
339
+ }
340
+
341
+ .docs-code-copy {
342
+ position: absolute;
343
+ z-index: 10;
344
+ top: 0.75rem;
345
+ right: 0.75rem;
346
+ display: inline-flex;
347
+ width: 2rem;
348
+ height: 2rem;
349
+ align-items: center;
350
+ justify-content: center;
351
+ border: 1px solid var(--color-border);
352
+ border-radius: var(--radius-md);
353
+ background: var(--color-background);
354
+ color: var(--color-muted-foreground);
355
+ box-shadow: var(--shadow-sm);
356
+ transition:
357
+ color 150ms,
358
+ background-color 150ms;
359
+ }
360
+
361
+ .docs-code-copy:hover {
362
+ background: var(--color-accent);
363
+ color: var(--color-accent-foreground);
364
+ }
365
+
366
+ .docs-code-copy:focus-visible {
367
+ outline: 2px solid var(--color-ring);
368
+ outline-offset: 2px;
369
+ }
370
+
371
+ .docs-code-copy svg {
372
+ width: 1rem;
373
+ height: 1rem;
374
+ }
375
+ </style>
376
+
377
+ <script>
303
378
  const copyIcon = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect width="14" height="14" x="8" y="8" rx="2" ry="2"></rect><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"></path></svg>`
304
379
  const checkIcon = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5"></path></svg>`
305
- document.querySelectorAll("[data-slot='typography'] > pre").forEach((pre) => {
306
- if (pre.closest(".docs-code-block")) return
307
- const wrapper = document.createElement("div")
308
- const button = document.createElement("button")
309
- wrapper.className = "docs-code-block"
310
- button.type = "button"
311
- button.className = "docs-code-copy"
312
- button.ariaLabel = "Copy code"
313
- button.innerHTML = `<span data-copy-icon>${copyIcon}</span><span data-check-icon class="hidden">${checkIcon}</span>`
314
- pre.before(wrapper)
315
- wrapper.append(pre, button)
316
- })
317
- document.addEventListener("click", (event) => {
318
- const button = event.target?.closest?.(
380
+ const initializeCodeBlocks = () => {
381
+ document
382
+ .querySelectorAll("[data-slot='typography'] > pre")
383
+ .forEach((pre) => {
384
+ if (pre.closest(".docs-code-block")) return
385
+ const wrapper = document.createElement("div")
386
+ const button = document.createElement("button")
387
+ wrapper.className = "docs-code-block"
388
+ wrapper.dataset.notTypeset = ""
389
+ button.type = "button"
390
+ button.className = "docs-code-copy"
391
+ button.ariaLabel = "Copy code"
392
+ button.innerHTML = `<span data-copy-icon>${copyIcon}</span><span data-check-icon class="hidden">${checkIcon}</span>`
393
+ pre.before(wrapper)
394
+ wrapper.append(pre, button)
395
+ })
396
+ }
397
+
398
+ initializeCodeBlocks()
399
+ document.addEventListener("astro:page-load", initializeCodeBlocks)
400
+
401
+ document.addEventListener("click", async (event) => {
402
+ if (!(event.target instanceof Element)) return
403
+ const button = event.target.closest(
319
404
  "[id^='docs-copy-page-'], .docs-code-copy"
320
405
  )
321
- if (!button) return
406
+ if (!(button instanceof HTMLButtonElement)) return
322
407
  const source =
323
408
  button.dataset.source ??
324
409
  button
325
410
  .closest(".docs-code-block")
326
411
  ?.querySelector("pre")
327
412
  ?.textContent?.replace(/\n$/, "")
328
- button.querySelector("[data-copy-icon]")?.classList.add("hidden")
329
- button.querySelector("[data-check-icon]")?.classList.remove("hidden")
330
- navigator.clipboard?.writeText(source ?? "")
331
- setTimeout(() => {
332
- button.querySelector("[data-copy-icon]")?.classList.remove("hidden")
333
- button.querySelector("[data-check-icon]")?.classList.add("hidden")
334
- }, 1200)
413
+
414
+ try {
415
+ await navigator.clipboard.writeText(source ?? "")
416
+ button.querySelector("[data-copy-icon]")?.classList.add("hidden")
417
+ button.querySelector("[data-check-icon]")?.classList.remove("hidden")
418
+ setTimeout(() => {
419
+ button.querySelector("[data-copy-icon]")?.classList.remove("hidden")
420
+ button.querySelector("[data-check-icon]")?.classList.add("hidden")
421
+ }, 1200)
422
+ } catch {
423
+ // Keep the copy state unchanged so the action can be retried.
424
+ }
335
425
  })
336
426
  </script>
@@ -50,7 +50,7 @@ const { class: className, title, description, reviews, ...props } = Astro.props
50
50
  )
51
51
  }
52
52
  <SectionContainer>
53
- <Carousel opts={{ loop: true, align: "center" }} class="mx-auto max-w-3xl">
53
+ <Carousel loop drag class="mx-auto w-[calc(100%-6rem)] max-w-3xl">
54
54
  <CarouselContent>
55
55
  {
56
56
  reviews.map((item) => (
@@ -23,11 +23,12 @@ import {
23
23
  CommandList,
24
24
  CommandShortcut,
25
25
  } from "@/components/ui/command"
26
- import { Dialog, DialogTrigger } from "@/components/ui/dialog"
26
+ import { DialogTrigger } from "@/components/ui/dialog"
27
27
  import {
28
28
  DropdownMenu,
29
29
  DropdownMenuContent,
30
30
  DropdownMenuGroup,
31
+ DropdownMenuItem,
31
32
  DropdownMenuTrigger,
32
33
  } from "@/components/ui/dropdown-menu"
33
34
  import { Header, HeaderContainer, HeaderGroup } from "@/components/ui/header"
@@ -139,7 +140,7 @@ try {
139
140
  <SidebarProvider>
140
141
  <Sidebar class={cn("", className)} collapsible="offcanvas" variant="inset">
141
142
  <SidebarHeader class="flex-col">
142
- <SidebarMenuButton size="lg" variant="ghost" href={logo.href}>
143
+ <SidebarMenuButton size="lg" href={logo.href}>
143
144
  <LogoImage
144
145
  src={logo.src}
145
146
  srcLight={logo.srcLight}
@@ -148,8 +149,14 @@ try {
148
149
  />
149
150
  <LogoText class="font-semibold">{logo.label}</LogoText>
150
151
  </SidebarMenuButton>
151
- <Dialog class="w-full" data-search-dialog>
152
+ <CommandDialog
153
+ class="w-full"
154
+ data-search-dialog
155
+ title={search.label}
156
+ description={search.label}
157
+ >
152
158
  <DialogTrigger
159
+ slot="trigger"
153
160
  variant="outline"
154
161
  size="sm"
155
162
  class="w-full justify-start shadow-none"
@@ -165,40 +172,38 @@ try {
165
172
  </Kbd>
166
173
  </DialogTrigger>
167
174
 
168
- <CommandDialog title={search.label} description={search.label}>
169
- <Command
170
- class="[&_[data-slot=command-item][data-selected]]:bg-accent [&_[data-slot=command-item][data-selected]]:text-accent-foreground"
171
- >
172
- <CommandInput placeholder={search.label} />
173
- <CommandList>
174
- <CommandEmpty>{search.empty}</CommandEmpty>
175
+ <Command
176
+ class="[&_[data-slot=command-item][data-selected]]:bg-accent [&_[data-slot=command-item][data-selected]]:text-accent-foreground"
177
+ >
178
+ <CommandInput autofocus placeholder={search.label} />
179
+ <CommandList>
180
+ <CommandEmpty>{search.empty}</CommandEmpty>
175
181
 
176
- {
177
- searchGroups.map((group) => (
178
- <CommandGroup heading={group.label}>
179
- {group.items.map((item) => (
180
- <CommandItem
181
- href={item.href}
182
- value={`${item.group} ${item.label}`}
183
- label={item.label}
184
- keywords={[
185
- item.group,
186
- item.title,
187
- item.path,
188
- item.description,
189
- ]}
190
- >
191
- {item.label}
192
- <CommandShortcut>{item.href}</CommandShortcut>
193
- </CommandItem>
194
- ))}
195
- </CommandGroup>
196
- ))
197
- }
198
- </CommandList>
199
- </Command>
200
- </CommandDialog>
201
- </Dialog>
182
+ {
183
+ searchGroups.map((group) => (
184
+ <CommandGroup heading={group.label}>
185
+ {group.items.map((item) => (
186
+ <CommandItem
187
+ href={item.href}
188
+ value={`${item.group} ${item.label}`}
189
+ label={item.label}
190
+ keywords={[
191
+ item.group,
192
+ item.title,
193
+ item.path,
194
+ item.description,
195
+ ]}
196
+ >
197
+ {item.label}
198
+ <CommandShortcut>{item.href}</CommandShortcut>
199
+ </CommandItem>
200
+ ))}
201
+ </CommandGroup>
202
+ ))
203
+ }
204
+ </CommandList>
205
+ </Command>
206
+ </CommandDialog>
202
207
  </SidebarHeader>
203
208
  <SidebarContent
204
209
  class="[mask-image:linear-gradient(to_bottom,transparent,black_1rem,black_calc(100%_-_1rem),transparent)] [-webkit-mask-image:linear-gradient(to_bottom,transparent,black_1rem,black_calc(100%_-_1rem),transparent)] group-data-[collapsible=icon]:[mask-image:none] group-data-[collapsible=icon]:[-webkit-mask-image:none]"
@@ -268,7 +273,7 @@ try {
268
273
  <DropdownMenuContent align="start">
269
274
  <DropdownMenuGroup>
270
275
  {breadcrumb.menu.map((menuItem) => (
271
- <a
276
+ <DropdownMenuItem
272
277
  href={menuItem.href}
273
278
  aria-current={
274
279
  normalizePath(menuItem.href) ===
@@ -276,10 +281,10 @@ try {
276
281
  ? "page"
277
282
  : undefined
278
283
  }
279
- class="hover:bg-accent hover:text-accent-foreground aria-[current=page]:text-foreground flex items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none select-none"
284
+ class="aria-[current=page]:text-foreground"
280
285
  >
281
286
  {menuItem.label}
282
- </a>
287
+ </DropdownMenuItem>
283
288
  ))}
284
289
  </DropdownMenuGroup>
285
290
  </DropdownMenuContent>
@@ -308,12 +313,9 @@ try {
308
313
  <DropdownMenuContent align="start">
309
314
  <DropdownMenuGroup>
310
315
  {breadcrumb.menu.map((item) => (
311
- <a
312
- href={item.href}
313
- class="hover:bg-accent hover:text-accent-foreground flex items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none select-none"
314
- >
316
+ <DropdownMenuItem href={item.href}>
315
317
  {item.label}
316
- </a>
318
+ </DropdownMenuItem>
317
319
  ))}
318
320
  </DropdownMenuGroup>
319
321
  </DropdownMenuContent>
@@ -48,6 +48,12 @@ const serializedDefaultValue = Array.isArray(defaultValue)
48
48
  <script>
49
49
  import { create } from "@data-slot/accordion"
50
50
 
51
- create()
52
- document.addEventListener("astro:page-load", () => create())
51
+ const controllers: ReturnType<typeof create> = []
52
+ const initialize = () => controllers.push(...create())
53
+ initialize()
54
+ document.addEventListener("astro:page-load", initialize)
55
+ document.addEventListener("astro:before-swap", () => {
56
+ for (const controller of controllers) controller.destroy()
57
+ controllers.length = 0
58
+ })
53
59
  </script>
@@ -33,6 +33,12 @@ const {
33
33
  <script>
34
34
  import { create } from "@data-slot/alert-dialog"
35
35
 
36
- create()
37
- document.addEventListener("astro:page-load", () => create())
36
+ const controllers: ReturnType<typeof create> = []
37
+ const initialize = () => controllers.push(...create())
38
+ initialize()
39
+ document.addEventListener("astro:page-load", initialize)
40
+ document.addEventListener("astro:before-swap", () => {
41
+ for (const controller of controllers) controller.destroy()
42
+ controllers.length = 0
43
+ })
38
44
  </script>
@@ -0,0 +1,25 @@
1
+ ---
2
+ import type { HTMLAttributes } from "astro/types"
3
+
4
+ import { cn } from "@/lib/utils"
5
+
6
+ type Props = HTMLAttributes<"div"> & {
7
+ ratio: number
8
+ }
9
+
10
+ const { class: className, ratio, style, ...props } = Astro.props
11
+
12
+ const resolvedStyle =
13
+ typeof style === "string"
14
+ ? `--ratio: ${ratio}; ${style}`
15
+ : { "--ratio": ratio, ...(style ?? {}) }
16
+ ---
17
+
18
+ <div
19
+ data-slot="aspect-ratio"
20
+ style={resolvedStyle}
21
+ class={cn("relative aspect-(--ratio)", className)}
22
+ {...props}
23
+ >
24
+ <slot />
25
+ </div>
@@ -0,0 +1 @@
1
+ export { default as AspectRatio } from "./aspect-ratio.astro"
@@ -0,0 +1,20 @@
1
+ ---
2
+ import type { HTMLTag, Polymorphic } from "astro/types"
3
+
4
+ import { Button, type ButtonVariantProps } from "@/components/ui/button"
5
+
6
+ type Props<Tag extends HTMLTag = "button"> = Polymorphic<{ as: Tag }> &
7
+ ButtonVariantProps
8
+
9
+ const { as, variant = "ghost", size = "icon-xs", ...props } = Astro.props
10
+ ---
11
+
12
+ <Button
13
+ as={as}
14
+ data-slot="attachment-action"
15
+ variant={variant}
16
+ size={size}
17
+ {...props}
18
+ >
19
+ <slot />
20
+ </Button>
@@ -0,0 +1,20 @@
1
+ ---
2
+ import type { HTMLAttributes } from "astro/types"
3
+
4
+ import { cn } from "@/lib/utils"
5
+
6
+ type Props = HTMLAttributes<"div">
7
+
8
+ const { class: className, ...props } = Astro.props
9
+ ---
10
+
11
+ <div
12
+ data-slot="attachment-actions"
13
+ class={cn(
14
+ "relative z-20 flex shrink-0 items-center group-data-[orientation=vertical]/attachment:absolute group-data-[orientation=vertical]/attachment:top-3 group-data-[orientation=vertical]/attachment:right-3 group-data-[orientation=vertical]/attachment:gap-1",
15
+ className
16
+ )}
17
+ {...props}
18
+ >
19
+ <slot />
20
+ </div>
@@ -0,0 +1,20 @@
1
+ ---
2
+ import type { HTMLAttributes } from "astro/types"
3
+
4
+ import { cn } from "@/lib/utils"
5
+
6
+ type Props = HTMLAttributes<"div">
7
+
8
+ const { class: className, ...props } = Astro.props
9
+ ---
10
+
11
+ <div
12
+ data-slot="attachment-content"
13
+ class={cn(
14
+ "max-w-full min-w-0 flex-1 leading-tight group-data-[orientation=vertical]/attachment:px-1",
15
+ className
16
+ )}
17
+ {...props}
18
+ >
19
+ <slot />
20
+ </div>
@@ -0,0 +1,20 @@
1
+ ---
2
+ import type { HTMLAttributes } from "astro/types"
3
+
4
+ import { cn } from "@/lib/utils"
5
+
6
+ type Props = HTMLAttributes<"span">
7
+
8
+ const { class: className, ...props } = Astro.props
9
+ ---
10
+
11
+ <span
12
+ data-slot="attachment-description"
13
+ class={cn(
14
+ "text-muted-foreground group-data-[state=error]/attachment:text-destructive/80 mt-0.5 block max-w-full min-w-0 truncate text-xs",
15
+ className
16
+ )}
17
+ {...props}
18
+ >
19
+ <slot />
20
+ </span>
@@ -0,0 +1,20 @@
1
+ ---
2
+ import type { HTMLAttributes } from "astro/types"
3
+
4
+ import { cn } from "@/lib/utils"
5
+
6
+ type Props = HTMLAttributes<"div">
7
+
8
+ const { class: className, ...props } = Astro.props
9
+ ---
10
+
11
+ <div
12
+ data-slot="attachment-group"
13
+ class={cn(
14
+ "flex min-w-0 snap-x snap-mandatory scroll-px-1 gap-3 overflow-x-auto overscroll-x-contain py-1 *:data-[slot=attachment]:flex-none *:data-[slot=attachment]:snap-start",
15
+ className
16
+ )}
17
+ {...props}
18
+ >
19
+ <slot />
20
+ </div>
@@ -0,0 +1,36 @@
1
+ ---
2
+ import type { HTMLAttributes } from "astro/types"
3
+ import { cva, type VariantProps } from "class-variance-authority"
4
+
5
+ import { cn } from "@/lib/utils"
6
+
7
+ const attachmentMediaVariants = cva(
8
+ "bg-muted text-foreground group-data-[state=error]/attachment:bg-destructive/10 group-data-[state=error]/attachment:text-destructive relative flex aspect-square w-10 shrink-0 items-center justify-center overflow-hidden rounded-lg group-data-[orientation=vertical]/attachment:w-full group-data-[size=sm]/attachment:w-8 group-data-[size=xs]/attachment:w-7 group-data-[size=xs]/attachment:rounded-md group-data-[orientation=vertical]/attachment:*:data-[slot=spinner]:size-6! [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 group-data-[orientation=vertical]/attachment:[&_svg:not([class*='size-'])]:size-6 group-data-[size=xs]/attachment:[&_svg:not([class*='size-'])]:size-3.5",
9
+ {
10
+ variants: {
11
+ variant: {
12
+ icon: "",
13
+ image:
14
+ "opacity-60 group-data-[state=done]/attachment:opacity-100 group-data-[state=idle]/attachment:opacity-100 *:[img]:aspect-square *:[img]:w-full *:[img]:object-cover",
15
+ },
16
+ },
17
+ defaultVariants: {
18
+ variant: "icon",
19
+ },
20
+ }
21
+ )
22
+
23
+ type Props = HTMLAttributes<"div"> &
24
+ VariantProps<typeof attachmentMediaVariants>
25
+
26
+ const { class: className, variant = "icon", ...props } = Astro.props
27
+ ---
28
+
29
+ <div
30
+ data-slot="attachment-media"
31
+ data-variant={variant}
32
+ class={cn(attachmentMediaVariants({ variant }), className)}
33
+ {...props}
34
+ >
35
+ <slot />
36
+ </div>
@@ -0,0 +1,20 @@
1
+ ---
2
+ import type { HTMLAttributes } from "astro/types"
3
+
4
+ import { cn } from "@/lib/utils"
5
+
6
+ type Props = HTMLAttributes<"span">
7
+
8
+ const { class: className, ...props } = Astro.props
9
+ ---
10
+
11
+ <span
12
+ data-slot="attachment-title"
13
+ class={cn(
14
+ "block max-w-full min-w-0 truncate font-medium group-data-[state=processing]/attachment:animate-pulse group-data-[state=uploading]/attachment:animate-pulse",
15
+ className
16
+ )}
17
+ {...props}
18
+ >
19
+ <slot />
20
+ </span>