@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
@@ -2,78 +2,37 @@
2
2
  @component Toast
3
3
 
4
4
  A toast notification system with stacking, auto-dismiss, and animations.
5
- Demonstrates advanced Svelte 5 patterns:
6
-
7
- - Reactive class with ThemeState pattern
8
- - $state.raw for non-proxied arrays (performance)
9
- - $effect with cleanup for timers
10
- - Context API for global toast access
11
- - Portal action for DOM placement
12
- - Compound variant styling
13
5
 
14
6
  @example
15
7
  // In your root layout
16
- <ToastProvider>
17
- <slot />
18
- </ToastProvider>
8
+ <script>
9
+ import { Toast, createToastContext } from '@miozu/jera';
10
+ const toast = createToastContext();
11
+ </script>
12
+ <Toast />
19
13
 
20
14
  // In any component
21
- import { toast } from '@miozu/jera';
15
+ import { getToastContext } from '@miozu/jera';
16
+ const toast = getToastContext();
22
17
  toast.success('Saved successfully!');
23
- toast.error('Something went wrong');
24
- toast.info('Did you know?');
25
- toast.custom({ title: 'Custom', message: 'With title', duration: 5000 });
26
18
  -->
27
19
  <script module>
28
20
  import { getContext, setContext } from 'svelte';
29
- import { cv } from '../../utils/cn.svelte.js';
30
21
 
31
22
  const TOAST_KEY = Symbol('jera-toast');
32
23
 
33
- /**
34
- * @typedef {'info' | 'success' | 'warning' | 'error'} ToastType
35
- * @typedef {'top-left' | 'top-center' | 'top-right' | 'bottom-left' | 'bottom-center' | 'bottom-right'} ToastPosition
36
- *
37
- * @typedef {{
38
- * id: string,
39
- * type: ToastType,
40
- * title?: string,
41
- * message: string,
42
- * duration: number,
43
- * createdAt: number,
44
- * pausedAt?: number
45
- * }} ToastItem
46
- */
47
-
48
24
  /**
49
25
  * Toast Controller Class
50
- *
51
- * Manages toast state and provides methods for showing toasts.
52
- * Uses Svelte 5 reactive class pattern.
53
26
  */
54
27
  export class ToastController {
55
- /** @type {ToastItem[]} */
56
28
  toasts = $state.raw([]);
57
-
58
- /** @type {ToastPosition} */
59
29
  position = $state('bottom-right');
60
-
61
- /** @type {number} */
62
30
  defaultDuration = 4000;
63
-
64
- /** @type {number} */
65
31
  maxToasts = 5;
66
-
67
32
  #counter = 0;
68
33
 
69
- /**
70
- * Show a toast
71
- * @param {Partial<ToastItem> & { message: string }} options
72
- * @returns {string} Toast ID
73
- */
74
34
  show(options) {
75
35
  const id = `toast-${++this.#counter}`;
76
-
77
36
  const toast = {
78
37
  id,
79
38
  type: options.type ?? 'info',
@@ -82,196 +41,99 @@
82
41
  duration: options.duration ?? this.defaultDuration,
83
42
  createdAt: Date.now()
84
43
  };
85
-
86
- // Add to beginning (newest first for top positions)
87
44
  this.toasts = [toast, ...this.toasts].slice(0, this.maxToasts);
88
-
89
45
  return id;
90
46
  }
91
47
 
92
- /**
93
- * Dismiss a toast by ID
94
- * @param {string} id
95
- */
96
48
  dismiss(id) {
97
49
  this.toasts = this.toasts.filter(t => t.id !== id);
98
50
  }
99
51
 
100
- /**
101
- * Dismiss all toasts
102
- */
103
52
  dismissAll() {
104
53
  this.toasts = [];
105
54
  }
106
55
 
107
- /**
108
- * Pause a toast's auto-dismiss timer
109
- * @param {string} id
110
- */
111
56
  pause(id) {
112
57
  this.toasts = this.toasts.map(t =>
113
58
  t.id === id ? { ...t, pausedAt: Date.now() } : t
114
59
  );
115
60
  }
116
61
 
117
- /**
118
- * Resume a toast's auto-dismiss timer
119
- * @param {string} id
120
- */
121
62
  resume(id) {
122
63
  this.toasts = this.toasts.map(t => {
123
64
  if (t.id !== id || !t.pausedAt) return t;
124
65
  const pausedDuration = Date.now() - t.pausedAt;
125
- return {
126
- ...t,
127
- createdAt: t.createdAt + pausedDuration,
128
- pausedAt: undefined
129
- };
66
+ return { ...t, createdAt: t.createdAt + pausedDuration, pausedAt: undefined };
130
67
  });
131
68
  }
132
69
 
133
- // Convenience methods
134
70
  info = (message, options = {}) => this.show({ ...options, message, type: 'info' });
135
71
  success = (message, options = {}) => this.show({ ...options, message, type: 'success' });
136
72
  warning = (message, options = {}) => this.show({ ...options, message, type: 'warning' });
137
73
  error = (message, options = {}) => this.show({ ...options, message, type: 'error' });
138
74
  }
