@miozu/jera 0.0.2 → 0.3.0
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/CLAUDE.md +443 -0
- package/README.md +211 -1
- package/llms.txt +64 -0
- package/package.json +44 -14
- package/src/actions/index.js +375 -0
- package/src/components/feedback/EmptyState.svelte +179 -0
- package/src/components/feedback/ProgressBar.svelte +116 -0
- package/src/components/feedback/Skeleton.svelte +107 -0
- package/src/components/feedback/Spinner.svelte +77 -0
- package/src/components/feedback/Toast.svelte +297 -0
- package/src/components/forms/Checkbox.svelte +147 -0
- package/src/components/forms/Dropzone.svelte +248 -0
- package/src/components/forms/FileUpload.svelte +266 -0
- package/src/components/forms/IconInput.svelte +184 -0
- package/src/components/forms/Input.svelte +121 -0
- package/src/components/forms/NumberInput.svelte +225 -0
- package/src/components/forms/PinInput.svelte +169 -0
- package/src/components/forms/Radio.svelte +143 -0
- package/src/components/forms/RadioGroup.svelte +62 -0
- package/src/components/forms/RangeSlider.svelte +212 -0
- package/src/components/forms/SearchInput.svelte +175 -0
- package/src/components/forms/Select.svelte +326 -0
- package/src/components/forms/Switch.svelte +159 -0
- package/src/components/forms/Textarea.svelte +122 -0
- package/src/components/navigation/Accordion.svelte +65 -0
- package/src/components/navigation/AccordionItem.svelte +146 -0
- package/src/components/navigation/Tabs.svelte +239 -0
- package/src/components/overlays/ConfirmDialog.svelte +272 -0
- package/src/components/overlays/Dropdown.svelte +153 -0
- package/src/components/overlays/DropdownDivider.svelte +23 -0
- package/src/components/overlays/DropdownItem.svelte +97 -0
- package/src/components/overlays/Modal.svelte +232 -0
- package/src/components/overlays/Popover.svelte +206 -0
- package/src/components/primitives/Avatar.svelte +132 -0
- package/src/components/primitives/Badge.svelte +118 -0
- package/src/components/primitives/Button.svelte +262 -0
- package/src/components/primitives/Card.svelte +104 -0
- package/src/components/primitives/Divider.svelte +105 -0
- package/src/components/primitives/LazyImage.svelte +104 -0
- package/src/components/primitives/Link.svelte +122 -0
- package/src/components/primitives/StatusBadge.svelte +122 -0
- package/src/index.js +128 -0
- package/src/tokens/colors.css +189 -0
- package/src/tokens/effects.css +128 -0
- package/src/tokens/index.css +81 -0
- package/src/tokens/spacing.css +49 -0
- package/src/tokens/typography.css +79 -0
- package/src/utils/cn.svelte.js +175 -0
- package/src/utils/index.js +17 -0
- package/src/utils/reactive.svelte.js +239 -0
- package/jera.js +0 -135
- package/www/components/jera/Input/Input.svelte +0 -63
- package/www/components/jera/Input/index.js +0 -1
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Miozu Color System
|
|
3
|
+
*
|
|
4
|
+
* A Base16-inspired palette designed using Newton's color wheel
|
|
5
|
+
* for visual harmony and reduced eye strain.
|
|
6
|
+
*
|
|
7
|
+
* Documentation: https://miozu.com/colors
|
|
8
|
+
* Source: https://github.com/miozu-com
|
|
9
|
+
* Author: Nicholas Glazer <glazer.nicholas@gmail.com>
|
|
10
|
+
*
|
|
11
|
+
* USAGE:
|
|
12
|
+
* @import '@miozu/jera/tokens/colors.css';
|
|
13
|
+
*
|
|
14
|
+
* Or with Tailwind 4:
|
|
15
|
+
* @import '@miozu/jera/tokens/colors.css' theme(static);
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
:root {
|
|
19
|
+
/* ========================================
|
|
20
|
+
* BASE COLORS (Grayscale Spectrum)
|
|
21
|
+
* From darkest (base0) to lightest (base7)
|
|
22
|
+
* ======================================== */
|
|
23
|
+
|
|
24
|
+
--base0: #232733; /* Darkest background */
|
|
25
|
+
--base1: #2C3040; /* Default dark background */
|
|
26
|
+
--base2: #3E4359; /* Selection, highlights */
|
|
27
|
+
--base3: #565E78; /* Comments, subtle text */
|
|
28
|
+
--base4: #737E99; /* Muted foreground */
|
|
29
|
+
--base5: #D0D2DB; /* Default foreground */
|
|
30
|
+
--base6: #F3F4F7; /* Light foreground */
|
|
31
|
+
--base7: #FAFBFD; /* Lightest/white */
|
|
32
|
+
|
|
33
|
+
/* ========================================
|
|
34
|
+
* ACCENT COLORS (Base16 Extended Palette)
|
|
35
|
+
* Official miozu palette from @miozu/js-theme
|
|
36
|
+
* ======================================== */
|
|
37
|
+
|
|
38
|
+
--base8: #EB3137; /* Red - errors, destructive */
|
|
39
|
+
--base9: #FF9837; /* Orange - numbers, attention */
|
|
40
|
+
--base10: #6DD672; /* Green - success, positive */
|
|
41
|
+
--base11: #E8D176; /* Yellow - warnings, highlights */
|
|
42
|
+
--base12: #83D2FC; /* Blue - info, links */
|
|
43
|
+
--base13: #C974E6; /* Magenta - primary brand, functions */
|
|
44
|
+
--base14: #FF9982; /* Peach - keywords, warm accent */
|
|
45
|
+
--base15: #40FFE2; /* Cyan - methods, cool accent */
|
|
46
|
+
|
|
47
|
+
/* Named color aliases */
|
|
48
|
+
--red: var(--base8);
|
|
49
|
+
--orange: var(--base9);
|
|
50
|
+
--green: var(--base10);
|
|
51
|
+
--yellow: var(--base11);
|
|
52
|
+
--blue: var(--base12);
|
|
53
|
+
--magenta: var(--base13);
|
|
54
|
+
--peach: var(--base14);
|
|
55
|
+
--cyan: var(--base15);
|
|
56
|
+
|
|
57
|
+
/* ========================================
|
|
58
|
+
* SEMANTIC MAPPINGS (Dark Theme Default)
|
|
59
|
+
* Use these in components for consistency
|
|
60
|
+
* ======================================== */
|
|
61
|
+
|
|
62
|
+
/* Backgrounds */
|
|
63
|
+
--color-bg: var(--base0);
|
|
64
|
+
--color-surface: var(--base1);
|
|
65
|
+
--color-surface-alt: var(--base2);
|
|
66
|
+
--color-hover: var(--base2);
|
|
67
|
+
--color-surface-hover: var(--base2);
|
|
68
|
+
|
|
69
|
+
/* Foregrounds */
|
|
70
|
+
--color-text: var(--base5);
|
|
71
|
+
--color-text-strong: var(--base7);
|
|
72
|
+
--color-text-muted: var(--base4);
|
|
73
|
+
--color-text-subtle: var(--base3);
|
|
74
|
+
|
|
75
|
+
/* Borders */
|
|
76
|
+
--color-border: var(--base3);
|
|
77
|
+
--color-border-muted: var(--base2);
|
|
78
|
+
|
|
79
|
+
/* Brand */
|
|
80
|
+
--color-primary: var(--magenta); /* base13 - #C974E6 */
|
|
81
|
+
--color-secondary: var(--blue); /* base12 - #83D2FC */
|
|
82
|
+
--color-accent: var(--cyan); /* base15 - #40FFE2 */
|
|
83
|
+
|
|
84
|
+
/* States */
|
|
85
|
+
--color-success: var(--green); /* base10 - #6DD672 */
|
|
86
|
+
--color-warning: var(--yellow); /* base11 - #E8D176 */
|
|
87
|
+
--color-error: var(--red); /* base8 - #EB3137 */
|
|
88
|
+
--color-info: var(--blue); /* base12 - #83D2FC */
|
|
89
|
+
|
|
90
|
+
/* ========================================
|
|
91
|
+
* BASE COLOR ALIASES
|
|
92
|
+
* For direct base color access in components
|
|
93
|
+
* ======================================== */
|
|
94
|
+
|
|
95
|
+
/* Grayscale (base0-7) */
|
|
96
|
+
--color-base0: var(--base0);
|
|
97
|
+
--color-base1: var(--base1);
|
|
98
|
+
--color-base2: var(--base2);
|
|
99
|
+
--color-base3: var(--base3);
|
|
100
|
+
--color-base4: var(--base4);
|
|
101
|
+
--color-base5: var(--base5);
|
|
102
|
+
--color-base6: var(--base6);
|
|
103
|
+
--color-base7: var(--base7);
|
|
104
|
+
|
|
105
|
+
/* Accents (base8-15) */
|
|
106
|
+
--color-base8: var(--base8);
|
|
107
|
+
--color-base9: var(--base9);
|
|
108
|
+
--color-base10: var(--base10);
|
|
109
|
+
--color-base11: var(--base11);
|
|
110
|
+
--color-base12: var(--base12);
|
|
111
|
+
--color-base13: var(--base13);
|
|
112
|
+
--color-base14: var(--base14);
|
|
113
|
+
--color-base15: var(--base15);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/* ========================================
|
|
117
|
+
* LIGHT THEME
|
|
118
|
+
* Inverted grayscale, same accents
|
|
119
|
+
*
|
|
120
|
+
* Supports multiple selectors for flexibility:
|
|
121
|
+
* - data-theme="light" (generic)
|
|
122
|
+
* - data-theme="miozu-light" (Selify/Miozu apps)
|
|
123
|
+
* - .light (class-based)
|
|
124
|
+
* ======================================== */
|
|
125
|
+
|
|
126
|
+
[data-theme="light"],
|
|
127
|
+
[data-theme="miozu-light"],
|
|
128
|
+
.light {
|
|
129
|
+
/* Inverted base colors */
|
|
130
|
+
--color-bg: var(--base7);
|
|
131
|
+
--color-surface: var(--base6);
|
|
132
|
+
--color-surface-alt: var(--base5);
|
|
133
|
+
--color-hover: var(--base5);
|
|
134
|
+
--color-surface-hover: var(--base5);
|
|
135
|
+
|
|
136
|
+
/* Inverted foregrounds */
|
|
137
|
+
--color-text: var(--base2);
|
|
138
|
+
--color-text-strong: var(--base0);
|
|
139
|
+
--color-text-muted: var(--base3);
|
|
140
|
+
--color-text-subtle: var(--base4);
|
|
141
|
+
|
|
142
|
+
/* Inverted borders */
|
|
143
|
+
--color-border: var(--base4);
|
|
144
|
+
--color-border-muted: var(--base5);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/* ========================================
|
|
148
|
+
* DARK THEME (Explicit)
|
|
149
|
+
* Same as :root default, for explicit dark mode
|
|
150
|
+
*
|
|
151
|
+
* Supports multiple selectors:
|
|
152
|
+
* - data-theme="dark" (generic)
|
|
153
|
+
* - data-theme="miozu-dark" (Selify/Miozu apps)
|
|
154
|
+
* - .dark (class-based)
|
|
155
|
+
* ======================================== */
|
|
156
|
+
|
|
157
|
+
[data-theme="dark"],
|
|
158
|
+
[data-theme="miozu-dark"],
|
|
159
|
+
.dark {
|
|
160
|
+
--color-bg: var(--base0);
|
|
161
|
+
--color-surface: var(--base1);
|
|
162
|
+
--color-surface-alt: var(--base2);
|
|
163
|
+
--color-hover: var(--base2);
|
|
164
|
+
--color-surface-hover: var(--base2);
|
|
165
|
+
|
|
166
|
+
--color-text: var(--base5);
|
|
167
|
+
--color-text-strong: var(--base7);
|
|
168
|
+
--color-text-muted: var(--base4);
|
|
169
|
+
--color-text-subtle: var(--base3);
|
|
170
|
+
|
|
171
|
+
--color-border: var(--base3);
|
|
172
|
+
--color-border-muted: var(--base2);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/* ========================================
|
|
176
|
+
* HIGH CONTRAST THEME
|
|
177
|
+
* For accessibility
|
|
178
|
+
* ======================================== */
|
|
179
|
+
|
|
180
|
+
[data-theme="high-contrast"] {
|
|
181
|
+
--color-bg: #000000;
|
|
182
|
+
--color-surface: #0a0a0a;
|
|
183
|
+
--color-surface-alt: #1a1a1a;
|
|
184
|
+
--color-text: var(--base7);
|
|
185
|
+
--color-text-strong: #FFFFFF;
|
|
186
|
+
--color-text-muted: var(--base5);
|
|
187
|
+
--color-border: var(--base5);
|
|
188
|
+
--color-border-muted: var(--base4);
|
|
189
|
+
}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Miozu Effects System
|
|
3
|
+
*
|
|
4
|
+
* Shadows, borders, radius, and transitions.
|
|
5
|
+
* Consistent visual language for depth and motion.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
:root {
|
|
9
|
+
/* ========================================
|
|
10
|
+
* BORDER WIDTHS
|
|
11
|
+
* ======================================== */
|
|
12
|
+
|
|
13
|
+
--border-width-thin: 1px;
|
|
14
|
+
--border-width-default: 1px;
|
|
15
|
+
--border-width-thick: 2px;
|
|
16
|
+
|
|
17
|
+
/* ========================================
|
|
18
|
+
* FOCUS RING
|
|
19
|
+
* ======================================== */
|
|
20
|
+
|
|
21
|
+
--focus-ring-width: 2px;
|
|
22
|
+
--focus-ring-offset: 2px;
|
|
23
|
+
--focus-ring-color: var(--color-primary);
|
|
24
|
+
--focus-ring: var(--focus-ring-width) solid var(--focus-ring-color);
|
|
25
|
+
|
|
26
|
+
/* ========================================
|
|
27
|
+
* BORDER RADIUS
|
|
28
|
+
* ======================================== */
|
|
29
|
+
|
|
30
|
+
--radius-none: 0;
|
|
31
|
+
--radius-sm: 0.125rem; /* 2px */
|
|
32
|
+
--radius-default: 0.25rem; /* 4px */
|
|
33
|
+
--radius-md: 0.375rem; /* 6px */
|
|
34
|
+
--radius-lg: 0.5rem; /* 8px */
|
|
35
|
+
--radius-xl: 0.75rem; /* 12px */
|
|
36
|
+
--radius-2xl: 1rem; /* 16px */
|
|
37
|
+
--radius-3xl: 1.5rem; /* 24px */
|
|
38
|
+
--radius-full: 9999px; /* Pill shape */
|
|
39
|
+
|
|
40
|
+
/* ========================================
|
|
41
|
+
* BOX SHADOWS (Dark theme optimized)
|
|
42
|
+
* ======================================== */
|
|
43
|
+
|
|
44
|
+
--shadow-xs: 0 1px 2px 0 rgb(0 0 0 / 0.05);
|
|
45
|
+
|
|
46
|
+
--shadow-sm: 0 1px 3px 0 rgb(0 0 0 / 0.1),
|
|
47
|
+
0 1px 2px -1px rgb(0 0 0 / 0.1);
|
|
48
|
+
|
|
49
|
+
--shadow-default: 0 4px 6px -1px rgb(0 0 0 / 0.1),
|
|
50
|
+
0 2px 4px -2px rgb(0 0 0 / 0.1);
|
|
51
|
+
|
|
52
|
+
--shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1),
|
|
53
|
+
0 2px 4px -2px rgb(0 0 0 / 0.1);
|
|
54
|
+
|
|
55
|
+
--shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1),
|
|
56
|
+
0 4px 6px -4px rgb(0 0 0 / 0.1);
|
|
57
|
+
|
|
58
|
+
--shadow-xl: 0 20px 25px -5px rgb(0 0 0 / 0.1),
|
|
59
|
+
0 8px 10px -6px rgb(0 0 0 / 0.1);
|
|
60
|
+
|
|
61
|
+
--shadow-2xl: 0 25px 50px -12px rgb(0 0 0 / 0.25);
|
|
62
|
+
|
|
63
|
+
--shadow-inner: inset 0 2px 4px 0 rgb(0 0 0 / 0.05);
|
|
64
|
+
|
|
65
|
+
--shadow-none: 0 0 #0000;
|
|
66
|
+
|
|
67
|
+
/* Colored shadows for states */
|
|
68
|
+
--shadow-primary: 0 4px 14px 0 rgb(201 116 230 / 0.25);
|
|
69
|
+
--shadow-error: 0 4px 14px 0 rgb(235 49 55 / 0.25);
|
|
70
|
+
--shadow-success: 0 4px 14px 0 rgb(109 214 114 / 0.25);
|
|
71
|
+
|
|
72
|
+
/* ========================================
|
|
73
|
+
* TRANSITIONS
|
|
74
|
+
* ======================================== */
|
|
75
|
+
|
|
76
|
+
/* Durations */
|
|
77
|
+
--duration-75: 75ms;
|
|
78
|
+
--duration-100: 100ms;
|
|
79
|
+
--duration-150: 150ms;
|
|
80
|
+
--duration-200: 200ms;
|
|
81
|
+
--duration-300: 300ms;
|
|
82
|
+
--duration-500: 500ms;
|
|
83
|
+
--duration-700: 700ms;
|
|
84
|
+
--duration-1000: 1000ms;
|
|
85
|
+
|
|
86
|
+
/* Semantic durations */
|
|
87
|
+
--duration-fast: var(--duration-150);
|
|
88
|
+
--duration-base: var(--duration-200);
|
|
89
|
+
--duration-slow: var(--duration-300);
|
|
90
|
+
|
|
91
|
+
/* Easings */
|
|
92
|
+
--ease-linear: linear;
|
|
93
|
+
--ease-in: cubic-bezier(0.4, 0, 1, 1);
|
|
94
|
+
--ease-out: cubic-bezier(0, 0, 0.2, 1);
|
|
95
|
+
--ease-in-out: cubic-bezier(0.4, 0, 0.2, 1);
|
|
96
|
+
--ease-bounce: cubic-bezier(0.68, -0.55, 0.265, 1.55);
|
|
97
|
+
--ease-spring: cubic-bezier(0.175, 0.885, 0.32, 1.275);
|
|
98
|
+
|
|
99
|
+
/* Semantic easings */
|
|
100
|
+
--ease-default: var(--ease-out);
|
|
101
|
+
|
|
102
|
+
/* Common transitions */
|
|
103
|
+
--transition-colors: color var(--duration-fast) var(--ease-default),
|
|
104
|
+
background-color var(--duration-fast) var(--ease-default),
|
|
105
|
+
border-color var(--duration-fast) var(--ease-default);
|
|
106
|
+
|
|
107
|
+
--transition-opacity: opacity var(--duration-fast) var(--ease-default);
|
|
108
|
+
|
|
109
|
+
--transition-transform: transform var(--duration-base) var(--ease-default);
|
|
110
|
+
|
|
111
|
+
--transition-all: all var(--duration-base) var(--ease-default);
|
|
112
|
+
|
|
113
|
+
/* ========================================
|
|
114
|
+
* Z-INDEX SCALE
|
|
115
|
+
* ======================================== */
|
|
116
|
+
|
|
117
|
+
--z-behind: -1;
|
|
118
|
+
--z-default: 0;
|
|
119
|
+
--z-dropdown: 10;
|
|
120
|
+
--z-sticky: 20;
|
|
121
|
+
--z-fixed: 30;
|
|
122
|
+
--z-modal-backdrop: 40;
|
|
123
|
+
--z-modal: 50;
|
|
124
|
+
--z-popover: 60;
|
|
125
|
+
--z-tooltip: 70;
|
|
126
|
+
--z-toast: 80;
|
|
127
|
+
--z-max: 9999;
|
|
128
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Miozu Design Tokens
|
|
3
|
+
*
|
|
4
|
+
* A complete design token system for building consistent interfaces.
|
|
5
|
+
* Works standalone or with Tailwind CSS.
|
|
6
|
+
*
|
|
7
|
+
* @package @miozu/jera
|
|
8
|
+
* @author Nicholas Glazer <glazer.nicholas@gmail.com>
|
|
9
|
+
* @license MIT
|
|
10
|
+
*
|
|
11
|
+
* USAGE:
|
|
12
|
+
*
|
|
13
|
+
* 1. Import all tokens:
|
|
14
|
+
* @import '@miozu/jera/tokens';
|
|
15
|
+
*
|
|
16
|
+
* 2. Import individual token sets:
|
|
17
|
+
* @import '@miozu/jera/tokens/colors.css';
|
|
18
|
+
* @import '@miozu/jera/tokens/spacing.css';
|
|
19
|
+
*
|
|
20
|
+
* 3. With Tailwind 4:
|
|
21
|
+
* @import '@miozu/jera/tokens' theme(static);
|
|
22
|
+
*
|
|
23
|
+
* THEMING:
|
|
24
|
+
*
|
|
25
|
+
* Dark (default):
|
|
26
|
+
* <html data-theme="dark">
|
|
27
|
+
*
|
|
28
|
+
* Light:
|
|
29
|
+
* <html data-theme="light">
|
|
30
|
+
*
|
|
31
|
+
* System preference (JS):
|
|
32
|
+
* const theme = matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
|
|
33
|
+
* document.documentElement.setAttribute('data-theme', theme);
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
@import './colors.css';
|
|
37
|
+
@import './spacing.css';
|
|
38
|
+
@import './typography.css';
|
|
39
|
+
@import './effects.css';
|
|
40
|
+
|
|
41
|
+
/* ========================================
|
|
42
|
+
* BASE STYLES (Optional)
|
|
43
|
+
* Reset and sensible defaults
|
|
44
|
+
* ======================================== */
|
|
45
|
+
|
|
46
|
+
*,
|
|
47
|
+
*::before,
|
|
48
|
+
*::after {
|
|
49
|
+
box-sizing: border-box;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
html {
|
|
53
|
+
font-family: var(--font-sans);
|
|
54
|
+
font-size: 16px;
|
|
55
|
+
line-height: var(--leading-normal);
|
|
56
|
+
-webkit-font-smoothing: antialiased;
|
|
57
|
+
-moz-osx-font-smoothing: grayscale;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
body {
|
|
61
|
+
margin: 0;
|
|
62
|
+
background-color: var(--color-bg);
|
|
63
|
+
color: var(--color-text);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/* Focus visible for accessibility */
|
|
67
|
+
:focus-visible {
|
|
68
|
+
outline: 2px solid var(--color-primary);
|
|
69
|
+
outline-offset: 2px;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/* Remove default focus for mouse users */
|
|
73
|
+
:focus:not(:focus-visible) {
|
|
74
|
+
outline: none;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/* Selection color */
|
|
78
|
+
::selection {
|
|
79
|
+
background-color: var(--color-primary);
|
|
80
|
+
color: var(--base7);
|
|
81
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Miozu Spacing System
|
|
3
|
+
*
|
|
4
|
+
* Based on 4px base unit with geometric progression.
|
|
5
|
+
* Consistent spacing creates visual rhythm.
|
|
6
|
+
*
|
|
7
|
+
* USAGE:
|
|
8
|
+
* padding: var(--space-4); // 16px
|
|
9
|
+
* gap: var(--space-3); // 12px
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
:root {
|
|
13
|
+
/* Base unit: 4px */
|
|
14
|
+
--space-px: 1px;
|
|
15
|
+
--space-0: 0;
|
|
16
|
+
--space-0-5: 2px; /* 0.5 * 4 */
|
|
17
|
+
--space-1: 4px; /* 1 * 4 */
|
|
18
|
+
--space-1-5: 6px; /* 1.5 * 4 */
|
|
19
|
+
--space-2: 8px; /* 2 * 4 */
|
|
20
|
+
--space-2-5: 10px; /* 2.5 * 4 */
|
|
21
|
+
--space-3: 12px; /* 3 * 4 */
|
|
22
|
+
--space-3-5: 14px; /* 3.5 * 4 */
|
|
23
|
+
--space-4: 16px; /* 4 * 4 */
|
|
24
|
+
--space-5: 20px; /* 5 * 4 */
|
|
25
|
+
--space-6: 24px; /* 6 * 4 */
|
|
26
|
+
--space-7: 28px; /* 7 * 4 */
|
|
27
|
+
--space-8: 32px; /* 8 * 4 */
|
|
28
|
+
--space-9: 36px; /* 9 * 4 */
|
|
29
|
+
--space-10: 40px; /* 10 * 4 */
|
|
30
|
+
--space-11: 44px; /* 11 * 4 */
|
|
31
|
+
--space-12: 48px; /* 12 * 4 */
|
|
32
|
+
--space-14: 56px; /* 14 * 4 */
|
|
33
|
+
--space-16: 64px; /* 16 * 4 */
|
|
34
|
+
--space-20: 80px; /* 20 * 4 */
|
|
35
|
+
--space-24: 96px; /* 24 * 4 */
|
|
36
|
+
--space-28: 112px; /* 28 * 4 */
|
|
37
|
+
--space-32: 128px; /* 32 * 4 */
|
|
38
|
+
--space-36: 144px; /* 36 * 4 */
|
|
39
|
+
--space-40: 160px; /* 40 * 4 */
|
|
40
|
+
--space-44: 176px; /* 44 * 4 */
|
|
41
|
+
--space-48: 192px; /* 48 * 4 */
|
|
42
|
+
--space-52: 208px; /* 52 * 4 */
|
|
43
|
+
--space-56: 224px; /* 56 * 4 */
|
|
44
|
+
--space-60: 240px; /* 60 * 4 */
|
|
45
|
+
--space-64: 256px; /* 64 * 4 */
|
|
46
|
+
--space-72: 288px; /* 72 * 4 */
|
|
47
|
+
--space-80: 320px; /* 80 * 4 */
|
|
48
|
+
--space-96: 384px; /* 96 * 4 */
|
|
49
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Miozu Typography System
|
|
3
|
+
*
|
|
4
|
+
* Font scales using minor third ratio (1.2).
|
|
5
|
+
* Optimized for readability on screens.
|
|
6
|
+
*
|
|
7
|
+
* USAGE:
|
|
8
|
+
* font-size: var(--text-base);
|
|
9
|
+
* font-family: var(--font-sans);
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
:root {
|
|
13
|
+
/* ========================================
|
|
14
|
+
* FONT FAMILIES
|
|
15
|
+
* ======================================== */
|
|
16
|
+
|
|
17
|
+
--font-sans: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont,
|
|
18
|
+
"Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif,
|
|
19
|
+
"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
|
|
20
|
+
|
|
21
|
+
--font-serif: ui-serif, Georgia, Cambria, "Times New Roman", Times, serif;
|
|
22
|
+
|
|
23
|
+
--font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas,
|
|
24
|
+
"Liberation Mono", "Courier New", monospace;
|
|
25
|
+
|
|
26
|
+
/* ========================================
|
|
27
|
+
* FONT SIZES (Minor Third Scale - 1.2)
|
|
28
|
+
* ======================================== */
|
|
29
|
+
|
|
30
|
+
--text-xs: 0.75rem; /* 12px */
|
|
31
|
+
--text-sm: 0.875rem; /* 14px */
|
|
32
|
+
--text-base: 1rem; /* 16px */
|
|
33
|
+
--text-lg: 1.125rem; /* 18px */
|
|
34
|
+
--text-xl: 1.25rem; /* 20px */
|
|
35
|
+
--text-2xl: 1.5rem; /* 24px */
|
|
36
|
+
--text-3xl: 1.875rem; /* 30px */
|
|
37
|
+
--text-4xl: 2.25rem; /* 36px */
|
|
38
|
+
--text-5xl: 3rem; /* 48px */
|
|
39
|
+
--text-6xl: 3.75rem; /* 60px */
|
|
40
|
+
--text-7xl: 4.5rem; /* 72px */
|
|
41
|
+
--text-8xl: 6rem; /* 96px */
|
|
42
|
+
--text-9xl: 8rem; /* 128px */
|
|
43
|
+
|
|
44
|
+
/* ========================================
|
|
45
|
+
* LINE HEIGHTS
|
|
46
|
+
* ======================================== */
|
|
47
|
+
|
|
48
|
+
--leading-none: 1;
|
|
49
|
+
--leading-tight: 1.25;
|
|
50
|
+
--leading-snug: 1.375;
|
|
51
|
+
--leading-normal: 1.5;
|
|
52
|
+
--leading-relaxed: 1.625;
|
|
53
|
+
--leading-loose: 2;
|
|
54
|
+
|
|
55
|
+
/* ========================================
|
|
56
|
+
* FONT WEIGHTS
|
|
57
|
+
* ======================================== */
|
|
58
|
+
|
|
59
|
+
--font-thin: 100;
|
|
60
|
+
--font-extralight: 200;
|
|
61
|
+
--font-light: 300;
|
|
62
|
+
--font-normal: 400;
|
|
63
|
+
--font-medium: 500;
|
|
64
|
+
--font-semibold: 600;
|
|
65
|
+
--font-bold: 700;
|
|
66
|
+
--font-extrabold: 800;
|
|
67
|
+
--font-black: 900;
|
|
68
|
+
|
|
69
|
+
/* ========================================
|
|
70
|
+
* LETTER SPACING
|
|
71
|
+
* ======================================== */
|
|
72
|
+
|
|
73
|
+
--tracking-tighter: -0.05em;
|
|
74
|
+
--tracking-tight: -0.025em;
|
|
75
|
+
--tracking-normal: 0em;
|
|
76
|
+
--tracking-wide: 0.025em;
|
|
77
|
+
--tracking-wider: 0.05em;
|
|
78
|
+
--tracking-widest: 0.1em;
|
|
79
|
+
}
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reactive Class Composer (cn)
|
|
3
|
+
*
|
|
4
|
+
* Advanced Svelte 5 pattern for composing classes reactively.
|
|
5
|
+
* Uses $derived internally for fine-grained reactivity.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* // Basic usage
|
|
9
|
+
* const classes = cn('base', condition && 'conditional', ['array', 'of', 'classes']);
|
|
10
|
+
*
|
|
11
|
+
* // With variants
|
|
12
|
+
* const button = cv({
|
|
13
|
+
* base: 'inline-flex items-center justify-center',
|
|
14
|
+
* variants: {
|
|
15
|
+
* intent: {
|
|
16
|
+
* primary: 'bg-primary text-white',
|
|
17
|
+
* secondary: 'bg-surface text-text',
|
|
18
|
+
* },
|
|
19
|
+
* size: {
|
|
20
|
+
* sm: 'h-8 px-3 text-sm',
|
|
21
|
+
* md: 'h-10 px-4 text-base',
|
|
22
|
+
* lg: 'h-12 px-6 text-lg',
|
|
23
|
+
* }
|
|
24
|
+
* },
|
|
25
|
+
* defaults: { intent: 'primary', size: 'md' }
|
|
26
|
+
* });
|
|
27
|
+
*
|
|
28
|
+
* // Use in component
|
|
29
|
+
* <button class={button({ intent: 'secondary', size: 'lg' })}>Click</button>
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Concatenate class names, filtering out falsy values
|
|
34
|
+
* @param {...(string|boolean|null|undefined|string[])} args
|
|
35
|
+
* @returns {string}
|
|
36
|
+
*/
|
|
37
|
+
export function cn(...args) {
|
|
38
|
+
return args
|
|
39
|
+
.flat(Infinity)
|
|
40
|
+
.filter(Boolean)
|
|
41
|
+
.join(' ')
|
|
42
|
+
.replace(/\s+/g, ' ')
|
|
43
|
+
.trim();
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Create a reactive class string using $derived
|
|
48
|
+
* Returns a getter that recomputes when dependencies change
|
|
49
|
+
*
|
|
50
|
+
* @param {() => (string|boolean|null|undefined|string[])[]} classFactory
|
|
51
|
+
* @returns {string} Reactive class string (use as class={rcn(() => [...])})
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* let isActive = $state(false);
|
|
55
|
+
* let size = $state('md');
|
|
56
|
+
*
|
|
57
|
+
* // This recomputes automatically when isActive or size changes
|
|
58
|
+
* const buttonClass = $derived(cn(
|
|
59
|
+
* 'base-button',
|
|
60
|
+
* isActive && 'is-active',
|
|
61
|
+
* `size-${size}`
|
|
62
|
+
* ));
|
|
63
|
+
*/
|
|
64
|
+
// Note: rcn is just cn - the reactivity comes from using it inside $derived
|
|
65
|
+
export const rcn = cn;
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Class Variants (cv) - Type-safe variant composition
|
|
69
|
+
*
|
|
70
|
+
* Creates a function that generates class strings based on variant props.
|
|
71
|
+
* Inspired by CVA but optimized for Svelte 5 patterns.
|
|
72
|
+
*
|
|
73
|
+
* @template {Record<string, Record<string, string>>} V
|
|
74
|
+
* @template {Partial<{[K in keyof V]: keyof V[K]}>} D
|
|
75
|
+
*
|
|
76
|
+
* @param {{
|
|
77
|
+
* base?: string | string[],
|
|
78
|
+
* variants?: V,
|
|
79
|
+
* compounds?: Array<{condition: Partial<{[K in keyof V]: keyof V[K]}>, class: string}>,
|
|
80
|
+
* defaults?: D
|
|
81
|
+
* }} config
|
|
82
|
+
*
|
|
83
|
+
* @returns {(props?: Partial<{[K in keyof V]: keyof V[K]}> & {class?: string}) => string}
|
|
84
|
+
*/
|
|
85
|
+
export function cv(config) {
|
|
86
|
+
const { base = '', variants = {}, compounds = [], defaults = {} } = config;
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* @param {Record<string, any>} [props]
|
|
90
|
+
* @returns {string}
|
|
91
|
+
*/
|
|
92
|
+
return function (props = {}) {
|
|
93
|
+
// Start with base classes
|
|
94
|
+
/** @type {(string | string[])[]} */
|
|
95
|
+
const classes = [base];
|
|
96
|
+
|
|
97
|
+
// Apply variant classes
|
|
98
|
+
for (const [variantKey, variantOptions] of Object.entries(variants)) {
|
|
99
|
+
const selectedVariant = /** @type {string} */ (props[variantKey] ?? defaults[variantKey]);
|
|
100
|
+
const variantMap = /** @type {Record<string, string>} */ (variantOptions);
|
|
101
|
+
if (selectedVariant && variantMap[selectedVariant]) {
|
|
102
|
+
classes.push(variantMap[selectedVariant]);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Apply compound variants (when multiple conditions match)
|
|
107
|
+
for (const compound of compounds) {
|
|
108
|
+
const { condition, class: compoundClass } = compound;
|
|
109
|
+
const conditionEntries = /** @type {[string, string][]} */ (Object.entries(condition));
|
|
110
|
+
const matches = conditionEntries.every(([key, value]) => {
|
|
111
|
+
const actualValue = /** @type {string} */ (props[key] ?? defaults[key]);
|
|
112
|
+
return actualValue === value;
|
|
113
|
+
});
|
|
114
|
+
if (matches) {
|
|
115
|
+
classes.push(compoundClass);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Append any additional classes passed via props.class
|
|
120
|
+
if (props.class) {
|
|
121
|
+
classes.push(props.class);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return cn(...classes);
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Create a reactive variant class using $derived
|
|
130
|
+
*
|
|
131
|
+
* @example
|
|
132
|
+
* const buttonVariants = cv({...});
|
|
133
|
+
*
|
|
134
|
+
* let intent = $state('primary');
|
|
135
|
+
* let size = $state('md');
|
|
136
|
+
*
|
|
137
|
+
* // Reactive: recomputes when intent or size changes
|
|
138
|
+
* const buttonClass = $derived(buttonVariants({ intent, size }));
|
|
139
|
+
*/
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Slot class merger - combines component classes with user-provided classes
|
|
143
|
+
* Useful for compound components where parent passes classes to children
|
|
144
|
+
*
|
|
145
|
+
* @param {string} componentClass - The component's own classes
|
|
146
|
+
* @param {string} [userClass] - Classes provided by the user
|
|
147
|
+
* @returns {string}
|
|
148
|
+
*/
|
|
149
|
+
export function mergeClasses(componentClass, userClass) {
|
|
150
|
+
return cn(componentClass, userClass);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Conditional class helper - returns class only if condition is truthy
|
|
155
|
+
*
|
|
156
|
+
* @param {boolean} condition
|
|
157
|
+
* @param {string} trueClass
|
|
158
|
+
* @param {string} [falseClass]
|
|
159
|
+
* @returns {string}
|
|
160
|
+
*/
|
|
161
|
+
export function when(condition, trueClass, falseClass = '') {
|
|
162
|
+
return condition ? trueClass : falseClass;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Switch class helper - returns class based on value matching
|
|
167
|
+
*
|
|
168
|
+
* @param {string | number} value
|
|
169
|
+
* @param {Record<string, string>} cases
|
|
170
|
+
* @param {string} [fallback]
|
|
171
|
+
* @returns {string}
|
|
172
|
+
*/
|
|
173
|
+
export function match(value, cases, fallback = '') {
|
|
174
|
+
return cases[String(value)] ?? fallback;
|
|
175
|
+
}
|