@miozu/jera 0.4.4 → 0.4.5
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/package.json +2 -2
- package/src/components/navigation/DropdownContainer.svelte +575 -0
- package/src/components/navigation/LeftBar.svelte +179 -0
- package/src/components/navigation/LeftBarItem.svelte +267 -0
- package/src/components/navigation/LeftBarPopover.svelte +121 -0
- package/src/components/navigation/LeftBarSection.svelte +63 -0
- package/src/components/navigation/LeftBarToggle.svelte +87 -0
- package/src/components/primitives/Button.svelte +147 -94
- package/src/index.js +8 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@miozu/jera",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.5",
|
|
4
4
|
"description": "Minimal, reactive component library for Svelte 5",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
@@ -58,6 +58,6 @@
|
|
|
58
58
|
"url": "https://github.com/miozu-com/jera/issues"
|
|
59
59
|
},
|
|
60
60
|
"dependencies": {
|
|
61
|
-
"@miozu/jera": "0.4.
|
|
61
|
+
"@miozu/jera": "0.4.4"
|
|
62
62
|
}
|
|
63
63
|
}
|
|
@@ -0,0 +1,575 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
@component DropdownContainer
|
|
3
|
+
|
|
4
|
+
A user/account dropdown with avatar trigger for use in LeftBar header.
|
|
5
|
+
Exact 1:1 match with admin.selify.ai AdminUserDropdown styles.
|
|
6
|
+
|
|
7
|
+
@example Basic usage
|
|
8
|
+
<DropdownContainer
|
|
9
|
+
user={{ full_name: 'John Doe', avatar_url: '/avatar.jpg', role_name: 'admin' }}
|
|
10
|
+
title="Admin Dashboard"
|
|
11
|
+
{isCollapsed}
|
|
12
|
+
{themeState}
|
|
13
|
+
onSignOut={handleSignOut}
|
|
14
|
+
>
|
|
15
|
+
{#snippet menuItems()}
|
|
16
|
+
<button class="menu-item" onclick={toggleTheme}>
|
|
17
|
+
<Sun size={16} />
|
|
18
|
+
<span class="menu-label">Light Mode</span>
|
|
19
|
+
</button>
|
|
20
|
+
{/snippet}
|
|
21
|
+
</DropdownContainer>
|
|
22
|
+
-->
|
|
23
|
+
<script>
|
|
24
|
+
import { onMount, getContext } from 'svelte';
|
|
25
|
+
|
|
26
|
+
let {
|
|
27
|
+
user = null,
|
|
28
|
+
title = '',
|
|
29
|
+
isCollapsed = false,
|
|
30
|
+
themeState = null,
|
|
31
|
+
signOutLoading = false,
|
|
32
|
+
signOutAction = '/auth?/signout',
|
|
33
|
+
onSignOut = null,
|
|
34
|
+
roleVariants = {
|
|
35
|
+
super_admin: 'primary',
|
|
36
|
+
admin: 'primary',
|
|
37
|
+
developer: 'primary',
|
|
38
|
+
ops: 'success',
|
|
39
|
+
support: 'default'
|
|
40
|
+
},
|
|
41
|
+
class: className = '',
|
|
42
|
+
// Snippets
|
|
43
|
+
userHeader,
|
|
44
|
+
envSection,
|
|
45
|
+
menuItems,
|
|
46
|
+
footerContent,
|
|
47
|
+
// Icons (optional - defaults to inline SVGs)
|
|
48
|
+
ChevronDownIcon = null,
|
|
49
|
+
ChevronUpIcon = null,
|
|
50
|
+
SunIcon = null,
|
|
51
|
+
MoonIcon = null,
|
|
52
|
+
LogOutIcon = null,
|
|
53
|
+
children
|
|
54
|
+
} = $props();
|
|
55
|
+
|
|
56
|
+
// Get initials from name
|
|
57
|
+
function getInitials(name) {
|
|
58
|
+
if (!name) return '?';
|
|
59
|
+
const parts = name.trim().split(' ');
|
|
60
|
+
if (parts.length >= 2) {
|
|
61
|
+
return (parts[0][0] + parts[parts.length - 1][0]).toUpperCase();
|
|
62
|
+
}
|
|
63
|
+
return name.slice(0, 2).toUpperCase();
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
let isOpen = $state(false);
|
|
67
|
+
let dropdownReady = $state(false);
|
|
68
|
+
let dropdownRef = $state(null);
|
|
69
|
+
let triggerRef = $state(null);
|
|
70
|
+
let dropdownPosition = $state({ top: 0, left: 0, right: 0 });
|
|
71
|
+
let isMobileView = $state(false);
|
|
72
|
+
|
|
73
|
+
function toggleDropdown() {
|
|
74
|
+
isOpen = !isOpen;
|
|
75
|
+
|
|
76
|
+
if (isOpen && triggerRef) {
|
|
77
|
+
isMobileView = typeof window !== 'undefined' && window.innerWidth < 1024;
|
|
78
|
+
dropdownReady = false;
|
|
79
|
+
|
|
80
|
+
const calculatePosition = () => {
|
|
81
|
+
if (!triggerRef) return;
|
|
82
|
+
|
|
83
|
+
const rect = triggerRef.getBoundingClientRect();
|
|
84
|
+
|
|
85
|
+
if (isMobileView) {
|
|
86
|
+
const spaceBelow = window.innerHeight - rect.bottom;
|
|
87
|
+
const dropdownHeight = 400;
|
|
88
|
+
|
|
89
|
+
if (spaceBelow < dropdownHeight && rect.top > dropdownHeight) {
|
|
90
|
+
dropdownPosition = {
|
|
91
|
+
top: rect.top - dropdownHeight - 8,
|
|
92
|
+
left: 16,
|
|
93
|
+
right: 16
|
|
94
|
+
};
|
|
95
|
+
} else {
|
|
96
|
+
dropdownPosition = {
|
|
97
|
+
top: rect.bottom + 8,
|
|
98
|
+
left: 16,
|
|
99
|
+
right: 16
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
} else {
|
|
103
|
+
dropdownPosition = {
|
|
104
|
+
top: rect.bottom + 8,
|
|
105
|
+
left: rect.left,
|
|
106
|
+
right: 'auto'
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
dropdownReady = true;
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
if (isMobileView) {
|
|
114
|
+
setTimeout(() => {
|
|
115
|
+
requestAnimationFrame(() => {
|
|
116
|
+
requestAnimationFrame(() => {
|
|
117
|
+
calculatePosition();
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
}, 500);
|
|
121
|
+
} else {
|
|
122
|
+
calculatePosition();
|
|
123
|
+
}
|
|
124
|
+
} else {
|
|
125
|
+
dropdownReady = false;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function closeDropdown() {
|
|
130
|
+
isOpen = false;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function handleClickOutside(event) {
|
|
134
|
+
if (
|
|
135
|
+
isOpen &&
|
|
136
|
+
dropdownRef &&
|
|
137
|
+
!dropdownRef.contains(event.target) &&
|
|
138
|
+
triggerRef &&
|
|
139
|
+
!triggerRef.contains(event.target)
|
|
140
|
+
) {
|
|
141
|
+
closeDropdown();
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
onMount(() => {
|
|
146
|
+
const handleCloseDropdowns = () => {
|
|
147
|
+
closeDropdown();
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
window.addEventListener('closedropdowns', handleCloseDropdowns);
|
|
151
|
+
document.addEventListener('click', handleClickOutside);
|
|
152
|
+
|
|
153
|
+
return () => {
|
|
154
|
+
window.removeEventListener('closedropdowns', handleCloseDropdowns);
|
|
155
|
+
document.removeEventListener('click', handleClickOutside);
|
|
156
|
+
};
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
// Handle theme toggle
|
|
160
|
+
function toggleTheme() {
|
|
161
|
+
themeState?.toggle?.();
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// Format role name
|
|
165
|
+
let formatRoleName = $derived.by(() => {
|
|
166
|
+
if (!user?.role_name) return 'Unknown';
|
|
167
|
+
return user.role_name.replace('_', ' ');
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
// Get badge variant
|
|
171
|
+
let badgeVariant = $derived(roleVariants[user?.role_name] || 'default');
|
|
172
|
+
</script>
|
|
173
|
+
|
|
174
|
+
<!-- Dropdown Container -->
|
|
175
|
+
<div class="dropdown-container {className}">
|
|
176
|
+
<!-- Avatar Trigger Button -->
|
|
177
|
+
<button
|
|
178
|
+
bind:this={triggerRef}
|
|
179
|
+
class="avatar-trigger"
|
|
180
|
+
class:collapsed={isCollapsed}
|
|
181
|
+
onclick={toggleDropdown}
|
|
182
|
+
aria-expanded={isOpen}
|
|
183
|
+
aria-haspopup="true"
|
|
184
|
+
title={isCollapsed ? (user?.full_name || 'User') : 'Account menu'}
|
|
185
|
+
>
|
|
186
|
+
<div class="avatar avatar-sm">
|
|
187
|
+
{#if user?.avatar_url}
|
|
188
|
+
<img src={user.avatar_url} alt={user?.full_name || 'Avatar'} />
|
|
189
|
+
{:else}
|
|
190
|
+
<span class="avatar-initials">{getInitials(user?.full_name)}</span>
|
|
191
|
+
{/if}
|
|
192
|
+
</div>
|
|
193
|
+
{#if !isCollapsed}
|
|
194
|
+
<div class="trigger-info">
|
|
195
|
+
<div class="trigger-workspace">{title}</div>
|
|
196
|
+
<div class="trigger-name">{user?.full_name || 'User'}</div>
|
|
197
|
+
</div>
|
|
198
|
+
<div class="trigger-chevron">
|
|
199
|
+
{#if ChevronUpIcon && ChevronDownIcon}
|
|
200
|
+
{#if isOpen}
|
|
201
|
+
<ChevronUpIcon size={16} />
|
|
202
|
+
{:else}
|
|
203
|
+
<ChevronDownIcon size={16} />
|
|
204
|
+
{/if}
|
|
205
|
+
{:else}
|
|
206
|
+
{#if isOpen}
|
|
207
|
+
<!-- ChevronUp -->
|
|
208
|
+
<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">
|
|
209
|
+
<polyline points="18 15 12 9 6 15"></polyline>
|
|
210
|
+
</svg>
|
|
211
|
+
{:else}
|
|
212
|
+
<!-- ChevronDown -->
|
|
213
|
+
<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">
|
|
214
|
+
<polyline points="6 9 12 15 18 9"></polyline>
|
|
215
|
+
</svg>
|
|
216
|
+
{/if}
|
|
217
|
+
{/if}
|
|
218
|
+
</div>
|
|
219
|
+
{/if}
|
|
220
|
+
</button>
|
|
221
|
+
|
|
222
|
+
<!-- Dropdown Menu -->
|
|
223
|
+
{#if isOpen && dropdownReady}
|
|
224
|
+
<div
|
|
225
|
+
bind:this={dropdownRef}
|
|
226
|
+
class="dropdown-menu"
|
|
227
|
+
class:mobile-dropdown={isMobileView}
|
|
228
|
+
style="top: {dropdownPosition.top}px; left: {dropdownPosition.left}px; {dropdownPosition.right !== 'auto' ? `right: ${dropdownPosition.right}px;` : ''}"
|
|
229
|
+
>
|
|
230
|
+
<!-- User Header -->
|
|
231
|
+
{#if userHeader}
|
|
232
|
+
{@render userHeader()}
|
|
233
|
+
{:else}
|
|
234
|
+
<div class="user-header">
|
|
235
|
+
<div class="avatar avatar-md">
|
|
236
|
+
{#if user?.avatar_url}
|
|
237
|
+
<img src={user.avatar_url} alt={user?.full_name || 'Avatar'} />
|
|
238
|
+
{:else}
|
|
239
|
+
<span class="avatar-initials">{getInitials(user?.full_name)}</span>
|
|
240
|
+
{/if}
|
|
241
|
+
</div>
|
|
242
|
+
<div class="user-info">
|
|
243
|
+
<div class="user-name">{user?.full_name || 'User'}</div>
|
|
244
|
+
<span class="badge badge-{badgeVariant}">{formatRoleName}</span>
|
|
245
|
+
</div>
|
|
246
|
+
</div>
|
|
247
|
+
{/if}
|
|
248
|
+
|
|
249
|
+
<!-- Environment Section (optional slot) -->
|
|
250
|
+
{#if envSection}
|
|
251
|
+
{@render envSection()}
|
|
252
|
+
{/if}
|
|
253
|
+
|
|
254
|
+
<!-- Menu Items -->
|
|
255
|
+
<div class="menu-list">
|
|
256
|
+
{#if menuItems}
|
|
257
|
+
{@render menuItems()}
|
|
258
|
+
{:else}
|
|
259
|
+
<!-- Default: Theme Toggle -->
|
|
260
|
+
{#if themeState}
|
|
261
|
+
<button class="menu-item" onclick={toggleTheme}>
|
|
262
|
+
{#if SunIcon && MoonIcon}
|
|
263
|
+
{#if themeState.isDark}
|
|
264
|
+
<SunIcon size={16} />
|
|
265
|
+
<span class="menu-label">Light Mode</span>
|
|
266
|
+
{:else}
|
|
267
|
+
<MoonIcon size={16} />
|
|
268
|
+
<span class="menu-label">Dark Mode</span>
|
|
269
|
+
{/if}
|
|
270
|
+
{:else}
|
|
271
|
+
{#if themeState.isDark}
|
|
272
|
+
<!-- Sun -->
|
|
273
|
+
<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">
|
|
274
|
+
<circle cx="12" cy="12" r="5"></circle>
|
|
275
|
+
<line x1="12" y1="1" x2="12" y2="3"></line>
|
|
276
|
+
<line x1="12" y1="21" x2="12" y2="23"></line>
|
|
277
|
+
<line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line>
|
|
278
|
+
<line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line>
|
|
279
|
+
<line x1="1" y1="12" x2="3" y2="12"></line>
|
|
280
|
+
<line x1="21" y1="12" x2="23" y2="12"></line>
|
|
281
|
+
<line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line>
|
|
282
|
+
<line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line>
|
|
283
|
+
</svg>
|
|
284
|
+
<span class="menu-label">Light Mode</span>
|
|
285
|
+
{:else}
|
|
286
|
+
<!-- Moon -->
|
|
287
|
+
<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">
|
|
288
|
+
<path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"></path>
|
|
289
|
+
</svg>
|
|
290
|
+
<span class="menu-label">Dark Mode</span>
|
|
291
|
+
{/if}
|
|
292
|
+
{/if}
|
|
293
|
+
</button>
|
|
294
|
+
{/if}
|
|
295
|
+
|
|
296
|
+
<!-- Default: Sign Out -->
|
|
297
|
+
<form method="post" action={signOutAction}>
|
|
298
|
+
<button type="submit" class="menu-item signout-item" disabled={signOutLoading}>
|
|
299
|
+
{#if LogOutIcon}
|
|
300
|
+
<LogOutIcon size={16} />
|
|
301
|
+
{:else}
|
|
302
|
+
<!-- LogOut -->
|
|
303
|
+
<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">
|
|
304
|
+
<path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"></path>
|
|
305
|
+
<polyline points="16 17 21 12 16 7"></polyline>
|
|
306
|
+
<line x1="21" y1="12" x2="9" y2="12"></line>
|
|
307
|
+
</svg>
|
|
308
|
+
{/if}
|
|
309
|
+
<span class="menu-label">
|
|
310
|
+
{signOutLoading ? 'Signing out...' : 'Sign out'}
|
|
311
|
+
</span>
|
|
312
|
+
</button>
|
|
313
|
+
</form>
|
|
314
|
+
{/if}
|
|
315
|
+
</div>
|
|
316
|
+
|
|
317
|
+
<!-- Footer -->
|
|
318
|
+
{#if footerContent}
|
|
319
|
+
<div class="menu-footer">
|
|
320
|
+
{@render footerContent()}
|
|
321
|
+
</div>
|
|
322
|
+
{/if}
|
|
323
|
+
</div>
|
|
324
|
+
{/if}
|
|
325
|
+
</div>
|
|
326
|
+
|
|
327
|
+
<style>
|
|
328
|
+
.dropdown-container {
|
|
329
|
+
position: relative;
|
|
330
|
+
margin: 0.5rem;
|
|
331
|
+
margin-top: 0.5rem;
|
|
332
|
+
margin-bottom: 0.75rem;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
.avatar-trigger {
|
|
336
|
+
padding: 0.5rem 0.75rem;
|
|
337
|
+
border-radius: 0.5rem;
|
|
338
|
+
transition: all 200ms;
|
|
339
|
+
cursor: pointer;
|
|
340
|
+
display: flex;
|
|
341
|
+
align-items: center;
|
|
342
|
+
gap: 0.75rem;
|
|
343
|
+
width: 100%;
|
|
344
|
+
background: transparent;
|
|
345
|
+
border: none;
|
|
346
|
+
font: inherit;
|
|
347
|
+
text-align: left;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
.avatar-trigger:hover {
|
|
351
|
+
background-color: color-mix(in srgb, var(--color-base0D) 5%, transparent);
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
.avatar-trigger.collapsed {
|
|
355
|
+
justify-content: center;
|
|
356
|
+
padding: 0.5rem;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
/* Custom squarish avatar - 4px border radius */
|
|
360
|
+
.avatar {
|
|
361
|
+
display: flex;
|
|
362
|
+
flex-shrink: 0;
|
|
363
|
+
overflow: hidden;
|
|
364
|
+
align-items: center;
|
|
365
|
+
justify-content: center;
|
|
366
|
+
border-radius: 4px;
|
|
367
|
+
background: linear-gradient(to bottom right, color-mix(in srgb, var(--color-base0D) 20%, transparent), color-mix(in srgb, var(--color-base0E) 20%, transparent));
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
.avatar img {
|
|
371
|
+
width: 100%;
|
|
372
|
+
height: 100%;
|
|
373
|
+
object-fit: cover;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
.avatar-initials {
|
|
377
|
+
font-weight: 600;
|
|
378
|
+
color: var(--color-base0D);
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
/* Trigger avatar - 32px */
|
|
382
|
+
.avatar-sm {
|
|
383
|
+
width: 2rem;
|
|
384
|
+
height: 2rem;
|
|
385
|
+
font-size: 0.75rem;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
/* Header avatar - 40px */
|
|
389
|
+
.avatar-md {
|
|
390
|
+
width: 2.5rem;
|
|
391
|
+
height: 2.5rem;
|
|
392
|
+
font-size: 0.875rem;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
.trigger-info {
|
|
396
|
+
display: flex;
|
|
397
|
+
flex-direction: column;
|
|
398
|
+
align-items: flex-start;
|
|
399
|
+
flex: 1;
|
|
400
|
+
min-width: 0;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
.trigger-workspace {
|
|
404
|
+
font-size: 0.875rem;
|
|
405
|
+
font-weight: 600;
|
|
406
|
+
color: var(--color-base06);
|
|
407
|
+
overflow: hidden;
|
|
408
|
+
text-overflow: ellipsis;
|
|
409
|
+
white-space: nowrap;
|
|
410
|
+
width: 100%;
|
|
411
|
+
text-align: left;
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
.trigger-name {
|
|
415
|
+
font-size: 0.75rem;
|
|
416
|
+
color: var(--color-base05);
|
|
417
|
+
overflow: hidden;
|
|
418
|
+
text-overflow: ellipsis;
|
|
419
|
+
white-space: nowrap;
|
|
420
|
+
width: 100%;
|
|
421
|
+
text-align: left;
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
.trigger-chevron {
|
|
425
|
+
display: flex;
|
|
426
|
+
align-items: center;
|
|
427
|
+
justify-content: center;
|
|
428
|
+
color: var(--color-base05);
|
|
429
|
+
transition: all 200ms;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
.trigger-chevron :global(svg) {
|
|
433
|
+
flex-shrink: 0;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
.dropdown-menu {
|
|
437
|
+
position: fixed;
|
|
438
|
+
margin-top: 0.5rem;
|
|
439
|
+
width: 18rem;
|
|
440
|
+
background-color: var(--color-base00);
|
|
441
|
+
border: 1px solid color-mix(in srgb, var(--color-base03) 30%, transparent);
|
|
442
|
+
border-radius: 0.5rem;
|
|
443
|
+
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
|
|
444
|
+
overflow-y: auto;
|
|
445
|
+
max-height: calc(100vh - 120px);
|
|
446
|
+
z-index: 9999;
|
|
447
|
+
animation: dropdown-appear 0.15s ease-out;
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
.dropdown-menu.mobile-dropdown {
|
|
451
|
+
width: auto;
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
@keyframes dropdown-appear {
|
|
455
|
+
from {
|
|
456
|
+
opacity: 0;
|
|
457
|
+
transform: translateY(-8px) scale(0.96);
|
|
458
|
+
}
|
|
459
|
+
to {
|
|
460
|
+
opacity: 1;
|
|
461
|
+
transform: translateY(0) scale(1);
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
.user-header {
|
|
466
|
+
padding: 0.75rem 1rem;
|
|
467
|
+
display: flex;
|
|
468
|
+
align-items: center;
|
|
469
|
+
gap: 0.75rem;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
.user-info {
|
|
473
|
+
flex: 1;
|
|
474
|
+
min-width: 0;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
.user-name {
|
|
478
|
+
font-size: 0.875rem;
|
|
479
|
+
font-weight: 600;
|
|
480
|
+
color: var(--color-base06);
|
|
481
|
+
overflow: hidden;
|
|
482
|
+
text-overflow: ellipsis;
|
|
483
|
+
white-space: nowrap;
|
|
484
|
+
margin-bottom: 0.25rem;
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
/* Badge styles */
|
|
488
|
+
.badge {
|
|
489
|
+
display: inline-flex;
|
|
490
|
+
align-items: center;
|
|
491
|
+
padding: 0.125rem 0.5rem;
|
|
492
|
+
font-size: 0.625rem;
|
|
493
|
+
font-weight: 500;
|
|
494
|
+
border-radius: 9999px;
|
|
495
|
+
text-transform: capitalize;
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
.badge-default {
|
|
499
|
+
background-color: var(--color-base02);
|
|
500
|
+
color: var(--color-base05);
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
.badge-primary {
|
|
504
|
+
background-color: color-mix(in srgb, var(--color-base0D) 20%, transparent);
|
|
505
|
+
color: var(--color-base0D);
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
.badge-success {
|
|
509
|
+
background-color: color-mix(in srgb, var(--color-base0B) 20%, transparent);
|
|
510
|
+
color: var(--color-base0B);
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
.menu-list {
|
|
514
|
+
padding: 0.5rem;
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
.menu-item {
|
|
518
|
+
width: 100%;
|
|
519
|
+
padding: 0.5rem 0.75rem;
|
|
520
|
+
display: flex;
|
|
521
|
+
align-items: center;
|
|
522
|
+
gap: 0.75rem;
|
|
523
|
+
font-size: 0.875rem;
|
|
524
|
+
color: var(--color-base06);
|
|
525
|
+
transition: all 150ms;
|
|
526
|
+
cursor: pointer;
|
|
527
|
+
border-radius: 0.375rem;
|
|
528
|
+
background: transparent;
|
|
529
|
+
border: none;
|
|
530
|
+
font: inherit;
|
|
531
|
+
text-align: left;
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
.menu-item:hover:not(:disabled) {
|
|
535
|
+
color: var(--color-base0D);
|
|
536
|
+
background-color: color-mix(in srgb, var(--color-base0D) 5%, transparent);
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
.menu-item:disabled {
|
|
540
|
+
opacity: 0.5;
|
|
541
|
+
cursor: not-allowed;
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
.menu-label {
|
|
545
|
+
flex: 1;
|
|
546
|
+
text-align: left;
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
.signout-item:hover:not(:disabled) {
|
|
550
|
+
color: var(--color-base08);
|
|
551
|
+
background-color: color-mix(in srgb, var(--color-base08) 10%, transparent);
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
.menu-item :global(svg) {
|
|
555
|
+
flex-shrink: 0;
|
|
556
|
+
color: var(--color-base05);
|
|
557
|
+
transition: color 150ms;
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
.menu-item:hover :global(svg) {
|
|
561
|
+
color: var(--color-base0D);
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
.signout-item:hover :global(svg) {
|
|
565
|
+
color: var(--color-base08);
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
.menu-footer {
|
|
569
|
+
padding: 0.5rem 1rem;
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
form {
|
|
573
|
+
width: 100%;
|
|
574
|
+
}
|
|
575
|
+
</style>
|