@miozu/jera 0.0.2 → 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 (82) hide show
  1. package/CLAUDE.md +734 -0
  2. package/README.md +219 -1
  3. package/llms.txt +97 -0
  4. package/package.json +54 -14
  5. package/src/actions/index.js +375 -0
  6. package/src/components/docs/CodeBlock.svelte +203 -0
  7. package/src/components/docs/DocSection.svelte +120 -0
  8. package/src/components/docs/PropsTable.svelte +136 -0
  9. package/src/components/docs/SplitPane.svelte +98 -0
  10. package/src/components/docs/index.js +14 -0
  11. package/src/components/feedback/Alert.svelte +234 -0
  12. package/src/components/feedback/EmptyState.svelte +179 -0
  13. package/src/components/feedback/ProgressBar.svelte +116 -0
  14. package/src/components/feedback/Skeleton.svelte +107 -0
  15. package/src/components/feedback/Spinner.svelte +77 -0
  16. package/src/components/feedback/Toast.svelte +261 -0
  17. package/src/components/forms/Checkbox.svelte +147 -0
  18. package/src/components/forms/Dropzone.svelte +248 -0
  19. package/src/components/forms/FileUpload.svelte +266 -0
  20. package/src/components/forms/IconInput.svelte +184 -0
  21. package/src/components/forms/Input.svelte +121 -0
  22. package/src/components/forms/NumberInput.svelte +225 -0
  23. package/src/components/forms/PinInput.svelte +169 -0
  24. package/src/components/forms/Radio.svelte +143 -0
  25. package/src/components/forms/RadioGroup.svelte +62 -0
  26. package/src/components/forms/RangeSlider.svelte +212 -0
  27. package/src/components/forms/SearchInput.svelte +175 -0
  28. package/src/components/forms/Select.svelte +324 -0
  29. package/src/components/forms/Switch.svelte +159 -0
  30. package/src/components/forms/Textarea.svelte +122 -0
  31. package/src/components/navigation/Accordion.svelte +65 -0
  32. package/src/components/navigation/AccordionItem.svelte +146 -0
  33. package/src/components/navigation/NavigationContainer.svelte +344 -0
  34. package/src/components/navigation/Sidebar.svelte +334 -0
  35. package/src/components/navigation/SidebarAccountGroup.svelte +495 -0
  36. package/src/components/navigation/SidebarAccountItem.svelte +492 -0
  37. package/src/components/navigation/SidebarGroup.svelte +230 -0
  38. package/src/components/navigation/SidebarGroupSwitcher.svelte +262 -0
  39. package/src/components/navigation/SidebarItem.svelte +210 -0
  40. package/src/components/navigation/SidebarNavigationItem.svelte +470 -0
  41. package/src/components/navigation/SidebarPopover.svelte +145 -0
  42. package/src/components/navigation/SidebarSearch.svelte +236 -0
  43. package/src/components/navigation/SidebarSection.svelte +158 -0
  44. package/src/components/navigation/SidebarToggle.svelte +86 -0
  45. package/src/components/navigation/Tabs.svelte +239 -0
  46. package/src/components/navigation/WorkspaceMenu.svelte +416 -0
  47. package/src/components/navigation/blocks/NavigationAccountGroup.svelte +396 -0
  48. package/src/components/navigation/blocks/NavigationCustomBlock.svelte +74 -0
  49. package/src/components/navigation/blocks/NavigationGroupSwitcher.svelte +277 -0
  50. package/src/components/navigation/blocks/NavigationSearch.svelte +300 -0
  51. package/src/components/navigation/blocks/NavigationSection.svelte +230 -0
  52. package/src/components/navigation/index.js +22 -0
  53. package/src/components/overlays/ConfirmDialog.svelte +272 -0
  54. package/src/components/overlays/Dropdown.svelte +153 -0
  55. package/src/components/overlays/DropdownDivider.svelte +23 -0
  56. package/src/components/overlays/DropdownItem.svelte +97 -0
  57. package/src/components/overlays/Modal.svelte +232 -0
  58. package/src/components/overlays/Popover.svelte +206 -0
  59. package/src/components/primitives/Avatar.svelte +132 -0
  60. package/src/components/primitives/Badge.svelte +118 -0
  61. package/src/components/primitives/Button.svelte +214 -0
  62. package/src/components/primitives/Card.svelte +104 -0
  63. package/src/components/primitives/Divider.svelte +105 -0
  64. package/src/components/primitives/LazyImage.svelte +104 -0
  65. package/src/components/primitives/Link.svelte +122 -0
  66. package/src/components/primitives/Stat.svelte +197 -0
  67. package/src/components/primitives/StatusBadge.svelte +122 -0
  68. package/src/index.js +183 -0
  69. package/src/tokens/colors.css +157 -0
  70. package/src/tokens/effects.css +128 -0
  71. package/src/tokens/index.css +81 -0
  72. package/src/tokens/spacing.css +49 -0
  73. package/src/tokens/typography.css +79 -0
  74. package/src/utils/cn.svelte.js +175 -0
  75. package/src/utils/highlighter.js +124 -0
  76. package/src/utils/index.js +22 -0
  77. package/src/utils/navigation.svelte.js +423 -0
  78. package/src/utils/reactive.svelte.js +328 -0
  79. package/src/utils/sidebar.svelte.js +211 -0
  80. package/jera.js +0 -135
  81. package/www/components/jera/Input/Input.svelte +0 -63
  82. package/www/components/jera/Input/index.js +0 -1
