@autumnsgrove/groveengine 0.1.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 (219) hide show
  1. package/README.md +163 -0
  2. package/dist/auth/jwt.d.ts +14 -0
  3. package/dist/auth/jwt.js +109 -0
  4. package/dist/auth/session.d.ts +42 -0
  5. package/dist/auth/session.js +105 -0
  6. package/dist/components/admin/GutterManager.svelte +910 -0
  7. package/dist/components/admin/GutterManager.svelte.d.ts +15 -0
  8. package/dist/components/admin/MarkdownEditor.svelte +3114 -0
  9. package/dist/components/admin/MarkdownEditor.svelte.d.ts +43 -0
  10. package/dist/components/custom/CollapsibleSection.svelte +74 -0
  11. package/dist/components/custom/CollapsibleSection.svelte.d.ts +15 -0
  12. package/dist/components/custom/ContentWithGutter.svelte +646 -0
  13. package/dist/components/custom/ContentWithGutter.svelte.d.ts +19 -0
  14. package/dist/components/custom/GutterItem.svelte +201 -0
  15. package/dist/components/custom/GutterItem.svelte.d.ts +11 -0
  16. package/dist/components/custom/LeftGutter.svelte +271 -0
  17. package/dist/components/custom/LeftGutter.svelte.d.ts +17 -0
  18. package/dist/components/custom/MobileTOC.svelte +273 -0
  19. package/dist/components/custom/MobileTOC.svelte.d.ts +11 -0
  20. package/dist/components/custom/TableOfContents.svelte +163 -0
  21. package/dist/components/custom/TableOfContents.svelte.d.ts +11 -0
  22. package/dist/components/gallery/ImageGallery.svelte +681 -0
  23. package/dist/components/gallery/ImageGallery.svelte.d.ts +11 -0
  24. package/dist/components/gallery/Lightbox.svelte +107 -0
  25. package/dist/components/gallery/Lightbox.svelte.d.ts +19 -0
  26. package/dist/components/gallery/LightboxCaption.svelte +25 -0
  27. package/dist/components/gallery/LightboxCaption.svelte.d.ts +11 -0
  28. package/dist/components/gallery/ZoomableImage.svelte +163 -0
  29. package/dist/components/gallery/ZoomableImage.svelte.d.ts +17 -0
  30. package/dist/components/ui/Accordion.svelte +74 -0
  31. package/dist/components/ui/Accordion.svelte.d.ts +42 -0
  32. package/dist/components/ui/Badge.svelte +48 -0
  33. package/dist/components/ui/Badge.svelte.d.ts +26 -0
  34. package/dist/components/ui/Button.svelte +74 -0
  35. package/dist/components/ui/Button.svelte.d.ts +34 -0
  36. package/dist/components/ui/Card.svelte +102 -0
  37. package/dist/components/ui/Card.svelte.d.ts +46 -0
  38. package/dist/components/ui/Dialog.svelte +91 -0
  39. package/dist/components/ui/Dialog.svelte.d.ts +43 -0
  40. package/dist/components/ui/Input.svelte +81 -0
  41. package/dist/components/ui/Input.svelte.d.ts +35 -0
  42. package/dist/components/ui/Select.svelte +69 -0
  43. package/dist/components/ui/Select.svelte.d.ts +36 -0
  44. package/dist/components/ui/Sheet.svelte +98 -0
  45. package/dist/components/ui/Sheet.svelte.d.ts +45 -0
  46. package/dist/components/ui/Skeleton.svelte +31 -0
  47. package/dist/components/ui/Skeleton.svelte.d.ts +26 -0
  48. package/dist/components/ui/Table.svelte +59 -0
  49. package/dist/components/ui/Table.svelte.d.ts +44 -0
  50. package/dist/components/ui/Tabs.svelte +76 -0
  51. package/dist/components/ui/Tabs.svelte.d.ts +41 -0
  52. package/dist/components/ui/Textarea.svelte +81 -0
  53. package/dist/components/ui/Textarea.svelte.d.ts +35 -0
  54. package/dist/components/ui/Toast.svelte +18 -0
  55. package/dist/components/ui/Toast.svelte.d.ts +7 -0
  56. package/dist/components/ui/accordion/accordion-content.svelte +24 -0
  57. package/dist/components/ui/accordion/accordion-content.svelte.d.ts +4 -0
  58. package/dist/components/ui/accordion/accordion-item.svelte +12 -0
  59. package/dist/components/ui/accordion/accordion-item.svelte.d.ts +4 -0
  60. package/dist/components/ui/accordion/accordion-trigger.svelte +29 -0
  61. package/dist/components/ui/accordion/accordion-trigger.svelte.d.ts +7 -0
  62. package/dist/components/ui/accordion/index.d.ts +6 -0
  63. package/dist/components/ui/accordion/index.js +8 -0
  64. package/dist/components/ui/badge/badge.svelte +50 -0
  65. package/dist/components/ui/badge/badge.svelte.d.ts +60 -0
  66. package/dist/components/ui/badge/index.d.ts +2 -0
  67. package/dist/components/ui/badge/index.js +2 -0
  68. package/dist/components/ui/button/button.svelte +82 -0
  69. package/dist/components/ui/button/button.svelte.d.ts +132 -0
  70. package/dist/components/ui/button/index.d.ts +2 -0
  71. package/dist/components/ui/button/index.js +4 -0
  72. package/dist/components/ui/card/card-content.svelte +16 -0
  73. package/dist/components/ui/card/card-content.svelte.d.ts +5 -0
  74. package/dist/components/ui/card/card-description.svelte +16 -0
  75. package/dist/components/ui/card/card-description.svelte.d.ts +5 -0
  76. package/dist/components/ui/card/card-footer.svelte +16 -0
  77. package/dist/components/ui/card/card-footer.svelte.d.ts +5 -0
  78. package/dist/components/ui/card/card-header.svelte +16 -0
  79. package/dist/components/ui/card/card-header.svelte.d.ts +5 -0
  80. package/dist/components/ui/card/card-title.svelte +25 -0
  81. package/dist/components/ui/card/card-title.svelte.d.ts +8 -0
  82. package/dist/components/ui/card/card.svelte +20 -0
  83. package/dist/components/ui/card/card.svelte.d.ts +5 -0
  84. package/dist/components/ui/card/index.d.ts +7 -0
  85. package/dist/components/ui/card/index.js +9 -0
  86. package/dist/components/ui/dialog/dialog-content.svelte +38 -0
  87. package/dist/components/ui/dialog/dialog-content.svelte.d.ts +9 -0
  88. package/dist/components/ui/dialog/dialog-description.svelte +16 -0
  89. package/dist/components/ui/dialog/dialog-description.svelte.d.ts +4 -0
  90. package/dist/components/ui/dialog/dialog-footer.svelte +20 -0
  91. package/dist/components/ui/dialog/dialog-footer.svelte.d.ts +5 -0
  92. package/dist/components/ui/dialog/dialog-header.svelte +20 -0
  93. package/dist/components/ui/dialog/dialog-header.svelte.d.ts +5 -0
  94. package/dist/components/ui/dialog/dialog-overlay.svelte +19 -0
  95. package/dist/components/ui/dialog/dialog-overlay.svelte.d.ts +4 -0
  96. package/dist/components/ui/dialog/dialog-title.svelte +16 -0
  97. package/dist/components/ui/dialog/dialog-title.svelte.d.ts +4 -0
  98. package/dist/components/ui/dialog/index.d.ts +12 -0
  99. package/dist/components/ui/dialog/index.js +14 -0
  100. package/dist/components/ui/index.d.ts +26 -0
  101. package/dist/components/ui/index.js +29 -0
  102. package/dist/components/ui/input/index.d.ts +2 -0
  103. package/dist/components/ui/input/index.js +4 -0
  104. package/dist/components/ui/input/input.svelte +46 -0
  105. package/dist/components/ui/input/input.svelte.d.ts +13 -0
  106. package/dist/components/ui/select/index.d.ts +11 -0
  107. package/dist/components/ui/select/index.js +13 -0
  108. package/dist/components/ui/select/select-content.svelte +39 -0
  109. package/dist/components/ui/select/select-content.svelte.d.ts +7 -0
  110. package/dist/components/ui/select/select-group-heading.svelte +16 -0
  111. package/dist/components/ui/select/select-group-heading.svelte.d.ts +4 -0
  112. package/dist/components/ui/select/select-item.svelte +37 -0
  113. package/dist/components/ui/select/select-item.svelte.d.ts +4 -0
  114. package/dist/components/ui/select/select-scroll-down-button.svelte +19 -0
  115. package/dist/components/ui/select/select-scroll-down-button.svelte.d.ts +4 -0
  116. package/dist/components/ui/select/select-scroll-up-button.svelte +19 -0
  117. package/dist/components/ui/select/select-scroll-up-button.svelte.d.ts +4 -0
  118. package/dist/components/ui/select/select-separator.svelte +13 -0
  119. package/dist/components/ui/select/select-separator.svelte.d.ts +4 -0
  120. package/dist/components/ui/select/select-trigger.svelte +24 -0
  121. package/dist/components/ui/select/select-trigger.svelte.d.ts +4 -0
  122. package/dist/components/ui/separator/index.d.ts +2 -0
  123. package/dist/components/ui/separator/index.js +4 -0
  124. package/dist/components/ui/separator/separator.svelte +22 -0
  125. package/dist/components/ui/separator/separator.svelte.d.ts +4 -0
  126. package/dist/components/ui/sheet/index.d.ts +12 -0
  127. package/dist/components/ui/sheet/index.js +14 -0
  128. package/dist/components/ui/sheet/sheet-content.svelte +53 -0
  129. package/dist/components/ui/sheet/sheet-content.svelte.d.ts +62 -0
  130. package/dist/components/ui/sheet/sheet-description.svelte +16 -0
  131. package/dist/components/ui/sheet/sheet-description.svelte.d.ts +4 -0
  132. package/dist/components/ui/sheet/sheet-footer.svelte +20 -0
  133. package/dist/components/ui/sheet/sheet-footer.svelte.d.ts +5 -0
  134. package/dist/components/ui/sheet/sheet-header.svelte +20 -0
  135. package/dist/components/ui/sheet/sheet-header.svelte.d.ts +5 -0
  136. package/dist/components/ui/sheet/sheet-overlay.svelte +21 -0
  137. package/dist/components/ui/sheet/sheet-overlay.svelte.d.ts +6 -0
  138. package/dist/components/ui/sheet/sheet-title.svelte +16 -0
  139. package/dist/components/ui/sheet/sheet-title.svelte.d.ts +4 -0
  140. package/dist/components/ui/skeleton/index.d.ts +2 -0
  141. package/dist/components/ui/skeleton/index.js +4 -0
  142. package/dist/components/ui/skeleton/skeleton.svelte +17 -0
  143. package/dist/components/ui/skeleton/skeleton.svelte.d.ts +5 -0
  144. package/dist/components/ui/table/index.d.ts +9 -0
  145. package/dist/components/ui/table/index.js +11 -0
  146. package/dist/components/ui/table/table-body.svelte +16 -0
  147. package/dist/components/ui/table/table-body.svelte.d.ts +5 -0
  148. package/dist/components/ui/table/table-caption.svelte +16 -0
  149. package/dist/components/ui/table/table-caption.svelte.d.ts +5 -0
  150. package/dist/components/ui/table/table-cell.svelte +20 -0
  151. package/dist/components/ui/table/table-cell.svelte.d.ts +5 -0
  152. package/dist/components/ui/table/table-footer.svelte +16 -0
  153. package/dist/components/ui/table/table-footer.svelte.d.ts +5 -0
  154. package/dist/components/ui/table/table-head.svelte +23 -0
  155. package/dist/components/ui/table/table-head.svelte.d.ts +5 -0
  156. package/dist/components/ui/table/table-header.svelte +16 -0
  157. package/dist/components/ui/table/table-header.svelte.d.ts +5 -0
  158. package/dist/components/ui/table/table-row.svelte +23 -0
  159. package/dist/components/ui/table/table-row.svelte.d.ts +5 -0
  160. package/dist/components/ui/table/table.svelte +18 -0
  161. package/dist/components/ui/table/table.svelte.d.ts +5 -0
  162. package/dist/components/ui/tabs/index.d.ts +6 -0
  163. package/dist/components/ui/tabs/index.js +8 -0
  164. package/dist/components/ui/tabs/tabs-content.svelte +19 -0
  165. package/dist/components/ui/tabs/tabs-content.svelte.d.ts +4 -0
  166. package/dist/components/ui/tabs/tabs-list.svelte +19 -0
  167. package/dist/components/ui/tabs/tabs-list.svelte.d.ts +4 -0
  168. package/dist/components/ui/tabs/tabs-trigger.svelte +19 -0
  169. package/dist/components/ui/tabs/tabs-trigger.svelte.d.ts +4 -0
  170. package/dist/components/ui/textarea/index.d.ts +2 -0
  171. package/dist/components/ui/textarea/index.js +4 -0
  172. package/dist/components/ui/textarea/textarea.svelte +24 -0
  173. package/dist/components/ui/textarea/textarea.svelte.d.ts +6 -0
  174. package/dist/components/ui/toast.d.ts +86 -0
  175. package/dist/components/ui/toast.js +99 -0
  176. package/dist/db/schema.sql +238 -0
  177. package/dist/index.d.ts +14 -0
  178. package/dist/index.js +20 -0
  179. package/dist/payments/index.d.ts +33 -0
  180. package/dist/payments/index.js +47 -0
  181. package/dist/payments/shop.d.ts +165 -0
  182. package/dist/payments/shop.js +588 -0
  183. package/dist/payments/stripe/client.d.ts +231 -0
  184. package/dist/payments/stripe/client.js +198 -0
  185. package/dist/payments/stripe/index.d.ts +18 -0
  186. package/dist/payments/stripe/index.js +17 -0
  187. package/dist/payments/stripe/provider.d.ts +50 -0
  188. package/dist/payments/stripe/provider.js +530 -0
  189. package/dist/payments/types.d.ts +355 -0
  190. package/dist/payments/types.js +7 -0
  191. package/dist/server/logger.d.ts +53 -0
  192. package/dist/server/logger.js +252 -0
  193. package/dist/styles/content.css +514 -0
  194. package/dist/styles/tokens.css +175 -0
  195. package/dist/utils/api.d.ts +20 -0
  196. package/dist/utils/api.js +109 -0
  197. package/dist/utils/cn.d.ts +15 -0
  198. package/dist/utils/cn.js +18 -0
  199. package/dist/utils/csrf.d.ts +22 -0
  200. package/dist/utils/csrf.js +72 -0
  201. package/dist/utils/debounce.d.ts +7 -0
  202. package/dist/utils/debounce.js +14 -0
  203. package/dist/utils/gallery.d.ts +66 -0
  204. package/dist/utils/gallery.js +181 -0
  205. package/dist/utils/gutter.d.ts +54 -0
  206. package/dist/utils/gutter.js +169 -0
  207. package/dist/utils/imageProcessor.d.ts +58 -0
  208. package/dist/utils/imageProcessor.js +205 -0
  209. package/dist/utils/json.d.ts +17 -0
  210. package/dist/utils/json.js +26 -0
  211. package/dist/utils/markdown.d.ts +101 -0
  212. package/dist/utils/markdown.js +947 -0
  213. package/dist/utils/sanitize.d.ts +25 -0
  214. package/dist/utils/sanitize.js +127 -0
  215. package/dist/utils/validation.d.ts +46 -0
  216. package/dist/utils/validation.js +169 -0
  217. package/dist/utils.d.ts +5 -0
  218. package/dist/utils.js +5 -0
  219. package/package.json +129 -0
