@joewinke/jatui 0.1.24 → 0.1.26

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 (242) hide show
  1. package/dist/actions/collapse.d.ts +80 -0
  2. package/dist/actions/collapse.js +134 -0
  3. package/dist/actions/railNav.d.ts +167 -0
  4. package/dist/actions/railNav.js +351 -0
  5. package/dist/components/AnnotationLayer.svelte +108 -0
  6. package/dist/components/AnnotationLayer.svelte.d.ts +12 -0
  7. package/dist/components/AnnotationPanel.svelte +319 -0
  8. package/dist/components/AnnotationPanel.svelte.d.ts +13 -0
  9. package/dist/components/AudioWaveform.svelte +701 -0
  10. package/dist/components/AudioWaveform.svelte.d.ts +19 -0
  11. package/dist/components/AvailabilityModal.svelte +177 -0
  12. package/dist/components/AvailabilityModal.svelte.d.ts +14 -0
  13. package/dist/components/AvatarUpload.svelte +234 -0
  14. package/dist/components/AvatarUpload.svelte.d.ts +23 -0
  15. package/dist/components/Badge.svelte +38 -0
  16. package/dist/components/Badge.svelte.d.ts +14 -0
  17. package/dist/components/BookingForm.svelte +278 -0
  18. package/dist/components/BookingForm.svelte.d.ts +37 -0
  19. package/dist/components/BurndownChart.svelte +778 -0
  20. package/dist/components/BurndownChart.svelte.d.ts +17 -0
  21. package/dist/components/Button.svelte +81 -0
  22. package/dist/components/Button.svelte.d.ts +21 -0
  23. package/dist/components/CalendarPicker.svelte +284 -0
  24. package/dist/components/CalendarPicker.svelte.d.ts +22 -0
  25. package/dist/components/Card.svelte +67 -0
  26. package/dist/components/Card.svelte.d.ts +17 -0
  27. package/dist/components/CharacterCounter.svelte +82 -0
  28. package/dist/components/CharacterCounter.svelte.d.ts +10 -0
  29. package/dist/components/ChipInput.svelte +609 -0
  30. package/dist/components/ChipInput.svelte.d.ts +55 -0
  31. package/dist/components/Collapse.svelte +91 -0
  32. package/dist/components/Collapse.svelte.d.ts +18 -0
  33. package/dist/components/ColorSelector.svelte +167 -0
  34. package/dist/components/ColorSelector.svelte.d.ts +9 -0
  35. package/dist/components/CommentThread.svelte +773 -0
  36. package/dist/components/CommentThread.svelte.d.ts +32 -0
  37. package/dist/components/ConfirmDialog.svelte +348 -0
  38. package/dist/components/ConfirmDialog.svelte.d.ts +3 -0
  39. package/dist/components/ConfirmModal.svelte +142 -0
  40. package/dist/components/ConfirmModal.svelte.d.ts +15 -0
  41. package/dist/components/ContextMenu.svelte +188 -0
  42. package/dist/components/ContextMenu.svelte.d.ts +31 -0
  43. package/dist/components/CountdownTimer.svelte +94 -0
  44. package/dist/components/CountdownTimer.svelte.d.ts +10 -0
  45. package/dist/components/DateRangePicker.svelte +194 -0
  46. package/dist/components/DateRangePicker.svelte.d.ts +10 -0
  47. package/dist/components/Drawer.svelte +143 -0
  48. package/dist/components/Drawer.svelte.d.ts +33 -0
  49. package/dist/components/EmojiPicker.svelte +159 -0
  50. package/dist/components/EmojiPicker.svelte.d.ts +8 -0
  51. package/dist/components/EntityPreviewCard.svelte +104 -0
  52. package/dist/components/EntityPreviewCard.svelte.d.ts +9 -0
  53. package/dist/components/FileDropzone.svelte +493 -0
  54. package/dist/components/FileDropzone.svelte.d.ts +40 -0
  55. package/dist/components/FilePicker.svelte +488 -0
  56. package/dist/components/FilePicker.svelte.d.ts +20 -0
  57. package/dist/components/FileThumbnail.svelte +80 -0
  58. package/dist/components/FileThumbnail.svelte.d.ts +12 -0
  59. package/dist/components/FilterDropdown.svelte +203 -0
  60. package/dist/components/FilterDropdown.svelte.d.ts +48 -0
  61. package/dist/components/FloatingActionBar.svelte +354 -0
  62. package/dist/components/FloatingActionBar.svelte.d.ts +51 -0
  63. package/dist/components/GPSTracker.svelte +202 -0
  64. package/dist/components/GPSTracker.svelte.d.ts +34 -0
  65. package/dist/components/HunkDiffView.svelte +348 -0
  66. package/dist/components/HunkDiffView.svelte.d.ts +9 -0
  67. package/dist/components/ImageLightbox.svelte +274 -0
  68. package/dist/components/ImageLightbox.svelte.d.ts +25 -0
  69. package/dist/components/ImageUpload.svelte +147 -0
  70. package/dist/components/ImageUpload.svelte.d.ts +10 -0
  71. package/dist/components/InlineEdit.svelte +291 -0
  72. package/dist/components/InlineEdit.svelte.d.ts +45 -0
  73. package/dist/components/InputDialog.svelte +327 -0
  74. package/dist/components/InputDialog.svelte.d.ts +3 -0
  75. package/dist/components/KeyboardShortcutsOverlay.svelte +296 -0
  76. package/dist/components/KeyboardShortcutsOverlay.svelte.d.ts +42 -0
  77. package/dist/components/LazyImage.svelte +123 -0
  78. package/dist/components/LazyImage.svelte.d.ts +14 -0
  79. package/dist/components/LinkShortener.svelte +274 -0
  80. package/dist/components/LinkShortener.svelte.d.ts +27 -0
  81. package/dist/components/LoadingSpinner.svelte +106 -0
  82. package/dist/components/LoadingSpinner.svelte.d.ts +21 -0
  83. package/dist/components/LocationMap.svelte +186 -0
  84. package/dist/components/LocationMap.svelte.d.ts +11 -0
  85. package/dist/components/MapView.svelte +341 -0
  86. package/dist/components/MapView.svelte.d.ts +20 -0
  87. package/dist/components/MarkupEditor.svelte +485 -0
  88. package/dist/components/MarkupEditor.svelte.d.ts +10 -0
  89. package/dist/components/MarkupOverlay.svelte +55 -0
  90. package/dist/components/MarkupOverlay.svelte.d.ts +8 -0
  91. package/dist/components/MediaWorkbench.svelte +871 -0
  92. package/dist/components/MediaWorkbench.svelte.d.ts +9 -0
  93. package/dist/components/MilestoneCard.svelte +98 -0
  94. package/dist/components/MilestoneCard.svelte.d.ts +16 -0
  95. package/dist/components/MilestoneTimeline.svelte +91 -0
  96. package/dist/components/MilestoneTimeline.svelte.d.ts +15 -0
  97. package/dist/components/Modal.svelte +244 -0
  98. package/dist/components/Modal.svelte.d.ts +35 -0
  99. package/dist/components/PDFViewer.svelte +105 -0
  100. package/dist/components/PDFViewer.svelte.d.ts +9 -0
  101. package/dist/components/PdfThumbnail.svelte +63 -0
  102. package/dist/components/PdfThumbnail.svelte.d.ts +9 -0
  103. package/dist/components/PhoneInput.svelte +212 -0
  104. package/dist/components/PhoneInput.svelte.d.ts +25 -0
  105. package/dist/components/ResizableDivider.svelte +307 -0
  106. package/dist/components/ResizableDivider.svelte.d.ts +26 -0
  107. package/dist/components/ResizablePanel.svelte +305 -0
  108. package/dist/components/ResizablePanel.svelte.d.ts +18 -0
  109. package/dist/components/SearchDropdown.svelte +421 -0
  110. package/dist/components/SearchDropdown.svelte.d.ts +24 -0
  111. package/dist/components/SelectInput.svelte +237 -0
  112. package/dist/components/SelectInput.svelte.d.ts +26 -0
  113. package/dist/components/SidebarUserFooter.svelte +34 -0
  114. package/dist/components/SidebarUserFooter.svelte.d.ts +16 -0
  115. package/dist/components/SignaturePad.svelte +175 -0
  116. package/dist/components/SignaturePad.svelte.d.ts +17 -0
  117. package/dist/components/SmartImageEditor.svelte +720 -0
  118. package/dist/components/SmartImageEditor.svelte.d.ts +24 -0
  119. package/dist/components/SortDropdown.svelte +156 -0
  120. package/dist/components/SortDropdown.svelte.d.ts +40 -0
  121. package/dist/components/Sparkline.svelte +116 -0
  122. package/dist/components/Sparkline.svelte.d.ts +12 -0
  123. package/dist/components/SpeechForm.svelte +114 -0
  124. package/dist/components/SpeechForm.svelte.d.ts +17 -0
  125. package/dist/components/StatusBadge.svelte +157 -0
  126. package/dist/components/StatusBadge.svelte.d.ts +24 -0
  127. package/dist/components/TaskTypeIcon.svelte +54 -0
  128. package/dist/components/TaskTypeIcon.svelte.d.ts +17 -0
  129. package/dist/components/TextArea.svelte +162 -0
  130. package/dist/components/TextArea.svelte.d.ts +30 -0
  131. package/dist/components/TextInput.svelte +131 -0
  132. package/dist/components/TextInput.svelte.d.ts +29 -0
  133. package/dist/components/ThemeSelector.svelte +206 -0
  134. package/dist/components/ThemeSelector.svelte.d.ts +14 -0
  135. package/dist/components/TimeSlotPicker.svelte +162 -0
  136. package/dist/components/TimeSlotPicker.svelte.d.ts +18 -0
  137. package/dist/components/UserAvatar.svelte +72 -0
  138. package/dist/components/UserAvatar.svelte.d.ts +11 -0
  139. package/dist/components/VariablePicker.svelte +170 -0
  140. package/dist/components/VariablePicker.svelte.d.ts +40 -0
  141. package/dist/components/VoicePlayer.svelte +422 -0
  142. package/dist/components/VoicePlayer.svelte.d.ts +18 -0
  143. package/dist/components/linked-columns/LinkedColumns.svelte +526 -0
  144. package/dist/components/linked-columns/LinkedColumns.svelte.d.ts +130 -0
  145. package/dist/components/markup.d.ts +47 -0
  146. package/dist/components/markup.js +201 -0
  147. package/dist/components/messaging/Avatar.svelte +81 -0
  148. package/dist/components/messaging/Avatar.svelte.d.ts +11 -0
  149. package/dist/components/messaging/ChannelInfoModal.svelte +163 -0
  150. package/dist/components/messaging/ChannelInfoModal.svelte.d.ts +18 -0
  151. package/dist/components/messaging/ChannelList.svelte +107 -0
  152. package/dist/components/messaging/ChannelList.svelte.d.ts +11 -0
  153. package/dist/components/messaging/ChannelMemberAvatarStack.svelte +69 -0
  154. package/dist/components/messaging/ChannelMemberAvatarStack.svelte.d.ts +11 -0
  155. package/dist/components/messaging/ChannelMembersModal.svelte +182 -0
  156. package/dist/components/messaging/ChannelMembersModal.svelte.d.ts +16 -0
  157. package/dist/components/messaging/CreateChannelModal.svelte +190 -0
  158. package/dist/components/messaging/CreateChannelModal.svelte.d.ts +14 -0
  159. package/dist/components/messaging/DirectMessageList.svelte +145 -0
  160. package/dist/components/messaging/DirectMessageList.svelte.d.ts +12 -0
  161. package/dist/components/messaging/EmojiSelector.svelte +261 -0
  162. package/dist/components/messaging/EmojiSelector.svelte.d.ts +19 -0
  163. package/dist/components/messaging/MentionAutocomplete.svelte +193 -0
  164. package/dist/components/messaging/MentionAutocomplete.svelte.d.ts +17 -0
  165. package/dist/components/messaging/MessageAttachment.svelte +273 -0
  166. package/dist/components/messaging/MessageAttachment.svelte.d.ts +13 -0
  167. package/dist/components/messaging/MessageAttachmentUpload.svelte +243 -0
  168. package/dist/components/messaging/MessageAttachmentUpload.svelte.d.ts +19 -0
  169. package/dist/components/messaging/MessageInput.svelte +452 -0
  170. package/dist/components/messaging/MessageInput.svelte.d.ts +28 -0
  171. package/dist/components/messaging/MessageItem.svelte +341 -0
  172. package/dist/components/messaging/MessageItem.svelte.d.ts +41 -0
  173. package/dist/components/messaging/MessageThread.svelte +306 -0
  174. package/dist/components/messaging/MessageThread.svelte.d.ts +30 -0
  175. package/dist/components/messaging/NotificationSettingsModal.svelte +234 -0
  176. package/dist/components/messaging/NotificationSettingsModal.svelte.d.ts +13 -0
  177. package/dist/components/messaging/QuotedMessageDisplay.svelte +123 -0
  178. package/dist/components/messaging/QuotedMessageDisplay.svelte.d.ts +10 -0
  179. package/dist/components/messaging/StartDMModal.svelte +100 -0
  180. package/dist/components/messaging/StartDMModal.svelte.d.ts +14 -0
  181. package/dist/components/messaging/ThreadPanel.svelte +153 -0
  182. package/dist/components/messaging/ThreadPanel.svelte.d.ts +16 -0
  183. package/dist/components/pipeline/DESIGN.md +361 -0
  184. package/dist/components/pipeline/Pipeline.svelte +391 -0
  185. package/dist/components/pipeline/Pipeline.svelte.d.ts +28 -0
  186. package/dist/components/pipeline/PipelineCard.svelte +94 -0
  187. package/dist/components/pipeline/PipelineCard.svelte.d.ts +13 -0
  188. package/dist/components/pipeline/PipelineColumn.svelte +163 -0
  189. package/dist/components/pipeline/PipelineColumn.svelte.d.ts +30 -0
  190. package/dist/components/replay/ChapterTimeline.svelte +326 -0
  191. package/dist/components/replay/ChapterTimeline.svelte.d.ts +39 -0
  192. package/dist/components/session-nav/transcriptModel.d.ts +132 -0
  193. package/dist/components/session-nav/transcriptModel.js +285 -0
  194. package/dist/data/emojis.d.ts +18 -0
  195. package/dist/data/emojis.js +1196 -0
  196. package/dist/index.d.ts +142 -0
  197. package/dist/index.js +142 -0
  198. package/dist/stores/confirmDialog.svelte.d.ts +21 -0
  199. package/dist/stores/confirmDialog.svelte.js +31 -0
  200. package/dist/stores/inputDialog.svelte.d.ts +24 -0
  201. package/dist/stores/inputDialog.svelte.js +32 -0
  202. package/dist/styles/rail.css +63 -0
  203. package/dist/types/annotation.d.ts +32 -0
  204. package/dist/types/annotation.js +3 -0
  205. package/dist/types/booking.d.ts +115 -0
  206. package/dist/types/booking.js +24 -0
  207. package/dist/types/comments.d.ts +65 -0
  208. package/dist/types/comments.js +22 -0
  209. package/dist/types/entityPreview.d.ts +42 -0
  210. package/dist/types/entityPreview.js +10 -0
  211. package/dist/types/filePicker.d.ts +15 -0
  212. package/dist/types/filePicker.js +1 -0
  213. package/dist/types/googleMaps.d.ts +51 -0
  214. package/dist/types/maps.d.ts +43 -0
  215. package/dist/types/maps.js +4 -0
  216. package/dist/types/messaging.d.ts +282 -0
  217. package/dist/types/messaging.js +100 -0
  218. package/dist/types/milestone.d.ts +20 -0
  219. package/dist/types/milestone.js +7 -0
  220. package/dist/types/pipeline.d.ts +115 -0
  221. package/dist/types/pipeline.js +15 -0
  222. package/dist/types/smartImageEditor.d.ts +42 -0
  223. package/dist/types/smartImageEditor.js +1 -0
  224. package/dist/types/templateVars.d.ts +34 -0
  225. package/dist/types/templateVars.js +12 -0
  226. package/dist/utils/currency.d.ts +8 -0
  227. package/dist/utils/currency.js +17 -0
  228. package/dist/utils/daisyuiColors.d.ts +37 -0
  229. package/dist/utils/daisyuiColors.js +152 -0
  230. package/dist/utils/dateFormatters.d.ts +69 -0
  231. package/dist/utils/dateFormatters.js +199 -0
  232. package/dist/utils/googleMapsLoader.d.ts +19 -0
  233. package/dist/utils/googleMapsLoader.js +121 -0
  234. package/dist/utils/mentionParser.d.ts +67 -0
  235. package/dist/utils/mentionParser.js +132 -0
  236. package/dist/utils/phone.d.ts +13 -0
  237. package/dist/utils/phone.js +67 -0
  238. package/dist/utils/phoneFormat.d.ts +26 -0
  239. package/dist/utils/phoneFormat.js +69 -0
  240. package/dist/utils/taskUtils.d.ts +37 -0
  241. package/dist/utils/taskUtils.js +71 -0
  242. package/package.json +3 -2