@@ -0,0 +1,136 @@
1
+ <!--
2
+ @component PropsTable
3
+
4
+ Display component/function props in a clean, readable table.
5
+ Commonly used for API documentation.
6
+
7
+ @example
8
+ ```svelte
9
+ <PropsTable props={[
10
+ { name: 'variant', type: 'string', default: '"default"', description: 'Visual style' },
11
+ { name: 'disabled', type: 'boolean', default: 'false', description: 'Disable interactions' },
12
+ { name: 'onclick', type: 'function', required: true, description: 'Click handler' }
13
+ ]} />
14
+ ```
15
+ -->
16
+ <script>
17
+ /**
18
+ * @typedef {Object} PropDef
19
+ * @property {string} name - Property name
20
+ * @property {string} type - Type annotation
21
+ * @property {string} [default] - Default value
22
+ * @property {string} description - Description
23
+ * @property {boolean} [required] - Whether prop is required
24
+ */
25
+
26
+ /** @type {{ props: PropDef[], class?: string }} */
27
+ let {
28
+ props = [],
29
+ class: className = ''
30
+ } = $props();
31
+ </script>
32
+
33
+ <div class="jera-props-table {className}">
34
+ <table>
35
+ <thead>
36
+ <tr>
37
+ <th>Prop</th>
38
+ <th>Type</th>
39
+ <th>Default</th>
40
+ <th>Description</th>
41
+ </tr>
42
+ </thead>
43
+ <tbody>
44
+ {#each props as prop}
45
+ <tr>
46
+ <td class="prop-name">
47
+ <code>{prop.name}</code>
48
+ {#if prop.required}
49
+ <span class="required" title="Required">*</span>
50
+ {/if}
51
+ </td>
52
+ <td class="prop-type">
53
+ <code>{prop.type}</code>
54
+ </td>
55
+ <td class="prop-default">
56
+ {#if prop.default !== undefined}
57
+ <code>{prop.default}</code>
58
+ {:else}
59
+ <span class="muted">-</span>
60
+ {/if}
61
+ </td>
62
+ <td class="prop-desc">{prop.description}</td>
63
+ </tr>
64
+ {/each}
65
+ </tbody>
66
+ </table>
67
+ </div>
68
+
69
+ <style>
70
+ .jera-props-table {
71
+ overflow-x: auto;
72
+ border: 1px solid var(--color-border, var(--base2, #2d3748));
73
+ border-radius: var(--radius-md, 0.5rem);
74
+ }
75
+
76
+ table {
77
+ width: 100%;
78
+ border-collapse: collapse;
79
+ font-size: 0.875rem;
80
+ }
81
+
82
+ th {
83
+ text-align: left;
84
+ padding: 0.75rem 1rem;
85
+ background: var(--color-base1, var(--base1, #1a1f26));
86
+ border-bottom: 1px solid var(--color-border, var(--base2, #2d3748));
87
+ font-weight: 500;
88
+ color: var(--color-base5, var(--base5, #e2e8f0));
89
+ white-space: nowrap;
90
+ }
91
+
92
+ td {
93
+ padding: 0.75rem 1rem;
94
+ border-bottom: 1px solid var(--color-border, var(--base2, #2d3748));
95
+ vertical-align: top;
96
+ }
97
+
98
+ tr:last-child td {
99
+ border-bottom: none;
100
+ }
101
+
102
+ .prop-name code {
103
+ font-family: var(--font-mono, monospace);
104
+ font-weight: 500;
105
+ color: var(--color-primary, var(--magenta, #c974e6));
106
+ }
107
+
108
+ .required {
109
+ color: var(--color-error, var(--red, #eb3137));
110
+ margin-left: 0.25rem;
111
+ }
112
+
113
+ .prop-type code {
114
+ font-family: var(--font-mono, monospace);
115
+ font-size: 0.8125rem;
116
+ color: var(--color-base4, var(--base4, #a0aec0));
117
+ background: var(--color-base1, var(--base1, #1a1f26));
118
+ padding: 0.125rem 0.375rem;
119
+ border-radius: 0.25rem;
120
+ }
121
+
122
+ .prop-default code {
123
+ font-family: var(--font-mono, monospace);
124
+ font-size: 0.8125rem;
125
+ color: var(--color-success, var(--green, #6dd672));
126
+ }
127
+
128
+ .muted {
129
+ color: var(--color-base3, var(--base3, #4a5568));
130
+ }
131
+
132
+ .prop-desc {
133
+ color: var(--color-base4, var(--base4, #a0aec0));
134
+ line-height: 1.5;
135
+ }
136
+ </style>
@@ -0,0 +1,98 @@
1
+ <!--
2
+ @component SplitPane
3
+
4
+ Two-pane layout component for documentation with description on the left
5
+ and code/examples on the right. Responsive - stacks vertically on mobile.
6
+
7
+ @example
8
+ ```svelte
9
+ <SplitPane>
10
+ {#snippet left()}
11
+ <h2>Function Description</h2>
12
+ <p>This function does something amazing...</p>
13
+ {/snippet}
14
+ {#snippet right()}
15
+ <CodeBlock code={exampleCode} lang="javascript" />
16
+ {/snippet}
17
+ </SplitPane>
18
+ ```
19
+ -->
20
+ <script>
21
+ let {
22
+ /** Left pane content (description, prose) */
23
+ left,
24
+ /** Right pane content (code, examples) */
25
+ right,
26
+ /** Ratio of left:right pane widths (e.g., '1:1', '2:1', '3:2') */
27
+ ratio = '1:1',
28
+ /** Gap between panes */
29
+ gap = '2rem',
30
+ /** Minimum height */
31
+ minHeight = 'auto',
32
+ /** Whether both panes should independently scroll */
33
+ stickyRight = false,
34
+ /** Additional CSS classes */
35
+ class: className = ''
36
+ } = $props();
37
+
38
+ // Parse ratio into flex values
39
+ const [leftFlex, rightFlex] = $derived.by(() => {
40
+ const parts = ratio.split(':').map(Number);
41
+ return [parts[0] || 1, parts[1] || 1];
42
+ });
43
+ </script>
44
+
45
+ <div
46
+ class="jera-split-pane {className}"
47
+ class:sticky-right={stickyRight}
48
+ style:--gap={gap}
49
+ style:--left-flex={leftFlex}
50
+ style:--right-flex={rightFlex}
51
+ style:--min-height={minHeight}
52
+ >
53
+ <div class="pane pane-left">
54
+ {@render left?.()}
55
+ </div>
56
+ <div class="pane pane-right">
57
+ {@render right?.()}
58
+ </div>
59
+ </div>
60
+
61
+ <style>
62
+ .jera-split-pane {
63
+ display: flex;
64
+ flex-direction: column;
65
+ gap: var(--gap);
66
+ min-height: var(--min-height);
67
+ width: 100%;
68
+ }
69
+
70
+ @media (min-width: 1024px) {
71
+ .jera-split-pane {
72
+ flex-direction: row;
73
+ }
74
+ }
75
+
76
+ .pane {
77
+ min-width: 0;
78
+ }
79
+
80
+ .pane-left {
81
+ flex: var(--left-flex);
82
+ }
83
+
84
+ .pane-right {
85
+ flex: var(--right-flex);
86
+ }
87
+
88
+ /* Sticky right pane for scrollable docs */
89
+ @media (min-width: 1024px) {
90
+ .sticky-right .pane-right {
91
+ position: sticky;
92
+ top: 1rem;
93
+ align-self: flex-start;
94
+ max-height: calc(100vh - 2rem);
95
+ overflow-y: auto;
96
+ }
97
+ }
98
+ </style>
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Documentation components for @miozu/jera
3
+ *
4
+ * Components for building documentation sites with syntax highlighting,
5
+ * split-pane layouts, and structured content sections.
6
+ *
7
+ * @example
8
+ * import { CodeBlock, PropsTable, SplitPane, DocSection } from '@miozu/jera';
9
+ */
10
+
11
+ export { default as CodeBlock } from './CodeBlock.svelte';
12
+ export { default as PropsTable } from './PropsTable.svelte';
13
+ export { default as SplitPane } from './SplitPane.svelte';
14
+ export { default as DocSection } from './DocSection.svelte';
@@ -0,0 +1,234 @@
1
+ <!--
2
+ @component Alert
3
+
4
+ An inline alert/notice banner for displaying messages.
5
+ Different from Toast (which is transient) - Alert stays visible in the layout.
6
+
7
+ @example Basic
8
+ <Alert variant="info">This is an informational message.</Alert>
9
+
10
+ @example With title
11
+ <Alert variant="warning" title="Warning">
12
+ Please review your settings before continuing.
13
+ </Alert>
14
+
15
+ @example Dismissible
16
+ <Alert variant="error" dismissible onclose={() => showAlert = false}>
17
+ An error occurred while processing your request.
18
+ </Alert>
19
+
20
+ @example With icon snippet
21
+ <Alert variant="success">
22
+ {#snippet icon()}
23
+ <CheckIcon size={16} />
24
+ {/snippet}
25
+ Your changes have been saved successfully.
26
+ </Alert>
27
+
28
+ @example With actions
29
+ <Alert variant="info" title="New version available">
30
+ A new version is available for download.
31
+ {#snippet actions()}
32
+ <Button size="sm" variant="primary">Update Now</Button>
33
+ <Button size="sm" variant="ghost">Later</Button>
34
+ {/snippet}
35
+ </Alert>
36
+ -->
37
+ <script>
38
+ let {
39
+ variant = 'info',
40
+ title = '',
41
+ dismissible = false,
42
+ size = 'md',
43
+ class: className = '',
44
+ onclose,
45
+ icon,
46
+ actions,
47
+ children
48
+ } = $props();
49
+
50
+ let visible = $state(true);
51
+
52
+ function handleClose() {
53
+ visible = false;
54
+ onclose?.();
55
+ }
56
+ </script>
57
+
58
+ {#if visible}
59
+ <div
60
+ class="alert alert-{variant} alert-{size} {className}"
61
+ role="alert"
62
+ >
63
+ {#if icon}
64
+ <div class="alert-icon">
65
+ {@render icon()}
66
+ </div>
67
+ {:else}
68
+ <div class="alert-icon alert-icon-default">
69
+ {#if variant === 'success'}
70
+ <svg viewBox="0 0 16 16" fill="currentColor"><path d="M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14zm0-1.5a5.5 5.5 0 1 0 0-11 5.5 5.5 0 0 0 0 11zm2.354-7.354a.5.5 0 0 1 0 .708l-3 3a.5.5 0 0 1-.708 0l-1.5-1.5a.5.5 0 1 1 .708-.708L7 8.793l2.646-2.647a.5.5 0 0 1 .708 0z"/></svg>
71
+ {:else if variant === 'error'}
72
+ <svg viewBox="0 0 16 16" fill="currentColor"><path d="M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14zm0-1.5a5.5 5.5 0 1 0 0-11 5.5 5.5 0 0 0 0 11zM7.25 5v3.5a.75.75 0 0 0 1.5 0V5a.75.75 0 0 0-1.5 0zm.75 6a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5z"/></svg>
73
+ {:else if variant === 'warning'}
74
+ <svg viewBox="0 0 16 16" fill="currentColor"><path d="M8 1.5a.75.75 0 0 1 .65.38l6.25 10.75a.75.75 0 0 1-.65 1.12H1.75a.75.75 0 0 1-.65-1.12L7.35 1.88A.75.75 0 0 1 8 1.5zm0 1.73L2.57 12.25h10.86L8 3.23zM7.25 6v2.5a.75.75 0 0 0 1.5 0V6a.75.75 0 0 0-1.5 0zm.75 5a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5z"/></svg>
75
+ {:else}
76
+ <svg viewBox="0 0 16 16" fill="currentColor"><path d="M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14zm0-1.5a5.5 5.5 0 1 0 0-11 5.5 5.5 0 0 0 0 11zM7.25 5a.75.75 0 0 1 1.5 0v3.5a.75.75 0 0 1-1.5 0V5zm.75 6a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5z"/></svg>
77
+ {/if}
78
+ </div>
79
+ {/if}
80
+
81
+ <div class="alert-content">
82
+ {#if title}
83
+ <div class="alert-title">{title}</div>
84
+ {/if}
85
+ <div class="alert-message">
86
+ {@render children?.()}
87
+ </div>
88
+ {#if actions}
89
+ <div class="alert-actions">
90
+ {@render actions()}
91
+ </div>
92
+ {/if}
93
+ </div>
94
+
95
+ {#if dismissible}
96
+ <button
97
+ type="button"
98
+ class="alert-close"
99
+ onclick={handleClose}
100
+ aria-label="Dismiss"
101
+ >
102
+ <svg viewBox="0 0 16 16" fill="currentColor"><path d="M4.28 3.22a.75.75 0 0 0-1.06 1.06L6.94 8l-3.72 3.72a.75.75 0 1 0 1.06 1.06L8 9.06l3.72 3.72a.75.75 0 1 0 1.06-1.06L9.06 8l3.72-3.72a.75.75 0 0 0-1.06-1.06L8 6.94 4.28 3.22z"/></svg>
103
+ </button>
104
+ {/if}
105
+ </div>
106
+ {/if}
107
+
108
+ <style>
109
+ .alert {
110
+ display: flex;
111
+ align-items: flex-start;
112
+ gap: var(--space-3);
113
+ border-radius: var(--radius-lg);
114
+ border: 1px solid;
115
+ }
116
+
117
+ /* Size variants */
118
+ .alert-sm {
119
+ padding: var(--space-2) var(--space-3);
120
+ }
121
+
122
+ .alert-md {
123
+ padding: var(--space-3) var(--space-4);
124
+ }
125
+
126
+ .alert-lg {
127
+ padding: var(--space-4) var(--space-5);
128
+ }
129
+
130
+ /* Variant colors */
131
+ .alert-info {
132
+ background: color-mix(in srgb, var(--color-base0D) 8%, transparent);
133
+ border-color: color-mix(in srgb, var(--color-base0D) 25%, transparent);
134
+ color: var(--color-base0D);
135
+ }
136
+
137
+ .alert-success {
138
+ background: color-mix(in srgb, var(--color-base0B) 8%, transparent);
139
+ border-color: color-mix(in srgb, var(--color-base0B) 25%, transparent);
140
+ color: var(--color-base0B);
141
+ }
142
+
143
+ .alert-warning {
144
+ background: color-mix(in srgb, var(--color-base0A) 8%, transparent);
145
+ border-color: color-mix(in srgb, var(--color-base0A) 25%, transparent);
146
+ color: var(--color-base0A);
147
+ }
148
+
149
+ .alert-error {
150
+ background: color-mix(in srgb, var(--color-base08) 8%, transparent);
151
+ border-color: color-mix(in srgb, var(--color-base08) 25%, transparent);
152
+ color: var(--color-base08);
153
+ }
154
+
155
+ /* Icon */
156
+ .alert-icon {
157
+ flex-shrink: 0;
158
+ display: flex;
159
+ align-items: center;
160
+ justify-content: center;
161
+ }
162
+
163
+ .alert-icon-default svg {
164
+ width: 16px;
165
+ height: 16px;
166
+ }
167
+
168
+ .alert-lg .alert-icon-default svg {
169
+ width: 20px;
170
+ height: 20px;
171
+ }
172
+
173
+ /* Content */
174
+ .alert-content {
175
+ flex: 1;
176
+ min-width: 0;
177
+ }
178
+
179
+ .alert-title {
180
+ font-weight: 600;
181
+ font-size: var(--text-sm);
182
+ margin-bottom: var(--space-1);
183
+ }
184
+
185
+ .alert-info .alert-title { color: var(--color-base0D); }
186
+ .alert-success .alert-title { color: var(--color-base0B); }
187
+ .alert-warning .alert-title { color: var(--color-base0A); }
188
+ .alert-error .alert-title { color: var(--color-base08); }
189
+
190
+ .alert-message {
191
+ font-size: var(--text-sm);
192
+ color: var(--color-base05);
193
+ line-height: 1.5;
194
+ }
195
+
196
+ .alert-lg .alert-message {
197
+ font-size: var(--text-base);
198
+ }
199
+
200
+ .alert-actions {
201
+ display: flex;
202
+ gap: var(--space-2);
203
+ margin-top: var(--space-3);
204
+ }
205
+
206
+ /* Close button */
207
+ .alert-close {
208
+ flex-shrink: 0;
209
+ display: flex;
210
+ align-items: center;
211
+ justify-content: center;
212
+ width: 24px;
213
+ height: 24px;
214
+ padding: 0;
215
+ margin: calc(var(--space-1) * -1);
216
+ border: none;
217
+ border-radius: var(--radius-md);
218
+ background: transparent;
219
+ color: currentColor;
220
+ opacity: 0.6;
221
+ cursor: pointer;
222
+ transition: opacity 0.2s ease, background 0.2s ease;
223
+ }
224
+
225
+ .alert-close:hover {
226
+ opacity: 1;
227
+ background: color-mix(in srgb, currentColor 10%, transparent);
228
+ }
229
+
230
+ .alert-close svg {
231
+ width: 14px;
232
+ height: 14px;
233
+ }
234
+ </style>
@@ -0,0 +1,179 @@
1
+ <!--
2
+ @component EmptyState
3
+
4
+ A complete empty state UI with icon, title, description, and action buttons.
5
+
6
+ @example Basic
7
+ <EmptyState
8
+ title="No items found"
9
+ description="Try adjusting your search or filters"
10
+ />
11
+
12
+ @example With icon and action
13
+ <EmptyState
14
+ title="No messages"
15
+ description="Start a conversation to see messages here"
16
+ >
17
+ {#snippet icon()}
18
+ <MessageIcon size={32} />
19
+ {/snippet}
20
+ {#snippet actions()}
21
+ <Button variant="primary" onclick={startChat}>New Message</Button>
22
+ {/snippet}
23
+ </EmptyState>
24
+
25
+ @example Compact size
26
+ <EmptyState size="compact" title="No results" />
27
+ -->
28
+ <script>
29
+ let {
30
+ title = 'No data found',
31
+ description = '',
32
+ size = 'default',
33
+ class: className = '',
34
+ icon,
35
+ actions
36
+ } = $props();
37
+ </script>
38
+
39
+ <div class="empty-state empty-state-{size} {className}">
40
+ <div class="empty-state-content">
41
+ {#if icon}
42
+ <div class="empty-state-icon">
43
+ {@render icon()}
44
+ </div>
45
+ {/if}
46
+
47
+ <div class="empty-state-text">
48
+ <h3 class="empty-state-title">{title}</h3>
49
+ {#if description}
50
+ <p class="empty-state-description">{description}</p>
51
+ {/if}
52
+ </div>
53
+
54
+ {#if actions}
55
+ <div class="empty-state-actions">
56
+ {@render actions()}
57
+ </div>
58
+ {/if}
59
+ </div>
60
+ </div>
61
+
62
+ <style>
63
+ .empty-state {
64
+ display: flex;
65
+ align-items: center;
66
+ justify-content: center;
67
+ width: 100%;
68
+ padding: var(--space-16) var(--space-6);
69
+ }
70
+
71
+ .empty-state-compact {
72
+ padding: var(--space-8) var(--space-4);
73
+ }
74
+
75
+ .empty-state-large {
76
+ padding: var(--space-24) var(--space-6);
77
+ }
78
+
79
+ .empty-state-content {
80
+ display: flex;
81
+ flex-direction: column;
82
+ align-items: center;
83
+ text-align: center;
84
+ max-width: 24rem;
85
+ }
86
+
87
+ .empty-state-icon {
88
+ display: flex;
89
+ align-items: center;
90
+ justify-content: center;
91
+ width: 4rem;
92
+ height: 4rem;
93
+ margin-bottom: var(--space-6);
94
+ border-radius: 9999px;
95
+ background: var(--color-base01);
96
+ color: var(--color-base04);
97
+ transition: background 0.3s ease, color 0.3s ease, transform 0.3s ease;
98
+ }
99
+
100
+ .empty-state-compact .empty-state-icon {
101
+ width: 3rem;
102
+ height: 3rem;
103
+ margin-bottom: var(--space-4);
104
+ }
105
+
106
+ .empty-state-large .empty-state-icon {
107
+ width: 5rem;
108
+ height: 5rem;
109
+ margin-bottom: var(--space-8);
110
+ }
111
+
112
+ .empty-state:hover .empty-state-icon {
113
+ background: var(--color-base02);
114
+ color: var(--color-base05);
115
+ transform: scale(1.05);
116
+ }
117
+
118
+ .empty-state-text {
119
+ margin-bottom: var(--space-6);
120
+ }
121
+
122
+ .empty-state-compact .empty-state-text {
123
+ margin-bottom: var(--space-4);
124
+ }
125
+
126
+ .empty-state-large .empty-state-text {
127
+ margin-bottom: var(--space-8);
128
+ }
129
+
130
+ .empty-state-title {
131
+ margin: 0 0 var(--space-2) 0;
132
+ font-size: var(--text-lg);
133
+ font-weight: 600;
134
+ color: var(--color-base07);
135
+ line-height: 1.3;
136
+ }
137
+
138
+ .empty-state-compact .empty-state-title {
139
+ font-size: var(--text-base);
140
+ font-weight: 500;
141
+ }
142
+
143
+ .empty-state-large .empty-state-title {
144
+ font-size: var(--text-xl);
145
+ }
146
+
147
+ .empty-state-description {
148
+ margin: 0;
149
+ font-size: var(--text-sm);
150
+ color: var(--color-base04);
151
+ line-height: 1.5;
152
+ max-width: 20rem;
153
+ }
154
+
155
+ .empty-state-compact .empty-state-description {
156
+ font-size: var(--text-xs);
157
+ }
158
+
159
+ .empty-state-large .empty-state-description {
160
+ font-size: var(--text-base);
161
+ max-width: 24rem;
162
+ }
163
+
164
+ .empty-state-actions {
165
+ display: flex;
166
+ align-items: center;
167
+ gap: var(--space-3);
168
+ flex-wrap: wrap;
169
+ justify-content: center;
170
+ }
171
+
172
+ .empty-state-compact .empty-state-actions {
173
+ gap: var(--space-2);
174
+ }
175
+
176
+ .empty-state-large .empty-state-actions {
177
+ gap: var(--space-4);
178
+ }
179
+ </style>