139
75
 
140
- /**
141
- * Create toast context (call in ToastProvider)
142
- */
143
76
  export function createToastContext() {
144
77
  const controller = new ToastController();
145
78
  setContext(TOAST_KEY, controller);
146
79
  return controller;
147
80
  }
148
81
 
149
- /**
150
- * Get toast controller from context
151
- * @returns {ToastController}
152
- */
153
82
  export function getToastContext() {
154
83
  return getContext(TOAST_KEY);
155
84
  }
156
-
157
- // Toast styles
158
- export const toastStyles = cv({
159
- base: [
160
- 'relative flex items-start gap-3 w-full max-w-sm',
161
- 'p-4 rounded-lg shadow-lg',
162
- 'border',
163
- 'animate-in fade-in slide-in-from-right-4 duration-200'
164
- ].join(' '),
165
-
166
- variants: {
167
- type: {
168
- info: 'bg-surface border-border text-text',
169
- success: 'bg-success/10 border-success/30 text-success',
170
- warning: 'bg-warning/10 border-warning/30 text-warning',
171
- error: 'bg-error/10 border-error/30 text-error'
172
- }
173
- },
174
-
175
- defaults: { type: 'info' }
176
- });
177
-
178
- export const positionStyles = {
179
- 'top-left': 'top-4 left-4 flex-col',
180
- 'top-center': 'top-4 left-1/2 -translate-x-1/2 flex-col',
181
- 'top-right': 'top-4 right-4 flex-col',
182
- 'bottom-left': 'bottom-4 left-4 flex-col-reverse',
183
- 'bottom-center': 'bottom-4 left-1/2 -translate-x-1/2 flex-col-reverse',
184
- 'bottom-right': 'bottom-4 right-4 flex-col-reverse'
185
- };
186
85
  </script>
187
86
 
188
87
  <script>
189
88
  import { cn } from '../../utils/cn.svelte.js';
190
89
  import { portal } from '../../actions/index.js';
191
90
 
192
- // Get toast controller from context
193
91
  const toast = getToastContext();
194
92
 
195
- // Icon components for each type
196
93
  const icons = {
197
94
  info: `<circle cx="12" cy="12" r="10"/><path d="M12 16v-4"/><path d="M12 8h.01"/>`,
198
95
  success: `<circle cx="12" cy="12" r="10"/><path d="m9 12 2 2 4-4"/>`,
199
96
  warning: `<path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3Z"/><path d="M12 9v4"/><path d="M12 17h.01"/>`,
200
97
  error: `<circle cx="12" cy="12" r="10"/><path d="m15 9-6 6"/><path d="m9 9 6 6"/>`
201
98
  };
99
+
100
+ const positionClass = $derived({
101
+ 'top-left': 'toast-top-left',
102
+ 'top-center': 'toast-top-center',
103
+ 'top-right': 'toast-top-right',
104
+ 'bottom-left': 'toast-bottom-left',
105
+ 'bottom-center': 'toast-bottom-center',
106
+ 'bottom-right': 'toast-bottom-right'
107
+ }[toast.position]);
202
108
  </script>
203
109
 
