@skaile/brand 0.5.0 → 0.7.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 +25 -0
- package/package.json +2 -1
- package/src/css/nuxt-ui.css +63 -0
- package/src/css/theme.css +30 -11
- package/src/tokens.json +9 -9
package/README.md
CHANGED
|
@@ -9,6 +9,8 @@ properties, a Tailwind preset, and brand assets (logo, icon, identity).
|
|
|
9
9
|
marketing/website surface (gradient, persona avatars, spacing/shadow scales).
|
|
10
10
|
- `@skaile/brand/theme.css` — shadcn-semantic CSS variables, light + dark, the
|
|
11
11
|
app surface (platform, store).
|
|
12
|
+
- `@skaile/brand/nuxt-ui.css` — Nuxt UI 4 bridge: imports `theme.css` and maps its variables onto
|
|
13
|
+
the semantic `--ui-*` tokens Nuxt UI components read (palette, radius, light/dark).
|
|
12
14
|
- `@skaile/brand/tailwind-preset` — Tailwind preset bound to `theme.css` vars.
|
|
13
15
|
- `@skaile/brand/tokens` — canonical `tokens.json`.
|
|
14
16
|
- `@skaile/brand/assets/*` — `skaile-logo.svg`, `skaile-icon.svg`, `favicon.svg`, `identity.md`.
|
|
@@ -23,3 +25,26 @@ properties, a Tailwind preset, and brand assets (logo, icon, identity).
|
|
|
23
25
|
// Marketing (Astro) — plain CSS asset import
|
|
24
26
|
import '@skaile/brand/brand.css'
|
|
25
27
|
```
|
|
28
|
+
```css
|
|
29
|
+
/* Nuxt UI 4 app (Tailwind v4): import AFTER "@nuxt/ui" — same specificity, source order decides */
|
|
30
|
+
@import "tailwindcss";
|
|
31
|
+
@import "@nuxt/ui";
|
|
32
|
+
@import "@skaile/brand/nuxt-ui.css"; /* includes theme.css */
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### Nuxt UI bridge (`nuxt-ui.css`)
|
|
36
|
+
|
|
37
|
+
Takes the brand palette, radius and light/dark switch into every Nuxt UI component with no
|
|
38
|
+
per-app overrides. Dark mode follows the `.dark` class Nuxt UI's color mode puts on `<html>`.
|
|
39
|
+
It replaces `@ecsplico/brand/nuxt-ui.css` with identical output; migrate by swapping the import
|
|
40
|
+
specifier and the dependency.
|
|
41
|
+
|
|
42
|
+
| Selector | Effect |
|
|
43
|
+
|---|---|
|
|
44
|
+
| `:root, .light, .dark` | `--ui-primary/secondary/success/warning/error/info`, `--ui-bg-*`, `--ui-text-*`, `--ui-border-*`, `--ui-radius` from the brand variables |
|
|
45
|
+
| `.dark .bg-inverted` | label on solid-neutral surfaces takes the dark page colour |
|
|
46
|
+
| `.dark` | `--ui-primary` switches to `--color-primary-bright`; #7300ff is ~2.3:1 on the dark page |
|
|
47
|
+
|
|
48
|
+
An app with its own dark selector (forge-common's `.forge-project-dark`) has to repeat the
|
|
49
|
+
`--ui-*` mapping under that selector, because a custom property referencing another is resolved
|
|
50
|
+
where it is declared.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@skaile/brand",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "Skaile brand: design tokens, CSS custom properties, Tailwind preset, and brand assets",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"type": "module",
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
"./tokens": "./src/tokens.json",
|
|
13
13
|
"./brand.css": "./src/css/brand.css",
|
|
14
14
|
"./theme.css": "./src/css/theme.css",
|
|
15
|
+
"./nuxt-ui.css": "./src/css/nuxt-ui.css",
|
|
15
16
|
"./tailwind-preset": "./src/tailwind-preset.ts",
|
|
16
17
|
"./assets/*": "./assets/*"
|
|
17
18
|
},
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* @skaile/brand/nuxt-ui.css: Skaile brand → Nuxt UI 4 bridge.
|
|
3
|
+
*
|
|
4
|
+
* Maps the semantic tokens Nuxt UI components read (--ui-*) onto the Skaile
|
|
5
|
+
* brand variables from ./theme.css, so every Nuxt UI component
|
|
6
|
+
* takes the brand palette, radius and light/dark switch with no per-app
|
|
7
|
+
* overrides. Nuxt UI 4 components use semantic tokens only, so overriding the
|
|
8
|
+
* semantic set is enough.
|
|
9
|
+
*
|
|
10
|
+
* Import AFTER "@nuxt/ui" (equal specificity, source order decides):
|
|
11
|
+
* @import "tailwindcss";
|
|
12
|
+
* @import "@nuxt/ui";
|
|
13
|
+
* @import "@skaile/brand/nuxt-ui.css";
|
|
14
|
+
*/
|
|
15
|
+
@import "./theme.css";
|
|
16
|
+
|
|
17
|
+
:root,
|
|
18
|
+
.light,
|
|
19
|
+
.dark {
|
|
20
|
+
--ui-primary: var(--primary);
|
|
21
|
+
--ui-secondary: var(--secondary);
|
|
22
|
+
--ui-success: var(--color-success);
|
|
23
|
+
--ui-warning: var(--color-warning);
|
|
24
|
+
--ui-error: var(--destructive);
|
|
25
|
+
--ui-info: var(--color-ai-accent); /* brand has no info colour */
|
|
26
|
+
--ui-bg: var(--background);
|
|
27
|
+
--ui-bg-muted: var(--muted);
|
|
28
|
+
--ui-bg-elevated: var(--card);
|
|
29
|
+
--ui-bg-accented: var(--accent);
|
|
30
|
+
--ui-bg-inverted: var(--foreground);
|
|
31
|
+
--ui-text: var(--foreground);
|
|
32
|
+
--ui-text-highlighted: var(--foreground);
|
|
33
|
+
--ui-text-toned: var(--foreground);
|
|
34
|
+
--ui-text-muted: var(--muted-foreground);
|
|
35
|
+
--ui-text-dimmed: var(--muted-foreground);
|
|
36
|
+
--ui-text-inverted: var(--primary-foreground);
|
|
37
|
+
--ui-border: var(--border);
|
|
38
|
+
--ui-border-muted: var(--border);
|
|
39
|
+
--ui-border-accented: var(--input);
|
|
40
|
+
--ui-border-inverted: var(--foreground);
|
|
41
|
+
--ui-radius: var(--radius);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/*
|
|
45
|
+
* `--ui-text-inverted` is the label on every solid colour (`bg-primary`, ...)
|
|
46
|
+
* AND on solid neutral (`bg-inverted`). Brand keeps the saturated #7300ff
|
|
47
|
+
* primary with a white label in dark, so the label stays white; only surfaces
|
|
48
|
+
* on `--ui-bg-inverted` (the light --foreground in dark) take the dark page
|
|
49
|
+
* colour. Descendants (alert titles, icons) inherit it.
|
|
50
|
+
*/
|
|
51
|
+
.dark .bg-inverted {
|
|
52
|
+
--ui-text-inverted: var(--background);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/*
|
|
56
|
+
* #7300ff on the dark page is ~2.3:1, too faint for the text and outlines
|
|
57
|
+
* Nuxt UI draws in `--ui-primary` (soft/outline badges, active tabs, links).
|
|
58
|
+
* Brand's dark highlight `--color-primary-bright` (#9b40ff) takes over; a
|
|
59
|
+
* white label on it stays above 4.5:1.
|
|
60
|
+
*/
|
|
61
|
+
.dark {
|
|
62
|
+
--ui-primary: var(--color-primary-bright);
|
|
63
|
+
}
|
package/src/css/theme.css
CHANGED
|
@@ -49,7 +49,10 @@
|
|
|
49
49
|
--secondary-foreground: hsl(0 0% 40%);
|
|
50
50
|
--muted: hsl(0 0% 96%);
|
|
51
51
|
--muted-foreground: hsl(0 0% 40%);
|
|
52
|
-
|
|
52
|
+
/* The hover ground for every menu item in the shell: DropdownMenuItem
|
|
53
|
+
highlights with focus:bg-accent and nothing else. At 96% it sat 1.09:1
|
|
54
|
+
from --popover and was invisible. */
|
|
55
|
+
--accent: hsl(0 0% 88%);
|
|
53
56
|
--accent-foreground: hsl(0 0% 11%);
|
|
54
57
|
--destructive: hsl(0 72.2% 50.6%);
|
|
55
58
|
--destructive-foreground: hsl(0 0% 100%);
|
|
@@ -120,13 +123,18 @@
|
|
|
120
123
|
--tab-inactive-hover: hsl(0 0% 87%);
|
|
121
124
|
/* Sampled from the design, and the one shell value both themes share. */
|
|
122
125
|
--tab-unread: #005eff;
|
|
123
|
-
|
|
124
|
-
|
|
126
|
+
/* The well has to read on the deepest ground it is mounted on, not just on
|
|
127
|
+
the header it was drawn against. At 88% it was 1.08:1 from the header and
|
|
128
|
+
1.03:1 from --sidebar, where the mode toggle sits — so the toggle had no
|
|
129
|
+
container at all. 82% sinks from both. */
|
|
130
|
+
--control-surface: hsl(0 0% 82%);
|
|
131
|
+
--control-surface-hover: hsl(0 0% 76%);
|
|
125
132
|
--control-selected: hsl(0 0% 100%);
|
|
126
133
|
/* Deliberately dimmer than --muted-foreground, and held at the 3:1 non-text
|
|
127
134
|
floor against --control-surface — the design samples about 2.3:1, and this
|
|
128
|
-
is the one place we knowingly part from it.
|
|
129
|
-
|
|
135
|
+
is the one place we knowingly part from it. It moves with the track or the
|
|
136
|
+
floor breaks — 49% falls to 2.70:1 once --control-surface sinks. */
|
|
137
|
+
--control-icon: hsl(0 0% 45%);
|
|
130
138
|
/* Stronger than --border against the same ground, because it is the only
|
|
131
139
|
line the shell has left. */
|
|
132
140
|
--content-border: hsl(0 0% 82%);
|
|
@@ -177,7 +185,10 @@
|
|
|
177
185
|
--secondary-foreground: #f5f5f5;
|
|
178
186
|
--muted: #2f2f2f;
|
|
179
187
|
--muted-foreground: #a1a1a1;
|
|
180
|
-
|
|
188
|
+
/* See the light block. It used to share #323131 with --border/--input,
|
|
189
|
+
which left the menu hover at 1.07:1; the two are unrelated roles that
|
|
190
|
+
collided by accident. This is --tab-inactive-hover, so no new grey. */
|
|
191
|
+
--accent: #4a4a4a;
|
|
181
192
|
--accent-foreground: #f5f5f5;
|
|
182
193
|
--destructive: hsl(0 84.2% 60.2%);
|
|
183
194
|
--destructive-foreground: #ffffff;
|
|
@@ -237,13 +248,21 @@
|
|
|
237
248
|
--tab-inactive-hover: #4a4a4a;
|
|
238
249
|
/* The one shell value both themes share. */
|
|
239
250
|
--tab-unread: #005eff;
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
251
|
+
/* Dark cannot sink. The well is mounted on two grounds: --background (#242424,
|
|
252
|
+
the toolbar) and --sidebar (#161515, the mode toggle). It cannot sit between
|
|
253
|
+
them without vanishing into one, and it cannot go under --sidebar — pure
|
|
254
|
+
black reaches only 1.15:1 there. So in dark the well inverts and lifts clear
|
|
255
|
+
of both. This is the grey --accent just vacated; no new grey enters.
|
|
256
|
+
Keep --popover (#2f2f2f) off this list of grounds: a control mounted inside
|
|
257
|
+
a menu would land 1.04:1 from it. None does today. */
|
|
258
|
+
--control-surface: #323131;
|
|
259
|
+
--control-surface-hover: #3e3e3e;
|
|
260
|
+
--control-selected: #484747;
|
|
243
261
|
/* Deliberately dimmer than --muted-foreground, and held at the 3:1 non-text
|
|
244
262
|
floor against --control-surface — the design samples about 2.3:1, and this
|
|
245
|
-
is the one place we knowingly part from it.
|
|
246
|
-
|
|
263
|
+
is the one place we knowingly part from it. It moves with the track or the
|
|
264
|
+
floor breaks — #666666 falls to 1.9:1 once --control-surface lifts. */
|
|
265
|
+
--control-icon: #7a7a7a;
|
|
247
266
|
/* Stronger than --border against the same ground, because it is the only
|
|
248
267
|
line the shell has left. */
|
|
249
268
|
--content-border: #3e3e3e;
|
package/src/tokens.json
CHANGED
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
"surface": "hsl(0 0% 100%)",
|
|
44
44
|
"secondary": "hsl(0 0% 96%)",
|
|
45
45
|
"muted": "hsl(0 0% 96%)",
|
|
46
|
-
"accent": "hsl(0 0%
|
|
46
|
+
"accent": "hsl(0 0% 88%)",
|
|
47
47
|
"surface-sunken": "hsl(0 0% 96%)",
|
|
48
48
|
"foreground": "hsl(0 0% 11%)",
|
|
49
49
|
"muted-foreground": "hsl(0 0% 40%)",
|
|
@@ -56,10 +56,10 @@
|
|
|
56
56
|
"tab-inactive": "hsl(0 0% 82%)",
|
|
57
57
|
"tab-inactive-hover": "hsl(0 0% 87%)",
|
|
58
58
|
"tab-unread": "#005eff",
|
|
59
|
-
"control-surface": "hsl(0 0%
|
|
60
|
-
"control-surface-hover": "hsl(0 0%
|
|
59
|
+
"control-surface": "hsl(0 0% 82%)",
|
|
60
|
+
"control-surface-hover": "hsl(0 0% 76%)",
|
|
61
61
|
"control-selected": "hsl(0 0% 100%)",
|
|
62
|
-
"control-icon": "hsl(0 0%
|
|
62
|
+
"control-icon": "hsl(0 0% 45%)",
|
|
63
63
|
"content-border": "hsl(0 0% 82%)",
|
|
64
64
|
"sidebar-foreground": "hsl(0 0% 11%)",
|
|
65
65
|
"sidebar-primary": "hsl(267 100% 50%)",
|
|
@@ -78,7 +78,7 @@
|
|
|
78
78
|
"surface": "#2f2f2f",
|
|
79
79
|
"secondary": "#2f2f2f",
|
|
80
80
|
"muted": "#2f2f2f",
|
|
81
|
-
"accent": "#
|
|
81
|
+
"accent": "#4a4a4a",
|
|
82
82
|
"surface-sunken": "#161515",
|
|
83
83
|
"foreground": "#f5f5f5",
|
|
84
84
|
"muted-foreground": "#a1a1a1",
|
|
@@ -91,10 +91,10 @@
|
|
|
91
91
|
"tab-inactive": "#3e3e3e",
|
|
92
92
|
"tab-inactive-hover": "#4a4a4a",
|
|
93
93
|
"tab-unread": "#005eff",
|
|
94
|
-
"control-surface": "#
|
|
95
|
-
"control-surface-hover": "#
|
|
96
|
-
"control-selected": "#
|
|
97
|
-
"control-icon": "#
|
|
94
|
+
"control-surface": "#323131",
|
|
95
|
+
"control-surface-hover": "#3e3e3e",
|
|
96
|
+
"control-selected": "#484747",
|
|
97
|
+
"control-icon": "#7a7a7a",
|
|
98
98
|
"content-border": "#3e3e3e",
|
|
99
99
|
"sidebar-foreground": "#f5f5f5",
|
|
100
100
|
"sidebar-primary": "#7300ff",
|