vunor 0.0.30 → 0.1.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/README.md +514 -17
- package/dist/AppLayout.d.mts +42 -0
- package/dist/AppLayout.mjs +0 -0
- package/dist/AppToasts.d.mts +10 -0
- package/dist/AppToasts.mjs +112 -0
- package/dist/Button.d.mts +38 -0
- package/dist/Button.mjs +116 -0
- package/dist/ButtonBase.d.mts +29 -0
- package/dist/ButtonBase.mjs +89 -0
- package/dist/Calendar.d.mts +14 -0
- package/dist/Calendar.mjs +212 -0
- package/dist/Card.d.mts +23 -0
- package/dist/Card.mjs +68 -0
- package/dist/CardHeader.d.mts +18 -0
- package/dist/CardHeader.mjs +51 -0
- package/dist/CardInner.d.mts +13 -0
- package/dist/CardInner.mjs +22 -0
- package/dist/Checkbox.d.mts +32 -0
- package/dist/Checkbox.mjs +109 -0
- package/dist/Combobox.d.mts +168 -0
- package/dist/Combobox.mjs +755 -0
- package/dist/DatePicker.d.mts +81 -0
- package/dist/DatePicker.mjs +283 -0
- package/dist/DatePickerBase.d.mts +97 -0
- package/dist/DatePickerBase.mjs +365 -0
- package/dist/DatePickerInner.d.mts +7 -0
- package/dist/DatePickerInner.mjs +44 -0
- package/dist/DatePickerPopup.d.mts +8 -0
- package/dist/DatePickerPopup.mjs +116 -0
- package/dist/DelayedSwitch.d.mts +23 -0
- package/dist/DelayedSwitch.mjs +43 -0
- package/dist/DevTools.d.mts +14 -0
- package/dist/DevTools.mjs +612 -0
- package/dist/Dialog.d.mts +59 -0
- package/dist/Dialog.mjs +264 -0
- package/dist/Icon.d.mts +6 -0
- package/dist/Icon.mjs +22 -0
- package/dist/InnerLoading.d.mts +16 -0
- package/dist/InnerLoading.mjs +24 -0
- package/dist/Input.d.mts +166 -0
- package/dist/Input.mjs +242 -0
- package/dist/InputBase.d.mts +129 -0
- package/dist/InputBase.mjs +228 -0
- package/dist/Label.d.mts +13 -0
- package/dist/Label.mjs +20 -0
- package/dist/LoadingIndicator.d.mts +8 -0
- package/dist/LoadingIndicator.mjs +38 -0
- package/dist/Menu.d.mts +33 -0
- package/dist/Menu.mjs +136 -0
- package/dist/MenuItem.d.mts +9 -0
- package/dist/MenuItem.mjs +47 -0
- package/dist/OverflowContainer.d.mts +30 -0
- package/dist/OverflowContainer.mjs +105 -0
- package/dist/Pagination.d.mts +22 -0
- package/dist/Pagination.mjs +131 -0
- package/dist/Popover.d.mts +40 -0
- package/dist/Popover.mjs +189 -0
- package/dist/ProgressBar.d.mts +10 -0
- package/dist/ProgressBar.mjs +63 -0
- package/dist/RadioGroup.d.mts +40 -0
- package/dist/RadioGroup.mjs +139 -0
- package/dist/Select.d.mts +115 -0
- package/dist/Select.mjs +305 -0
- package/dist/SelectBase.d.mts +66 -0
- package/dist/SelectBase.mjs +263 -0
- package/dist/Slider.d.mts +37 -0
- package/dist/Slider.mjs +167 -0
- package/dist/Tabs.d.mts +41 -0
- package/dist/Tabs.mjs +113 -0
- package/dist/nuxt.d.mts +6 -0
- package/dist/nuxt.mjs +24 -63
- package/dist/theme.d.mts +334 -0
- package/dist/theme.mjs +2265 -1460
- package/dist/utils-Z0nPSAzb.js +42 -0
- package/dist/utils.d.mts +25 -0
- package/dist/utils.mjs +50 -20
- package/dist/vite.d.mts +6 -0
- package/dist/vite.mjs +10 -12
- package/dist/vunor.d.mts +125 -0
- package/dist/vunor.mjs +167 -152
- package/package.json +184 -68
- package/scripts/setup-skills.js +69 -0
- package/skills/vunor/SKILL.md +115 -0
- package/skills/vunor/components.md +320 -0
- package/skills/vunor/core.md +173 -0
- package/skills/vunor/forms.md +348 -0
- package/skills/vunor/palette.md +223 -0
- package/skills/vunor/rules.md +263 -0
- package/skills/vunor/shortcuts.md +239 -0
- package/skills/vunor/typography.md +204 -0
- package/dist/nuxt.d.ts +0 -6
- package/dist/theme.d.ts +0 -336
- package/dist/utils.d.ts +0 -25
- package/dist/vite.d.ts +0 -5
- package/dist/vunor.d.ts +0 -121
- package/src/components/AppLayout/AppLayout.vue +0 -130
- package/src/components/AppToasts/AppToasts.vue +0 -76
- package/src/components/AppToasts/app-toasts.ts +0 -43
- package/src/components/AppToasts/shortcuts.ts +0 -26
- package/src/components/Button/Button.vue +0 -50
- package/src/components/Button/ButtonBase.vue +0 -47
- package/src/components/Button/index.ts +0 -1
- package/src/components/Button/shortcuts.ts +0 -29
- package/src/components/Calendar/Calendar.vue +0 -70
- package/src/components/Calendar/shortcuts.ts +0 -38
- package/src/components/Card/Card.vue +0 -48
- package/src/components/Card/CardHeader.vue +0 -27
- package/src/components/Card/CardInner.vue +0 -8
- package/src/components/Card/index.ts +0 -3
- package/src/components/Card/pi.ts +0 -47
- package/src/components/Card/shortcuts.ts +0 -21
- package/src/components/Checkbox/Checkbox.vue +0 -62
- package/src/components/Checkbox/index.ts +0 -1
- package/src/components/Checkbox/shortcuts.ts +0 -27
- package/src/components/Combobox/Combobox.vue +0 -552
- package/src/components/Combobox/index.ts +0 -2
- package/src/components/Combobox/shortcuts.ts +0 -12
- package/src/components/Combobox/types.ts +0 -33
- package/src/components/DatePicker/DatePicker.vue +0 -31
- package/src/components/DatePicker/DatePickerBase.vue +0 -139
- package/src/components/DatePicker/DatePickerInner.vue +0 -27
- package/src/components/DatePicker/DatePickerPopup.vue +0 -84
- package/src/components/DevTools/DevTools.vue +0 -374
- package/src/components/Dialog/DelayedSwitch.vue +0 -51
- package/src/components/Dialog/Dialog.vue +0 -199
- package/src/components/Dialog/shortcuts.ts +0 -17
- package/src/components/Icon/Icon.vue +0 -9
- package/src/components/Icon/index.ts +0 -1
- package/src/components/Input/Input.vue +0 -118
- package/src/components/Input/InputBase.vue +0 -149
- package/src/components/Input/index.ts +0 -3
- package/src/components/Input/pi.ts +0 -18
- package/src/components/Input/utils.ts +0 -160
- package/src/components/Label/Label.vue +0 -5
- package/src/components/Label/index.ts +0 -1
- package/src/components/Loading/InnerLoading.vue +0 -14
- package/src/components/Loading/LoadingIndicator.vue +0 -23
- package/src/components/Loading/index.ts +0 -1
- package/src/components/Loading/shortcuts.ts +0 -11
- package/src/components/Menu/Menu.vue +0 -112
- package/src/components/Menu/MenuItem.vue +0 -21
- package/src/components/Menu/index.ts +0 -2
- package/src/components/Menu/shortcuts.ts +0 -6
- package/src/components/OverflowContainer/OverflowContainer.vue +0 -123
- package/src/components/OverflowContainer/index.ts +0 -1
- package/src/components/Pagination/Pagination.vue +0 -84
- package/src/components/Popover/Popover.vue +0 -61
- package/src/components/Popover/index.ts +0 -1
- package/src/components/ProgressBar/ProgressBar.vue +0 -22
- package/src/components/ProgressBar/shortcuts.ts +0 -25
- package/src/components/RadioGroup/RadioGroup.vue +0 -84
- package/src/components/RadioGroup/index.ts +0 -1
- package/src/components/RadioGroup/shortcuts.ts +0 -34
- package/src/components/Select/Select.vue +0 -102
- package/src/components/Select/SelectBase.vue +0 -167
- package/src/components/Select/index.ts +0 -3
- package/src/components/Select/shortcuts.ts +0 -30
- package/src/components/Select/types.ts +0 -30
- package/src/components/Slider/Slider.vue +0 -75
- package/src/components/Slider/index.ts +0 -1
- package/src/components/Slider/shortcuts.ts +0 -23
- package/src/components/Tabs/Tabs.vue +0 -42
- package/src/components/Tabs/shortcuts.ts +0 -7
- package/src/components/shortcuts.ts +0 -34
- package/src/components/utils/index.ts +0 -2
- package/src/components/utils/merge-class.ts +0 -31
- package/src/components/utils/provide-inject.ts +0 -39
package/README.md
CHANGED
|
@@ -1,33 +1,530 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Vunor
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A **UnoCSS theme engine** that turns a handful of design decisions into a complete, perceptually consistent design system -- plus an optional set of 30+ Vue 3 components that use it.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
The core value is the theme: a golden-ratio-based type and spacing scale, an Oklab-graded color palette where every hue looks equally bright at the same step, and a deeply-mergeable shortcut object system that lets you customize any visual detail without rewriting CSS. The Vue components are a bonus -- you can use the theme engine on its own with any markup.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
## Design Philosophy
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
Most design systems hard-code dozens of magic numbers for font sizes, spacing, colors, and border radii. Vunor derives **everything from a few mathematical constants**:
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
- **Golden ratio (1.618)** drives the typography scale, spacing tokens, and default border radius
|
|
12
|
+
- **Oklab color model** ensures perceptual uniformity -- `primary-500` and `error-500` look equally bright to the human eye, regardless of hue
|
|
13
|
+
- **Object-driven shortcuts** make every visual style surgically overridable through deep merging, not string replacement
|
|
12
14
|
|
|
13
|
-
|
|
15
|
+
The result: change one seed color or one scale factor, and the entire system recalculates consistently.
|
|
14
16
|
|
|
15
|
-
|
|
17
|
+
---
|
|
16
18
|
|
|
17
|
-
##
|
|
19
|
+
## Perceptual Color Palette
|
|
18
20
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
+
Vunor generates its full color system using [`@prostojs/palitra`](https://github.com/prostojs/palitra), a palette generator built on the **Oklab perceptual color model**.
|
|
22
|
+
|
|
23
|
+
### Why Oklab?
|
|
24
|
+
|
|
25
|
+
Traditional RGB/HSL-based palette generators produce steps that _look_ uneven: yellow-500 appears much brighter than blue-500 at the same lightness value, because RGB lightness doesn't match human perception. Oklab solves this -- it grades colors by how people actually see them. When palitra generates `primary-500` and `secondary-500`, they sit at the same perceptual luminance regardless of their hue. This means:
|
|
26
|
+
|
|
27
|
+
- Swapping your primary color from blue to green doesn't break visual hierarchy
|
|
28
|
+
- Numbered steps (50..900) have visually equal spacing between them
|
|
29
|
+
- Dark/light mode palettes stay balanced without manual correction
|
|
30
|
+
|
|
31
|
+
### How It Works
|
|
32
|
+
|
|
33
|
+
You provide up to 7 semantic seed colors. Palitra takes each one and generates:
|
|
34
|
+
|
|
35
|
+
1. **Main palette** (10 steps: 50, 100..900) -- luminance-graded from light to dark with perceptually uniform steps, optional saturation and hue-shift (vivid) adjustments at the extremes
|
|
36
|
+
2. **Layer palette** (5 steps: 0..4) -- desaturated variants for backgrounds that subtly tint without overwhelming content
|
|
37
|
+
|
|
38
|
+
All values are emitted as CSS custom properties, ready for use in any CSS-based system.
|
|
39
|
+
|
|
40
|
+
### Semantic Colors
|
|
41
|
+
|
|
42
|
+
| Name | Default | Purpose |
|
|
43
|
+
|------|---------|---------|
|
|
44
|
+
| `primary` | `#004eaf` | Main brand color |
|
|
45
|
+
| `secondary` | `#edd812` | Accent / highlight |
|
|
46
|
+
| `good` | `#7bc76a` | Success / positive |
|
|
47
|
+
| `warn` | `#ef9421` | Warning |
|
|
48
|
+
| `error` | `#bf5a5f` | Error / negative |
|
|
49
|
+
| `grey` | `#858892` | Neutral greys |
|
|
50
|
+
| `neutral` | `#5da0c5` | Alternative neutral |
|
|
51
|
+
|
|
52
|
+
### Per-Color Fine-Tuning
|
|
53
|
+
|
|
54
|
+
Each color can be a simple hex string or an object with saturation/vivid controls:
|
|
55
|
+
|
|
56
|
+
```ts
|
|
57
|
+
palette: {
|
|
58
|
+
colors: {
|
|
59
|
+
primary: '#6B4EFF', // simple swap
|
|
60
|
+
error: {
|
|
61
|
+
color: '#DC2626',
|
|
62
|
+
vivid: { dark: 0.3, light: 0.3 }, // boost hue rotation at palette edges
|
|
63
|
+
saturate: { dark: -0.1, light: -0.1 }, // desaturate slightly
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Advanced Palette Controls
|
|
70
|
+
|
|
71
|
+
Fine-tune the global palette generation curves:
|
|
72
|
+
|
|
73
|
+
```ts
|
|
74
|
+
palette: {
|
|
75
|
+
lightest: 0.97, // max luminance for the lightest step (0-1)
|
|
76
|
+
darkest: 0.24, // min luminance for the darkest step (0-1)
|
|
77
|
+
layersDepth: 0.08, // brightness step between layer-0 and layer-4
|
|
78
|
+
|
|
79
|
+
mainPalette: {
|
|
80
|
+
luminance: { dark: 0.26, middle: 0.62, light: 0.97 },
|
|
81
|
+
saturate: { dark: -0.25, light: -0.25 },
|
|
82
|
+
vivid: { dark: 0.1, light: 0.2 }, // hue rotation at edges
|
|
83
|
+
},
|
|
84
|
+
layerPalette: {
|
|
85
|
+
desaturate: 0.2, // pre-desaturate before generating layers
|
|
86
|
+
luminance: { dark: 0.24, light: 0.32 },
|
|
87
|
+
},
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
## Golden-Ratio Typography & Spacing
|
|
94
|
+
|
|
95
|
+
All dimensions in Vunor derive from the golden ratio (`k = 1.618`).
|
|
96
|
+
|
|
97
|
+
### Typography Scale
|
|
98
|
+
|
|
99
|
+
Font sizes, line heights, and letter spacing are computed from powers of `k`:
|
|
100
|
+
|
|
101
|
+
| Name | Size | Weight | Bold | Line Height |
|
|
102
|
+
|------|------|--------|------|-------------|
|
|
103
|
+
| `h1` | k^3.5 | 400 | 700 | k^0.5 |
|
|
104
|
+
| `h2` | k^2.5 | 400 | 700 | k^0.5 |
|
|
105
|
+
| `h3` | k^2 | 400 | 700 | k^0.5 |
|
|
106
|
+
| `h4` | k^1 | 400 | 600 | k^0.5 |
|
|
107
|
+
| `h5` | k^0.5 | 400 | 600 | k^0.5 |
|
|
108
|
+
| `h6` | k^0.25 | 600 | 700 | k^0.5 |
|
|
109
|
+
| `body` | 1 | 400 | 600 | k^0.75 |
|
|
110
|
+
| `body-s` | k^-0.5 | 400 | 600 | k^1 |
|
|
111
|
+
| `label` | k^-0.25 | 500 | 700 | k^0.5 |
|
|
112
|
+
| `caption` | k^-0.5 | 400 | 600 | k^0.5 |
|
|
113
|
+
|
|
114
|
+
Applied as UnoCSS utilities: `text-h1`, `text-body`, `text-label`, etc. Each sets `--font-size`, `--font-bold`, `--font-corrected` (actual rendered glyph height), line-height, letter-spacing, and top/bottom trim correction CSS vars.
|
|
115
|
+
|
|
116
|
+
Every entry is individually overridable:
|
|
117
|
+
|
|
118
|
+
```ts
|
|
119
|
+
typography: {
|
|
120
|
+
h1: { size: 4, weight: 300, boldWeight: 700 },
|
|
121
|
+
body: { height: 1.75 }, // taller line-height
|
|
122
|
+
label: { weight: 600 },
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### Spacing Scale
|
|
127
|
+
|
|
128
|
+
Spacing tokens follow the same golden-ratio progression:
|
|
129
|
+
|
|
130
|
+
| Token | Scale | ~Value |
|
|
131
|
+
|-------|-------|--------|
|
|
132
|
+
| `$xxs` | 1/k^3 | 0.24em |
|
|
133
|
+
| `$xs` | 1/k^2 | 0.38em |
|
|
134
|
+
| `$s` | 1/k | 0.62em |
|
|
135
|
+
| `$m` | 1 | 1em |
|
|
136
|
+
| `$l` | k | 1.62em |
|
|
137
|
+
| `$xl` | k^2 | 2.62em |
|
|
138
|
+
| `$xxl` | k^3 | 4.24em |
|
|
139
|
+
|
|
140
|
+
Used as `p-$m`, `m-$l`, `gap-$s`, etc. Text-aware margin utilities (`text-mt-$m`, `text-mb-$s`) compensate for line-height to maintain optically correct spacing.
|
|
141
|
+
|
|
142
|
+
### Other Derived Values
|
|
143
|
+
|
|
144
|
+
- **Border radius**: defaults to `0.618em` (1/golden-ratio), configurable via `baseRadius`
|
|
145
|
+
- **Touch targets** (`fingertip-xs` through `fingertip-xl`): sized using `sqrt(k)` progressions
|
|
146
|
+
- **Card spacing**: `card-{typography}` sets `--card-spacing` proportional to the heading's corrected size; `card-dense` switches to 0.6x
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
## Object-Driven Shortcuts
|
|
151
|
+
|
|
152
|
+
This is Vunor's approach to component styling. Instead of flat UnoCSS shortcut strings, Vunor uses **structured nested objects** where keys are variant prefixes and values are the classes to apply. This makes styles readable, deeply mergeable, and surgically overridable.
|
|
153
|
+
|
|
154
|
+
### How It Works
|
|
155
|
+
|
|
156
|
+
`defineShortcuts()` creates shortcut objects:
|
|
157
|
+
|
|
158
|
+
```ts
|
|
159
|
+
import { defineShortcuts } from 'vunor/theme'
|
|
160
|
+
|
|
161
|
+
const shortcuts = defineShortcuts({
|
|
162
|
+
// 'btn' is the shortcut name (used as a CSS class)
|
|
163
|
+
'btn': {
|
|
164
|
+
'': 'h-fingertip flex items-center', // base classes (no prefix)
|
|
165
|
+
'hover:': 'bg-current/05', // → "hover:bg-current/05"
|
|
166
|
+
'dark:': 'text-white', // → "dark:text-white"
|
|
167
|
+
'[&.btn-round]:': 'rounded-full', // → "[&.btn-round]:rounded-full"
|
|
168
|
+
},
|
|
169
|
+
})
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
Each key is a **variant prefix** that gets prepended to every class in the value. At build time, `toUnoShortcut()` flattens the object into a single UnoCSS shortcut string:
|
|
173
|
+
|
|
174
|
+
```
|
|
175
|
+
h-fingertip flex items-center hover:bg-current/05 dark:text-white [&.btn-round]:rounded-full
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
Wherever you use `class="btn"`, UnoCSS applies all those classes. The nesting is purely for readability and mergeability.
|
|
179
|
+
|
|
180
|
+
### Compound Variants
|
|
181
|
+
|
|
182
|
+
Nesting can go deeper for compound variants:
|
|
183
|
+
|
|
184
|
+
```ts
|
|
185
|
+
defineShortcuts({
|
|
186
|
+
'c8-filled': {
|
|
187
|
+
'': 'current-bg-scope-color-500 text-white rounded-base',
|
|
188
|
+
'hover:': 'current-bg-scope-color-400',
|
|
189
|
+
'dark:': {
|
|
190
|
+
'': 'text-white/90',
|
|
191
|
+
'hover:': 'current-bg-scope-color-600 border-solid',
|
|
192
|
+
// produces: "dark:text-white/90 dark:hover:current-bg-scope-color-600 dark:hover:border-solid"
|
|
193
|
+
},
|
|
194
|
+
},
|
|
195
|
+
})
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### Why Objects Instead of Strings?
|
|
199
|
+
|
|
200
|
+
**Because they merge.** When two shortcut objects define the same key, `mergeVunorShortcuts()` deep-merges them with later entries winning. This is the key to Vunor's customization model: you can surgically override a single variant of a built-in style without rewriting the whole shortcut.
|
|
201
|
+
|
|
202
|
+
For example, to make all filled buttons pill-shaped while keeping every other variant (hover, active, dark mode, disabled) intact:
|
|
203
|
+
|
|
204
|
+
```ts
|
|
205
|
+
import { vunorShortcuts, defineShortcuts } from 'vunor/theme'
|
|
206
|
+
|
|
207
|
+
const myOverrides = defineShortcuts({
|
|
208
|
+
'c8-filled': {
|
|
209
|
+
'': 'rounded-full', // only overrides base classes
|
|
210
|
+
},
|
|
211
|
+
'i8-flat': {
|
|
212
|
+
'': 'border-b-2', // only overrides base classes
|
|
213
|
+
},
|
|
214
|
+
})
|
|
215
|
+
|
|
216
|
+
export default defineConfig({
|
|
217
|
+
presets: [presetVunor()],
|
|
218
|
+
shortcuts: [vunorShortcuts(myOverrides)],
|
|
219
|
+
})
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
Your `'c8-filled'.'':` replaces only the base classes of `c8-filled`, while all its `hover:`, `dark:`, `active:` variants remain intact from the defaults. Everything flows through a single merge pipeline, producing consistent CSS passed to UnoCSS.
|
|
223
|
+
|
|
224
|
+
`vunorShortcuts()` returns the merged default shortcuts for all built-in styles (c8, i8, card, dialog, etc.). Pass your overrides as the first argument -- they take priority.
|
|
225
|
+
|
|
226
|
+
---
|
|
227
|
+
|
|
228
|
+
## Semantic CSS Classes
|
|
229
|
+
|
|
230
|
+
All visual styling uses UnoCSS class strings -- no CSS files or scoped styles. Component appearance is defined through shortcuts, rules, and CSS custom properties.
|
|
231
|
+
|
|
232
|
+
### Layers (`layer-0` .. `layer-4`)
|
|
233
|
+
|
|
234
|
+
Layers provide full background + text + icon styling that automatically adapts to light/dark mode:
|
|
235
|
+
|
|
236
|
+
```html
|
|
237
|
+
<div class="layer-0 scope-primary">
|
|
238
|
+
<!-- Light: lightest bg, dark text. Dark mode: darkest bg, light text. -->
|
|
239
|
+
<div class="layer-1">
|
|
240
|
+
<!-- One step deeper -->
|
|
241
|
+
</div>
|
|
242
|
+
</div>
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
- `layer-0` is the outermost (lightest in light mode, darkest in dark)
|
|
246
|
+
- Each subsequent layer steps progressively toward the opposite extreme
|
|
247
|
+
- Apply `scope-{color}` to set which palette the layers use
|
|
248
|
+
|
|
249
|
+
### Surfaces
|
|
250
|
+
|
|
251
|
+
Surfaces apply specific palette stops as background + text + icon:
|
|
252
|
+
|
|
253
|
+
```html
|
|
254
|
+
<div class="scope-primary surface-100">Lightly tinted</div>
|
|
255
|
+
<div class="scope-error surface-500">Bold error banner</div>
|
|
21
256
|
```
|
|
22
257
|
|
|
23
|
-
|
|
258
|
+
`surface-0` through `surface-4` map to the layer scale. `surface-50` through `surface-900` map to the main 10-step palette. Custom surfaces can be defined in `palette.surfaces`.
|
|
24
259
|
|
|
25
|
-
|
|
26
|
-
|
|
260
|
+
### Current-Color System
|
|
261
|
+
|
|
262
|
+
Fine-grained color control via CSS custom properties:
|
|
263
|
+
|
|
264
|
+
```html
|
|
265
|
+
<div class="current-bg-primary-500 bg-current text-current">
|
|
266
|
+
Colored via CSS vars
|
|
267
|
+
</div>
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
- `scope-{color}` sets `--scope-color-*` vars for a palette
|
|
271
|
+
- `current-bg-{color}-{step}` sets `--current-bg`
|
|
272
|
+
- `bg-current` / `text-current` / `icon-current` apply the current-scoped colors
|
|
273
|
+
|
|
274
|
+
### Clickable Styles (`c8`)
|
|
275
|
+
|
|
276
|
+
Button and clickable element design variants:
|
|
277
|
+
|
|
278
|
+
| Class | Description |
|
|
279
|
+
|-------|-------------|
|
|
280
|
+
| `c8-filled` | Solid background, white text |
|
|
281
|
+
| `c8-flat` | Transparent background, colored text |
|
|
282
|
+
| `c8-outlined` | Border + colored text, transparent fill |
|
|
283
|
+
| `c8-light` | Light tinted background, colored text |
|
|
284
|
+
|
|
285
|
+
Each includes hover, active, focus, and disabled states. Apply on any element alongside `scope-{color}`:
|
|
286
|
+
|
|
287
|
+
```html
|
|
288
|
+
<button class="scope-primary c8-filled">Save</button>
|
|
289
|
+
<button class="scope-error c8-flat">Cancel</button>
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
### Inputable Styles (`i8`)
|
|
293
|
+
|
|
294
|
+
Input field design variants:
|
|
295
|
+
|
|
296
|
+
| Class | Description |
|
|
297
|
+
|-------|-------------|
|
|
298
|
+
| `i8-flat` | Bottom border only (minimal) |
|
|
299
|
+
| `i8-filled` | Full border with background |
|
|
300
|
+
| `i8-round` | Pill-shaped (fully rounded) |
|
|
301
|
+
|
|
302
|
+
Common sub-shortcuts: `i8-input`, `i8-label` (floating label), `i8-hint`, `i8-prepend` / `i8-append`, `i8-before` / `i8-after`.
|
|
303
|
+
|
|
304
|
+
---
|
|
305
|
+
|
|
306
|
+
## Full Configuration Example
|
|
307
|
+
|
|
308
|
+
```ts
|
|
309
|
+
import { defineConfig } from 'unocss'
|
|
310
|
+
import { presetVunor, vunorShortcuts } from 'vunor/theme'
|
|
311
|
+
|
|
312
|
+
export default defineConfig({
|
|
313
|
+
presets: [
|
|
314
|
+
presetVunor({
|
|
315
|
+
// -- Perceptual color palette --
|
|
316
|
+
palette: {
|
|
317
|
+
colors: {
|
|
318
|
+
primary: '#6B4EFF',
|
|
319
|
+
secondary: '#FF6B4E',
|
|
320
|
+
good: '#22C55E',
|
|
321
|
+
error: {
|
|
322
|
+
color: '#DC2626',
|
|
323
|
+
vivid: { dark: 0.3, light: 0.3 },
|
|
324
|
+
saturate: { dark: -0.1, light: -0.1 },
|
|
325
|
+
},
|
|
326
|
+
},
|
|
327
|
+
lightest: 0.97,
|
|
328
|
+
darkest: 0.24,
|
|
329
|
+
layersDepth: 0.08,
|
|
330
|
+
},
|
|
331
|
+
|
|
332
|
+
// -- Golden-ratio spacing --
|
|
333
|
+
spacingFactor: 1.618,
|
|
334
|
+
|
|
335
|
+
// -- Global border radius --
|
|
336
|
+
baseRadius: '0.5em', // default: 0.618em (1/golden-ratio)
|
|
337
|
+
|
|
338
|
+
// -- Typography overrides --
|
|
339
|
+
typography: {
|
|
340
|
+
h1: { size: 4, weight: 300, boldWeight: 700 },
|
|
341
|
+
body: { height: 1.75 },
|
|
342
|
+
label: { weight: 600 },
|
|
343
|
+
},
|
|
344
|
+
|
|
345
|
+
// -- Font rendering --
|
|
346
|
+
actualFontHeightFactor: 0.76,
|
|
347
|
+
actualFontHeightTopBottomRatio: 0.5,
|
|
348
|
+
|
|
349
|
+
// -- Touch targets --
|
|
350
|
+
fingertip: {
|
|
351
|
+
xs: '1.25em',
|
|
352
|
+
s: '2em',
|
|
353
|
+
m: '3em',
|
|
354
|
+
l: '3.5em',
|
|
355
|
+
xl: '4em',
|
|
356
|
+
},
|
|
357
|
+
|
|
358
|
+
// -- Card padding multipliers --
|
|
359
|
+
cardSpacingFactor: {
|
|
360
|
+
regular: 1,
|
|
361
|
+
dense: 0.6,
|
|
362
|
+
},
|
|
363
|
+
|
|
364
|
+
// -- Layer direction --
|
|
365
|
+
layers: {
|
|
366
|
+
reverseDark: false,
|
|
367
|
+
reverseLight: false,
|
|
368
|
+
},
|
|
369
|
+
}),
|
|
370
|
+
],
|
|
371
|
+
shortcuts: [vunorShortcuts()],
|
|
372
|
+
})
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
---
|
|
376
|
+
|
|
377
|
+
## Quick Start
|
|
378
|
+
|
|
379
|
+
### Vue 3 + Vite
|
|
380
|
+
|
|
381
|
+
```bash
|
|
382
|
+
pnpm add vunor
|
|
27
383
|
```
|
|
28
384
|
|
|
29
|
-
|
|
385
|
+
**vite.config.ts**
|
|
30
386
|
|
|
31
|
-
```
|
|
32
|
-
|
|
387
|
+
```ts
|
|
388
|
+
import { defineConfig } from 'vite'
|
|
389
|
+
import vue from '@vitejs/plugin-vue'
|
|
390
|
+
import UnoCSS from 'unocss/vite'
|
|
391
|
+
import Components from 'unplugin-vue-components/vite'
|
|
392
|
+
import { VunorVueResolver } from 'vunor/vite'
|
|
393
|
+
|
|
394
|
+
export default defineConfig({
|
|
395
|
+
plugins: [
|
|
396
|
+
vue(),
|
|
397
|
+
UnoCSS(),
|
|
398
|
+
Components({
|
|
399
|
+
resolvers: [VunorVueResolver],
|
|
400
|
+
}),
|
|
401
|
+
],
|
|
402
|
+
})
|
|
33
403
|
```
|
|
404
|
+
|
|
405
|
+
**uno.config.ts**
|
|
406
|
+
|
|
407
|
+
```ts
|
|
408
|
+
import { defineConfig } from 'unocss'
|
|
409
|
+
import { presetVunor, vunorShortcuts } from 'vunor/theme'
|
|
410
|
+
|
|
411
|
+
export default defineConfig({
|
|
412
|
+
presets: [presetVunor()],
|
|
413
|
+
shortcuts: [vunorShortcuts()],
|
|
414
|
+
})
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
**main.ts**
|
|
418
|
+
|
|
419
|
+
```ts
|
|
420
|
+
import { createApp } from 'vue'
|
|
421
|
+
import '@unocss/reset/tailwind.css'
|
|
422
|
+
import 'virtual:uno.css'
|
|
423
|
+
import App from './App.vue'
|
|
424
|
+
|
|
425
|
+
createApp(App).mount('#app')
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
No `safelist` is needed. The UnoCSS preset includes a built-in extractor that detects `<VuButton>`, `<VuInput>`, etc. in your templates and automatically includes the required component CSS classes.
|
|
429
|
+
|
|
430
|
+
### Nuxt 3
|
|
431
|
+
|
|
432
|
+
```ts
|
|
433
|
+
// nuxt.config.ts
|
|
434
|
+
export default defineNuxtConfig({
|
|
435
|
+
modules: ['vunor/nuxt'],
|
|
436
|
+
})
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
The Nuxt module auto-registers all `Vu*` components.
|
|
440
|
+
|
|
441
|
+
---
|
|
442
|
+
|
|
443
|
+
## Vue Components (Optional)
|
|
444
|
+
|
|
445
|
+
Vunor ships 30+ accessible Vue 3 components built on Reka UI. All use the `Vu` prefix in templates. Auto-import via `VunorVueResolver` or the Nuxt module.
|
|
446
|
+
|
|
447
|
+
The components are consumers of the theme system described above -- they use `c8`, `i8`, layers, surfaces, and the typography scale. You can use the theme engine without any of these components, or use them as-is, or override their styles through the shortcut object system.
|
|
448
|
+
|
|
449
|
+
### Layout
|
|
450
|
+
|
|
451
|
+
| Component | Description |
|
|
452
|
+
|-----------|-------------|
|
|
453
|
+
| `VuAppLayout` | App shell with header, sidebar, footer slots |
|
|
454
|
+
| `VuCard` | Card container with typography-driven spacing |
|
|
455
|
+
| `VuCardHeader` | Card header with title and actions |
|
|
456
|
+
| `VuCardInner` | Nested card section |
|
|
457
|
+
| `VuTabs` | Tabbed content panels |
|
|
458
|
+
| `VuDialog` | Modal dialog with overlay |
|
|
459
|
+
| `VuPopover` | Floating popover anchored to a trigger |
|
|
460
|
+
|
|
461
|
+
### Form Inputs
|
|
462
|
+
|
|
463
|
+
| Component | Description |
|
|
464
|
+
|-----------|-------------|
|
|
465
|
+
| `VuInput` | Text / textarea input with floating label |
|
|
466
|
+
| `VuSelect` | Dropdown select |
|
|
467
|
+
| `VuCombobox` | Searchable dropdown with filtering |
|
|
468
|
+
| `VuCheckbox` | Checkbox with indeterminate state |
|
|
469
|
+
| `VuRadioGroup` | Radio button group |
|
|
470
|
+
| `VuSlider` | Range slider |
|
|
471
|
+
| `VuDatePicker` | Date picker with calendar popup |
|
|
472
|
+
| `VuLabel` | Form label |
|
|
473
|
+
|
|
474
|
+
### Actions
|
|
475
|
+
|
|
476
|
+
| Component | Description |
|
|
477
|
+
|-----------|-------------|
|
|
478
|
+
| `VuButton` | Button with icon, loading, and link support |
|
|
479
|
+
| `VuMenu` | Navigation / command menu |
|
|
480
|
+
| `VuMenuItem` | Menu item |
|
|
481
|
+
| `VuPagination` | Page navigation |
|
|
482
|
+
|
|
483
|
+
### Feedback
|
|
484
|
+
|
|
485
|
+
| Component | Description |
|
|
486
|
+
|-----------|-------------|
|
|
487
|
+
| `VuAppToasts` | Toast notification container |
|
|
488
|
+
| `VuProgressBar` | Progress bar |
|
|
489
|
+
| `VuLoadingIndicator` | Circular loading spinner |
|
|
490
|
+
| `VuInnerLoading` | Overlay loading within a container |
|
|
491
|
+
|
|
492
|
+
### Utility
|
|
493
|
+
|
|
494
|
+
| Component | Description |
|
|
495
|
+
|-----------|-------------|
|
|
496
|
+
| `VuIcon` | Icon display (integrates with UnoCSS icons) |
|
|
497
|
+
| `VuOverflowContainer` | Handles content overflow |
|
|
498
|
+
| `VuCalendar` | Standalone calendar grid |
|
|
499
|
+
|
|
500
|
+
## Package Exports
|
|
501
|
+
|
|
502
|
+
```
|
|
503
|
+
vunor PI composables (provide/inject helpers)
|
|
504
|
+
vunor/theme UnoCSS preset, shortcuts, palette, component classes
|
|
505
|
+
vunor/utils mergeCssClasses, useProvideInject
|
|
506
|
+
vunor/vite VunorVueResolver for unplugin-vue-components
|
|
507
|
+
vunor/nuxt Nuxt 3 module
|
|
508
|
+
vunor/{Name} Individual Vue components (e.g. vunor/Button)
|
|
509
|
+
```
|
|
510
|
+
|
|
511
|
+
## AI Agent Skills
|
|
512
|
+
|
|
513
|
+
`vunor` ships an AI agent skill for Claude Code, Cursor, Windsurf, Codex and other compatible agents.
|
|
514
|
+
The skill teaches your agent the library's APIs, patterns, and best practices — so it can help you write correct code without hallucinating.
|
|
515
|
+
|
|
516
|
+
**Install the skill into your agent:**
|
|
517
|
+
|
|
518
|
+
```bash
|
|
519
|
+
# Project-local (recommended — commits with your repo)
|
|
520
|
+
npx vunor setup-skills
|
|
521
|
+
|
|
522
|
+
# Global (available in all your projects)
|
|
523
|
+
npx vunor setup-skills --global
|
|
524
|
+
```
|
|
525
|
+
|
|
526
|
+
Restart your agent after installing. The skill is version-locked to the package — re-run after upgrading.
|
|
527
|
+
|
|
528
|
+
## License
|
|
529
|
+
|
|
530
|
+
MIT
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
type __VLS_Props = {
|
|
2
|
+
maxW?: string;
|
|
3
|
+
headerH?: string;
|
|
4
|
+
footerH?: string;
|
|
5
|
+
leftW?: string;
|
|
6
|
+
rightW?: string;
|
|
7
|
+
footer?: boolean;
|
|
8
|
+
header?: boolean;
|
|
9
|
+
left?: boolean;
|
|
10
|
+
right?: boolean;
|
|
11
|
+
headerClass?: string | Record<string, boolean>;
|
|
12
|
+
footerClass?: string | Record<string, boolean>;
|
|
13
|
+
leftClass?: string | Record<string, boolean>;
|
|
14
|
+
rightClass?: string | Record<string, boolean>;
|
|
15
|
+
mainClass?: string | Record<string, boolean>;
|
|
16
|
+
scrollTopOnChangeView?: boolean;
|
|
17
|
+
};
|
|
18
|
+
declare var __VLS_1: {}, __VLS_3: {}, __VLS_5: {}, __VLS_7: {};
|
|
19
|
+
type __VLS_Slots = {} & {
|
|
20
|
+
header?: (props: typeof __VLS_1) => any;
|
|
21
|
+
} & {
|
|
22
|
+
left?: (props: typeof __VLS_3) => any;
|
|
23
|
+
} & {
|
|
24
|
+
default?: (props: typeof __VLS_5) => any;
|
|
25
|
+
} & {
|
|
26
|
+
right?: (props: typeof __VLS_7) => any;
|
|
27
|
+
};
|
|
28
|
+
declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
|
|
29
|
+
maxW: string;
|
|
30
|
+
headerH: string;
|
|
31
|
+
footerH: string;
|
|
32
|
+
leftW: string;
|
|
33
|
+
rightW: string;
|
|
34
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
35
|
+
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
36
|
+
declare const _default: typeof __VLS_export;
|
|
37
|
+
export default _default;
|
|
38
|
+
type __VLS_WithSlots<T, S> = T & {
|
|
39
|
+
new (): {
|
|
40
|
+
$slots: S;
|
|
41
|
+
};
|
|
42
|
+
};
|
|
Binary file
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ToastProviderProps } from 'reka-ui';
|
|
2
|
+
import type { TVueCssClass } from 'vunor/utils';
|
|
3
|
+
type __VLS_Props = ToastProviderProps & {
|
|
4
|
+
class?: TVueCssClass;
|
|
5
|
+
};
|
|
6
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
|
|
7
|
+
swipeDirection: "left" | "right" | "down" | "up";
|
|
8
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
9
|
+
declare const _default: typeof __VLS_export;
|
|
10
|
+
export default _default;
|