@miozu/jera 0.3.0 → 0.4.2

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 (72) hide show
  1. package/CLAUDE.md +350 -59
  2. package/README.md +30 -22
  3. package/llms.txt +37 -4
  4. package/package.json +12 -2
  5. package/src/components/docs/CodeBlock.svelte +203 -0
  6. package/src/components/docs/DocSection.svelte +120 -0
  7. package/src/components/docs/PropsTable.svelte +136 -0
  8. package/src/components/docs/SplitPane.svelte +98 -0
  9. package/src/components/docs/index.js +14 -0
  10. package/src/components/feedback/Alert.svelte +234 -0
  11. package/src/components/feedback/EmptyState.svelte +6 -6
  12. package/src/components/feedback/ProgressBar.svelte +8 -8
  13. package/src/components/feedback/Skeleton.svelte +4 -4
  14. package/src/components/feedback/Spinner.svelte +1 -1
  15. package/src/components/feedback/Toast.svelte +137 -173
  16. package/src/components/forms/Checkbox.svelte +10 -10
  17. package/src/components/forms/Dropzone.svelte +14 -14
  18. package/src/components/forms/FileUpload.svelte +16 -16
  19. package/src/components/forms/IconInput.svelte +4 -4
  20. package/src/components/forms/Input.svelte +14 -14
  21. package/src/components/forms/NumberInput.svelte +13 -13
  22. package/src/components/forms/PinInput.svelte +8 -8
  23. package/src/components/forms/Radio.svelte +8 -8
  24. package/src/components/forms/RangeSlider.svelte +12 -12
  25. package/src/components/forms/SearchInput.svelte +10 -10
  26. package/src/components/forms/Select.svelte +156 -158
  27. package/src/components/forms/Switch.svelte +4 -4
  28. package/src/components/forms/Textarea.svelte +9 -9
  29. package/src/components/navigation/Accordion.svelte +1 -1
  30. package/src/components/navigation/AccordionItem.svelte +6 -6
  31. package/src/components/navigation/NavigationContainer.svelte +344 -0
  32. package/src/components/navigation/Sidebar.svelte +334 -0
  33. package/src/components/navigation/SidebarAccountGroup.svelte +495 -0
  34. package/src/components/navigation/SidebarAccountItem.svelte +492 -0
  35. package/src/components/navigation/SidebarGroup.svelte +230 -0
  36. package/src/components/navigation/SidebarGroupSwitcher.svelte +262 -0
  37. package/src/components/navigation/SidebarItem.svelte +210 -0
  38. package/src/components/navigation/SidebarNavigationItem.svelte +470 -0
  39. package/src/components/navigation/SidebarPopover.svelte +145 -0
  40. package/src/components/navigation/SidebarSearch.svelte +236 -0
  41. package/src/components/navigation/SidebarSection.svelte +158 -0
  42. package/src/components/navigation/SidebarToggle.svelte +86 -0
  43. package/src/components/navigation/Tabs.svelte +18 -18
  44. package/src/components/navigation/WorkspaceMenu.svelte +416 -0
  45. package/src/components/navigation/blocks/NavigationAccountGroup.svelte +396 -0
  46. package/src/components/navigation/blocks/NavigationCustomBlock.svelte +74 -0
  47. package/src/components/navigation/blocks/NavigationGroupSwitcher.svelte +277 -0
  48. package/src/components/navigation/blocks/NavigationSearch.svelte +300 -0
  49. package/src/components/navigation/blocks/NavigationSection.svelte +230 -0
  50. package/src/components/navigation/index.js +22 -0
  51. package/src/components/overlays/ConfirmDialog.svelte +18 -18
  52. package/src/components/overlays/Dropdown.svelte +2 -2
  53. package/src/components/overlays/DropdownDivider.svelte +1 -1
  54. package/src/components/overlays/DropdownItem.svelte +5 -5
  55. package/src/components/overlays/Modal.svelte +13 -13
  56. package/src/components/overlays/Popover.svelte +3 -3
  57. package/src/components/primitives/Avatar.svelte +12 -12
  58. package/src/components/primitives/Badge.svelte +7 -7
  59. package/src/components/primitives/Button.svelte +126 -174
  60. package/src/components/primitives/Card.svelte +15 -15
  61. package/src/components/primitives/Divider.svelte +3 -3
  62. package/src/components/primitives/LazyImage.svelte +1 -1
  63. package/src/components/primitives/Link.svelte +2 -2
  64. package/src/components/primitives/Stat.svelte +197 -0
  65. package/src/components/primitives/StatusBadge.svelte +24 -24
  66. package/src/index.js +62 -7
  67. package/src/tokens/colors.css +96 -128
  68. package/src/utils/highlighter.js +124 -0
  69. package/src/utils/index.js +7 -2
  70. package/src/utils/navigation.svelte.js +423 -0
  71. package/src/utils/reactive.svelte.js +126 -37
  72. package/src/utils/sidebar.svelte.js +211 -0
