@svadmin/ui 0.37.0 → 0.38.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/app.css +42 -88
- package/dist/components/AdminApp.svelte +38 -35
- package/dist/components/CanAccess.svelte +3 -2
- package/dist/components/CanAccess.svelte.d.ts +1 -0
- package/dist/components/CreateInferencer.svelte +13 -0
- package/dist/components/CreateInferencer.svelte.d.ts +7 -0
- package/dist/components/EditInferencer.svelte +21 -0
- package/dist/components/EditInferencer.svelte.d.ts +9 -0
- package/dist/components/Header.svelte +4 -4
- package/dist/components/Layout.svelte +26 -13
- package/dist/components/ListInferencer.svelte +14 -0
- package/dist/components/ListInferencer.svelte.d.ts +7 -0
- package/dist/components/ResourceInferencer.svelte +28 -0
- package/dist/components/ResourceInferencer.svelte.d.ts +7 -0
- package/dist/components/ResourceOperationsPage.svelte +168 -21
- package/dist/components/ResourceOperationsPage.svelte.d.ts +2 -0
- package/dist/components/SettingsPage.svelte +3 -2
- package/dist/components/ShowInferencer.svelte +21 -0
- package/dist/components/ShowInferencer.svelte.d.ts +9 -0
- package/dist/components/ShowPage.svelte +2 -2
- package/dist/components/ShowPage.svelte.d.ts +1 -0
- package/dist/components/Sidebar.svelte +101 -104
- package/dist/components/Sidebar.svelte.d.ts +0 -1
- package/dist/components/SidebarItem.svelte +114 -52
- package/dist/components/StepsForm.svelte +2 -1
- package/dist/components/UndoableNotification.svelte +2 -1
- package/dist/components/account/TeamMembersPage.svelte +9 -3
- package/dist/components/buttons/CloneButton.svelte +10 -2
- package/dist/components/buttons/CloneButton.svelte.d.ts +2 -4
- package/dist/components/buttons/CreateButton.svelte +9 -2
- package/dist/components/buttons/CreateButton.svelte.d.ts +2 -4
- package/dist/components/buttons/DeleteButton.svelte +10 -2
- package/dist/components/buttons/DeleteButton.svelte.d.ts +2 -4
- package/dist/components/buttons/EditButton.svelte +10 -2
- package/dist/components/buttons/EditButton.svelte.d.ts +2 -4
- package/dist/components/buttons/ExportButton.svelte +9 -2
- package/dist/components/buttons/ExportButton.svelte.d.ts +2 -4
- package/dist/components/buttons/ImportButton.svelte +9 -2
- package/dist/components/buttons/ImportButton.svelte.d.ts +2 -4
- package/dist/components/buttons/ShowButton.svelte +10 -2
- package/dist/components/buttons/ShowButton.svelte.d.ts +2 -4
- package/dist/components/buttons/access-control.d.ts +7 -0
- package/dist/components/buttons/access-control.js +5 -0
- package/dist/components/ui/sheet/sheet.svelte +3 -3
- package/dist/index.d.ts +5 -0
- package/dist/index.js +5 -0
- package/dist/router-state.svelte.js +15 -0
- package/package.json +2 -2
|
@@ -18,8 +18,8 @@
|
|
|
18
18
|
ChevronLeft, ChevronRight, ChevronDown, LogOut, Sun, Moon, Palette,
|
|
19
19
|
Image as ImageIcon, Layout, Folder, Type, Video,
|
|
20
20
|
Download, ListTodo, TrendingUp, Sparkles, Images, Bot, Key, KeyRound, CreditCard, BookOpen, Wrench,
|
|
21
|
-
Repeat, ClipboardCheck, SlidersHorizontal, AlertTriangle, Mail, Send, ShoppingBag, Briefcase, Building2,
|
|
22
|
-
Calendar, Bell, Clock, Trash2, Shield
|
|
21
|
+
Repeat, ClipboardCheck, SlidersHorizontal, AlertTriangle, Mail, Map as MapIcon, MessageSquare, Send, ShoppingBag, Star, Briefcase, Building2,
|
|
22
|
+
Calendar, Bell, Clock, Tag, Trash2, Shield
|
|
23
23
|
} from '@lucide/svelte';
|
|
24
24
|
|
|
25
25
|
let { collapsed, identity, title, onToggle, onLogout, menu, routeMode = 'auto' }: {
|
|
@@ -29,7 +29,6 @@
|
|
|
29
29
|
onToggle: () => void;
|
|
30
30
|
onLogout: () => void;
|
|
31
31
|
menu?: MenuItem[];
|
|
32
|
-
/** 'hash' for SPA hash routing, 'path' for SvelteKit/filesystem routing, 'auto' to detect */
|
|
33
32
|
routeMode?: 'hash' | 'path' | 'auto';
|
|
34
33
|
} = $props();
|
|
35
34
|
|
|
@@ -68,13 +67,17 @@
|
|
|
68
67
|
'sliders-horizontal': SlidersHorizontal,
|
|
69
68
|
'alert-triangle': AlertTriangle,
|
|
70
69
|
'mail': Mail,
|
|
70
|
+
'map': MapIcon,
|
|
71
|
+
'message-square': MessageSquare,
|
|
71
72
|
'send': Send,
|
|
72
73
|
'shopping-bag': ShoppingBag,
|
|
74
|
+
'star': Star,
|
|
73
75
|
'briefcase': Briefcase,
|
|
74
76
|
'building': Building2,
|
|
75
77
|
'calendar': Calendar,
|
|
76
78
|
'bell': Bell,
|
|
77
79
|
'clock': Clock,
|
|
80
|
+
'tag': Tag,
|
|
78
81
|
'trash': Trash2,
|
|
79
82
|
'shield': Shield,
|
|
80
83
|
};
|
|
@@ -87,11 +90,10 @@
|
|
|
87
90
|
}
|
|
88
91
|
|
|
89
92
|
interface NavGroup {
|
|
90
|
-
name: string | null;
|
|
93
|
+
name: string | null;
|
|
91
94
|
items: NavItem[];
|
|
92
95
|
}
|
|
93
96
|
|
|
94
|
-
// Use effect to build nav items, taking access control into account
|
|
95
97
|
let navItems = $state.raw<NavItem[]>([]);
|
|
96
98
|
|
|
97
99
|
$effect(() => {
|
|
@@ -125,7 +127,6 @@
|
|
|
125
127
|
return () => { cancelled = true; };
|
|
126
128
|
});
|
|
127
129
|
|
|
128
|
-
/** Toggle between available locales */
|
|
129
130
|
function toggleLocale() {
|
|
130
131
|
const locales = getAvailableLocales();
|
|
131
132
|
const current = getLocale();
|
|
@@ -134,10 +135,8 @@
|
|
|
134
135
|
setLocale(next);
|
|
135
136
|
}
|
|
136
137
|
|
|
137
|
-
/** Short display label for current locale */
|
|
138
138
|
const localeLabel = $derived(getLocale() === 'zh-CN' ? '中' : 'EN');
|
|
139
139
|
|
|
140
|
-
// Track current hash for active state
|
|
141
140
|
const path = $derived(getPath());
|
|
142
141
|
|
|
143
142
|
function isActive(itemPath: string): boolean {
|
|
@@ -145,7 +144,6 @@
|
|
|
145
144
|
return path === itemPath || path.startsWith(itemPath + "/");
|
|
146
145
|
}
|
|
147
146
|
|
|
148
|
-
// Group nav items by group field (null = ungrouped)
|
|
149
147
|
const navGroups = $derived.by((): NavGroup[] => {
|
|
150
148
|
const groups: NavGroup[] = [];
|
|
151
149
|
const groupMap = new Map<string | null, NavItem[]>();
|
|
@@ -162,13 +160,11 @@
|
|
|
162
160
|
return groups;
|
|
163
161
|
});
|
|
164
162
|
|
|
165
|
-
// Track which groups are open
|
|
166
163
|
let openGroups = $state<Set<string>>(new Set());
|
|
167
164
|
let colorPickerOpen = $state(false);
|
|
168
165
|
let colorPickerRef = $state<HTMLDivElement | null>(null);
|
|
169
166
|
let colorPickerOpenedAt = 0;
|
|
170
167
|
|
|
171
|
-
// Density state
|
|
172
168
|
let density = $state<'compact' | 'standard'>('standard');
|
|
173
169
|
|
|
174
170
|
$effect(() => {
|
|
@@ -185,15 +181,12 @@
|
|
|
185
181
|
}
|
|
186
182
|
});
|
|
187
183
|
|
|
188
|
-
const pyClass = $derived(density === 'compact' ? 'py-1
|
|
189
|
-
const pyClassGroupItem = $derived(density === 'compact' ? 'py-1
|
|
190
|
-
const footerIconClass = 'h-9 w-9 rounded-lg text-sidebar-foreground/60 transition-all duration-200 hover:bg-sidebar-accent/60 hover:text-sidebar-foreground';
|
|
184
|
+
const pyClass = $derived(density === 'compact' ? 'py-1' : 'py-[7px]');
|
|
185
|
+
const pyClassGroupItem = $derived(density === 'compact' ? 'py-1' : 'py-[6px]');
|
|
191
186
|
|
|
192
|
-
// Click-outside to close color picker
|
|
193
187
|
$effect(() => {
|
|
194
188
|
if (!colorPickerOpen) return;
|
|
195
189
|
function handleMouseDown(e: MouseEvent) {
|
|
196
|
-
// Ignore if opened within last 200ms (same interaction)
|
|
197
190
|
if (Date.now() - colorPickerOpenedAt < 200) return;
|
|
198
191
|
if (colorPickerRef && !colorPickerRef.contains(e.target as Node)) {
|
|
199
192
|
colorPickerOpen = false;
|
|
@@ -210,68 +203,59 @@
|
|
|
210
203
|
|
|
211
204
|
<aside
|
|
212
205
|
aria-label="Sidebar navigation"
|
|
213
|
-
class="fixed inset-y-0 left-0 z-30 flex flex-col
|
|
206
|
+
class="fixed inset-y-0 left-0 z-30 flex flex-col border-r border-border/40 transition-all duration-300"
|
|
214
207
|
style="background-color: var(--sidebar);"
|
|
215
|
-
class:w-
|
|
216
|
-
class:w-
|
|
208
|
+
class:w-[252px]={!collapsed}
|
|
209
|
+
class:w-[70px]={collapsed}
|
|
217
210
|
>
|
|
218
|
-
|
|
219
|
-
<div class="flex h-16 items-center justify-between px-4">
|
|
211
|
+
<div class="flex h-[70px] items-center shrink-0" class:px-5={!collapsed} class:justify-center={collapsed}>
|
|
220
212
|
{#if !collapsed}
|
|
221
|
-
<
|
|
222
|
-
<div class="w-
|
|
223
|
-
<span class="font-semibold text-
|
|
224
|
-
</
|
|
213
|
+
<a href="#/" class="flex items-center gap-2.5 group" onclick={(e) => { e.preventDefault(); navigate('/'); }}>
|
|
214
|
+
<div class="w-[34px] h-[34px] rounded-lg bg-gradient-to-tr from-primary to-purple-500 shrink-0 transition-transform group-hover:scale-105" style="box-shadow: 0 4px 12px oklch(0.488 0.243 264.376 / 20%);"></div>
|
|
215
|
+
<span class="font-semibold text-[15px] tracking-[-0.01em] text-sidebar-foreground">{title}</span>
|
|
216
|
+
</a>
|
|
225
217
|
{:else}
|
|
226
|
-
<
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
<TooltipButton tooltip={t('common.toggleSidebar')} variant="ghost" size="icon-sm" onclick={onToggle}>
|
|
230
|
-
<ChevronLeft class="h-4 w-4" />
|
|
231
|
-
</TooltipButton>
|
|
232
|
-
{:else}
|
|
233
|
-
<TooltipButton tooltip={t('common.toggleSidebar')} variant="ghost" size="icon-sm" onclick={onToggle} class="mx-auto mt-2 mb-2 block">
|
|
234
|
-
<ChevronRight class="h-4 w-4" />
|
|
235
|
-
</TooltipButton>
|
|
218
|
+
<a href="#/" class="group" aria-label={title} onclick={(e) => { e.preventDefault(); navigate('/'); }}>
|
|
219
|
+
<div class="w-[34px] h-[34px] rounded-lg bg-gradient-to-tr from-primary to-purple-500 shrink-0 transition-transform group-hover:scale-105" style="box-shadow: 0 4px 12px oklch(0.488 0.243 264.376 / 20%);"></div>
|
|
220
|
+
</a>
|
|
236
221
|
{/if}
|
|
237
222
|
</div>
|
|
238
223
|
|
|
239
|
-
<ScrollArea class="flex-1">
|
|
240
|
-
<nav aria-label="Main menu" class="
|
|
224
|
+
<ScrollArea class="flex-1 sidebar-scroll">
|
|
225
|
+
<nav aria-label="Main menu" class="pb-4" class:px-[10px]={!collapsed} class:px-2={collapsed}>
|
|
241
226
|
{#if menu && menu.length > 0}
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
227
|
+
<div class="space-y-[2px]">
|
|
228
|
+
{#each menu as item, _i (_i)}
|
|
229
|
+
<SidebarItem {item} currentPath={path} {collapsed} depth={0} />
|
|
230
|
+
{/each}
|
|
231
|
+
</div>
|
|
246
232
|
{:else}
|
|
247
|
-
<!-- Auto-generated menu from resources (fallback) -->
|
|
248
233
|
{#each navGroups as group, _i (_i)}
|
|
249
234
|
{#if group.name && !collapsed}
|
|
250
|
-
<!-- Grouped section with Collapsible -->
|
|
251
235
|
<Collapsible.Root open={openGroups.has(group.name)} onOpenChange={(isOpen) => {
|
|
252
236
|
const next = new Set(openGroups);
|
|
253
237
|
if (isOpen) next.add(group.name as string); else next.delete(group.name as string);
|
|
254
238
|
openGroups = next;
|
|
255
239
|
}}>
|
|
256
240
|
<Collapsible.Trigger
|
|
257
|
-
class="flex w-full items-center justify-between px-
|
|
241
|
+
class="flex w-full items-center justify-between px-[10px] py-[6px] mt-4 mb-[2px] text-[10.5px] font-semibold tracking-[0.06em] uppercase text-sidebar-foreground/45 hover:text-sidebar-foreground/70 transition-colors"
|
|
258
242
|
>
|
|
259
243
|
<span>{group.name}</span>
|
|
260
|
-
<ChevronDown class="h-3 w-3 transition-transform {openGroups.has(group.name) ? 'rotate-180' : ''}" />
|
|
244
|
+
<ChevronDown class="h-3 w-3 transition-transform duration-200 {openGroups.has(group.name) ? 'rotate-180' : ''}" />
|
|
261
245
|
</Collapsible.Trigger>
|
|
262
246
|
<Collapsible.Content>
|
|
263
|
-
<div class="
|
|
247
|
+
<div class="space-y-[2px]">
|
|
264
248
|
{#each group.items as item, _i (_i)}
|
|
265
249
|
{@const active = isActive(item.path)}
|
|
266
250
|
<a
|
|
267
251
|
href={effectiveRouteMode === 'hash' ? `#${item.path}` : item.path}
|
|
268
252
|
onclick={(e) => { e.preventDefault(); navigate(item.path); }}
|
|
269
|
-
class="flex items-center gap-
|
|
253
|
+
class="sidebar-menu-item flex items-center gap-2.5 rounded-md px-[10px] {pyClassGroupItem} text-[13px] font-medium transition-colors duration-150
|
|
270
254
|
{active
|
|
271
|
-
? '
|
|
272
|
-
: 'text-sidebar-foreground/70 hover:
|
|
255
|
+
? 'sidebar-menu-item-active bg-sidebar-accent text-primary'
|
|
256
|
+
: 'text-sidebar-foreground/70 hover:text-sidebar-foreground hover:bg-sidebar-accent/50'}"
|
|
273
257
|
>
|
|
274
|
-
<item.Icon class="h-
|
|
258
|
+
<item.Icon class="h-[18px] w-[18px] flex-shrink-0 {active ? 'text-primary' : 'text-sidebar-foreground/50'}" />
|
|
275
259
|
<span>{item.label}</span>
|
|
276
260
|
</a>
|
|
277
261
|
{/each}
|
|
@@ -279,7 +263,6 @@
|
|
|
279
263
|
</Collapsible.Content>
|
|
280
264
|
</Collapsible.Root>
|
|
281
265
|
{:else}
|
|
282
|
-
<!-- Ungrouped items (flat) -->
|
|
283
266
|
{#each group.items as item, _i (_i)}
|
|
284
267
|
{@const active = isActive(item.path)}
|
|
285
268
|
{#if collapsed}
|
|
@@ -290,12 +273,12 @@
|
|
|
290
273
|
{...props}
|
|
291
274
|
href={effectiveRouteMode === 'hash' ? `#${item.path}` : item.path}
|
|
292
275
|
onclick={(e) => { e.preventDefault(); navigate(item.path); }}
|
|
293
|
-
class="flex items-center justify-center
|
|
276
|
+
class="sidebar-menu-item flex items-center justify-center rounded-md px-2 {pyClass} transition-colors duration-150
|
|
294
277
|
{active
|
|
295
|
-
? '
|
|
296
|
-
: 'text-sidebar-foreground/
|
|
278
|
+
? 'sidebar-menu-item-active bg-sidebar-accent text-primary'
|
|
279
|
+
: 'text-sidebar-foreground/50 hover:bg-sidebar-accent/50 hover:text-sidebar-foreground'}"
|
|
297
280
|
>
|
|
298
|
-
<item.Icon class="h-
|
|
281
|
+
<item.Icon class="h-[18px] w-[18px] flex-shrink-0" />
|
|
299
282
|
</a>
|
|
300
283
|
{/snippet}
|
|
301
284
|
</Tooltip.Trigger>
|
|
@@ -307,12 +290,12 @@
|
|
|
307
290
|
<a
|
|
308
291
|
href={effectiveRouteMode === 'hash' ? `#${item.path}` : item.path}
|
|
309
292
|
onclick={(e) => { e.preventDefault(); navigate(item.path); }}
|
|
310
|
-
class="flex items-center gap-
|
|
293
|
+
class="sidebar-menu-item flex items-center gap-2.5 rounded-md px-[10px] {pyClass} text-[13px] font-medium transition-colors duration-150
|
|
311
294
|
{active
|
|
312
|
-
? '
|
|
295
|
+
? 'sidebar-menu-item-active bg-sidebar-accent text-primary'
|
|
313
296
|
: 'text-sidebar-foreground/70 hover:bg-sidebar-accent/50 hover:text-sidebar-foreground'}"
|
|
314
297
|
>
|
|
315
|
-
<item.Icon class="h-
|
|
298
|
+
<item.Icon class="h-[18px] w-[18px] flex-shrink-0 {active ? 'text-primary' : 'text-sidebar-foreground/50'}" />
|
|
316
299
|
<span>{item.label}</span>
|
|
317
300
|
</a>
|
|
318
301
|
{/if}
|
|
@@ -323,24 +306,21 @@
|
|
|
323
306
|
</nav>
|
|
324
307
|
</ScrollArea>
|
|
325
308
|
|
|
326
|
-
|
|
327
|
-
<div>
|
|
328
|
-
<!-- Color theme picker -->
|
|
309
|
+
<div class="shrink-0 border-t border-border/40">
|
|
329
310
|
{#if !collapsed}
|
|
330
311
|
<div class="px-3 pt-3 pb-1">
|
|
331
312
|
<div class="relative" bind:this={colorPickerRef}>
|
|
332
|
-
<
|
|
333
|
-
|
|
334
|
-
class="flex w-full items-center gap-2 rounded-lg px-2 py-1.5 text-sm text-sidebar-foreground/70 hover:bg-sidebar-accent hover:text-sidebar-foreground transition-colors h-auto justify-start"
|
|
313
|
+
<button
|
|
314
|
+
class="flex w-full items-center gap-2 rounded-md px-2 py-1.5 text-[12px] text-sidebar-foreground/60 hover:bg-sidebar-accent/50 hover:text-sidebar-foreground transition-colors"
|
|
335
315
|
onclick={() => { if (!colorPickerOpen) colorPickerOpenedAt = Date.now(); colorPickerOpen = !colorPickerOpen; }}
|
|
336
316
|
>
|
|
337
|
-
<Palette class="h-
|
|
338
|
-
<span class="flex-1 text-left
|
|
317
|
+
<Palette class="h-3.5 w-3.5" />
|
|
318
|
+
<span class="flex-1 text-left">{t('common.toggleTheme')}</span>
|
|
339
319
|
<span
|
|
340
|
-
class="h-3
|
|
320
|
+
class="h-3 w-3 rounded-full ring-1 ring-offset-1 ring-offset-sidebar"
|
|
341
321
|
style="background-color: {getColorThemes().find(c => c.id === getColorTheme())?.color ?? '#6366f1'}; --tw-ring-color: {getColorThemes().find(c => c.id === getColorTheme())?.color ?? '#6366f1'}"
|
|
342
322
|
></span>
|
|
343
|
-
</
|
|
323
|
+
</button>
|
|
344
324
|
{#if colorPickerOpen}
|
|
345
325
|
<div class="absolute bottom-full left-0 mb-1 z-50 w-40 rounded-lg border bg-popover p-1 text-popover-foreground shadow-lg animate-in fade-in-0 zoom-in-95">
|
|
346
326
|
{#each getColorThemes() as ct, _i (_i)}
|
|
@@ -349,7 +329,7 @@
|
|
|
349
329
|
onclick={() => { setColorTheme(ct.id as typeof ct.id & import('@svadmin/core').ColorTheme); colorPickerOpen = false; }}
|
|
350
330
|
>
|
|
351
331
|
<span
|
|
352
|
-
class="h-3
|
|
332
|
+
class="h-3 w-3 rounded-full {getColorTheme() === ct.id ? 'ring-2 ring-offset-1 scale-110' : 'opacity-70'}"
|
|
353
333
|
style="background-color: {ct.color}; {getColorTheme() === ct.id ? `--tw-ring-color: ${ct.color}` : ''}"
|
|
354
334
|
></span>
|
|
355
335
|
<span class="text-xs">{ct.label}</span>
|
|
@@ -361,10 +341,9 @@
|
|
|
361
341
|
</div>
|
|
362
342
|
{/if}
|
|
363
343
|
|
|
364
|
-
<!-- User info -->
|
|
365
344
|
{#if !collapsed && identity}
|
|
366
|
-
<div class="px-3 pb-3 pt-1
|
|
367
|
-
<div class="flex items-center gap-
|
|
345
|
+
<div class="px-3 pb-3 pt-1">
|
|
346
|
+
<div class="flex items-center gap-2.5 rounded-lg p-2 transition-colors hover:bg-sidebar-accent/40 cursor-pointer">
|
|
368
347
|
<Avatar
|
|
369
348
|
src={(identity as Record<string, unknown>).avatar as string | undefined}
|
|
370
349
|
alt={identity.name ?? 'User'}
|
|
@@ -372,36 +351,44 @@
|
|
|
372
351
|
size="sm"
|
|
373
352
|
/>
|
|
374
353
|
<div class="flex-1 min-w-0">
|
|
375
|
-
<p class="truncate text-
|
|
376
|
-
<p class="truncate text-[
|
|
354
|
+
<p class="truncate text-[13px] font-medium text-sidebar-foreground">{identity.name}</p>
|
|
355
|
+
<p class="truncate text-[11px] text-sidebar-foreground/45">{((identity as Record<string, unknown>).role || (identity as Record<string, unknown>).roleName) ?? 'User'}</p>
|
|
377
356
|
</div>
|
|
357
|
+
<button
|
|
358
|
+
class="h-7 w-7 flex items-center justify-center rounded-md text-sidebar-foreground/40 hover:text-sidebar-foreground hover:bg-sidebar-accent/60 transition-colors"
|
|
359
|
+
onclick={onLogout}
|
|
360
|
+
>
|
|
361
|
+
<LogOut class="h-3.5 w-3.5" />
|
|
362
|
+
</button>
|
|
378
363
|
</div>
|
|
379
|
-
<div class="mt-1
|
|
380
|
-
<
|
|
381
|
-
<
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
{
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
<
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
364
|
+
<div class="mt-1 flex items-center justify-between px-1">
|
|
365
|
+
<div class="flex items-center gap-0.5">
|
|
366
|
+
<TooltipButton tooltip={t('common.switchLanguage')} variant="ghost" size="icon-sm" onclick={toggleLocale} class="h-8 w-8 rounded-md text-sidebar-foreground/50 hover:bg-sidebar-accent/50 hover:text-sidebar-foreground">
|
|
367
|
+
<span class="text-[11px] font-semibold">{localeLabel}</span>
|
|
368
|
+
</TooltipButton>
|
|
369
|
+
<TooltipButton tooltip={t('common.toggleTheme')} variant="ghost" size="icon-sm" onclick={toggleTheme} class="h-8 w-8 rounded-md text-sidebar-foreground/50 hover:bg-sidebar-accent/50 hover:text-sidebar-foreground">
|
|
370
|
+
{#if getResolvedTheme() === 'dark'}
|
|
371
|
+
<Sun class="h-3.5 w-3.5" />
|
|
372
|
+
{:else}
|
|
373
|
+
<Moon class="h-3.5 w-3.5" />
|
|
374
|
+
{/if}
|
|
375
|
+
</TooltipButton>
|
|
376
|
+
<TooltipButton tooltip={t('settings.title')} variant="ghost" size="icon-sm" onclick={() => navigate('/settings')} class="h-8 w-8 rounded-md text-sidebar-foreground/50 hover:bg-sidebar-accent/50 hover:text-sidebar-foreground">
|
|
377
|
+
<Settings class="h-3.5 w-3.5" />
|
|
378
|
+
</TooltipButton>
|
|
379
|
+
</div>
|
|
380
|
+
<TooltipButton tooltip={t('common.toggleSidebar')} variant="ghost" size="icon-sm" onclick={onToggle} class="h-8 w-8 rounded-md text-sidebar-foreground/50 hover:bg-sidebar-accent/50 hover:text-sidebar-foreground">
|
|
381
|
+
<ChevronLeft class="h-3.5 w-3.5" />
|
|
395
382
|
</TooltipButton>
|
|
396
383
|
</div>
|
|
397
384
|
</div>
|
|
398
385
|
{:else if collapsed}
|
|
399
|
-
<div class="flex flex-col items-center gap-
|
|
386
|
+
<div class="flex flex-col items-center gap-0.5 px-2 py-3">
|
|
400
387
|
<Tooltip.Root>
|
|
401
388
|
<Tooltip.Trigger>
|
|
402
389
|
{#snippet child({ props }: { props: Record<string, unknown> })}
|
|
403
|
-
<Button {...props} variant="ghost" size="icon" onclick={toggleLocale} class=
|
|
404
|
-
<span class="text-
|
|
390
|
+
<Button {...props} variant="ghost" size="icon" onclick={toggleLocale} class="h-8 w-8 rounded-md text-sidebar-foreground/50 hover:bg-sidebar-accent/50 hover:text-sidebar-foreground">
|
|
391
|
+
<span class="text-[11px] font-semibold">{localeLabel}</span>
|
|
405
392
|
</Button>
|
|
406
393
|
{/snippet}
|
|
407
394
|
</Tooltip.Trigger>
|
|
@@ -410,11 +397,11 @@
|
|
|
410
397
|
<Tooltip.Root>
|
|
411
398
|
<Tooltip.Trigger>
|
|
412
399
|
{#snippet child({ props }: { props: Record<string, unknown> })}
|
|
413
|
-
<Button {...props} variant="ghost" size="icon" onclick={toggleTheme} class=
|
|
400
|
+
<Button {...props} variant="ghost" size="icon" onclick={toggleTheme} class="h-8 w-8 rounded-md text-sidebar-foreground/50 hover:bg-sidebar-accent/50 hover:text-sidebar-foreground">
|
|
414
401
|
{#if getResolvedTheme() === 'dark'}
|
|
415
|
-
<Sun class="h-
|
|
402
|
+
<Sun class="h-3.5 w-3.5" />
|
|
416
403
|
{:else}
|
|
417
|
-
<Moon class="h-
|
|
404
|
+
<Moon class="h-3.5 w-3.5" />
|
|
418
405
|
{/if}
|
|
419
406
|
</Button>
|
|
420
407
|
{/snippet}
|
|
@@ -424,8 +411,18 @@
|
|
|
424
411
|
<Tooltip.Root>
|
|
425
412
|
<Tooltip.Trigger>
|
|
426
413
|
{#snippet child({ props }: { props: Record<string, unknown> })}
|
|
427
|
-
<Button {...props} variant="ghost" size="icon" onclick={
|
|
428
|
-
<
|
|
414
|
+
<Button {...props} variant="ghost" size="icon" onclick={onToggle} class="h-8 w-8 rounded-md text-sidebar-foreground/50 hover:bg-sidebar-accent/50 hover:text-sidebar-foreground">
|
|
415
|
+
<ChevronRight class="h-3.5 w-3.5" />
|
|
416
|
+
</Button>
|
|
417
|
+
{/snippet}
|
|
418
|
+
</Tooltip.Trigger>
|
|
419
|
+
<Tooltip.Content side="right">{t('common.toggleSidebar')}</Tooltip.Content>
|
|
420
|
+
</Tooltip.Root>
|
|
421
|
+
<Tooltip.Root>
|
|
422
|
+
<Tooltip.Trigger>
|
|
423
|
+
{#snippet child({ props }: { props: Record<string, unknown> })}
|
|
424
|
+
<Button {...props} variant="ghost" size="icon" onclick={onLogout} class="h-8 w-8 rounded-md text-sidebar-foreground/50 hover:bg-sidebar-accent/50 hover:text-destructive">
|
|
425
|
+
<LogOut class="h-3.5 w-3.5" />
|
|
429
426
|
</Button>
|
|
430
427
|
{/snippet}
|
|
431
428
|
</Tooltip.Trigger>
|
|
@@ -433,15 +430,15 @@
|
|
|
433
430
|
</Tooltip.Root>
|
|
434
431
|
</div>
|
|
435
432
|
{:else}
|
|
436
|
-
<div class="flex justify-center gap-
|
|
437
|
-
<TooltipButton tooltip={t('common.switchLanguage')} variant="ghost" size="icon" onclick={toggleLocale} class=
|
|
438
|
-
<span class="text-
|
|
433
|
+
<div class="flex justify-center gap-1 p-3">
|
|
434
|
+
<TooltipButton tooltip={t('common.switchLanguage')} variant="ghost" size="icon" onclick={toggleLocale} class="h-8 w-8 rounded-md text-sidebar-foreground/50 hover:bg-sidebar-accent/50 hover:text-sidebar-foreground">
|
|
435
|
+
<span class="text-[11px] font-semibold">{localeLabel}</span>
|
|
439
436
|
</TooltipButton>
|
|
440
|
-
<TooltipButton tooltip={t('common.toggleTheme')} variant="ghost" size="icon" onclick={toggleTheme} class=
|
|
437
|
+
<TooltipButton tooltip={t('common.toggleTheme')} variant="ghost" size="icon" onclick={toggleTheme} class="h-8 w-8 rounded-md text-sidebar-foreground/50 hover:bg-sidebar-accent/50 hover:text-sidebar-foreground">
|
|
441
438
|
{#if getResolvedTheme() === 'dark'}
|
|
442
|
-
<Sun class="h-
|
|
439
|
+
<Sun class="h-3.5 w-3.5" />
|
|
443
440
|
{:else}
|
|
444
|
-
<Moon class="h-
|
|
441
|
+
<Moon class="h-3.5 w-3.5" />
|
|
445
442
|
{/if}
|
|
446
443
|
</TooltipButton>
|
|
447
444
|
</div>
|
|
@@ -6,7 +6,6 @@ type $$ComponentProps = {
|
|
|
6
6
|
onToggle: () => void;
|
|
7
7
|
onLogout: () => void;
|
|
8
8
|
menu?: MenuItem[];
|
|
9
|
-
/** 'hash' for SPA hash routing, 'path' for SvelteKit/filesystem routing, 'auto' to detect */
|
|
10
9
|
routeMode?: 'hash' | 'path' | 'auto';
|
|
11
10
|
};
|
|
12
11
|
declare const Sidebar: import("svelte").Component<$$ComponentProps, {}, "">;
|