@@ -0,0 +1,24 @@
1
+ import type { ImageProcessingSpec, VariantResult } from "../types/smartImageEditor";
2
+ type $$ComponentProps = {
3
+ spec?: ImageProcessingSpec;
4
+ uploadEndpoint?: string;
5
+ value?: string;
6
+ onComplete?: (variants: VariantResult[]) => void;
7
+ /** Called when the user confirms delete on a variant tile. The host
8
+ * decides what "delete" means (typically: remove from storage + clear
9
+ * the stored URL). Returning false (or throwing) leaves the tile in
10
+ * place; returning truthy clears the tile's variant state. */
11
+ onDelete?: (variantName: string) => Promise<boolean | void> | boolean | void;
12
+ /** Called when the user drops/picks a file directly into an empty
13
+ * variant tile — bypasses the AI pipeline. The host uploads the file
14
+ * to its variant slot and returns the resulting VariantResult (or
15
+ * null on failure). When provided, idle tiles become drop-targets. */
16
+ onDirectUpload?: (variantName: string, file: File) => Promise<VariantResult | null>;
17
+ accept?: string;
18
+ maxSizeMb?: number;
19
+ /** Pre-populate variant cells with existing stored URLs (keyed by variant name). */
20
+ previewUrls?: Record<string, string>;
21
+ };
22
+ declare const SmartImageEditor: import("svelte").Component<$$ComponentProps, {}, "value">;
23
+ type SmartImageEditor = ReturnType<typeof SmartImageEditor>;
24
+ export default SmartImageEditor;
@@ -0,0 +1,156 @@
1
+ <script lang="ts">
2
+ /**
3
+ * SortDropdown Component - Reusable sort dropdown with optional filter input
4
+ *
5
+ * A standardized dropdown for sorting lists with:
6
+ * - Sort button showing current option icon, label, and direction indicator
7
+ * - Dropdown menu with configurable sort options
8
+ * - Optional filter input for search/filtering
9
+ */
10
+
11
+ type SortDirection = 'asc' | 'desc';
12
+
13
+ export interface SortOption {
14
+ value: string;
15
+ label: string;
16
+ icon: string;
17
+ defaultDir?: SortDirection;
18
+ }
19
+
20
+ interface Props {
21
+ /** Sort options array (required) */
22
+ options: SortOption[];
23
+ /** Current sort value */
24
+ sortBy: string;
25
+ /** Current sort direction */
26
+ sortDir: SortDirection;
27
+ /** Current filter input value */
28
+ filterValue?: string;
29
+ /** Whether to show the filter input */
30
+ showFilter?: boolean;
31
+ /** Placeholder text for filter input */
32
+ filterPlaceholder?: string;
33
+ /** Button size variant */
34
+ size?: 'xs' | 'sm' | 'md';
35
+ /** Show label on small screens */
36
+ showLabelOnMobile?: boolean;
37
+ /** Callback when sort changes */
38
+ onSortChange?: (value: string, dir: SortDirection) => void;
39
+ /** Callback when filter changes */
40
+ onFilterChange?: (value: string) => void;
41
+ }
42
+
43
+ let {
44
+ options,
45
+ sortBy,
46
+ sortDir,
47
+ filterValue = '',
48
+ showFilter = false,
49
+ filterPlaceholder = 'Filter...',
50
+ size = 'xs',
51
+ showLabelOnMobile = false,
52
+ onSortChange,
53
+ onFilterChange
54
+ }: Props = $props();
55
+
56
+ // Find current sort option
57
+ const currentOption = $derived(options.find(o => o.value === sortBy));
58
+ const currentIcon = $derived(currentOption?.icon || '');
59
+ const currentLabel = $derived(currentOption?.label || 'Sort');
60
+
61
+ // Handle sort option click
62
+ function handleSortClick(value: string) {
63
+ if (sortBy === value) {
64
+ onSortChange?.(value, sortDir === 'asc' ? 'desc' : 'asc');
65
+ } else {
66
+ const opt = options.find(o => o.value === value);
67
+ onSortChange?.(value, opt?.defaultDir ?? 'asc');
68
+ }
69
+ }
70
+
71
+ // Handle filter input change
72
+ function handleFilterInput(e: Event) {
73
+ const target = e.currentTarget as HTMLInputElement;
74
+ onFilterChange?.(target.value);
75
+ }
76
+
77
+ // Size classes
78
+ const buttonSizeClass = $derived({
79
+ xs: 'btn-xs',
80
+ sm: 'btn-sm',
81
+ md: ''
82
+ }[size]);
83
+
84
+ const menuSizeClass = $derived({
85
+ xs: 'menu-xs',
86
+ sm: 'menu-sm',
87
+ md: ''
88
+ }[size]);
89
+
90
+ const inputSizeClass = $derived({
91
+ xs: 'input-xs',
92
+ sm: 'input-sm',
93
+ md: ''
94
+ }[size]);
95
+
96
+ const inputWidthClass = $derived({
97
+ xs: 'w-20 focus:w-32',
98
+ sm: 'w-24 focus:w-36',
99
+ md: 'w-32 focus:w-44'
100
+ }[size]);
101
+
102
+ import { fly } from 'svelte/transition';
103
+ import { cubicOut } from 'svelte/easing';
104
+ </script>
105
+
106
+ <div class="flex items-center gap-1">
107
+ <!-- Sort dropdown -->
108
+ <!-- svelte-ignore a11y_click_events_have_key_events -->
109
+ <!-- svelte-ignore a11y_no_static_element_interactions -->
110
+ <div class="dropdown dropdown-end flex-shrink-0" onclick={(e) => e.stopPropagation()}>
111
+ <button
112
+ tabindex="0"
113
+ class="btn {buttonSizeClass} btn-ghost gap-1 text-[0.75rem] opacity-70 hover:opacity-100"
114
+ title="Sort"
115
+ >
116
+ <span>{currentIcon}</span>
117
+ <span class="{showLabelOnMobile ? '' : 'hidden sm:inline'}">{currentLabel}</span>
118
+ <span class="text-[9px]">{sortDir === 'asc' ? '▲' : '▼'}</span>
119
+ </button>
120
+ <!-- svelte-ignore a11y_no_noninteractive_tabindex -->
121
+ <ul tabindex="0" class="dropdown-content menu {menuSizeClass} bg-base-200 rounded-box z-40 w-36 p-1 border border-base-300">
122
+ {#each options as opt (opt.value)}
123
+ <li>
124
+ <button
125
+ class="flex items-center gap-2 {sortBy === opt.value ? 'active' : ''}"
126
+ onclick={() => handleSortClick(opt.value)}
127
+ >
128
+ <span>{opt.icon}</span>
129
+ <span class="flex-1">{opt.label}</span>
130
+ {#if sortBy === opt.value}
131
+ <span class="text-[9px] opacity-70">{sortDir === 'asc' ? '▲' : '▼'}</span>
132
+ {/if}
133
+ </button>
134
+ </li>
135
+ {/each}
136
+ </ul>
137
+ </div>
138
+
139
+ <!-- Filter input (optional) -->
140
+ {#if showFilter}
141
+ <!-- svelte-ignore a11y_click_events_have_key_events -->
142
+ <!-- svelte-ignore a11y_no_static_element_interactions -->
143
+ <div class="flex-shrink-0" onclick={(e) => e.stopPropagation()}
144
+ in:fly={{ x: -8, duration: 180, easing: cubicOut }}
145
+ out:fly={{ x: -4, duration: 120, easing: cubicOut }}
146
+ >
147
+ <input
148
+ type="text"
149
+ placeholder={filterPlaceholder}
150
+ value={filterValue}
151
+ oninput={handleFilterInput}
152
+ class="input {inputSizeClass} input-bordered {inputWidthClass} transition-all duration-200 bg-base-200/50"
153
+ />
154
+ </div>
155
+ {/if}
156
+ </div>
@@ -0,0 +1,40 @@
1
+ /**
2
+ * SortDropdown Component - Reusable sort dropdown with optional filter input
3
+ *
4
+ * A standardized dropdown for sorting lists with:
5
+ * - Sort button showing current option icon, label, and direction indicator
6
+ * - Dropdown menu with configurable sort options
7
+ * - Optional filter input for search/filtering
8
+ */
9
+ type SortDirection = 'asc' | 'desc';
10
+ export interface SortOption {
11
+ value: string;
12
+ label: string;
13
+ icon: string;
14
+ defaultDir?: SortDirection;
15
+ }
16
+ interface Props {
17
+ /** Sort options array (required) */
18
+ options: SortOption[];
19
+ /** Current sort value */
20
+ sortBy: string;
21
+ /** Current sort direction */
22
+ sortDir: SortDirection;
23
+ /** Current filter input value */
24
+ filterValue?: string;
25
+ /** Whether to show the filter input */
26
+ showFilter?: boolean;
27
+ /** Placeholder text for filter input */
28
+ filterPlaceholder?: string;
29
+ /** Button size variant */
30
+ size?: 'xs' | 'sm' | 'md';
31
+ /** Show label on small screens */
32
+ showLabelOnMobile?: boolean;
33
+ /** Callback when sort changes */
34
+ onSortChange?: (value: string, dir: SortDirection) => void;
35
+ /** Callback when filter changes */
36
+ onFilterChange?: (value: string) => void;
37
+ }
38
+ declare const SortDropdown: import("svelte").Component<Props, {}, "">;
39
+ type SortDropdown = ReturnType<typeof SortDropdown>;
40
+ export default SortDropdown;
@@ -0,0 +1,116 @@
1
+ <script lang="ts">
2
+ /**
3
+ * Sparkline — Lightweight D3 bar chart for trend visualization.
4
+ * Animated entrance with staggered bars, configurable color and opacity gradient.
5
+ *
6
+ * Requires `d3` as a peer dependency.
7
+ */
8
+ import * as d3 from 'd3';
9
+
10
+ let {
11
+ values,
12
+ width = 120,
13
+ height = 32,
14
+ color = 'var(--color-primary)',
15
+ fillOpacity = 0.15,
16
+ labels,
17
+ }: {
18
+ values: number[];
19
+ width?: number | 'auto';
20
+ height?: number;
21
+ color?: string;
22
+ fillOpacity?: number;
23
+ /** Optional tooltip label per bar. If provided, shown as SVG title on hover. */
24
+ labels?: string[];
25
+ } = $props();
26
+
27
+ let el: HTMLDivElement | undefined = $state();
28
+ let animated = false;
29
+
30
+ function getEffectiveWidth(): number {
31
+ if (width === 'auto' && el) return el.clientWidth;
32
+ if (typeof width === 'number') return width;
33
+ return 120;
34
+ }
35
+
36
+ $effect(() => {
37
+ if (!el || values.length < 2) return;
38
+
39
+ const w = getEffectiveWidth();
40
+ if (w <= 0) return;
41
+
42
+ d3.select(el).select('svg').remove();
43
+
44
+ const pad = 1;
45
+ const innerW = w - pad * 2;
46
+ const innerH = height - pad * 2;
47
+
48
+ if (innerW <= 0 || innerH <= 0) return;
49
+
50
+ const svg = d3
51
+ .select(el)
52
+ .append('svg')
53
+ .attr('width', w)
54
+ .attr('height', height);
55
+
56
+ const g = svg.append('g').attr('transform', `translate(${pad},${pad})`);
57
+
58
+ const x = d3
59
+ .scaleBand<number>()
60
+ .domain(values.map((_, i) => i))
61
+ .range([0, innerW])
62
+ .padding(0.15);
63
+
64
+ const yMin = d3.min(values)! * 0.95;
65
+ const yMax = d3.max(values)! * 1.05;
66
+ const y = d3.scaleLinear().domain([yMin, yMax]).range([innerH, 0]);
67
+
68
+ const n = Math.max(1, values.length - 1);
69
+ const shouldAnimate = !animated;
70
+ animated = true;
71
+
72
+ const bars = g
73
+ .selectAll('.bar')
74
+ .data(values)
75
+ .join('rect')
76
+ .attr('x', (_, i) => x(i)!)
77
+ .attr('width', x.bandwidth())
78
+ .attr('rx', Math.min(1, x.bandwidth() / 4))
79
+ .style('fill', color)
80
+ .style('fill-opacity', (_, i) => fillOpacity + (1 - fillOpacity) * (i / n));
81
+
82
+ bars.each(function (d, i) {
83
+ d3.select(this).selectAll('title').remove();
84
+ const label = labels && labels[i] !== undefined ? labels[i] : String(d);
85
+ d3.select(this).append('title').text(label);
86
+ });
87
+
88
+ if (shouldAnimate) {
89
+ bars
90
+ .attr('y', innerH)
91
+ .attr('height', 0)
92
+ .transition()
93
+ .duration(400)
94
+ .delay((_, i) => i * 15)
95
+ .ease(d3.easeCubicOut)
96
+ .attr('y', (d) => y(d))
97
+ .attr('height', (d) => innerH - y(d));
98
+ } else {
99
+ bars.attr('y', (d) => y(d)).attr('height', (d) => innerH - y(d));
100
+ }
101
+ });
102
+ </script>
103
+
104
+ {#if values.length >= 2}
105
+ <div
106
+ bind:this={el}
107
+ style="{width === 'auto' ? 'width: 100%' : `width: ${width}px`}; height: {height}px"
108
+ ></div>
109
+ {:else}
110
+ <div
111
+ class="flex items-center justify-center text-base-content/30 text-xs"
112
+ style="{width === 'auto' ? 'width: 100%' : `width: ${width}px`}; height: {height}px"
113
+ >
114
+ --
115
+ </div>
116
+ {/if}
@@ -0,0 +1,12 @@
1
+ type $$ComponentProps = {
2
+ values: number[];
3
+ width?: number | 'auto';
4
+ height?: number;
5
+ color?: string;
6
+ fillOpacity?: number;
7
+ /** Optional tooltip label per bar. If provided, shown as SVG title on hover. */
8
+ labels?: string[];
9
+ };
10
+ declare const Sparkline: import("svelte").Component<$$ComponentProps, {}, "">;
11
+ type Sparkline = ReturnType<typeof Sparkline>;
12
+ export default Sparkline;
@@ -0,0 +1,114 @@
1
+ <script lang="ts">
2
+ /**
3
+ * SpeechForm — Text-to-speech generation form with voice selection, character limit, and audio preview.
4
+ *
5
+ * Voice options are configurable via the `voiceOptions` prop. Includes a textarea with character counter,
6
+ * voice selector dropdown, optional audio preview player, and submit/cancel buttons.
7
+ */
8
+
9
+ let {
10
+ text = $bindable(""),
11
+ voice = $bindable("en-US-female-27"),
12
+ previewUrl = null,
13
+ isCreating = false,
14
+ maxLength = 1000,
15
+ voiceOptions = [
16
+ { id: "en-US-female-27", label: "US Female (Clear)" },
17
+ { id: "en-US-male-27", label: "US Male (Clear)" },
18
+ { id: "en-GB-female-11", label: "UK Female" },
19
+ { id: "en-GB-male-10", label: "UK Male" },
20
+ { id: "en-US-female-24", label: "US Female (Warm)" },
21
+ { id: "en-US-male-24", label: "US Male (Deep)" },
22
+ ],
23
+ infoText = "The system will convert your text to natural-sounding speech which you can download and use.",
24
+ onSubmit,
25
+ onCancel,
26
+ } = $props<{
27
+ text?: string
28
+ voice?: string
29
+ previewUrl?: string | null
30
+ isCreating?: boolean
31
+ maxLength?: number
32
+ voiceOptions?: { id: string; label: string }[]
33
+ infoText?: string
34
+ onSubmit: () => void
35
+ onCancel: () => void
36
+ }>()
37
+
38
+ let remaining = $derived(maxLength - (text?.length || 0))
39
+
40
+ $effect(() => {
41
+ return () => {
42
+ if (previewUrl) {
43
+ URL.revokeObjectURL(previewUrl)
44
+ }
45
+ }
46
+ })
47
+ </script>
48
+
49
+ <div class="space-y-4">
50
+ <div class="form-control">
51
+ <label class="label" for="speech-text-input">
52
+ <span class="label-text font-medium">Text to Convert</span>
53
+ <span class="label-text-alt">{remaining} characters left</span>
54
+ </label>
55
+ <textarea
56
+ id="speech-text-input"
57
+ bind:value={text}
58
+ placeholder="Enter the text you want to convert to speech..."
59
+ class="textarea min-h-32"
60
+ maxlength={maxLength}
61
+ disabled={isCreating}
62
+ ></textarea>
63
+ </div>
64
+
65
+ <div class="form-control">
66
+ <label class="label" for="speech-voice-select">
67
+ <span class="label-text font-medium">Voice</span>
68
+ </label>
69
+ <select id="speech-voice-select" bind:value={voice} class="select" disabled={isCreating}>
70
+ {#each voiceOptions as option}
71
+ <option value={option.id}>{option.label}</option>
72
+ {/each}
73
+ </select>
74
+ </div>
75
+
76
+ {#if previewUrl}
77
+ <div class="form-control">
78
+ <div class="label">
79
+ <span class="label-text font-medium">Preview</span>
80
+ </div>
81
+ <audio src={previewUrl} controls class="w-full" aria-label="Generated speech preview">
82
+ Your browser does not support the audio element.
83
+ </audio>
84
+ </div>
85
+ {/if}
86
+
87
+ {#if infoText}
88
+ <div class="flex items-center gap-2 text-info bg-info/10 p-3 rounded">
89
+ <!-- Info icon -->
90
+ <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="M12 16v-4"/><path d="M12 8h.01"/></svg>
91
+ <p class="text-sm">{infoText}</p>
92
+ </div>
93
+ {/if}
94
+ </div>
95
+
96
+ <div class="flex justify-end gap-2 mt-6">
97
+ <button class="btn btn-ghost" onclick={onCancel} disabled={isCreating}>
98
+ Cancel
99
+ </button>
100
+ <button
101
+ class="btn btn-primary gap-2"
102
+ onclick={onSubmit}
103
+ disabled={isCreating || !text}
104
+ >
105
+ {#if isCreating}
106
+ <span class="loading loading-spinner loading-sm"></span>
107
+ Converting...
108
+ {:else}
109
+ <!-- Mic icon -->
110
+ <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 2a3 3 0 0 0-3 3v7a3 3 0 0 0 6 0V5a3 3 0 0 0-3-3Z"/><path d="M19 10v2a7 7 0 0 1-14 0v-2"/><line x1="12" x2="12" y1="19" y2="22"/></svg>
111
+ Generate Speech
112
+ {/if}
113
+ </button>
114
+ </div>
@@ -0,0 +1,17 @@
1
+ type $$ComponentProps = {
2
+ text?: string;
3
+ voice?: string;
4
+ previewUrl?: string | null;
5
+ isCreating?: boolean;
6
+ maxLength?: number;
7
+ voiceOptions?: {
8
+ id: string;
9
+ label: string;
10
+ }[];
11
+ infoText?: string;
12
+ onSubmit: () => void;
13
+ onCancel: () => void;
14
+ };
15
+ declare const SpeechForm: import("svelte").Component<$$ComponentProps, {}, "text" | "voice">;
16
+ type SpeechForm = ReturnType<typeof SpeechForm>;
17
+ export default SpeechForm;
@@ -0,0 +1,157 @@
1
+ <script module lang="ts">
2
+ export type StatusValue =
3
+ | 'active'
4
+ | 'inactive'
5
+ | 'pending'
6
+ | 'completed'
7
+ | 'cancelled'
8
+ | 'draft'
9
+ | 'scheduled'
10
+ | 'in-progress'
11
+ | 'overdue'
12
+ | 'paid'
13
+ | 'unpaid'
14
+ | 'partial'
15
+ | 'assigned'
16
+ | 'available';
17
+ </script>
18
+
19
+ <script lang="ts">
20
+ /**
21
+ * StatusBadge Component
22
+ *
23
+ * Predefined status badge with semantic colors, icons, and dot indicators.
24
+ */
25
+
26
+ interface Props {
27
+ status: StatusValue;
28
+ size?: 'xs' | 'sm' | 'md' | 'lg';
29
+ showIcon?: boolean;
30
+ showDot?: boolean;
31
+ customText?: string;
32
+ clickable?: boolean;
33
+ outlined?: boolean;
34
+ class?: string;
35
+ ariaLabel?: string;
36
+ onclick?: (event: { event: MouseEvent; status: string }) => void;
37
+ }
38
+
39
+ let {
40
+ status,
41
+ size = 'md',
42
+ showIcon = false,
43
+ showDot = false,
44
+ customText = '',
45
+ clickable = false,
46
+ outlined = false,
47
+ class: className = '',
48
+ ariaLabel = '',
49
+ onclick
50
+ }: Props = $props();
51
+
52
+ const statusConfig: Record<string, { text: string; variant: string; icon: string }> = {
53
+ active: { text: 'Active', variant: 'success', icon: '✓' },
54
+ inactive: { text: 'Inactive', variant: 'error', icon: '✗' },
55
+ pending: { text: 'Pending', variant: 'warning', icon: '' },
56
+ completed: { text: 'Completed', variant: 'success', icon: '✓' },
57
+ cancelled: { text: 'Cancelled', variant: 'error', icon: '✗' },
58
+ draft: { text: 'Draft', variant: 'default', icon: '' },
59
+ scheduled: { text: 'Scheduled', variant: 'info', icon: '' },
60
+ 'in-progress': { text: 'In Progress', variant: 'primary', icon: '' },
61
+ overdue: { text: 'Overdue', variant: 'error', icon: '' },
62
+ paid: { text: 'Paid', variant: 'success', icon: '✓' },
63
+ unpaid: { text: 'Unpaid', variant: 'warning', icon: '' },
64
+ partial: { text: 'Partial', variant: 'warning', icon: '' },
65
+ assigned: { text: 'Assigned', variant: 'success', icon: '✓' },
66
+ available: { text: 'Available', variant: 'info', icon: '' }
67
+ };
68
+
69
+ const config = $derived(statusConfig[status] || { text: status || 'Unknown', variant: 'default', icon: '?' });
70
+ const displayText = $derived(customText || config.text);
71
+
72
+ const variantMap: Record<string, string> = {
73
+ default: 'badge-ghost',
74
+ primary: 'badge-primary',
75
+ secondary: 'badge-secondary',
76
+ accent: 'badge-accent',
77
+ success: 'badge-success',
78
+ warning: 'badge-warning',
79
+ error: 'badge-error',
80
+ info: 'badge-info'
81
+ };
82
+
83
+ const outlinedVariantMap: Record<string, string> = {
84
+ default: 'badge-outline',
85
+ primary: 'badge-primary badge-outline',
86
+ secondary: 'badge-secondary badge-outline',
87
+ accent: 'badge-accent badge-outline',
88
+ success: 'badge-success badge-outline',
89
+ warning: 'badge-warning badge-outline',
90
+ error: 'badge-error badge-outline',
91
+ info: 'badge-info badge-outline'
92
+ };
93
+
94
+ const variantClass = $derived(outlined ? outlinedVariantMap[config.variant] : variantMap[config.variant]);
95
+ const sizeClass = $derived({ xs: 'badge-xs', sm: 'badge-sm', md: 'badge-md', lg: 'badge-lg' }[size]);
96
+
97
+ const dotColor = $derived(
98
+ {
99
+ default: 'bg-base-content',
100
+ primary: 'bg-primary',
101
+ secondary: 'bg-secondary',
102
+ accent: 'bg-accent',
103
+ success: 'bg-success',
104
+ warning: 'bg-warning',
105
+ error: 'bg-error',
106
+ info: 'bg-info'
107
+ }[config.variant]
108
+ );
109
+
110
+ const badgeClass = $derived(
111
+ ['badge', variantClass, sizeClass, clickable ? 'cursor-pointer hover:opacity-80' : '', className]
112
+ .filter(Boolean)
113
+ .join(' ')
114
+ );
115
+
116
+ function handleClick(event: MouseEvent) {
117
+ if (clickable && onclick) {
118
+ onclick({ event, status });
119
+ }
120
+ }
121
+
122
+ function handleKeyDown(event: KeyboardEvent) {
123
+ if (clickable && onclick && (event.key === 'Enter' || event.key === ' ')) {
124
+ event.preventDefault();
125
+ onclick({ event: event as any, status });
126
+ }
127
+ }
128
+ </script>
129
+
130
+ {#if clickable}
131
+ <span
132
+ class={badgeClass}
133
+ role="button"
134
+ tabindex="0"
135
+ aria-label={ariaLabel || `Status: ${displayText}`}
136
+ onclick={handleClick}
137
+ onkeydown={handleKeyDown}
138
+ >
139
+ {#if showDot}
140
+ <span class="w-2 h-2 rounded-full {dotColor} mr-1.5 {status === 'active' ? 'animate-pulse' : ''}"></span>
141
+ {/if}
142
+ {#if showIcon}
143
+ <span class="mr-1">{config.icon}</span>
144
+ {/if}
145
+ {displayText}
146
+ </span>
147
+ {:else}
148
+ <span class={badgeClass} aria-label={ariaLabel || `Status: ${displayText}`}>
149
+ {#if showDot}
150
+ <span class="w-2 h-2 rounded-full {dotColor} mr-1.5 {status === 'active' ? 'animate-pulse' : ''}"></span>
151
+ {/if}
152
+ {#if showIcon}
153
+ <span class="mr-1">{config.icon}</span>
154
+ {/if}
155
+ {displayText}
156
+ </span>
157
+ {/if}
@@ -0,0 +1,24 @@
1
+ export type StatusValue = 'active' | 'inactive' | 'pending' | 'completed' | 'cancelled' | 'draft' | 'scheduled' | 'in-progress' | 'overdue' | 'paid' | 'unpaid' | 'partial' | 'assigned' | 'available';
2
+ /**
3
+ * StatusBadge Component
4
+ *
5
+ * Predefined status badge with semantic colors, icons, and dot indicators.
6
+ */
7
+ interface Props {
8
+ status: StatusValue;
9
+ size?: 'xs' | 'sm' | 'md' | 'lg';
10
+ showIcon?: boolean;
11
+ showDot?: boolean;
12
+ customText?: string;
13
+ clickable?: boolean;
14
+ outlined?: boolean;
15
+ class?: string;
16
+ ariaLabel?: string;
17
+ onclick?: (event: {
18
+ event: MouseEvent;
19
+ status: string;
20
+ }) => void;
21
+ }
22
+ declare const StatusBadge: import("svelte").Component<Props, {}, "">;
23
+ type StatusBadge = ReturnType<typeof StatusBadge>;
24
+ export default StatusBadge;