204
110
  {#if toast.toasts.length > 0}
205
- <div
206
- use:portal
207
- class={cn(
208
- 'fixed z-[var(--z-toast)] flex gap-2 pointer-events-none',
209
- positionStyles[toast.position]
210
- )}
211
- role="region"
212
- aria-label="Notifications"
213
- >
111
+ <div use:portal class={cn('toast-container', positionClass)} role="region" aria-label="Notifications">
214
112
  {#each toast.toasts as item (item.id)}
215
113
  {@const remaining = item.duration - (Date.now() - item.createdAt)}
216
-
217
114
  <div
218
- class={cn(toastStyles({ type: item.type }), 'pointer-events-auto')}
115
+ class={cn('toast-item', `toast-${item.type}`)}
219
116
  role="alert"
220
117
  aria-live="polite"
221
118
  onmouseenter={() => toast.pause(item.id)}
222
119
  onmouseleave={() => toast.resume(item.id)}
223
120
  >
224
- <!-- Icon -->
225
- <span class="shrink-0 w-5 h-5">
226
- <svg
227
- viewBox="0 0 24 24"
228
- fill="none"
229
- stroke="currentColor"
230
- stroke-width="2"
231
- stroke-linecap="round"
232
- stroke-linejoin="round"
233
- >
121
+ <span class="toast-icon">
122
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
234
123
  {@html icons[item.type]}
235
124
  </svg>
236
125
  </span>
237
-
238
- <!-- Content -->
239
- <div class="flex-1 min-w-0">
126
+ <div class="toast-content">
240
127
  {#if item.title}
241
- <p class="font-medium text-sm">{item.title}</p>
128
+ <p class="toast-title">{item.title}</p>
242
129
  {/if}
243
- <p class={cn('text-sm', item.title && 'mt-1 opacity-90')}>
244
- {item.message}
245
- </p>
130
+ <p class={cn('toast-message', item.title && 'has-title')}>{item.message}</p>
246
131
  </div>
247
-
248
- <!-- Close Button -->
249
- <button
250
- type="button"
251
- class={cn(
252
- 'shrink-0 p-1 rounded-md',
253
- 'opacity-60 hover:opacity-100',
254
- 'transition-opacity duration-150',
255
- 'focus:outline-none focus-visible:ring-2 focus-visible:ring-current/50'
256
- )}
257
- onclick={() => toast.dismiss(item.id)}
258
- aria-label="Dismiss notification"
259
- >
260
- <svg
261
- class="w-4 h-4"
262
- viewBox="0 0 24 24"
263
- fill="none"
264
- stroke="currentColor"
265
- stroke-width="2"
266
- stroke-linecap="round"
267
- stroke-linejoin="round"
268
- >
269
- <path d="M18 6 6 18" />
270
- <path d="m6 6 12 12" />
132
+ <button type="button" class="toast-close" onclick={() => toast.dismiss(item.id)} aria-label="Dismiss">
133
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
134
+ <path d="M18 6 6 18" /><path d="m6 6 12 12" />
271
135
  </svg>
272
136
  </button>
273
-
274
- <!-- Auto-dismiss timer -->
275
137
  {#if item.duration > 0 && !item.pausedAt}
276
138
  {@const _ = setTimeout(() => toast.dismiss(item.id), remaining)}
277
139
  {/if}
@@ -281,17 +143,119 @@
281
143
  {/if}
282
144
 
283
145
  <style>
284
- @keyframes fade-in {
285
- from { opacity: 0; }
286
- to { opacity: 1; }
146
+ .toast-container {
147
+ position: fixed;
148
+ z-index: 9999;
149
+ display: flex;
150
+ gap: 0.5rem;
151
+ pointer-events: none;
287
152
  }
288
153
 
289
- @keyframes slide-in-from-right-4 {
290
- from { transform: translateX(1rem); }
291
- to { transform: translateX(0); }
154
+ .toast-top-left { top: 1rem; left: 1rem; flex-direction: column; }
155
+ .toast-top-center { top: 1rem; left: 50%; transform: translateX(-50%); flex-direction: column; }
156
+ .toast-top-right { top: 1rem; right: 1rem; flex-direction: column; }
157
+ .toast-bottom-left { bottom: 1rem; left: 1rem; flex-direction: column-reverse; }
158
+ .toast-bottom-center { bottom: 1rem; left: 50%; transform: translateX(-50%); flex-direction: column-reverse; }
159
+ .toast-bottom-right { bottom: 1rem; right: 1rem; flex-direction: column-reverse; }
160
+
161
+ .toast-item {
162
+ display: flex;
163
+ align-items: flex-start;
164
+ gap: 0.75rem;
165
+ width: 100%;
166
+ max-width: 24rem;
167
+ padding: 1rem;
168
+ border-radius: 0.5rem;
169
+ border: 1px solid;
170
+ box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.3);
171
+ pointer-events: auto;
172
+ animation: toast-in 200ms ease-out;
292
173
  }
293
174
 
294
- .animate-in {
295
- animation: fade-in 200ms ease-out, slide-in-from-right-4 200ms ease-out;
175
+ .toast-info {
176
+ background-color: var(--color-base01);
177
+ border-color: var(--color-base03);
178
+ color: var(--color-base05);
179
+ }
180
+
181
+ .toast-success {
182
+ background-color: color-mix(in srgb, var(--color-base0B) 10%, var(--color-base00));
183
+ border-color: color-mix(in srgb, var(--color-base0B) 30%, transparent);
184
+ color: var(--color-base0B);
185
+ }
186
+
187
+ .toast-warning {
188
+ background-color: color-mix(in srgb, var(--color-base0A) 10%, var(--color-base00));
189
+ border-color: color-mix(in srgb, var(--color-base0A) 30%, transparent);
190
+ color: var(--color-base0A);
191
+ }
192
+
193
+ .toast-error {
194
+ background-color: color-mix(in srgb, var(--color-base08) 10%, var(--color-base00));
195
+ border-color: color-mix(in srgb, var(--color-base08) 30%, transparent);
196
+ color: var(--color-base08);
197
+ }
198
+
199
+ .toast-icon {
200
+ flex-shrink: 0;
201
+ width: 1.25rem;
202
+ height: 1.25rem;
203
+ }
204
+
205
+ .toast-icon svg {
206
+ width: 100%;
207
+ height: 100%;
208
+ }
209
+
210
+ .toast-content {
211
+ flex: 1;
212
+ min-width: 0;
213
+ }
214
+
215
+ .toast-title {
216
+ font-weight: 500;
217
+ font-size: 0.875rem;
218
+ margin: 0;
219
+ }
220
+
221
+ .toast-message {
222
+ font-size: 0.875rem;
223
+ margin: 0;
224
+ }
225
+
226
+ .toast-message.has-title {
227
+ margin-top: 0.25rem;
228
+ opacity: 0.9;
229
+ }
230
+
231
+ .toast-close {
232
+ flex-shrink: 0;
233
+ padding: 0.25rem;
234
+ border-radius: 0.375rem;
235
+ background: transparent;
236
+ border: none;
237
+ cursor: pointer;
238
+ opacity: 0.6;
239
+ transition: opacity 150ms;
240
+ }
241
+
242
+ .toast-close:hover {
243
+ opacity: 1;
244
+ }
245
+
246
+ .toast-close svg {
247
+ width: 1rem;
248
+ height: 1rem;
249
+ }
250
+
251
+ @keyframes toast-in {
252
+ from {
253
+ opacity: 0;
254
+ transform: translateX(1rem);
255
+ }
256
+ to {
257
+ opacity: 1;
258
+ transform: translateX(0);
259
+ }
296
260
  }
297
261
  </style>
@@ -105,33 +105,33 @@
105
105
  justify-content: center;
106
106
  width: 18px;
107
107
  height: 18px;
108
- border: 2px solid var(--color-border);
108
+ border: 2px solid var(--color-base03);
109
109
  border-radius: var(--radius-default);
110
- background-color: var(--color-bg);
110
+ background-color: var(--color-base00);
111
111
  transition: var(--transition-all);
112
112
  }
113
113
 
114
114
  .checkbox-input:checked + .checkbox-box {
115
- background-color: var(--color-primary);
116
- border-color: var(--color-primary);
115
+ background-color: var(--color-base0D);
116
+ border-color: var(--color-base0D);
117
117
  }
118
118
 
119
119
  .checkbox-error {
120
- border-color: var(--color-error);
120
+ border-color: var(--color-base08);
121
121
  }
122
122
 
123
123
  .checkbox-input:checked + .checkbox-error {
124
- background-color: var(--color-error);
125
- border-color: var(--color-error);
124
+ background-color: var(--color-base08);
125
+ border-color: var(--color-base08);
126
126
  }
127
127
 
128
128
  .checkbox-input:focus-visible + .checkbox-box {
129
- outline: 2px solid var(--color-primary);
129
+ outline: 2px solid var(--color-base0D);
130
130
  outline-offset: 2px;
131
131
  }
132
132
 
133
133
  .checkbox-input:focus-visible + .checkbox-error {
134
- outline-color: var(--color-error);
134
+ outline-color: var(--color-base08);
135
135
  }
136
136
 
137
137
  .checkbox-icon {
@@ -142,6 +142,6 @@
142
142
 
143
143
  .checkbox-label {
144
144
  font-size: var(--text-sm);
145
- color: var(--color-text);
145
+ color: var(--color-base05);
146
146
  }
147
147
  </style>
@@ -151,21 +151,21 @@
151
151
  justify-content: center;
152
152
  min-height: 8rem;
153
153
  padding: var(--space-4);
154
- border: 2px dashed var(--color-border-muted);
154
+ border: 2px dashed var(--color-base02);
155
155
  border-radius: var(--radius-lg);
156
- background: var(--color-surface);
156
+ background: var(--color-base01);
157
157
  cursor: pointer;
158
158
  transition: border-color 0.2s ease, background 0.2s ease;
159
159
  }
160
160
 
161
161
  .dropzone:hover:not(.dropzone-disabled) {
162
- border-color: var(--color-primary);
163
- background: color-mix(in srgb, var(--color-primary) 5%, transparent);
162
+ border-color: var(--color-base0D);
163
+ background: color-mix(in srgb, var(--color-base0D) 5%, transparent);
164
164
  }
165
165
 
166
166
  .dropzone-dragging {
167
- border-color: var(--color-primary);
168
- background: color-mix(in srgb, var(--color-primary) 10%, transparent);
167
+ border-color: var(--color-base0D);
168
+ background: color-mix(in srgb, var(--color-base0D) 10%, transparent);
169
169
  }
170
170
 
171
171
  .dropzone-disabled {
@@ -176,7 +176,7 @@
176
176
  .dropzone-message {
177
177
  margin: 0;
178
178
  font-size: var(--text-sm);
179
- color: var(--color-text-muted);
179
+ color: var(--color-base04);
180
180
  text-align: center;
181
181
  pointer-events: none;
182
182
  }
@@ -200,8 +200,8 @@
200
200
  gap: var(--space-3);
201
201
  width: 100%;
202
202
  padding: var(--space-3);
203
- background: var(--color-bg);
204
- border: 1px solid var(--color-border-muted);
203
+ background: var(--color-base00);
204
+ border: 1px solid var(--color-base02);
205
205
  border-radius: var(--radius-md);
206
206
  }
207
207
 
@@ -214,7 +214,7 @@
214
214
  margin: 0;
215
215
  font-size: var(--text-sm);
216
216
  font-weight: 500;
217
- color: var(--color-text-strong);
217
+ color: var(--color-base07);
218
218
  white-space: nowrap;
219
219
  overflow: hidden;
220
220
  text-overflow: ellipsis;
@@ -223,7 +223,7 @@
223
223
  .dropzone-file-meta {
224
224
  margin: var(--space-1) 0 0 0;
225
225
  font-size: var(--text-xs);
226
- color: var(--color-text-muted);
226
+ color: var(--color-base04);
227
227
  }
228
228
 
229
229
  .dropzone-clear {
@@ -235,14 +235,14 @@
235
235
  background: transparent;
236
236
  border: none;
237
237
  border-radius: var(--radius-sm);
238
- color: var(--color-text-muted);
238
+ color: var(--color-base04);
239
239
  cursor: pointer;
240
240
  transition: background 0.15s ease, color 0.15s ease;
241
241
  z-index: 1;
242
242
  }
243
243
 
244
244
  .dropzone-clear:hover {
245
- background: var(--color-surface-hover);
246
- color: var(--color-text);
245
+ background: var(--color-base02);
246
+ color: var(--color-base05);
247
247
  }
248
248
  </style>
@@ -171,21 +171,21 @@
171
171
  gap: var(--space-2);
172
172
  width: 100%;
173
173
  padding: var(--space-6) var(--space-4);
174
- background: var(--color-bg);
175
- border: 2px dashed var(--color-border);
174
+ background: var(--color-base00);
175
+ border: 2px dashed var(--color-base03);
176
176
  border-radius: var(--radius-lg);
177
177
  cursor: pointer;
178
178
  transition: var(--transition-colors);
179
179
  }
180
180
 
181
181
  .upload-zone:hover:not(:disabled) {
182
- border-color: var(--color-primary);
183
- background: color-mix(in srgb, var(--color-primary) 5%, transparent);
182
+ border-color: var(--color-base0D);
183
+ background: color-mix(in srgb, var(--color-base0D) 5%, transparent);
184
184
  }
185
185
 
186
186
  .upload-zone-dragging {
187
- border-color: var(--color-primary);
188
- background: color-mix(in srgb, var(--color-primary) 10%, transparent);
187
+ border-color: var(--color-base0D);
188
+ background: color-mix(in srgb, var(--color-base0D) 10%, transparent);
189
189
  }
190
190
 
191
191
  .upload-zone-disabled {
@@ -194,18 +194,18 @@
194
194
  }
195
195
 
196
196
  .upload-icon {
197
- color: var(--color-text-muted);
197
+ color: var(--color-base04);
198
198
  }
199
199
 
200
200
  .upload-label {
201
201
  font-size: var(--text-sm);
202
202
  font-weight: 500;
203
- color: var(--color-text);
203
+ color: var(--color-base05);
204
204
  }
205
205
 
206
206
  .upload-hint {
207
207
  font-size: var(--text-xs);
208
- color: var(--color-text-muted);
208
+ color: var(--color-base04);
209
209
  }
210
210
 
211
211
  .upload-input {
@@ -226,15 +226,15 @@
226
226
  align-items: center;
227
227
  gap: var(--space-2);
228
228
  padding: var(--space-2) var(--space-3);
229
- background: var(--color-surface);
230
- border: 1px solid var(--color-border-muted);
229
+ background: var(--color-base01);
230
+ border: 1px solid var(--color-base02);
231
231
  border-radius: var(--radius-md);
232
232
  }
233
233
 
234
234
  .file-name {
235
235
  flex: 1;
236
236
  font-size: var(--text-sm);
237
- color: var(--color-text);
237
+ color: var(--color-base05);
238
238
  overflow: hidden;
239
239
  text-overflow: ellipsis;
240
240
  white-space: nowrap;
@@ -242,7 +242,7 @@
242
242
 
243
243
  .file-size {
244
244
  font-size: var(--text-xs);
245
- color: var(--color-text-muted);
245
+ color: var(--color-base04);
246
246
  white-space: nowrap;
247
247
  }
248
248
 
@@ -254,13 +254,13 @@
254
254
  background: transparent;
255
255
  border: none;
256
256
  border-radius: var(--radius-sm);
257
- color: var(--color-text-muted);
257
+ color: var(--color-base04);
258
258
  cursor: pointer;
259
259
  transition: var(--transition-colors);
260
260
  }
261
261
 
262
262
  .file-remove:hover {
263
- color: var(--color-error);
264
- background: color-mix(in srgb, var(--color-error) 10%, transparent);
263
+ color: var(--color-base08);
264
+ background: color-mix(in srgb, var(--color-base08) 10%, transparent);
265
265
  }
266
266
  </style>
@@ -124,7 +124,7 @@
124
124
  display: flex;
125
125
  align-items: center;
126
126
  justify-content: center;
127
- color: var(--color-text-muted);
127
+ color: var(--color-base04);
128
128
  pointer-events: none;
129
129
  }
130
130
 
@@ -172,13 +172,13 @@
172
172
  background: transparent;
173
173
  border: none;
174
174
  border-radius: var(--radius-sm);
175
- color: var(--color-text-muted);
175
+ color: var(--color-base04);
176
176
  cursor: pointer;
177
177
  transition: var(--transition-colors);
178
178
  }
179
179
 
180
180
  .icon-clear:hover {
181
- color: var(--color-text);
182
- background: var(--color-surface-hover);
181
+ color: var(--color-base05);
182
+ background: var(--color-base02);
183
183
  }
184
184
  </style>