@joewinke/jatui 0.1.11 → 0.1.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +123 -0
- package/package.json +2 -1
- package/src/lib/actions/railNav.ts +473 -0
- package/src/lib/components/AnnotationLayer.svelte +108 -0
- package/src/lib/components/AnnotationPanel.svelte +319 -0
- package/src/lib/components/AudioWaveform.svelte +9 -5
- package/src/lib/components/AvailabilityModal.svelte +7 -3
- package/src/lib/components/AvatarUpload.svelte +27 -4
- package/src/lib/components/BookingForm.svelte +11 -9
- package/src/lib/components/BurndownChart.svelte +778 -0
- package/src/lib/components/Button.svelte +10 -1
- package/src/lib/components/CalendarPicker.svelte +3 -3
- package/src/lib/components/Card.svelte +2 -2
- package/src/lib/components/ChipInput.svelte +21 -15
- package/src/lib/components/ColorSelector.svelte +17 -13
- package/src/lib/components/CommentThread.svelte +773 -0
- package/src/lib/components/ConfirmDialog.svelte +348 -0
- package/src/lib/components/ConfirmModal.svelte +78 -11
- package/src/lib/components/ContextMenu.svelte +59 -19
- package/src/lib/components/CountdownTimer.svelte +1 -1
- package/src/lib/components/DateRangePicker.svelte +6 -4
- package/src/lib/components/Drawer.svelte +36 -3
- package/src/lib/components/EntityPreviewCard.svelte +104 -0
- package/src/lib/components/FileDropzone.svelte +493 -0
- package/src/lib/components/FilePicker.svelte +83 -14
- package/src/lib/components/FileThumbnail.svelte +80 -0
- package/src/lib/components/FilterDropdown.svelte +11 -11
- package/src/lib/components/HunkDiffView.svelte +348 -0
- package/src/lib/components/ImageLightbox.svelte +274 -0
- package/src/lib/components/ImageUpload.svelte +58 -9
- package/src/lib/components/InlineEdit.svelte +15 -9
- package/src/lib/components/InputDialog.svelte +327 -0
- package/src/lib/components/LazyImage.svelte +1 -0
- package/src/lib/components/LinkShortener.svelte +1 -1
- package/src/lib/components/LoadingSpinner.svelte +6 -2
- package/src/lib/components/MarkupEditor.svelte +485 -0
- package/src/lib/components/MarkupOverlay.svelte +55 -0
- package/src/lib/components/MediaWorkbench.svelte +871 -0
- package/src/lib/components/MilestoneCard.svelte +1 -1
- package/src/lib/components/MilestoneTimeline.svelte +1 -1
- package/src/lib/components/Modal.svelte +39 -4
- package/src/lib/components/PDFViewer.svelte +105 -0
- package/src/lib/components/PdfThumbnail.svelte +3 -1
- package/src/lib/components/PhoneInput.svelte +1 -1
- package/src/lib/components/ResizablePanel.svelte +4 -4
- package/src/lib/components/SearchDropdown.svelte +26 -13
- package/src/lib/components/SelectInput.svelte +26 -4
- package/src/lib/components/SidebarUserFooter.svelte +1 -1
- package/src/lib/components/SignaturePad.svelte +8 -4
- package/src/lib/components/SmartImageEditor.svelte +720 -0
- package/src/lib/components/SortDropdown.svelte +9 -3
- package/src/lib/components/Sparkline.svelte +9 -0
- package/src/lib/components/StatusBadge.svelte +20 -18
- package/src/lib/components/TextArea.svelte +24 -5
- package/src/lib/components/TextInput.svelte +29 -6
- package/src/lib/components/ThemeSelector.svelte +15 -4
- package/src/lib/components/TimeSlotPicker.svelte +7 -7
- package/src/lib/components/UserAvatar.svelte +14 -1
- package/src/lib/components/VariablePicker.svelte +170 -0
- package/src/lib/components/VoicePlayer.svelte +4 -3
- package/src/lib/components/markup.ts +287 -0
- package/src/lib/components/messaging/ChannelInfoModal.svelte +9 -9
- package/src/lib/components/messaging/ChannelList.svelte +1 -1
- package/src/lib/components/messaging/ChannelMembersModal.svelte +1 -1
- package/src/lib/components/messaging/CreateChannelModal.svelte +1 -1
- package/src/lib/components/messaging/DirectMessageList.svelte +1 -1
- package/src/lib/components/messaging/EmojiSelector.svelte +2 -1
- package/src/lib/components/messaging/MentionAutocomplete.svelte +1 -1
- package/src/lib/components/messaging/MessageAttachment.svelte +3 -3
- package/src/lib/components/messaging/MessageAttachmentUpload.svelte +3 -3
- package/src/lib/components/messaging/MessageInput.svelte +1 -1
- package/src/lib/components/messaging/MessageItem.svelte +6 -3
- package/src/lib/components/messaging/NotificationSettingsModal.svelte +1 -1
- package/src/lib/components/messaging/QuotedMessageDisplay.svelte +6 -1
- package/src/lib/components/messaging/StartDMModal.svelte +1 -1
- package/src/lib/components/pipeline/Pipeline.svelte +4 -4
- package/src/lib/components/pipeline/PipelineCard.svelte +1 -1
- package/src/lib/components/pipeline/PipelineColumn.svelte +8 -3
- package/src/lib/index.ts +91 -0
- package/src/lib/stores/confirmDialog.svelte.ts +48 -0
- package/src/lib/stores/inputDialog.svelte.ts +51 -0
- package/src/lib/styles/rail.css +63 -0
- package/src/lib/types/annotation.ts +38 -0
- package/src/lib/types/comments.ts +97 -0
- package/src/lib/types/entityPreview.ts +45 -0
- package/src/lib/types/filePicker.ts +2 -0
- package/src/lib/types/smartImageEditor.ts +39 -0
- package/src/lib/types/templateVars.ts +36 -0
- package/src/lib/utils/dateFormatters.ts +12 -10
- package/src/lib/utils/taskUtils.ts +21 -7
|
@@ -39,9 +39,26 @@
|
|
|
39
39
|
let uploadError = $state<string | null>(null)
|
|
40
40
|
let searchQuery = $state("")
|
|
41
41
|
let fileInput = $state<HTMLInputElement>(undefined!)
|
|
42
|
+
let dragOver = $state(false)
|
|
42
43
|
|
|
43
44
|
const currentFiles = $derived(activeTab === "personal" ? personalFiles : teamFiles)
|
|
44
45
|
|
|
46
|
+
const IMAGE_EXTS = new Set(["jpg", "jpeg", "png", "gif", "webp", "svg", "avif", "bmp", "ico", "tiff", "tif"])
|
|
47
|
+
const PDF_EXTS = new Set(["pdf"])
|
|
48
|
+
|
|
49
|
+
const EXT_TO_MIME: Record<string, string> = {
|
|
50
|
+
jpg: "image/jpeg", jpeg: "image/jpeg", png: "image/png", gif: "image/gif",
|
|
51
|
+
webp: "image/webp", svg: "image/svg+xml", avif: "image/avif",
|
|
52
|
+
bmp: "image/bmp", ico: "image/x-icon", tiff: "image/tiff", tif: "image/tiff",
|
|
53
|
+
pdf: "application/pdf",
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function getEffectiveMime(file: FilePickerFile): string {
|
|
57
|
+
if (file.metadata?.mimetype) return file.metadata.mimetype
|
|
58
|
+
const ext = file.name.split(".").pop()?.toLowerCase() ?? ""
|
|
59
|
+
return EXT_TO_MIME[ext] ?? ""
|
|
60
|
+
}
|
|
61
|
+
|
|
45
62
|
const filteredFiles = $derived(() => {
|
|
46
63
|
let files = currentFiles
|
|
47
64
|
if (searchQuery.trim()) {
|
|
@@ -51,8 +68,8 @@
|
|
|
51
68
|
if (accept) {
|
|
52
69
|
const acceptTypes = accept.split(",").map((t) => t.trim().toLowerCase())
|
|
53
70
|
files = files.filter((f) => {
|
|
54
|
-
const mime = f
|
|
55
|
-
const ext = "." + f.name.split(".").pop()?.toLowerCase()
|
|
71
|
+
const mime = getEffectiveMime(f)
|
|
72
|
+
const ext = "." + (f.name.split(".").pop()?.toLowerCase() ?? "")
|
|
56
73
|
return acceptTypes.some(
|
|
57
74
|
(t) =>
|
|
58
75
|
t === mime ||
|
|
@@ -121,7 +138,7 @@
|
|
|
121
138
|
if (file) {
|
|
122
139
|
selections.push({
|
|
123
140
|
file,
|
|
124
|
-
url: `${apiBase}/${encodeURIComponent(file.name)}/view?scope=${file.scope}`,
|
|
141
|
+
url: file.publicUrl ?? `${apiBase}/${encodeURIComponent(file.name)}/view?scope=${file.scope}`,
|
|
125
142
|
downloadUrl: `${apiBase}/${encodeURIComponent(file.name)}/download?scope=${file.scope}`,
|
|
126
143
|
})
|
|
127
144
|
}
|
|
@@ -165,11 +182,17 @@
|
|
|
165
182
|
}
|
|
166
183
|
|
|
167
184
|
function isImage(file: FilePickerFile): boolean {
|
|
168
|
-
|
|
185
|
+
const mime = getEffectiveMime(file)
|
|
186
|
+
if (mime) return mime.startsWith("image/")
|
|
187
|
+
const ext = file.name.split(".").pop()?.toLowerCase() ?? ""
|
|
188
|
+
return IMAGE_EXTS.has(ext)
|
|
169
189
|
}
|
|
170
190
|
|
|
171
191
|
function isPdf(file: FilePickerFile): boolean {
|
|
172
|
-
|
|
192
|
+
const mime = getEffectiveMime(file)
|
|
193
|
+
if (mime) return mime === "application/pdf"
|
|
194
|
+
const ext = file.name.split(".").pop()?.toLowerCase() ?? ""
|
|
195
|
+
return PDF_EXTS.has(ext)
|
|
173
196
|
}
|
|
174
197
|
|
|
175
198
|
function getPreviewUrl(file: FilePickerFile): string {
|
|
@@ -238,6 +261,7 @@
|
|
|
238
261
|
<div class="flex items-center gap-3 mb-4 shrink-0 flex-wrap">
|
|
239
262
|
<div role="tablist" class="tabs tabs-boxed tabs-sm">
|
|
240
263
|
<button
|
|
264
|
+
type="button"
|
|
241
265
|
role="tab"
|
|
242
266
|
class="tab {activeTab === 'personal' ? 'tab-active' : ''}"
|
|
243
267
|
onclick={() => (activeTab = "personal")}
|
|
@@ -248,6 +272,7 @@
|
|
|
248
272
|
{/if}
|
|
249
273
|
</button>
|
|
250
274
|
<button
|
|
275
|
+
type="button"
|
|
251
276
|
role="tab"
|
|
252
277
|
class="tab {activeTab === 'team' ? 'tab-active' : ''}"
|
|
253
278
|
onclick={() => (activeTab = "team")}
|
|
@@ -275,6 +300,7 @@
|
|
|
275
300
|
class="hidden"
|
|
276
301
|
/>
|
|
277
302
|
<button
|
|
303
|
+
type="button"
|
|
278
304
|
class="btn btn-sm btn-primary"
|
|
279
305
|
onclick={() => fileInput?.click()}
|
|
280
306
|
disabled={isUploading}
|
|
@@ -293,12 +319,35 @@
|
|
|
293
319
|
{#if uploadError}
|
|
294
320
|
<div class="alert alert-warning alert-sm mb-3 shrink-0">
|
|
295
321
|
<span class="text-sm">{uploadError}</span>
|
|
296
|
-
<button class="btn btn-xs btn-ghost" onclick={() => (uploadError = null)}>Dismiss</button>
|
|
322
|
+
<button type="button" class="btn btn-xs btn-ghost" onclick={() => (uploadError = null)}>Dismiss</button>
|
|
297
323
|
</div>
|
|
298
324
|
{/if}
|
|
299
325
|
|
|
300
326
|
<!-- File grid -->
|
|
301
|
-
|
|
327
|
+
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
|
328
|
+
<div
|
|
329
|
+
class="flex-1 overflow-y-auto min-h-0 relative"
|
|
330
|
+
ondragover={(e) => { e.preventDefault(); dragOver = true }}
|
|
331
|
+
ondragleave={(e) => { if (!e.currentTarget.contains(e.relatedTarget as Node)) dragOver = false }}
|
|
332
|
+
ondrop={(e) => {
|
|
333
|
+
e.preventDefault()
|
|
334
|
+
dragOver = false
|
|
335
|
+
if (e.dataTransfer?.files.length) {
|
|
336
|
+
const dt = new DataTransfer()
|
|
337
|
+
Array.from(e.dataTransfer.files).forEach(f => dt.items.add(f))
|
|
338
|
+
fileInput.files = dt.files
|
|
339
|
+
fileInput.dispatchEvent(new Event('change'))
|
|
340
|
+
}
|
|
341
|
+
}}
|
|
342
|
+
>
|
|
343
|
+
{#if dragOver && !loading}
|
|
344
|
+
<div class="absolute inset-0 z-10 flex flex-col items-center justify-center rounded-md border-2 border-dashed border-primary bg-primary/5 pointer-events-none">
|
|
345
|
+
<svg class="h-10 w-10 text-primary" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
|
|
346
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-8l-4-4m0 0L8 8m4-4v12" />
|
|
347
|
+
</svg>
|
|
348
|
+
<p class="mt-3 text-sm font-medium text-primary">Drop to upload</p>
|
|
349
|
+
</div>
|
|
350
|
+
{/if}
|
|
302
351
|
{#if loading}
|
|
303
352
|
<div class="flex items-center justify-center py-16">
|
|
304
353
|
<span class="loading loading-spinner loading-lg text-primary"></span>
|
|
@@ -306,21 +355,40 @@
|
|
|
306
355
|
{:else if error}
|
|
307
356
|
<div class="text-center py-16">
|
|
308
357
|
<p class="text-error text-sm">{error}</p>
|
|
309
|
-
<button class="btn btn-sm btn-ghost mt-2" onclick={loadFiles}>Retry</button>
|
|
358
|
+
<button type="button" class="btn btn-sm btn-ghost mt-2" onclick={loadFiles}>Retry</button>
|
|
310
359
|
</div>
|
|
311
360
|
{:else if filteredFiles().length === 0}
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
361
|
+
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
|
362
|
+
<div
|
|
363
|
+
class="flex flex-col items-center justify-center py-16 rounded-md border-2 border-dashed transition-colors duration-150 cursor-pointer
|
|
364
|
+
{dragOver ? 'border-primary bg-primary/5' : 'border-base-300 hover:border-base-content/20 hover:bg-base-200/40'}"
|
|
365
|
+
onclick={() => fileInput?.click()}
|
|
366
|
+
role="button"
|
|
367
|
+
tabindex="0"
|
|
368
|
+
onkeydown={(e) => e.key === 'Enter' && fileInput?.click()}
|
|
369
|
+
aria-label="Drop files here or click to upload"
|
|
370
|
+
>
|
|
371
|
+
<svg class="h-10 w-10 {dragOver ? 'text-primary' : 'text-base-content/20'} transition-colors" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
|
|
372
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-8l-4-4m0 0L8 8m4-4v12" />
|
|
315
373
|
</svg>
|
|
316
|
-
<p class="mt-3 text-sm text-base-content/50">
|
|
317
|
-
{
|
|
374
|
+
<p class="mt-3 text-sm font-medium {dragOver ? 'text-primary' : 'text-base-content/50'}">
|
|
375
|
+
{#if dragOver}
|
|
376
|
+
Drop to upload
|
|
377
|
+
{:else if searchQuery}
|
|
378
|
+
No files match your search
|
|
379
|
+
{:else}
|
|
380
|
+
Drop a file here, or <span class="text-primary underline">browse</span>
|
|
381
|
+
{/if}
|
|
318
382
|
</p>
|
|
383
|
+
{#if !searchQuery && !dragOver}
|
|
384
|
+
<p class="mt-1 text-xs text-base-content/30">{accept || "Any file type"}</p>
|
|
385
|
+
{/if}
|
|
319
386
|
</div>
|
|
320
387
|
{:else}
|
|
321
388
|
<div class="grid grid-cols-3 sm:grid-cols-4 md:grid-cols-5 gap-3">
|
|
322
389
|
{#each filteredFiles() as file (file.id)}
|
|
323
390
|
<button
|
|
391
|
+
type="button"
|
|
324
392
|
class="flex flex-col bg-base-100 border rounded-lg overflow-hidden text-left transition-all duration-150 hover:shadow-md
|
|
325
393
|
{isSelected(file)
|
|
326
394
|
? 'border-primary ring-2 ring-primary/30'
|
|
@@ -393,8 +461,9 @@
|
|
|
393
461
|
{/if}
|
|
394
462
|
</span>
|
|
395
463
|
<div class="flex gap-2">
|
|
396
|
-
<button class="btn btn-sm btn-ghost" onclick={close}>Cancel</button>
|
|
464
|
+
<button type="button" class="btn btn-sm btn-ghost" onclick={close}>Cancel</button>
|
|
397
465
|
<button
|
|
466
|
+
type="button"
|
|
398
467
|
class="btn btn-sm btn-primary"
|
|
399
468
|
disabled={selected.size === 0}
|
|
400
469
|
onclick={confirmSelection}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
interface Props {
|
|
3
|
+
/** Display name of the file */
|
|
4
|
+
name: string
|
|
5
|
+
/** MIME type — used to pick the right icon / thumbnail */
|
|
6
|
+
mimeType: string
|
|
7
|
+
/** URL to render as image thumbnail (for image files) */
|
|
8
|
+
url?: string
|
|
9
|
+
size?: "sm" | "md" | "lg" | "xl"
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
let { name, mimeType, url, size = "md" }: Props = $props()
|
|
13
|
+
|
|
14
|
+
let imageError = $state(false)
|
|
15
|
+
let isLoading = $state(true)
|
|
16
|
+
|
|
17
|
+
const sizeClasses: Record<string, string> = {
|
|
18
|
+
sm: "h-8 w-8",
|
|
19
|
+
md: "h-16 w-16",
|
|
20
|
+
lg: "h-24 w-24",
|
|
21
|
+
xl: "h-32 w-32",
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const isImageFile = $derived(mimeType.startsWith("image/"))
|
|
25
|
+
const isPdfFile = $derived(mimeType === "application/pdf")
|
|
26
|
+
const isCadFile = $derived(mimeType.includes("dwg") || mimeType.includes("autocad"))
|
|
27
|
+
const isZipFile = $derived(
|
|
28
|
+
mimeType === "application/zip" ||
|
|
29
|
+
mimeType === "application/x-zip-compressed" ||
|
|
30
|
+
mimeType === "application/x-zip"
|
|
31
|
+
)
|
|
32
|
+
</script>
|
|
33
|
+
|
|
34
|
+
<div class="relative {sizeClasses[size]} flex-shrink-0">
|
|
35
|
+
{#if isImageFile && url && !imageError}
|
|
36
|
+
<img
|
|
37
|
+
src={url}
|
|
38
|
+
alt={name}
|
|
39
|
+
class="w-full h-full object-cover rounded border border-base-300 shadow-sm"
|
|
40
|
+
onload={() => { isLoading = false }}
|
|
41
|
+
onerror={() => { imageError = true; isLoading = false }}
|
|
42
|
+
/>
|
|
43
|
+
{:else}
|
|
44
|
+
<div class="w-full h-full bg-base-200 rounded border border-base-300 flex items-center justify-center">
|
|
45
|
+
{#if isPdfFile}
|
|
46
|
+
<svg class="h-6 w-6 text-error" fill="currentColor" viewBox="0 0 24 24" aria-hidden="true">
|
|
47
|
+
<path d="M14,2H6A2,2 0 0,0 4,4V20A2,2 0 0,0 6,22H18A2,2 0 0,0 20,20V8L14,2M18,20H6V4H13V9H18V20M10.92,12.31C10.68,11.54 10.15,9.08 11.55,9.04C12.95,9 12.03,12.16 12.03,12.16C12.42,13.65 14.05,14.72 14.05,14.72C14.55,14.57 17.4,14.24 17,15.72C16.57,17.2 13.5,15.81 13.5,15.81C11.55,15.95 10.09,16.47 10.09,16.47C8.96,18.58 7.64,19.5 7.1,18.61C6.43,17.5 9.23,16.07 9.23,16.07C10.68,13.67 10.92,12.31 10.92,12.31Z" />
|
|
48
|
+
</svg>
|
|
49
|
+
{:else if isCadFile}
|
|
50
|
+
<svg class="h-6 w-6 text-info" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
|
|
51
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" />
|
|
52
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 10l5-5 5 5" />
|
|
53
|
+
</svg>
|
|
54
|
+
{:else if isZipFile}
|
|
55
|
+
<svg class="h-6 w-6 text-warning" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
|
|
56
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 8h14M5 8a2 2 0 110-4h14a2 2 0 110 4M5 8v10a2 2 0 002 2h10a2 2 0 002-2V8m-9 4h4" />
|
|
57
|
+
</svg>
|
|
58
|
+
{:else}
|
|
59
|
+
<svg class="h-6 w-6 text-base-content/40" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
|
|
60
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" />
|
|
61
|
+
</svg>
|
|
62
|
+
{/if}
|
|
63
|
+
</div>
|
|
64
|
+
{/if}
|
|
65
|
+
|
|
66
|
+
{#if isLoading && isImageFile && url}
|
|
67
|
+
<div class="absolute inset-0 bg-base-200 rounded animate-pulse"></div>
|
|
68
|
+
{/if}
|
|
69
|
+
|
|
70
|
+
<!-- File type badge for small size -->
|
|
71
|
+
{#if size === "sm" && (isPdfFile || isCadFile)}
|
|
72
|
+
<div
|
|
73
|
+
class="absolute -top-1 -right-1 w-3 h-3 rounded-full text-xs font-bold text-white flex items-center justify-center
|
|
74
|
+
{isPdfFile ? 'bg-error' : 'bg-info'}"
|
|
75
|
+
aria-hidden="true"
|
|
76
|
+
>
|
|
77
|
+
{isPdfFile ? "P" : "D"}
|
|
78
|
+
</div>
|
|
79
|
+
{/if}
|
|
80
|
+
</div>
|
|
@@ -109,18 +109,18 @@
|
|
|
109
109
|
onchange={() => handleToggle(opt.value)}
|
|
110
110
|
/>
|
|
111
111
|
<span>{opt.label}</span>
|
|
112
|
-
<span class="text-
|
|
112
|
+
<span class="text-[0.75rem] opacity-60">({opt.count})</span>
|
|
113
113
|
</label>
|
|
114
114
|
{:else}
|
|
115
115
|
<button
|
|
116
116
|
class="badge badge-sm transition-all duration-200 cursor-pointer {selected.has(opt.value)
|
|
117
|
-
? colorFn(opt.value, true)
|
|
118
|
-
: 'badge-ghost hover:badge-primary/20
|
|
117
|
+
? colorFn(opt.value, true)
|
|
118
|
+
: 'badge-ghost hover:badge-primary/20'}"
|
|
119
119
|
onclick={() => handleToggle(opt.value)}
|
|
120
120
|
onkeydown={(e) => handleKeydown(e, opt.value)}
|
|
121
121
|
>
|
|
122
122
|
{opt.label}
|
|
123
|
-
<span class="ml-1 opacity-
|
|
123
|
+
<span class="ml-1 text-[0.75rem] opacity-60">({opt.count})</span>
|
|
124
124
|
</button>
|
|
125
125
|
{/if}
|
|
126
126
|
{/each}
|
|
@@ -132,11 +132,11 @@
|
|
|
132
132
|
<div
|
|
133
133
|
tabindex="0"
|
|
134
134
|
role="button"
|
|
135
|
-
class="px-2.5 py-1 rounded cursor-pointer transition-all flex items-center gap-1.5
|
|
135
|
+
class="px-2.5 py-1 rounded cursor-pointer transition-all flex items-center gap-1.5 text-[0.8125rem] bg-base-200 border border-base-300 text-base-content/60"
|
|
136
136
|
>
|
|
137
|
-
<span
|
|
137
|
+
<span>{label}</span>
|
|
138
138
|
<span
|
|
139
|
-
class="px-1.5 py-0.5 rounded text-
|
|
139
|
+
class="px-1.5 py-0.5 rounded text-[0.75rem] {selected.size > 0 && !(emptyMeansAll && selected.size === 0) ? 'bg-primary/20 text-primary' : 'bg-base-300 text-base-content opacity-60'}"
|
|
140
140
|
>
|
|
141
141
|
{displayText}
|
|
142
142
|
</span>
|
|
@@ -171,8 +171,8 @@
|
|
|
171
171
|
checked={selected.has(opt.value)}
|
|
172
172
|
onchange={() => handleToggle(opt.value)}
|
|
173
173
|
/>
|
|
174
|
-
<span class="truncate
|
|
175
|
-
<span class="text-
|
|
174
|
+
<span class="truncate text-[0.8125rem]">{opt.label}</span>
|
|
175
|
+
<span class="text-[0.75rem] text-base-content/45">({opt.count})</span>
|
|
176
176
|
</label>
|
|
177
177
|
</li>
|
|
178
178
|
{/each}
|
|
@@ -183,12 +183,12 @@
|
|
|
183
183
|
<div
|
|
184
184
|
tabindex="0"
|
|
185
185
|
role="menu"
|
|
186
|
-
class="dropdown-content rounded-box
|
|
186
|
+
class="dropdown-content rounded-box p-2 z-40 {menuWidth} mt-1 {maxHeight ? maxHeight + ' overflow-y-auto' : ''} bg-base-200 border border-base-300"
|
|
187
187
|
>
|
|
188
188
|
<div class="flex flex-wrap gap-1.5">
|
|
189
189
|
{#each options as opt, index}
|
|
190
190
|
<button
|
|
191
|
-
class="px-2 py-0.5 rounded
|
|
191
|
+
class="px-2 py-0.5 rounded text-[0.75rem] transition-all cursor-pointer border {selected.has(opt.value) ? 'bg-primary/20 border-primary/40 text-primary' : 'bg-base-300 border-base-content/20 text-base-content opacity-70 hover:opacity-100'}"
|
|
192
192
|
onclick={() => handleToggle(opt.value)}
|
|
193
193
|
onkeydown={(e) => handleKeydown(e, opt.value)}
|
|
194
194
|
>
|