@@ -0,0 +1,416 @@
1
+ <!--
2
+ @component WorkspaceMenu
3
+
4
+ Enterprise workspace/organization switcher with dropdown menu.
5
+ Works in sidebar headers, top navbars, or standalone.
6
+ Auto-detects Sidebar context for collapse-aware behavior.
7
+
8
+ @example Basic usage in Sidebar
9
+ <Sidebar>
10
+ {#snippet header()}
11
+ <WorkspaceMenu
12
+ workspace={{ name: 'Acme Corp', logo: '/acme.png' }}
13
+ user={{ name: 'John Doe', email: 'john@acme.com', avatar: '/john.jpg' }}
14
+ >
15
+ {#snippet menu()}
16
+ <DropdownItem onclick={switchWorkspace}>Switch Workspace</DropdownItem>
17
+ <DropdownItem href="/settings">Settings</DropdownItem>
18
+ <DropdownDivider />
19
+ <DropdownItem onclick={signOut} variant="danger">Sign Out</DropdownItem>
20
+ {/snippet}
21
+ </WorkspaceMenu>
22
+ {/snippet}
23
+ </Sidebar>
24
+
25
+ @example In top navbar (standalone)
26
+ <nav class="top-nav">
27
+ <WorkspaceMenu
28
+ workspace={{ name: 'Acme Corp' }}
29
+ user={{ name: 'John Doe' }}
30
+ position="bottom-start"
31
+ />
32
+ </nav>
33
+
34
+ @example Minimal (workspace only)
35
+ <WorkspaceMenu workspace={{ name: 'My Workspace', initials: 'MW' }} />
36
+ -->
37
+ <script>
38
+ import { getContext, onMount } from 'svelte';
39
+ import { SIDEBAR_CONTEXT_KEY } from '../../utils/sidebar.svelte.js';
40
+ import { clickOutside } from '../../actions/index.js';
41
+
42
+ let {
43
+ workspace = null,
44
+ user = null,
45
+ badge = null,
46
+ showChevron = true,
47
+ position = 'bottom-start',
48
+ class: className = '',
49
+ menu
50
+ } = $props();
51
+
52
+ // Try to get sidebar context (may be null if used outside sidebar)
53
+ const sidebar = getContext(SIDEBAR_CONTEXT_KEY);
54
+ const isCollapsed = $derived(sidebar?.collapsed ?? false);
55
+ const isInSidebar = $derived(sidebar !== undefined);
56
+
57
+ // Dropdown state
58
+ let isOpen = $state(false);
59
+ let triggerRef = $state(null);
60
+ let dropdownRef = $state(null);
61
+
62
+ function toggle() {
63
+ isOpen = !isOpen;
64
+ }
65
+
66
+ function close() {
67
+ isOpen = false;
68
+ }
69
+
70
+ // Get workspace display info
71
+ const workspaceLogo = $derived(workspace?.logo || workspace?.avatar);
72
+ const workspaceInitials = $derived(
73
+ workspace?.initials ||
74
+ workspace?.name?.split(' ').map(w => w[0]).join('').slice(0, 2).toUpperCase() ||
75
+ 'W'
76
+ );
77
+
78
+ // Get user display info
79
+ const userAvatar = $derived(user?.avatar || user?.image);
80
+ const userInitials = $derived(
81
+ user?.initials ||
82
+ user?.name?.split(' ').map(w => w[0]).join('').slice(0, 2).toUpperCase() ||
83
+ 'U'
84
+ );
85
+
86
+ // Handle escape key
87
+ function handleKeydown(event) {
88
+ if (event.key === 'Escape' && isOpen) {
89
+ close();
90
+ }
91
+ }
92
+
93
+ onMount(() => {
94
+ document.addEventListener('keydown', handleKeydown);
95
+ return () => document.removeEventListener('keydown', handleKeydown);
96
+ });
97
+ </script>
98
+
99
+ <div
100
+ class="workspace-menu {className}"
101
+ class:collapsed={isCollapsed}
102
+ class:in-sidebar={isInSidebar}
103
+ use:clickOutside={close}
104
+ >
105
+ <button
106
+ bind:this={triggerRef}
107
+ type="button"
108
+ class="workspace-trigger"
109
+ class:open={isOpen}
110
+ onclick={toggle}
111
+ aria-expanded={isOpen}
112
+ aria-haspopup="menu"
113
+ >
114
+ <!-- Workspace/Org Avatar -->
115
+ <div class="workspace-avatar">
116
+ {#if workspaceLogo}
117
+ <img src={workspaceLogo} alt={workspace?.name || 'Workspace'} />
118
+ {:else}
119
+ <span class="avatar-initials">{workspaceInitials}</span>
120
+ {/if}
121
+ </div>
122
+
123
+ {#if !isCollapsed}
124
+ <div class="workspace-info">
125
+ <div class="workspace-name">
126
+ {workspace?.name || 'Workspace'}
127
+ {#if badge}
128
+ <span class="workspace-badge badge-{badge.variant || 'default'}">
129
+ {badge.text}
130
+ </span>
131
+ {/if}
132
+ </div>
133
+ {#if user}
134
+ <div class="user-subtitle">
135
+ {user.email || user.name}
136
+ </div>
137
+ {/if}
138
+ </div>
139
+
140
+ {#if showChevron}
141
+ <svg
142
+ class="chevron"
143
+ class:open={isOpen}
144
+ xmlns="http://www.w3.org/2000/svg"
145
+ width="16"
146
+ height="16"
147
+ viewBox="0 0 24 24"
148
+ fill="none"
149
+ stroke="currentColor"
150
+ stroke-width="2"
151
+ stroke-linecap="round"
152
+ stroke-linejoin="round"
153
+ >
154
+ <path d="m6 9 6 6 6-6"></path>
155
+ </svg>
156
+ {/if}
157
+ {/if}
158
+ </button>
159
+
160
+ {#if isOpen && menu}
161
+ <div
162
+ bind:this={dropdownRef}
163
+ class="workspace-dropdown"
164
+ class:position-bottom-start={position === 'bottom-start'}
165
+ class:position-bottom-end={position === 'bottom-end'}
166
+ class:position-right-start={position === 'right-start'}
167
+ class:collapsed-position={isCollapsed}
168
+ role="menu"
169
+ >
170
+ <!-- User header in dropdown -->
171
+ {#if user}
172
+ <div class="dropdown-header">
173
+ <div class="user-avatar">
174
+ {#if userAvatar}
175
+ <img src={userAvatar} alt={user.name || 'User'} />
176
+ {:else}
177
+ <span class="avatar-initials">{userInitials}</span>
178
+ {/if}
179
+ </div>
180
+ <div class="user-info">
181
+ <div class="user-name">{user.name || 'User'}</div>
182
+ {#if user.email}
183
+ <div class="user-email">{user.email}</div>
184
+ {/if}
185
+ </div>
186
+ </div>
187
+ {/if}
188
+
189
+ <div class="dropdown-content">
190
+ {@render menu()}
191
+ </div>
192
+ </div>
193
+ {/if}
194
+ </div>
195
+
196
+ <style>
197
+ .workspace-menu {
198
+ position: relative;
199
+ width: 100%;
200
+ }
201
+
202
+ .workspace-trigger {
203
+ width: 100%;
204
+ display: flex;
205
+ align-items: center;
206
+ gap: 0.75rem;
207
+ padding: 0.75rem;
208
+ background: transparent;
209
+ border: none;
210
+ border-radius: 0.5rem;
211
+ cursor: pointer;
212
+ text-align: left;
213
+ transition: background-color 150ms ease;
214
+ font-family: inherit;
215
+ }
216
+
217
+ .workspace-trigger:hover {
218
+ background-color: var(--color-surface-alt, var(--color-base02, #3E4359));
219
+ }
220
+
221
+ .workspace-trigger.open {
222
+ background-color: var(--color-surface-alt, var(--color-base02, #3E4359));
223
+ }
224
+
225
+ .collapsed .workspace-trigger {
226
+ justify-content: center;
227
+ padding: 0.5rem;
228
+ }
229
+
230
+ /* Workspace Avatar */
231
+ .workspace-avatar {
232
+ width: 2.25rem;
233
+ height: 2.25rem;
234
+ border-radius: 0.5rem;
235
+ background: linear-gradient(135deg, var(--color-primary, #83D2FC), var(--color-info, #40FFE2));
236
+ display: flex;
237
+ align-items: center;
238
+ justify-content: center;
239
+ flex-shrink: 0;
240
+ overflow: hidden;
241
+ }
242
+
243
+ .workspace-avatar img {
244
+ width: 100%;
245
+ height: 100%;
246
+ object-fit: cover;
247
+ }
248
+
249
+ .avatar-initials {
250
+ font-size: 0.75rem;
251
+ font-weight: 600;
252
+ color: white;
253
+ text-transform: uppercase;
254
+ }
255
+
256
+ /* Workspace Info */
257
+ .workspace-info {
258
+ flex: 1;
259
+ min-width: 0;
260
+ overflow: hidden;
261
+ }
262
+
263
+ .workspace-name {
264
+ display: flex;
265
+ align-items: center;
266
+ gap: 0.5rem;
267
+ font-size: 0.875rem;
268
+ font-weight: 600;
269
+ color: var(--color-text-strong, var(--color-base07, #FAFDFB));
270
+ white-space: nowrap;
271
+ overflow: hidden;
272
+ text-overflow: ellipsis;
273
+ }
274
+
275
+ .workspace-badge {
276
+ padding: 0.125rem 0.375rem;
277
+ font-size: 0.625rem;
278
+ font-weight: 600;
279
+ border-radius: 0.25rem;
280
+ text-transform: uppercase;
281
+ letter-spacing: 0.025em;
282
+ }
283
+
284
+ .workspace-badge.badge-default {
285
+ background-color: var(--color-surface-alt, var(--color-base02, #3E4359));
286
+ color: var(--color-text-muted, var(--color-base05, #D0D2DB));
287
+ }
288
+
289
+ .workspace-badge.badge-primary {
290
+ background-color: color-mix(in srgb, var(--color-primary, #83D2FC) 20%, transparent);
291
+ color: var(--color-primary, #83D2FC);
292
+ }
293
+
294
+ .workspace-badge.badge-success {
295
+ background-color: color-mix(in srgb, var(--color-success, #6DD672) 20%, transparent);
296
+ color: var(--color-success, #6DD672);
297
+ }
298
+
299
+ .user-subtitle {
300
+ font-size: 0.75rem;
301
+ color: var(--color-text-muted, var(--color-base05, #D0D2DB));
302
+ white-space: nowrap;
303
+ overflow: hidden;
304
+ text-overflow: ellipsis;
305
+ }
306
+
307
+ /* Chevron */
308
+ .chevron {
309
+ flex-shrink: 0;
310
+ color: var(--color-text-muted, var(--color-base05, #D0D2DB));
311
+ transition: transform 200ms ease;
312
+ }
313
+
314
+ .chevron.open {
315
+ transform: rotate(180deg);
316
+ }
317
+
318
+ /* Dropdown */
319
+ .workspace-dropdown {
320
+ position: absolute;
321
+ z-index: 50;
322
+ min-width: 280px;
323
+ max-width: 320px;
324
+ background-color: var(--color-surface, var(--color-base01, #2C3040));
325
+ border: 1px solid var(--color-border, color-mix(in srgb, var(--color-base03, #565E78) 40%, transparent));
326
+ border-radius: 0.75rem;
327
+ box-shadow:
328
+ 0 20px 25px -5px rgba(0, 0, 0, 0.3),
329
+ 0 8px 10px -6px rgba(0, 0, 0, 0.2);
330
+ overflow: hidden;
331
+ animation: dropdown-appear 150ms ease-out;
332
+ }
333
+
334
+ @keyframes dropdown-appear {
335
+ from {
336
+ opacity: 0;
337
+ transform: translateY(-4px) scale(0.98);
338
+ }
339
+ to {
340
+ opacity: 1;
341
+ transform: translateY(0) scale(1);
342
+ }
343
+ }
344
+
345
+ .workspace-dropdown.position-bottom-start {
346
+ top: calc(100% + 0.5rem);
347
+ left: 0;
348
+ }
349
+
350
+ .workspace-dropdown.position-bottom-end {
351
+ top: calc(100% + 0.5rem);
352
+ right: 0;
353
+ }
354
+
355
+ .workspace-dropdown.position-right-start {
356
+ top: 0;
357
+ left: calc(100% + 0.5rem);
358
+ }
359
+
360
+ .workspace-dropdown.collapsed-position {
361
+ top: 0;
362
+ left: calc(100% + 0.5rem);
363
+ }
364
+
365
+ /* Dropdown Header */
366
+ .dropdown-header {
367
+ display: flex;
368
+ align-items: center;
369
+ gap: 0.75rem;
370
+ padding: 1rem;
371
+ border-bottom: 1px solid var(--color-border, color-mix(in srgb, var(--color-base03, #565E78) 30%, transparent));
372
+ background-color: color-mix(in srgb, var(--color-surface-alt, var(--color-base02, #3E4359)) 50%, transparent);
373
+ }
374
+
375
+ .user-avatar {
376
+ width: 2.5rem;
377
+ height: 2.5rem;
378
+ border-radius: 50%;
379
+ background: linear-gradient(135deg, var(--color-primary, #83D2FC), var(--color-info, #40FFE2));
380
+ display: flex;
381
+ align-items: center;
382
+ justify-content: center;
383
+ flex-shrink: 0;
384
+ overflow: hidden;
385
+ }
386
+
387
+ .user-avatar img {
388
+ width: 100%;
389
+ height: 100%;
390
+ object-fit: cover;
391
+ }
392
+
393
+ .user-info {
394
+ flex: 1;
395
+ min-width: 0;
396
+ }
397
+
398
+ .user-name {
399
+ font-size: 0.875rem;
400
+ font-weight: 600;
401
+ color: var(--color-text-strong, var(--color-base07, #FAFDFB));
402
+ }
403
+
404
+ .user-email {
405
+ font-size: 0.75rem;
406
+ color: var(--color-text-muted, var(--color-base05, #D0D2DB));
407
+ white-space: nowrap;
408
+ overflow: hidden;
409
+ text-overflow: ellipsis;
410
+ }
411
+
412
+ /* Dropdown Content */
413
+ .dropdown-content {
414
+ padding: 0.5rem;
415
+ }
416
+ </style>