@autumnsgrove/groveengine 0.7.0 → 0.8.5

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 (230) hide show
  1. package/dist/components/OnboardingChecklist.svelte +2 -2
  2. package/dist/components/WispButton.svelte +83 -0
  3. package/dist/components/WispButton.svelte.d.ts +49 -0
  4. package/dist/components/WispPanel.svelte +1093 -0
  5. package/dist/components/WispPanel.svelte.d.ts +49 -0
  6. package/dist/components/custom/TableOfContents.svelte +12 -1
  7. package/dist/components/quota/UpgradePrompt.svelte +1 -0
  8. package/dist/config/wisp.d.ts +145 -0
  9. package/dist/config/wisp.js +175 -0
  10. package/dist/index.d.ts +2 -0
  11. package/dist/index.js +3 -0
  12. package/dist/server/inference-client.d.ts +139 -0
  13. package/dist/server/inference-client.js +294 -0
  14. package/dist/ui/components/content/RoadmapPreview.svelte +91 -0
  15. package/dist/ui/components/content/RoadmapPreview.svelte.d.ts +36 -0
  16. package/dist/ui/components/content/index.d.ts +1 -0
  17. package/dist/ui/components/content/index.js +1 -0
  18. package/dist/ui/components/nature/Logo.svelte +260 -0
  19. package/dist/ui/components/nature/Logo.svelte.d.ts +14 -0
  20. package/dist/ui/components/nature/botanical/Acorn.svelte +48 -0
  21. package/dist/ui/components/nature/botanical/Acorn.svelte.d.ts +8 -0
  22. package/dist/ui/components/nature/botanical/Berry.svelte +67 -0
  23. package/dist/ui/components/nature/botanical/Berry.svelte.d.ts +8 -0
  24. package/dist/ui/components/nature/botanical/DandelionPuff.svelte +98 -0
  25. package/dist/ui/components/nature/botanical/DandelionPuff.svelte.d.ts +8 -0
  26. package/dist/ui/components/nature/botanical/FallingLeavesLayer.svelte +170 -0
  27. package/dist/ui/components/nature/botanical/FallingLeavesLayer.svelte.d.ts +35 -0
  28. package/dist/ui/components/nature/botanical/FallingPetalsLayer.svelte +174 -0
  29. package/dist/ui/components/nature/botanical/FallingPetalsLayer.svelte.d.ts +25 -0
  30. package/dist/ui/components/nature/botanical/Leaf.svelte +77 -0
  31. package/dist/ui/components/nature/botanical/Leaf.svelte.d.ts +10 -0
  32. package/dist/ui/components/nature/botanical/LeafFalling.svelte +186 -0
  33. package/dist/ui/components/nature/botanical/LeafFalling.svelte.d.ts +22 -0
  34. package/dist/ui/components/nature/botanical/PetalFalling.svelte +266 -0
  35. package/dist/ui/components/nature/botanical/PetalFalling.svelte.d.ts +25 -0
  36. package/dist/ui/components/nature/botanical/PineCone.svelte +61 -0
  37. package/dist/ui/components/nature/botanical/PineCone.svelte.d.ts +7 -0
  38. package/dist/ui/components/nature/botanical/Vine.svelte +102 -0
  39. package/dist/ui/components/nature/botanical/Vine.svelte.d.ts +11 -0
  40. package/dist/ui/components/nature/botanical/index.d.ts +10 -0
  41. package/dist/ui/components/nature/botanical/index.js +11 -0
  42. package/dist/ui/components/nature/creatures/Bee.svelte +78 -0
  43. package/dist/ui/components/nature/creatures/Bee.svelte.d.ts +9 -0
  44. package/dist/ui/components/nature/creatures/Bird.svelte +94 -0
  45. package/dist/ui/components/nature/creatures/Bird.svelte.d.ts +11 -0
  46. package/dist/ui/components/nature/creatures/BirdFlying.svelte +83 -0
  47. package/dist/ui/components/nature/creatures/BirdFlying.svelte.d.ts +9 -0
  48. package/dist/ui/components/nature/creatures/Bluebird.svelte +95 -0
  49. package/dist/ui/components/nature/creatures/Bluebird.svelte.d.ts +12 -0
  50. package/dist/ui/components/nature/creatures/Butterfly.svelte +87 -0
  51. package/dist/ui/components/nature/creatures/Butterfly.svelte.d.ts +9 -0
  52. package/dist/ui/components/nature/creatures/Cardinal.svelte +95 -0
  53. package/dist/ui/components/nature/creatures/Cardinal.svelte.d.ts +12 -0
  54. package/dist/ui/components/nature/creatures/Chickadee.svelte +97 -0
  55. package/dist/ui/components/nature/creatures/Chickadee.svelte.d.ts +12 -0
  56. package/dist/ui/components/nature/creatures/Deer.svelte +95 -0
  57. package/dist/ui/components/nature/creatures/Deer.svelte.d.ts +9 -0
  58. package/dist/ui/components/nature/creatures/Firefly.svelte +111 -0
  59. package/dist/ui/components/nature/creatures/Firefly.svelte.d.ts +10 -0
  60. package/dist/ui/components/nature/creatures/Owl.svelte +91 -0
  61. package/dist/ui/components/nature/creatures/Owl.svelte.d.ts +9 -0
  62. package/dist/ui/components/nature/creatures/Rabbit.svelte +90 -0
  63. package/dist/ui/components/nature/creatures/Rabbit.svelte.d.ts +9 -0
  64. package/dist/ui/components/nature/creatures/Robin.svelte +98 -0
  65. package/dist/ui/components/nature/creatures/Robin.svelte.d.ts +12 -0
  66. package/dist/ui/components/nature/creatures/Squirrel.svelte +97 -0
  67. package/dist/ui/components/nature/creatures/Squirrel.svelte.d.ts +9 -0
  68. package/dist/ui/components/nature/creatures/index.d.ts +13 -0
  69. package/dist/ui/components/nature/creatures/index.js +14 -0
  70. package/dist/ui/components/nature/ground/Bush.svelte +57 -0
  71. package/dist/ui/components/nature/ground/Bush.svelte.d.ts +10 -0
  72. package/dist/ui/components/nature/ground/Crocus.svelte +83 -0
  73. package/dist/ui/components/nature/ground/Crocus.svelte.d.ts +12 -0
  74. package/dist/ui/components/nature/ground/Daffodil.svelte +75 -0
  75. package/dist/ui/components/nature/ground/Daffodil.svelte.d.ts +11 -0
  76. package/dist/ui/components/nature/ground/Fern.svelte +72 -0
  77. package/dist/ui/components/nature/ground/Fern.svelte.d.ts +10 -0
  78. package/dist/ui/components/nature/ground/FlowerWild.svelte +60 -0
  79. package/dist/ui/components/nature/ground/FlowerWild.svelte.d.ts +10 -0
  80. package/dist/ui/components/nature/ground/GrassTuft.svelte +49 -0
  81. package/dist/ui/components/nature/ground/GrassTuft.svelte.d.ts +10 -0
  82. package/dist/ui/components/nature/ground/Log.svelte +42 -0
  83. package/dist/ui/components/nature/ground/Log.svelte.d.ts +7 -0
  84. package/dist/ui/components/nature/ground/Mushroom.svelte +48 -0
  85. package/dist/ui/components/nature/ground/Mushroom.svelte.d.ts +9 -0
  86. package/dist/ui/components/nature/ground/MushroomCluster.svelte +41 -0
  87. package/dist/ui/components/nature/ground/MushroomCluster.svelte.d.ts +8 -0
  88. package/dist/ui/components/nature/ground/Rock.svelte +59 -0
  89. package/dist/ui/components/nature/ground/Rock.svelte.d.ts +8 -0
  90. package/dist/ui/components/nature/ground/Stump.svelte +44 -0
  91. package/dist/ui/components/nature/ground/Stump.svelte.d.ts +8 -0
  92. package/dist/ui/components/nature/ground/Tulip.svelte +79 -0
  93. package/dist/ui/components/nature/ground/Tulip.svelte.d.ts +11 -0
  94. package/dist/ui/components/nature/ground/index.d.ts +12 -0
  95. package/dist/ui/components/nature/ground/index.js +13 -0
  96. package/dist/ui/components/nature/index.d.ts +28 -0
  97. package/dist/ui/components/nature/index.js +38 -0
  98. package/dist/ui/components/nature/palette.d.ts +602 -0
  99. package/dist/ui/components/nature/palette.js +472 -0
  100. package/dist/ui/components/nature/sky/Cloud.svelte +122 -0
  101. package/dist/ui/components/nature/sky/Cloud.svelte.d.ts +11 -0
  102. package/dist/ui/components/nature/sky/CloudWispy.svelte +79 -0
  103. package/dist/ui/components/nature/sky/CloudWispy.svelte.d.ts +9 -0
  104. package/dist/ui/components/nature/sky/Moon.svelte +60 -0
  105. package/dist/ui/components/nature/sky/Moon.svelte.d.ts +9 -0
  106. package/dist/ui/components/nature/sky/Rainbow.svelte +101 -0
  107. package/dist/ui/components/nature/sky/Rainbow.svelte.d.ts +8 -0
  108. package/dist/ui/components/nature/sky/Star.svelte +84 -0
  109. package/dist/ui/components/nature/sky/Star.svelte.d.ts +10 -0
  110. package/dist/ui/components/nature/sky/StarCluster.svelte +85 -0
  111. package/dist/ui/components/nature/sky/StarCluster.svelte.d.ts +9 -0
  112. package/dist/ui/components/nature/sky/StarShooting.svelte +90 -0
  113. package/dist/ui/components/nature/sky/StarShooting.svelte.d.ts +9 -0
  114. package/dist/ui/components/nature/sky/Sun.svelte +70 -0
  115. package/dist/ui/components/nature/sky/Sun.svelte.d.ts +9 -0
  116. package/dist/ui/components/nature/sky/index.d.ts +8 -0
  117. package/dist/ui/components/nature/sky/index.js +9 -0
  118. package/dist/ui/components/nature/structural/Birdhouse.svelte +53 -0
  119. package/dist/ui/components/nature/structural/Birdhouse.svelte.d.ts +8 -0
  120. package/dist/ui/components/nature/structural/Bridge.svelte +65 -0
  121. package/dist/ui/components/nature/structural/Bridge.svelte.d.ts +7 -0
  122. package/dist/ui/components/nature/structural/FencePost.svelte +54 -0
  123. package/dist/ui/components/nature/structural/FencePost.svelte.d.ts +8 -0
  124. package/dist/ui/components/nature/structural/GardenGate.svelte +70 -0
  125. package/dist/ui/components/nature/structural/GardenGate.svelte.d.ts +8 -0
  126. package/dist/ui/components/nature/structural/Lantern.svelte +113 -0
  127. package/dist/ui/components/nature/structural/Lantern.svelte.d.ts +10 -0
  128. package/dist/ui/components/nature/structural/Lattice.svelte +89 -0
  129. package/dist/ui/components/nature/structural/Lattice.svelte.d.ts +8 -0
  130. package/dist/ui/components/nature/structural/LatticeWithVine.svelte +89 -0
  131. package/dist/ui/components/nature/structural/LatticeWithVine.svelte.d.ts +11 -0
  132. package/dist/ui/components/nature/structural/StonePath.svelte +48 -0
  133. package/dist/ui/components/nature/structural/StonePath.svelte.d.ts +7 -0
  134. package/dist/ui/components/nature/structural/index.d.ts +8 -0
  135. package/dist/ui/components/nature/structural/index.js +9 -0
  136. package/dist/ui/components/nature/trees/TreeAspen.svelte +163 -0
  137. package/dist/ui/components/nature/trees/TreeAspen.svelte.d.ts +11 -0
  138. package/dist/ui/components/nature/trees/TreeBirch.svelte +186 -0
  139. package/dist/ui/components/nature/trees/TreeBirch.svelte.d.ts +11 -0
  140. package/dist/ui/components/nature/trees/TreeCherry.svelte +108 -0
  141. package/dist/ui/components/nature/trees/TreeCherry.svelte.d.ts +11 -0
  142. package/dist/ui/components/nature/trees/TreePine.svelte +79 -0
  143. package/dist/ui/components/nature/trees/TreePine.svelte.d.ts +11 -0
  144. package/dist/ui/components/nature/trees/index.d.ts +4 -0
  145. package/dist/ui/components/nature/trees/index.js +5 -0
  146. package/dist/ui/components/nature/water/LilyPad.svelte +99 -0
  147. package/dist/ui/components/nature/water/LilyPad.svelte.d.ts +10 -0
  148. package/dist/ui/components/nature/water/Pond.svelte +104 -0
  149. package/dist/ui/components/nature/water/Pond.svelte.d.ts +8 -0
  150. package/dist/ui/components/nature/water/Reeds.svelte +85 -0
  151. package/dist/ui/components/nature/water/Reeds.svelte.d.ts +11 -0
  152. package/dist/ui/components/nature/water/Stream.svelte +98 -0
  153. package/dist/ui/components/nature/water/Stream.svelte.d.ts +8 -0
  154. package/dist/ui/components/nature/water/index.d.ts +4 -0
  155. package/dist/ui/components/nature/water/index.js +5 -0
  156. package/dist/ui/components/nature/weather/SnowfallLayer.svelte +175 -0
  157. package/dist/ui/components/nature/weather/SnowfallLayer.svelte.d.ts +25 -0
  158. package/dist/ui/components/nature/weather/Snowflake.svelte +99 -0
  159. package/dist/ui/components/nature/weather/Snowflake.svelte.d.ts +11 -0
  160. package/dist/ui/components/nature/weather/SnowflakeFalling.svelte +162 -0
  161. package/dist/ui/components/nature/weather/SnowflakeFalling.svelte.d.ts +23 -0
  162. package/dist/ui/components/nature/weather/index.d.ts +3 -0
  163. package/dist/ui/components/nature/weather/index.js +4 -0
  164. package/dist/ui/components/primitives/textarea/textarea.svelte +1 -1
  165. package/dist/ui/components/typography/Alagard.svelte +17 -0
  166. package/dist/ui/components/typography/Alagard.svelte.d.ts +10 -0
  167. package/dist/ui/components/typography/Atkinson.svelte +17 -0
  168. package/dist/ui/components/typography/Atkinson.svelte.d.ts +10 -0
  169. package/dist/ui/components/typography/BodoniModa.svelte +17 -0
  170. package/dist/ui/components/typography/BodoniModa.svelte.d.ts +10 -0
  171. package/dist/ui/components/typography/Calistoga.svelte +17 -0
  172. package/dist/ui/components/typography/Calistoga.svelte.d.ts +10 -0
  173. package/dist/ui/components/typography/Caveat.svelte +17 -0
  174. package/dist/ui/components/typography/Caveat.svelte.d.ts +10 -0
  175. package/dist/ui/components/typography/Cormorant.svelte +17 -0
  176. package/dist/ui/components/typography/Cormorant.svelte.d.ts +10 -0
  177. package/dist/ui/components/typography/Cozette.svelte +17 -0
  178. package/dist/ui/components/typography/Cozette.svelte.d.ts +10 -0
  179. package/dist/ui/components/typography/EBGaramond.svelte +17 -0
  180. package/dist/ui/components/typography/EBGaramond.svelte.d.ts +10 -0
  181. package/dist/ui/components/typography/FontProvider.svelte +98 -0
  182. package/dist/ui/components/typography/FontProvider.svelte.d.ts +17 -0
  183. package/dist/ui/components/typography/Fraunces.svelte +17 -0
  184. package/dist/ui/components/typography/Fraunces.svelte.d.ts +10 -0
  185. package/dist/ui/components/typography/IBMPlexMono.svelte +17 -0
  186. package/dist/ui/components/typography/IBMPlexMono.svelte.d.ts +10 -0
  187. package/dist/ui/components/typography/InstrumentSans.svelte +17 -0
  188. package/dist/ui/components/typography/InstrumentSans.svelte.d.ts +10 -0
  189. package/dist/ui/components/typography/Lexend.svelte +17 -0
  190. package/dist/ui/components/typography/Lexend.svelte.d.ts +10 -0
  191. package/dist/ui/components/typography/Lora.svelte +17 -0
  192. package/dist/ui/components/typography/Lora.svelte.d.ts +10 -0
  193. package/dist/ui/components/typography/Luciole.svelte +17 -0
  194. package/dist/ui/components/typography/Luciole.svelte.d.ts +10 -0
  195. package/dist/ui/components/typography/Manrope.svelte +17 -0
  196. package/dist/ui/components/typography/Manrope.svelte.d.ts +10 -0
  197. package/dist/ui/components/typography/Merriweather.svelte +17 -0
  198. package/dist/ui/components/typography/Merriweather.svelte.d.ts +10 -0
  199. package/dist/ui/components/typography/Nunito.svelte +17 -0
  200. package/dist/ui/components/typography/Nunito.svelte.d.ts +10 -0
  201. package/dist/ui/components/typography/OpenDyslexic.svelte +17 -0
  202. package/dist/ui/components/typography/OpenDyslexic.svelte.d.ts +10 -0
  203. package/dist/ui/components/typography/PlusJakartaSans.svelte +17 -0
  204. package/dist/ui/components/typography/PlusJakartaSans.svelte.d.ts +10 -0
  205. package/dist/ui/components/typography/Quicksand.svelte +17 -0
  206. package/dist/ui/components/typography/Quicksand.svelte.d.ts +10 -0
  207. package/dist/ui/components/typography/README.md +153 -0
  208. package/dist/ui/components/typography/index.d.ts +23 -0
  209. package/dist/ui/components/typography/index.js +42 -0
  210. package/dist/ui/components/ui/GlassCarousel.svelte +446 -0
  211. package/dist/ui/components/ui/GlassCarousel.svelte.d.ts +57 -0
  212. package/dist/ui/components/ui/GlassConfirmDialog.svelte +2 -1
  213. package/dist/ui/components/ui/GlassLogo.svelte +423 -0
  214. package/dist/ui/components/ui/GlassLogo.svelte.d.ts +23 -0
  215. package/dist/ui/components/ui/GlassNavbar.svelte +120 -0
  216. package/dist/ui/components/ui/GlassNavbar.svelte.d.ts +42 -0
  217. package/dist/ui/components/ui/GlassOverlay.svelte +1 -1
  218. package/dist/ui/components/ui/Logo.svelte +47 -52
  219. package/dist/ui/components/ui/Logo.svelte.d.ts +4 -3
  220. package/dist/ui/components/ui/index.d.ts +3 -0
  221. package/dist/ui/components/ui/index.js +3 -0
  222. package/dist/ui/index.d.ts +1 -0
  223. package/dist/ui/index.js +2 -0
  224. package/dist/ui/styles/grove.css +15 -1
  225. package/dist/ui/vineyard/index.d.ts +9 -0
  226. package/dist/ui/vineyard/index.js +8 -0
  227. package/dist/utils/csrf.js +5 -2
  228. package/dist/utils/readability.d.ts +89 -0
  229. package/dist/utils/readability.js +204 -0
  230. package/package.json +27 -1
