@classic-homes/theme-svelte 1.6.0 → 1.7.1
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/dist/lib/components/AlertDialog.svelte +1 -1
- package/dist/lib/components/OTPInput.svelte +4 -4
- package/dist/lib/components/Tabs.svelte +73 -28
- package/dist/lib/components/layout/AuthLayout.svelte +1 -1
- package/dist/lib/components/layout/DashboardLayout.svelte +4 -1
- package/dist/lib/components/layout/Header.svelte +1 -1
- package/dist/lib/components/layout/sidebar/SidebarNavItem.svelte +5 -2
- package/dist/lib/components/notifications/NotificationBulkActions.svelte +6 -3
- package/dist/lib/components/notifications/NotificationDialog.svelte +1 -1
- package/dist/lib/components/notifications/NotificationFilters.svelte +1 -1
- package/package.json +1 -1
|
@@ -97,7 +97,7 @@
|
|
|
97
97
|
/>
|
|
98
98
|
<AlertDialogPrimitive.Content
|
|
99
99
|
class={cn(
|
|
100
|
-
'fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border border-black bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%]
|
|
100
|
+
'fixed left-[50%] top-[50%] z-50 grid w-full max-w-[calc(100vw-2rem)] sm:max-w-lg max-h-[calc(100dvh-2rem)] overflow-y-auto translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border border-black bg-background p-4 sm:p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%]',
|
|
101
101
|
className
|
|
102
102
|
)}
|
|
103
103
|
>
|
|
@@ -224,7 +224,7 @@
|
|
|
224
224
|
{/if}
|
|
225
225
|
|
|
226
226
|
<div
|
|
227
|
-
class={cn('flex gap-2', className)}
|
|
227
|
+
class={cn('flex gap-1.5 sm:gap-2', className)}
|
|
228
228
|
role="group"
|
|
229
229
|
aria-label={label || 'One-time password input'}
|
|
230
230
|
aria-describedby={describedBy}
|
|
@@ -244,7 +244,7 @@
|
|
|
244
244
|
onpaste={handlePaste}
|
|
245
245
|
onfocus={handleFocus}
|
|
246
246
|
class={cn(
|
|
247
|
-
'h-12 w-12 text-
|
|
247
|
+
'h-10 w-10 text-base sm:h-12 sm:w-12 sm:text-lg text-center font-semibold rounded-md border border-input bg-background ring-offset-background transition-colors',
|
|
248
248
|
'focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2',
|
|
249
249
|
'disabled:cursor-not-allowed disabled:opacity-50',
|
|
250
250
|
error && 'border-destructive focus:ring-destructive'
|
|
@@ -275,7 +275,7 @@
|
|
|
275
275
|
</div>
|
|
276
276
|
{:else}
|
|
277
277
|
<div
|
|
278
|
-
class={cn('flex gap-2', className)}
|
|
278
|
+
class={cn('flex gap-1.5 sm:gap-2', className)}
|
|
279
279
|
role="group"
|
|
280
280
|
aria-label="One-time password input"
|
|
281
281
|
aria-describedby={describedBy}
|
|
@@ -295,7 +295,7 @@
|
|
|
295
295
|
onpaste={handlePaste}
|
|
296
296
|
onfocus={handleFocus}
|
|
297
297
|
class={cn(
|
|
298
|
-
'h-12 w-12 text-
|
|
298
|
+
'h-10 w-10 text-base sm:h-12 sm:w-12 sm:text-lg text-center font-semibold rounded-md border border-input bg-background ring-offset-background transition-colors',
|
|
299
299
|
'focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2',
|
|
300
300
|
'disabled:cursor-not-allowed disabled:opacity-50',
|
|
301
301
|
error && 'border-destructive focus:ring-destructive'
|
|
@@ -50,6 +50,35 @@
|
|
|
50
50
|
// Store references to tab button elements for direct focus management
|
|
51
51
|
let tabRefs: Record<string, HTMLButtonElement | undefined> = $state({});
|
|
52
52
|
|
|
53
|
+
// Horizontal-scroll handling for tab lists wider than their container
|
|
54
|
+
let tabList: HTMLDivElement | undefined = $state();
|
|
55
|
+
let canScrollLeft = $state(false);
|
|
56
|
+
let canScrollRight = $state(false);
|
|
57
|
+
|
|
58
|
+
function updateScrollShadows() {
|
|
59
|
+
if (!tabList) return;
|
|
60
|
+
canScrollLeft = tabList.scrollLeft > 1;
|
|
61
|
+
canScrollRight = tabList.scrollLeft + tabList.clientWidth < tabList.scrollWidth - 1;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Scroll only the tab list (never the page) so deep-linked tabs are visible
|
|
65
|
+
function scrollTabIntoView(el: HTMLButtonElement) {
|
|
66
|
+
if (!tabList) return;
|
|
67
|
+
const listRect = tabList.getBoundingClientRect();
|
|
68
|
+
const rect = el.getBoundingClientRect();
|
|
69
|
+
if (rect.left < listRect.left) {
|
|
70
|
+
tabList.scrollLeft += rect.left - listRect.left - 8;
|
|
71
|
+
} else if (rect.right > listRect.right) {
|
|
72
|
+
tabList.scrollLeft += rect.right - listRect.right + 8;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
$effect(() => {
|
|
77
|
+
const el = tabRefs[value];
|
|
78
|
+
if (el) scrollTabIntoView(el);
|
|
79
|
+
updateScrollShadows();
|
|
80
|
+
});
|
|
81
|
+
|
|
53
82
|
// Create a reactive object for context
|
|
54
83
|
// Initialize with empty values - the effect will set them immediately
|
|
55
84
|
const tabsState = $state({ activeTab: '', tabsId: '' });
|
|
@@ -108,34 +137,50 @@
|
|
|
108
137
|
|
|
109
138
|
<div class={cn('w-full', className)}>
|
|
110
139
|
<!-- Tab List -->
|
|
111
|
-
<div
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
140
|
+
<div class="relative inline-flex max-w-full">
|
|
141
|
+
{#if canScrollLeft}
|
|
142
|
+
<div
|
|
143
|
+
class="pointer-events-none absolute inset-y-0 left-0 z-10 w-6 rounded-l-md bg-gradient-to-r from-muted to-transparent"
|
|
144
|
+
aria-hidden="true"
|
|
145
|
+
></div>
|
|
146
|
+
{/if}
|
|
147
|
+
{#if canScrollRight}
|
|
148
|
+
<div
|
|
149
|
+
class="pointer-events-none absolute inset-y-0 right-0 z-10 w-6 rounded-r-md bg-gradient-to-l from-muted to-transparent"
|
|
150
|
+
aria-hidden="true"
|
|
151
|
+
></div>
|
|
152
|
+
{/if}
|
|
153
|
+
<div
|
|
154
|
+
bind:this={tabList}
|
|
155
|
+
onscroll={updateScrollShadows}
|
|
156
|
+
role="tablist"
|
|
157
|
+
aria-label={label}
|
|
158
|
+
class="inline-flex h-10 max-w-full items-center justify-center overflow-x-auto rounded-md bg-muted p-1 text-muted-foreground [scrollbar-width:none] [&::-webkit-scrollbar]:hidden"
|
|
159
|
+
>
|
|
160
|
+
{#each tabs as tab, index (tab.id)}
|
|
161
|
+
<button
|
|
162
|
+
bind:this={tabRefs[tab.id]}
|
|
163
|
+
id={`${id}-tab-${tab.id}`}
|
|
164
|
+
role="tab"
|
|
165
|
+
type="button"
|
|
166
|
+
aria-selected={value === tab.id}
|
|
167
|
+
aria-controls={children && value === tab.id ? `${id}-panel-${tab.id}` : undefined}
|
|
168
|
+
tabindex={value === tab.id ? 0 : -1}
|
|
169
|
+
disabled={tab.disabled}
|
|
170
|
+
class={cn(
|
|
171
|
+
'inline-flex items-center justify-center whitespace-nowrap rounded-sm px-3 py-1.5 text-sm font-medium ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2',
|
|
172
|
+
value === tab.id
|
|
173
|
+
? 'bg-background text-foreground shadow-sm'
|
|
174
|
+
: 'hover:bg-background-hover hover:text-foreground',
|
|
175
|
+
tab.disabled && 'opacity-50 pointer-events-none cursor-not-allowed'
|
|
176
|
+
)}
|
|
177
|
+
onclick={() => selectTab(tab.id)}
|
|
178
|
+
onkeydown={(e) => handleKeyDown(e, index)}
|
|
179
|
+
>
|
|
180
|
+
{tab.label}
|
|
181
|
+
</button>
|
|
182
|
+
{/each}
|
|
183
|
+
</div>
|
|
139
184
|
</div>
|
|
140
185
|
|
|
141
186
|
<!-- Tab Panels Container -->
|
|
@@ -80,7 +80,7 @@
|
|
|
80
80
|
<AppShell>
|
|
81
81
|
<div
|
|
82
82
|
class={cn(
|
|
83
|
-
'flex h-
|
|
83
|
+
'flex min-h-[100dvh] flex-col items-center justify-center bg-content-bg px-4 py-8 sm:px-6 lg:px-8',
|
|
84
84
|
showBackground && backgroundClasses[backgroundVariant],
|
|
85
85
|
className
|
|
86
86
|
)}
|
|
@@ -323,7 +323,10 @@
|
|
|
323
323
|
{/if}
|
|
324
324
|
|
|
325
325
|
<!-- Main Content -->
|
|
326
|
-
<main
|
|
326
|
+
<main
|
|
327
|
+
id="main-content"
|
|
328
|
+
class="min-w-0 flex-1 overflow-x-clip bg-content-bg {contentPaddingClass}"
|
|
329
|
+
>
|
|
327
330
|
{@render children()}
|
|
328
331
|
</main>
|
|
329
332
|
</div>
|
|
@@ -178,7 +178,7 @@
|
|
|
178
178
|
<div class={cn('h-16', strongBorder ? 'border-b-2 border-black' : 'border-b border-black')}>
|
|
179
179
|
<div
|
|
180
180
|
class={cn(
|
|
181
|
-
'flex h-full items-center justify-between px-2 sm:px-4 lg:px-4',
|
|
181
|
+
'flex h-full items-center justify-between gap-4 sm:gap-6 px-2 sm:px-4 lg:px-4',
|
|
182
182
|
maxWidth !== 'none' && 'mx-auto',
|
|
183
183
|
maxWidthClasses[maxWidth]
|
|
184
184
|
)}
|
|
@@ -190,8 +190,11 @@
|
|
|
190
190
|
class={cn(
|
|
191
191
|
'flex items-center justify-center p-1 rounded shrink-0',
|
|
192
192
|
'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-1',
|
|
193
|
-
// Show on hover for regular items, always show in pinned section
|
|
194
|
-
|
|
193
|
+
// Show on hover for regular items, always show in pinned section.
|
|
194
|
+
// Touch devices never fire hover (hoverOnlyWhenSupported), so keep it visible there.
|
|
195
|
+
isUnpin
|
|
196
|
+
? 'opacity-100'
|
|
197
|
+
: 'opacity-0 group-hover:opacity-100 focus-visible:opacity-100 [@media(hover:none)]:opacity-60',
|
|
195
198
|
// Light variant: white text when row is hovered (teal bg), red/primary text when active
|
|
196
199
|
isLight && !item.active && 'text-muted-foreground group-hover:text-white hover:bg-white/20',
|
|
197
200
|
isLight && item.active && 'text-primary hover:bg-primary/20',
|
|
@@ -51,10 +51,13 @@
|
|
|
51
51
|
</script>
|
|
52
52
|
|
|
53
53
|
<div
|
|
54
|
-
class={cn(
|
|
54
|
+
class={cn(
|
|
55
|
+
'flex flex-wrap items-center justify-between gap-x-4 gap-y-2 rounded-lg border bg-muted/50 p-3',
|
|
56
|
+
className
|
|
57
|
+
)}
|
|
55
58
|
>
|
|
56
59
|
<!-- Selection controls -->
|
|
57
|
-
<div class="flex items-center gap-3">
|
|
60
|
+
<div class="flex flex-wrap items-center gap-3">
|
|
58
61
|
<Checkbox checked={allSelected} onCheckedChange={handleSelectAllChange}>
|
|
59
62
|
{#snippet children()}
|
|
60
63
|
<span class="text-sm">
|
|
@@ -80,7 +83,7 @@
|
|
|
80
83
|
|
|
81
84
|
<!-- Bulk actions -->
|
|
82
85
|
{#if hasSelection}
|
|
83
|
-
<div class="flex items-center gap-2">
|
|
86
|
+
<div class="flex flex-wrap items-center gap-2">
|
|
84
87
|
{#if onMarkRead}
|
|
85
88
|
<Button variant="outline" size="sm" onclick={onMarkRead}>
|
|
86
89
|
{#snippet children()}
|
|
@@ -149,7 +149,7 @@
|
|
|
149
149
|
|
|
150
150
|
<!-- Metadata -->
|
|
151
151
|
<div class="border-t pt-4 mt-4">
|
|
152
|
-
<dl class="grid grid-cols-
|
|
152
|
+
<dl class="grid grid-cols-1 gap-4 text-sm sm:grid-cols-2">
|
|
153
153
|
<div>
|
|
154
154
|
<dt class="text-muted-foreground">Category</dt>
|
|
155
155
|
<dd class="font-medium capitalize">{notification.category}</dd>
|
|
@@ -69,7 +69,7 @@
|
|
|
69
69
|
role="tablist"
|
|
70
70
|
aria-label="Filter notifications"
|
|
71
71
|
class={cn(
|
|
72
|
-
'inline-flex h-10 items-center justify-center rounded-md bg-muted p-1 text-muted-foreground',
|
|
72
|
+
'inline-flex h-10 max-w-full items-center justify-center overflow-x-auto rounded-md bg-muted p-1 text-muted-foreground [scrollbar-width:none] [&::-webkit-scrollbar]:hidden',
|
|
73
73
|
className
|
|
74
74
|
)}
|
|
75
75
|
>
|