@@ -0,0 +1,107 @@
1
+ <script>
2
+ import ZoomableImage from './ZoomableImage.svelte';
3
+ import LightboxCaption from './LightboxCaption.svelte';
4
+
5
+ /**
6
+ * Lightbox - Full-screen image viewer
7
+ * Click to expand images to full size with zoom and pan support
8
+ */
9
+ let { src = '', alt = '', caption = '', isOpen = false, onClose = () => {} } = $props();
10
+
11
+ function handleKeydown(event) {
12
+ if (event.key === 'Escape') {
13
+ onClose();
14
+ }
15
+ }
16
+
17
+ function handleBackdropClick(event) {
18
+ if (event.target === event.currentTarget) {
19
+ onClose();
20
+ }
21
+ }
22
+ </script>
23
+
24
+ <svelte:window onkeydown={handleKeydown} />
25
+
26
+ {#if isOpen}
27
+ <div
28
+ class="lightbox-backdrop"
29
+ onclick={handleBackdropClick}
30
+ role="dialog"
31
+ aria-modal="true"
32
+ aria-label="Image viewer"
33
+ >
34
+ <button class="close-button" onclick={onClose} aria-label="Close">
35
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
36
+ <line x1="18" y1="6" x2="6" y2="18"></line>
37
+ <line x1="6" y1="6" x2="18" y2="18"></line>
38
+ </svg>
39
+ </button>
40
+ <div class="lightbox-content" onclick={handleBackdropClick}>
41
+ <ZoomableImage {src} {alt} isActive={isOpen} class="lightbox-image" />
42
+ </div>
43
+ <LightboxCaption {caption} />
44
+ </div>
45
+ {/if}
46
+
47
+ <style>
48
+ .lightbox-backdrop {
49
+ position: fixed;
50
+ top: 0;
51
+ left: 0;
52
+ right: 0;
53
+ bottom: 0;
54
+ background: rgba(0, 0, 0, 0.9);
55
+ display: flex;
56
+ flex-direction: column;
57
+ align-items: center;
58
+ justify-content: center;
59
+ z-index: 9999;
60
+ cursor: pointer;
61
+ padding: 2rem;
62
+ }
63
+
64
+ .lightbox-content {
65
+ display: flex;
66
+ flex-direction: column;
67
+ align-items: center;
68
+ max-width: 90vw;
69
+ max-height: 90vh;
70
+ overflow: auto;
71
+ }
72
+
73
+ :global(.lightbox-content .lightbox-image) {
74
+ max-width: 90vw;
75
+ -o-object-fit: contain;
76
+ object-fit: contain;
77
+ border-radius: 4px;
78
+ flex: 1 1 auto;
79
+ min-height: 0;
80
+ }
81
+
82
+ .close-button {
83
+ position: absolute;
84
+ top: 1rem;
85
+ right: 1rem;
86
+ width: 48px;
87
+ height: 48px;
88
+ border-radius: 50%;
89
+ background: rgba(255, 255, 255, 0.1);
90
+ border: none;
91
+ cursor: pointer;
92
+ display: flex;
93
+ align-items: center;
94
+ justify-content: center;
95
+ color: white;
96
+ transition: background 0.2s;
97
+ }
98
+
99
+ .close-button:hover {
100
+ background: rgba(255, 255, 255, 0.2);
101
+ }
102
+
103
+ .close-button svg {
104
+ width: 24px;
105
+ height: 24px;
106
+ }
107
+ </style>
@@ -0,0 +1,19 @@
1
+ export default Lightbox;
2
+ type Lightbox = {
3
+ $on?(type: string, callback: (e: any) => void): () => void;
4
+ $set?(props: Partial<$$ComponentProps>): void;
5
+ };
6
+ declare const Lightbox: import("svelte").Component<{
7
+ src?: string;
8
+ alt?: string;
9
+ caption?: string;
10
+ isOpen?: boolean;
11
+ onClose?: Function;
12
+ }, {}, "">;
13
+ type $$ComponentProps = {
14
+ src?: string;
15
+ alt?: string;
16
+ caption?: string;
17
+ isOpen?: boolean;
18
+ onClose?: Function;
19
+ };
@@ -0,0 +1,25 @@
1
+ <script>
2
+ /**
3
+ * LightboxCaption - Shared caption component for lightbox viewers
4
+ * Displays image captions with consistent styling
5
+ *
6
+ * @prop {string} caption - The caption text to display
7
+ */
8
+ let { caption = '' } = $props();
9
+ </script>
10
+
11
+ {#if caption}
12
+ <div class="lightbox-caption">{caption}</div>
13
+ {/if}
14
+
15
+ <style>
16
+ .lightbox-caption {
17
+ padding: 0.75rem 1rem;
18
+ color: rgba(255, 255, 255, 0.9);
19
+ font-size: 0.9rem;
20
+ font-style: italic;
21
+ text-align: center;
22
+ max-width: 90vw;
23
+ line-height: 1.5;
24
+ }
25
+ </style>
@@ -0,0 +1,11 @@
1
+ export default LightboxCaption;
2
+ type LightboxCaption = {
3
+ $on?(type: string, callback: (e: any) => void): () => void;
4
+ $set?(props: Partial<$$ComponentProps>): void;
5
+ };
6
+ declare const LightboxCaption: import("svelte").Component<{
7
+ caption?: string;
8
+ }, {}, "">;
9
+ type $$ComponentProps = {
10
+ caption?: string;
11
+ };
@@ -0,0 +1,163 @@
1
+ <script>
2
+ /**
3
+ * ZoomableImage - Image with zoom and pan functionality
4
+ * Click to cycle through zoom levels, drag to pan when zoomed
5
+ *
6
+ * @prop {string} src - Image source URL
7
+ * @prop {string} alt - Alt text for accessibility
8
+ * @prop {boolean} isActive - When false, resets zoom/pan state
9
+ * @prop {string} class - Additional CSS classes
10
+ */
11
+ let { src = '', alt = '', isActive = true, class: className = '' } = $props();
12
+
13
+ // Zoom state: 0 = normal, 1 = medium zoom (1.5x), 2 = max zoom (2.5x)
14
+ let zoomLevel = $state(0);
15
+
16
+ // Pan/drag state for zoomed images
17
+ let isDragging = $state(false);
18
+ let panX = $state(0);
19
+ let panY = $state(0);
20
+ let dragStartX = $state(0);
21
+ let dragStartY = $state(0);
22
+ let dragStartPanX = $state(0);
23
+ let dragStartPanY = $state(0);
24
+ let totalDragDistance = $state(0);
25
+
26
+ // Derived scale value based on zoom level
27
+ let scaleValue = $derived(zoomLevel === 0 ? 1 : zoomLevel === 1 ? 1.5 : 2.5);
28
+
29
+ // Reset zoom and pan when isActive becomes false or src changes
30
+ $effect(() => {
31
+ if (!isActive) {
32
+ zoomLevel = 0;
33
+ panX = 0;
34
+ panY = 0;
35
+ isDragging = false;
36
+ }
37
+ });
38
+
39
+ // Reset when image source changes
40
+ $effect(() => {
41
+ // Track src to trigger reset
42
+ src;
43
+ zoomLevel = 0;
44
+ panX = 0;
45
+ panY = 0;
46
+ isDragging = false;
47
+ });
48
+
49
+ function cycleZoom() {
50
+ zoomLevel = (zoomLevel + 1) % 3;
51
+ // Reset pan when zooming out to level 0
52
+ if (zoomLevel === 0) {
53
+ panX = 0;
54
+ panY = 0;
55
+ }
56
+ }
57
+
58
+ // Mouse event handlers for drag/pan
59
+ function handleMouseDown(event) {
60
+ if (zoomLevel === 0) return;
61
+
62
+ isDragging = true;
63
+ dragStartX = event.clientX;
64
+ dragStartY = event.clientY;
65
+ dragStartPanX = panX;
66
+ dragStartPanY = panY;
67
+ totalDragDistance = 0;
68
+ event.preventDefault();
69
+ }
70
+
71
+ function handleMouseMove(event) {
72
+ if (!isDragging) return;
73
+
74
+ const deltaX = event.clientX - dragStartX;
75
+ const deltaY = event.clientY - dragStartY;
76
+
77
+ panX = dragStartPanX + deltaX;
78
+ panY = dragStartPanY + deltaY;
79
+ totalDragDistance += Math.abs(deltaX) + Math.abs(deltaY);
80
+ }
81
+
82
+ function handleMouseUp() {
83
+ isDragging = false;
84
+ }
85
+
86
+ // Touch event handlers for drag/pan on mobile
87
+ function handleTouchStart(event) {
88
+ if (zoomLevel === 0) return;
89
+
90
+ // Only handle single touch for panning
91
+ if (event.touches.length === 1) {
92
+ isDragging = true;
93
+ dragStartX = event.touches[0].clientX;
94
+ dragStartY = event.touches[0].clientY;
95
+ dragStartPanX = panX;
96
+ dragStartPanY = panY;
97
+ totalDragDistance = 0;
98
+ event.preventDefault();
99
+ }
100
+ }
101
+
102
+ function handleTouchMove(event) {
103
+ if (!isDragging || event.touches.length !== 1) return;
104
+
105
+ const deltaX = event.touches[0].clientX - dragStartX;
106
+ const deltaY = event.touches[0].clientY - dragStartY;
107
+
108
+ panX = dragStartPanX + deltaX;
109
+ panY = dragStartPanY + deltaY;
110
+ totalDragDistance += Math.abs(deltaX) + Math.abs(deltaY);
111
+ event.preventDefault();
112
+ }
113
+
114
+ function handleTouchEnd() {
115
+ isDragging = false;
116
+ }
117
+
118
+ // Click handler that distinguishes between click and drag
119
+ function handleClick(event) {
120
+ // If we dragged more than 5px, don't treat as click
121
+ if (totalDragDistance > 5) {
122
+ totalDragDistance = 0;
123
+ return;
124
+ }
125
+ cycleZoom();
126
+ }
127
+ </script>
128
+
129
+ <svelte:window onmousemove={handleMouseMove} onmouseup={handleMouseUp} />
130
+
131
+ <img
132
+ {src}
133
+ {alt}
134
+ class="zoomable-image {className}"
135
+ class:zoomed={zoomLevel > 0}
136
+ class:dragging={isDragging}
137
+ style="transform: translate({panX}px, {panY}px) scale({scaleValue})"
138
+ onmousedown={handleMouseDown}
139
+ ontouchstart={handleTouchStart}
140
+ ontouchmove={handleTouchMove}
141
+ ontouchend={handleTouchEnd}
142
+ onclick={handleClick}
143
+ />
144
+
145
+ <style>
146
+ .zoomable-image {
147
+ cursor: zoom-in;
148
+ transition: transform 0.3s ease;
149
+ -webkit-user-select: none;
150
+ -moz-user-select: none;
151
+ user-select: none;
152
+ -webkit-user-drag: none;
153
+ }
154
+
155
+ .zoomable-image.zoomed {
156
+ cursor: grab;
157
+ }
158
+
159
+ .zoomable-image.dragging {
160
+ cursor: grabbing;
161
+ transition: none;
162
+ }
163
+ </style>
@@ -0,0 +1,17 @@
1
+ export default ZoomableImage;
2
+ type ZoomableImage = {
3
+ $on?(type: string, callback: (e: any) => void): () => void;
4
+ $set?(props: Partial<$$ComponentProps>): void;
5
+ };
6
+ declare const ZoomableImage: import("svelte").Component<{
7
+ src?: string;
8
+ alt?: string;
9
+ isActive?: boolean;
10
+ class?: string;
11
+ }, {}, "">;
12
+ type $$ComponentProps = {
13
+ src?: string;
14
+ alt?: string;
15
+ isActive?: boolean;
16
+ class?: string;
17
+ };
@@ -0,0 +1,74 @@
1
+ <script lang="ts">
2
+ import {
3
+ Accordion as ShadcnAccordion,
4
+ AccordionItem,
5
+ AccordionTrigger,
6
+ AccordionContent
7
+ } from "./accordion";
8
+ import type { Snippet } from "svelte";
9
+
10
+ interface AccordionItemConfig {
11
+ value: string;
12
+ title: string;
13
+ content?: string;
14
+ disabled?: boolean;
15
+ }
16
+
17
+ /**
18
+ * Accordion component wrapper for collapsible content sections
19
+ *
20
+ * @prop {AccordionItemConfig[]} items - Array of accordion items with value, title, optional content and disabled flag
21
+ * @prop {string} [type="single"] - Accordion behavior: "single" (one open) or "multiple" (many open)
22
+ * @prop {boolean} [collapsible=false] - Allow closing all items (only for type="single")
23
+ * @prop {Snippet<[AccordionItemConfig]>} [contentSnippet] - Custom content renderer (receives item data)
24
+ * @prop {string} [class] - Additional CSS classes for Accordion root
25
+ *
26
+ * @example
27
+ * <Accordion items={[
28
+ * { value: "faq1", title: "What is this?", content: "This is an FAQ" },
29
+ * { value: "faq2", title: "How does it work?", content: "Very well!" }
30
+ * ]} type="single" collapsible />
31
+ *
32
+ * @example
33
+ * <Accordion items={sections} type="multiple">
34
+ * {#snippet contentSnippet(item)}
35
+ * <DetailedContent data={item} />
36
+ * {/snippet}
37
+ * </Accordion>
38
+ *
39
+ * @example
40
+ * <Accordion items={helpTopics} type="single" class="w-full" />
41
+ */
42
+ interface Props {
43
+ items: AccordionItemConfig[];
44
+ type?: "single" | "multiple";
45
+ collapsible?: boolean;
46
+ class?: string;
47
+ contentSnippet?: Snippet<[item: AccordionItemConfig]>;
48
+ }
49
+
50
+ let {
51
+ items,
52
+ type = "single",
53
+ collapsible = false,
54
+ class: className,
55
+ contentSnippet
56
+ }: Props = $props();
57
+
58
+ const accordionType = $derived(type === "single" ? "single" : "multiple");
59
+ </script>
60
+
61
+ <ShadcnAccordion type={accordionType} {collapsible} class={className}>
62
+ {#each items as item (item.value)}
63
+ <AccordionItem value={item.value} disabled={item.disabled ?? false}>
64
+ <AccordionTrigger>{item.title}</AccordionTrigger>
65
+ <AccordionContent>
66
+ {#if contentSnippet}
67
+ {@render contentSnippet(item)}
68
+ {:else if item.content}
69
+ {item.content}
70
+ {/if}
71
+ </AccordionContent>
72
+ </AccordionItem>
73
+ {/each}
74
+ </ShadcnAccordion>
@@ -0,0 +1,42 @@
1
+ import type { Snippet } from "svelte";
2
+ interface AccordionItemConfig {
3
+ value: string;
4
+ title: string;
5
+ content?: string;
6
+ disabled?: boolean;
7
+ }
8
+ /**
9
+ * Accordion component wrapper for collapsible content sections
10
+ *
11
+ * @prop {AccordionItemConfig[]} items - Array of accordion items with value, title, optional content and disabled flag
12
+ * @prop {string} [type="single"] - Accordion behavior: "single" (one open) or "multiple" (many open)
13
+ * @prop {boolean} [collapsible=false] - Allow closing all items (only for type="single")
14
+ * @prop {Snippet<[AccordionItemConfig]>} [contentSnippet] - Custom content renderer (receives item data)
15
+ * @prop {string} [class] - Additional CSS classes for Accordion root
16
+ *
17
+ * @example
18
+ * <Accordion items={[
19
+ * { value: "faq1", title: "What is this?", content: "This is an FAQ" },
20
+ * { value: "faq2", title: "How does it work?", content: "Very well!" }
21
+ * ]} type="single" collapsible />
22
+ *
23
+ * @example
24
+ * <Accordion items={sections} type="multiple">
25
+ * {#snippet contentSnippet(item)}
26
+ * <DetailedContent data={item} />
27
+ * {/snippet}
28
+ * </Accordion>
29
+ *
30
+ * @example
31
+ * <Accordion items={helpTopics} type="single" class="w-full" />
32
+ */
33
+ interface Props {
34
+ items: AccordionItemConfig[];
35
+ type?: "single" | "multiple";
36
+ collapsible?: boolean;
37
+ class?: string;
38
+ contentSnippet?: Snippet<[item: AccordionItemConfig]>;
39
+ }
40
+ declare const Accordion: import("svelte").Component<Props, {}, "">;
41
+ type Accordion = ReturnType<typeof Accordion>;
42
+ export default Accordion;
@@ -0,0 +1,48 @@
1
+ <script lang="ts">
2
+ import { Badge as ShadcnBadge } from "./badge";
3
+ import type { Snippet } from "svelte";
4
+
5
+ type BadgeVariant = "default" | "secondary" | "destructive" | "tag";
6
+
7
+ /**
8
+ * Badge component wrapper for displaying small labels, tags, or status indicators
9
+ *
10
+ * @prop {BadgeVariant} [variant="default"] - Badge style variant (default|secondary|destructive|tag)
11
+ * @prop {string} [class] - Additional CSS classes to apply
12
+ * @prop {Snippet} [children] - Badge content (typically short text)
13
+ *
14
+ * @example
15
+ * <Badge variant="default">New</Badge>
16
+ *
17
+ * @example
18
+ * <Badge variant="destructive">Error</Badge>
19
+ *
20
+ * @example
21
+ * <Badge variant="tag">TypeScript</Badge>
22
+ */
23
+ interface Props {
24
+ variant?: BadgeVariant;
25
+ class?: string;
26
+ children?: Snippet;
27
+ }
28
+
29
+ let {
30
+ variant = "default",
31
+ class: className,
32
+ children
33
+ }: Props = $props();
34
+
35
+ // Map tag variant to secondary styling
36
+ const variantMap: Record<BadgeVariant, "default" | "secondary" | "destructive"> = {
37
+ default: "default",
38
+ secondary: "secondary",
39
+ destructive: "destructive",
40
+ tag: "secondary"
41
+ };
42
+
43
+ const shadcnVariant = $derived(variantMap[variant]);
44
+ </script>
45
+
46
+ <ShadcnBadge variant={shadcnVariant} class={className}>
47
+ {@render children?.()}
48
+ </ShadcnBadge>
@@ -0,0 +1,26 @@
1
+ import type { Snippet } from "svelte";
2
+ type BadgeVariant = "default" | "secondary" | "destructive" | "tag";
3
+ /**
4
+ * Badge component wrapper for displaying small labels, tags, or status indicators
5
+ *
6
+ * @prop {BadgeVariant} [variant="default"] - Badge style variant (default|secondary|destructive|tag)
7
+ * @prop {string} [class] - Additional CSS classes to apply
8
+ * @prop {Snippet} [children] - Badge content (typically short text)
9
+ *
10
+ * @example
11
+ * <Badge variant="default">New</Badge>
12
+ *
13
+ * @example
14
+ * <Badge variant="destructive">Error</Badge>
15
+ *
16
+ * @example
17
+ * <Badge variant="tag">TypeScript</Badge>
18
+ */
19
+ interface Props {
20
+ variant?: BadgeVariant;
21
+ class?: string;
22
+ children?: Snippet;
23
+ }
24
+ declare const Badge: import("svelte").Component<Props, {}, "">;
25
+ type Badge = ReturnType<typeof Badge>;
26
+ export default Badge;
@@ -0,0 +1,74 @@
1
+ <script lang="ts">
2
+ import { Button as ShadcnButton } from "./button";
3
+ import type { Snippet } from "svelte";
4
+ import type { HTMLButtonAttributes } from "svelte/elements";
5
+
6
+ type ButtonVariant = "primary" | "secondary" | "danger" | "ghost" | "link";
7
+ type ButtonSize = "sm" | "md" | "lg";
8
+
9
+ /**
10
+ * Button component wrapper around shadcn-svelte Button
11
+ *
12
+ * @prop {ButtonVariant} [variant="primary"] - Button style variant (primary|secondary|danger|ghost|link)
13
+ * @prop {ButtonSize} [size="md"] - Button size (sm|md|lg)
14
+ * @prop {boolean} [disabled=false] - Whether button is disabled
15
+ * @prop {Function} [onclick] - Click handler function
16
+ * @prop {string} [href] - Optional link href (renders as anchor element)
17
+ * @prop {string} [class] - Additional CSS classes to apply
18
+ * @prop {Snippet} [children] - Button content (text/icons/etc)
19
+ *
20
+ * @example
21
+ * <Button variant="primary" size="lg">Save Changes</Button>
22
+ *
23
+ * @example
24
+ * <Button variant="danger" onclick={() => handleDelete()}>Delete</Button>
25
+ *
26
+ * @example
27
+ * <Button variant="ghost" href="/settings">Settings</Button>
28
+ */
29
+ interface Props extends Omit<HTMLButtonAttributes, "class"> {
30
+ variant?: ButtonVariant;
31
+ size?: ButtonSize;
32
+ disabled?: boolean;
33
+ class?: string;
34
+ children?: Snippet;
35
+ }
36
+
37
+ let {
38
+ variant = "primary",
39
+ size = "md",
40
+ disabled = false,
41
+ class: className,
42
+ children,
43
+ ...restProps
44
+ }: Props = $props();
45
+
46
+ // Map our simplified variants to shadcn variants
47
+ const variantMap: Record<ButtonVariant, "default" | "secondary" | "destructive" | "ghost" | "link"> = {
48
+ primary: "default",
49
+ secondary: "secondary",
50
+ danger: "destructive",
51
+ ghost: "ghost",
52
+ link: "link"
53
+ };
54
+
55
+ // Map our size variants to shadcn sizes
56
+ const sizeMap: Record<ButtonSize, "sm" | "default" | "lg"> = {
57
+ sm: "sm",
58
+ md: "default",
59
+ lg: "lg"
60
+ };
61
+
62
+ const shadcnVariant = $derived(variantMap[variant]);
63
+ const shadcnSize = $derived(sizeMap[size]);
64
+ </script>
65
+
66
+ <ShadcnButton
67
+ variant={shadcnVariant}
68
+ size={shadcnSize}
69
+ disabled={disabled}
70
+ class={className}
71
+ {...restProps}
72
+ >
73
+ {@render children?.()}
74
+ </ShadcnButton>
@@ -0,0 +1,34 @@
1
+ import type { Snippet } from "svelte";
2
+ import type { HTMLButtonAttributes } from "svelte/elements";
3
+ type ButtonVariant = "primary" | "secondary" | "danger" | "ghost" | "link";
4
+ type ButtonSize = "sm" | "md" | "lg";
5
+ /**
6
+ * Button component wrapper around shadcn-svelte Button
7
+ *
8
+ * @prop {ButtonVariant} [variant="primary"] - Button style variant (primary|secondary|danger|ghost|link)
9
+ * @prop {ButtonSize} [size="md"] - Button size (sm|md|lg)
10
+ * @prop {boolean} [disabled=false] - Whether button is disabled
11
+ * @prop {Function} [onclick] - Click handler function
12
+ * @prop {string} [href] - Optional link href (renders as anchor element)
13
+ * @prop {string} [class] - Additional CSS classes to apply
14
+ * @prop {Snippet} [children] - Button content (text/icons/etc)
15
+ *
16
+ * @example
17
+ * <Button variant="primary" size="lg">Save Changes</Button>
18
+ *
19
+ * @example
20
+ * <Button variant="danger" onclick={() => handleDelete()}>Delete</Button>
21
+ *
22
+ * @example
23
+ * <Button variant="ghost" href="/settings">Settings</Button>
24
+ */
25
+ interface Props extends Omit<HTMLButtonAttributes, "class"> {
26
+ variant?: ButtonVariant;
27
+ size?: ButtonSize;
28
+ disabled?: boolean;
29
+ class?: string;
30
+ children?: Snippet;
31
+ }
32
+ declare const Button: import("svelte").Component<Props, {}, "">;
33
+ type Button = ReturnType<typeof Button>;
34
+ export default Button;