@@ -0,0 +1,446 @@
1
+ <script lang="ts">
2
+ import type { Snippet } from "svelte";
3
+ import type { HTMLAttributes } from "svelte/elements";
4
+ import { cn } from "../../utils";
5
+
6
+ /**
7
+ * GlassCarousel - A stack-style carousel with glassmorphism styling
8
+ *
9
+ * Mobile-first carousel where cards stack on top of each other.
10
+ * Supports images out of the box, or custom content via children snippet.
11
+ *
12
+ * Navigation: touch/swipe, mouse drag, click (arrows/dots), keyboard (arrow keys).
13
+ *
14
+ * @example Image carousel
15
+ * ```svelte
16
+ * <GlassCarousel images={[
17
+ * { url: '/photo1.jpg', alt: 'Beach sunset', caption: 'Summer vibes' },
18
+ * { url: '/photo2.jpg', alt: 'Mountain view' }
19
+ * ]} />
20
+ * ```
21
+ *
22
+ * @example Custom content carousel
23
+ * ```svelte
24
+ * <GlassCarousel itemCount={3} let:index>
25
+ * {#snippet item(index)}
26
+ * <TestimonialCard data={testimonials[index]} />
27
+ * {/snippet}
28
+ * </GlassCarousel>
29
+ * ```
30
+ */
31
+
32
+ interface CarouselImage {
33
+ url: string;
34
+ alt: string;
35
+ caption?: string;
36
+ }
37
+
38
+ /** Custom content renderer type - receives slide index */
39
+ type ItemRenderer = Snippet<[number]>;
40
+
41
+ interface Props extends Omit<HTMLAttributes<HTMLDivElement>, "class"> {
42
+ /** Array of images to display */
43
+ images?: CarouselImage[];
44
+ /** Number of items when using custom content (ignored if images provided) */
45
+ itemCount?: number;
46
+ /** Show navigation dots */
47
+ showDots?: boolean;
48
+ /** Show arrow buttons */
49
+ showArrows?: boolean;
50
+ /** Enable autoplay (disabled by default) */
51
+ autoplay?: boolean;
52
+ /** Autoplay interval in milliseconds */
53
+ autoplayInterval?: number;
54
+ /** Visual variant */
55
+ variant?: "default" | "frosted" | "minimal";
56
+ /** Custom class name */
57
+ class?: string;
58
+ /** Custom content renderer - receives index */
59
+ item?: ItemRenderer;
60
+ }
61
+
62
+ let {
63
+ images = [],
64
+ itemCount = 0,
65
+ showDots = true,
66
+ showArrows = true,
67
+ autoplay = false,
68
+ autoplayInterval = 5000,
69
+ variant = "default",
70
+ class: className,
71
+ item,
72
+ ...restProps
73
+ }: Props = $props();
74
+
75
+ // Determine total count from images or itemCount
76
+ let totalItems = $derived(images.length > 0 ? images.length : itemCount);
77
+
78
+ // Current slide state
79
+ let currentIndex = $state(0);
80
+ let isAnimating = $state(false);
81
+
82
+ // Touch/drag state
83
+ let touchStartX = $state(0);
84
+ let touchCurrentX = $state(0);
85
+ let isDragging = $state(false);
86
+ let dragOffset = $state(0);
87
+
88
+ // Autoplay interval reference
89
+ let autoplayTimer: ReturnType<typeof setInterval> | null = null;
90
+
91
+ // Configuration constants
92
+ const ANIMATION_DURATION_MS = 400;
93
+ const SWIPE_THRESHOLD_PX = 50;
94
+ const DRAG_INFLUENCE_FACTOR = 0.3;
95
+ const MIN_CARD_SCALE = 0.85;
96
+ const SCALE_STEP = 0.05;
97
+ const CARD_OFFSET_X = 20;
98
+ const CARD_OFFSET_Y = 8;
99
+ const MIN_OPACITY = 0.4;
100
+ const OPACITY_STEP = 0.3;
101
+
102
+ function goTo(index: number) {
103
+ if (isAnimating || index < 0 || index >= totalItems || index === currentIndex) return;
104
+
105
+ isAnimating = true;
106
+ currentIndex = index;
107
+
108
+ setTimeout(() => {
109
+ isAnimating = false;
110
+ }, ANIMATION_DURATION_MS);
111
+ }
112
+
113
+ function goNext() {
114
+ if (currentIndex < totalItems - 1) {
115
+ goTo(currentIndex + 1);
116
+ } else {
117
+ // Loop back to start
118
+ goTo(0);
119
+ }
120
+ }
121
+
122
+ function goPrev() {
123
+ if (currentIndex > 0) {
124
+ goTo(currentIndex - 1);
125
+ } else {
126
+ // Loop to end
127
+ goTo(totalItems - 1);
128
+ }
129
+ }
130
+
131
+ // Touch handlers
132
+ function handleTouchStart(event: TouchEvent) {
133
+ if (isAnimating) return;
134
+ touchStartX = event.touches[0].clientX;
135
+ touchCurrentX = touchStartX;
136
+ isDragging = true;
137
+ stopAutoplay();
138
+ }
139
+
140
+ function handleTouchMove(event: TouchEvent) {
141
+ if (!isDragging) return;
142
+ touchCurrentX = event.touches[0].clientX;
143
+ dragOffset = touchCurrentX - touchStartX;
144
+ }
145
+
146
+ function handleTouchEnd() {
147
+ if (!isDragging) return;
148
+
149
+ const diff = touchStartX - touchCurrentX;
150
+
151
+ if (Math.abs(diff) > SWIPE_THRESHOLD_PX) {
152
+ if (diff > 0) {
153
+ goNext();
154
+ } else {
155
+ goPrev();
156
+ }
157
+ }
158
+
159
+ isDragging = false;
160
+ dragOffset = 0;
161
+ touchStartX = 0;
162
+ touchCurrentX = 0;
163
+
164
+ if (autoplay) startAutoplay();
165
+ }
166
+
167
+ // Mouse drag handlers (for desktop)
168
+ function handleMouseDown(event: MouseEvent) {
169
+ if (isAnimating) return;
170
+ touchStartX = event.clientX;
171
+ touchCurrentX = touchStartX;
172
+ isDragging = true;
173
+ stopAutoplay();
174
+ }
175
+
176
+ function handleMouseMove(event: MouseEvent) {
177
+ if (!isDragging) return;
178
+ touchCurrentX = event.clientX;
179
+ dragOffset = touchCurrentX - touchStartX;
180
+ }
181
+
182
+ function handleMouseUp() {
183
+ handleTouchEnd();
184
+ }
185
+
186
+ function handleMouseLeave() {
187
+ if (isDragging) {
188
+ handleTouchEnd();
189
+ }
190
+ }
191
+
192
+ // Keyboard navigation
193
+ function handleKeydown(event: KeyboardEvent) {
194
+ switch (event.key) {
195
+ case 'ArrowLeft':
196
+ event.preventDefault();
197
+ goPrev();
198
+ break;
199
+ case 'ArrowRight':
200
+ event.preventDefault();
201
+ goNext();
202
+ break;
203
+ case 'Home':
204
+ event.preventDefault();
205
+ goTo(0);
206
+ break;
207
+ case 'End':
208
+ event.preventDefault();
209
+ goTo(totalItems - 1);
210
+ break;
211
+ }
212
+ }
213
+
214
+ // Autoplay controls
215
+ function startAutoplay() {
216
+ if (!autoplay || totalItems <= 1) return;
217
+ stopAutoplay();
218
+ autoplayTimer = setInterval(goNext, autoplayInterval);
219
+ }
220
+
221
+ function stopAutoplay() {
222
+ if (autoplayTimer) {
223
+ clearInterval(autoplayTimer);
224
+ autoplayTimer = null;
225
+ }
226
+ }
227
+
228
+ // Reset drag state helper
229
+ function resetDragState() {
230
+ isDragging = false;
231
+ dragOffset = 0;
232
+ touchStartX = 0;
233
+ touchCurrentX = 0;
234
+ }
235
+
236
+ // Start/stop autoplay based on prop, with cleanup for drag state
237
+ $effect(() => {
238
+ if (autoplay && totalItems > 1) {
239
+ startAutoplay();
240
+ } else {
241
+ stopAutoplay();
242
+ }
243
+
244
+ return () => {
245
+ stopAutoplay();
246
+ // Clean up drag state if component unmounts during drag
247
+ if (isDragging) {
248
+ resetDragState();
249
+ }
250
+ };
251
+ });
252
+
253
+ // Handle window-level mouseup for edge case: drag starts, mouse leaves window, released outside
254
+ $effect(() => {
255
+ if (!isDragging) return;
256
+
257
+ const handleWindowMouseUp = () => handleMouseUp();
258
+ window.addEventListener('mouseup', handleWindowMouseUp);
259
+
260
+ return () => window.removeEventListener('mouseup', handleWindowMouseUp);
261
+ });
262
+
263
+ // Reset currentIndex if totalItems changes and current index is out of bounds
264
+ $effect(() => {
265
+ if (totalItems > 0 && currentIndex >= totalItems) {
266
+ currentIndex = totalItems - 1;
267
+ }
268
+ });
269
+
270
+ // Calculate card transforms for stack effect
271
+ function getCardStyle(index: number): string {
272
+ const offset = index - currentIndex;
273
+ const dragInfluence = isDragging ? dragOffset * DRAG_INFLUENCE_FACTOR : 0;
274
+
275
+ // Current card - special case
276
+ if (offset === 0) {
277
+ const translateX = isDragging ? dragOffset : 0;
278
+ return `
279
+ transform: translateX(${translateX}px) scale(1);
280
+ opacity: 1;
281
+ z-index: ${totalItems + 1};
282
+ `;
283
+ }
284
+
285
+ // Cards behind or ahead - shared transform logic
286
+ const depth = Math.abs(offset);
287
+ const direction = offset < 0 ? -1 : 1;
288
+ const scale = Math.max(MIN_CARD_SCALE, 1 - depth * SCALE_STEP);
289
+ const translateX = direction * CARD_OFFSET_X * depth + dragInfluence;
290
+ const translateY = CARD_OFFSET_Y * depth;
291
+ const opacity = Math.max(MIN_OPACITY, 1 - depth * OPACITY_STEP);
292
+ const zIndex = totalItems - depth;
293
+
294
+ return `
295
+ transform: translateX(${translateX}px) translateY(${translateY}px) scale(${scale});
296
+ opacity: ${opacity};
297
+ z-index: ${zIndex};
298
+ `;
299
+ }
300
+
301
+ // Variant styles
302
+ const variantClasses = {
303
+ default: "bg-white/60 dark:bg-emerald-950/25 backdrop-blur-md border-white/40 dark:border-emerald-800/25",
304
+ frosted: "bg-white/70 dark:bg-emerald-950/35 backdrop-blur-lg border-white/50 dark:border-emerald-800/30",
305
+ minimal: "bg-transparent border-transparent"
306
+ };
307
+
308
+ const containerClass = $derived(
309
+ cn(
310
+ "relative overflow-hidden rounded-2xl border p-4 outline-none",
311
+ "focus-visible:ring-2 focus-visible:ring-emerald-500 focus-visible:ring-offset-2",
312
+ variant !== "minimal" && variantClasses[variant],
313
+ variant === "minimal" && "p-0",
314
+ className
315
+ )
316
+ );
317
+ </script>
318
+
319
+ {#if totalItems > 0}
320
+ <!-- svelte-ignore a11y_no_noninteractive_tabindex -->
321
+ <div
322
+ class={containerClass}
323
+ role="region"
324
+ aria-label="Image carousel"
325
+ aria-roledescription="carousel"
326
+ tabindex="0"
327
+ onkeydown={handleKeydown}
328
+ {...restProps}
329
+ >
330
+ <!-- Cards stack -->
331
+ <div
332
+ class="relative w-full aspect-[4/3] select-none"
333
+ ontouchstart={handleTouchStart}
334
+ ontouchmove={handleTouchMove}
335
+ ontouchend={handleTouchEnd}
336
+ onmousedown={handleMouseDown}
337
+ onmousemove={handleMouseMove}
338
+ onmouseup={handleMouseUp}
339
+ onmouseleave={handleMouseLeave}
340
+ role="presentation"
341
+ >
342
+ {#each { length: totalItems } as _, index (index)}
343
+ <div
344
+ class={cn(
345
+ "absolute inset-0 rounded-xl overflow-hidden shadow-lg transition-all duration-[400ms] ease-out",
346
+ "bg-white dark:bg-slate-900",
347
+ isDragging && "transition-none"
348
+ )}
349
+ style={getCardStyle(index)}
350
+ aria-hidden={index !== currentIndex}
351
+ >
352
+ {#if images.length > 0}
353
+ <!-- Image mode -->
354
+ <img
355
+ src={images[index].url}
356
+ alt={images[index].alt}
357
+ class="w-full h-full object-cover"
358
+ draggable="false"
359
+ />
360
+ {#if images[index].caption}
361
+ <div class="absolute bottom-0 left-0 right-0 p-4 bg-gradient-to-t from-black/70 to-transparent">
362
+ <p class="text-white text-sm font-medium">{images[index].caption}</p>
363
+ </div>
364
+ {/if}
365
+ {:else if item}
366
+ <!-- Custom content mode -->
367
+ {@render item(index)}
368
+ {/if}
369
+ </div>
370
+ {/each}
371
+ </div>
372
+
373
+ <!-- Navigation -->
374
+ {#if totalItems > 1}
375
+ <div class="flex items-center justify-between mt-4 px-2">
376
+ <!-- Previous arrow -->
377
+ {#if showArrows}
378
+ <button
379
+ type="button"
380
+ class={cn(
381
+ "w-10 h-10 rounded-full flex items-center justify-center",
382
+ "bg-white/60 dark:bg-emerald-950/40 backdrop-blur-sm",
383
+ "border border-white/40 dark:border-emerald-800/30",
384
+ "text-slate-700 dark:text-slate-200",
385
+ "hover:bg-white/80 dark:hover:bg-emerald-950/60",
386
+ "transition-all duration-200",
387
+ "disabled:opacity-40 disabled:cursor-not-allowed"
388
+ )}
389
+ onclick={goPrev}
390
+ aria-label="Previous slide"
391
+ >
392
+ <svg class="w-5 h-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
393
+ <polyline points="15 18 9 12 15 6"></polyline>
394
+ </svg>
395
+ </button>
396
+ {:else}
397
+ <div></div>
398
+ {/if}
399
+
400
+ <!-- Dots -->
401
+ {#if showDots}
402
+ <div class="flex items-center gap-2">
403
+ {#each { length: totalItems } as _, index (index)}
404
+ <button
405
+ type="button"
406
+ class={cn(
407
+ "h-2 rounded-full transition-all duration-300",
408
+ index === currentIndex
409
+ ? "w-6 bg-emerald-600 dark:bg-emerald-400"
410
+ : "w-2 bg-slate-300 dark:bg-slate-600 hover:bg-slate-400 dark:hover:bg-slate-500"
411
+ )}
412
+ onclick={() => goTo(index)}
413
+ aria-label={`Go to slide ${index + 1}`}
414
+ aria-current={index === currentIndex ? "true" : undefined}
415
+ ></button>
416
+ {/each}
417
+ </div>
418
+ {/if}
419
+
420
+ <!-- Next arrow -->
421
+ {#if showArrows}
422
+ <button
423
+ type="button"
424
+ class={cn(
425
+ "w-10 h-10 rounded-full flex items-center justify-center",
426
+ "bg-white/60 dark:bg-emerald-950/40 backdrop-blur-sm",
427
+ "border border-white/40 dark:border-emerald-800/30",
428
+ "text-slate-700 dark:text-slate-200",
429
+ "hover:bg-white/80 dark:hover:bg-emerald-950/60",
430
+ "transition-all duration-200",
431
+ "disabled:opacity-40 disabled:cursor-not-allowed"
432
+ )}
433
+ onclick={goNext}
434
+ aria-label="Next slide"
435
+ >
436
+ <svg class="w-5 h-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
437
+ <polyline points="9 18 15 12 9 6"></polyline>
438
+ </svg>
439
+ </button>
440
+ {:else}
441
+ <div></div>
442
+ {/if}
443
+ </div>
444
+ {/if}
445
+ </div>
446
+ {/if}
@@ -0,0 +1,57 @@
1
+ import type { Snippet } from "svelte";
2
+ import type { HTMLAttributes } from "svelte/elements";
3
+ /**
4
+ * GlassCarousel - A stack-style carousel with glassmorphism styling
5
+ *
6
+ * Mobile-first carousel where cards stack on top of each other.
7
+ * Supports images out of the box, or custom content via children snippet.
8
+ *
9
+ * Navigation: touch/swipe, mouse drag, click (arrows/dots), keyboard (arrow keys).
10
+ *
11
+ * @example Image carousel
12
+ * ```svelte
13
+ * <GlassCarousel images={[
14
+ * { url: '/photo1.jpg', alt: 'Beach sunset', caption: 'Summer vibes' },
15
+ * { url: '/photo2.jpg', alt: 'Mountain view' }
16
+ * ]} />
17
+ * ```
18
+ *
19
+ * @example Custom content carousel
20
+ * ```svelte
21
+ * <GlassCarousel itemCount={3} let:index>
22
+ * {#snippet item(index)}
23
+ * <TestimonialCard data={testimonials[index]} />
24
+ * {/snippet}
25
+ * </GlassCarousel>
26
+ * ```
27
+ */
28
+ interface CarouselImage {
29
+ url: string;
30
+ alt: string;
31
+ caption?: string;
32
+ }
33
+ /** Custom content renderer type - receives slide index */
34
+ type ItemRenderer = Snippet<[number]>;
35
+ interface Props extends Omit<HTMLAttributes<HTMLDivElement>, "class"> {
36
+ /** Array of images to display */
37
+ images?: CarouselImage[];
38
+ /** Number of items when using custom content (ignored if images provided) */
39
+ itemCount?: number;
40
+ /** Show navigation dots */
41
+ showDots?: boolean;
42
+ /** Show arrow buttons */
43
+ showArrows?: boolean;
44
+ /** Enable autoplay (disabled by default) */
45
+ autoplay?: boolean;
46
+ /** Autoplay interval in milliseconds */
47
+ autoplayInterval?: number;
48
+ /** Visual variant */
49
+ variant?: "default" | "frosted" | "minimal";
50
+ /** Custom class name */
51
+ class?: string;
52
+ /** Custom content renderer - receives index */
53
+ item?: ItemRenderer;
54
+ }
55
+ declare const GlassCarousel: import("svelte").Component<Props, {}, "">;
56
+ type GlassCarousel = ReturnType<typeof GlassCarousel>;
57
+ export default GlassCarousel;
@@ -129,6 +129,7 @@
129
129
  role="dialog"
130
130
  aria-modal="true"
131
131
  aria-labelledby="confirm-dialog-title"
132
+ tabindex="0"
132
133
  transition:fade={{ duration: 150 }}
133
134
  >
134
135
  <!-- Dark overlay with blur -->
@@ -157,7 +158,7 @@
157
158
  variant === "warning" && "bg-amber-100 dark:bg-amber-900/30",
158
159
  variant === "default" && "bg-accent/10 dark:bg-accent/20"
159
160
  )}>
160
- <svelte:component this={config.icon} class={cn("w-6 h-6", config.iconClass)} />
161
+ <config.icon class={cn("w-6 h-6", config.iconClass)} />
161
162
  </div>
162
163
  <div class="flex-1 min-w-0">
163
164
  <h3