@apliteni/apliteni-ui 0.12.0 → 0.23.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.
- package/package.json +1 -1
- package/react/dist/index.css +19 -0
- package/react/dist/index.d.ts +43 -2
- package/react/dist/index.js +98 -6
- package/src/assets/icons.js +5 -26
- package/src/components/account-nav.js +1 -1
- package/src/components/confirm.js +27 -28
- package/src/components/drawer.js +27 -28
- package/src/components/dropdown.js +26 -23
- package/src/components/index.js +9 -13
- package/src/components/loading.js +126 -0
- package/src/components/nav.js +7 -20
- package/src/components/overlay.js +7 -16
- package/src/components/shell.js +10 -9
- package/src/components/success.js +8 -17
- package/src/components/topbar.js +8 -12
- package/src/index.css +6 -1
- package/src/index.js +1 -0
- package/src/inline.js +4 -0
- package/src/styles/badge.css +1 -1
- package/src/styles/base.css +5 -18
- package/src/styles/button.css +18 -5
- package/src/styles/callout.css +37 -26
- package/src/styles/card.css +1 -1
- package/src/styles/code.css +7 -1
- package/src/styles/confirm.css +10 -13
- package/src/styles/drawer.css +9 -6
- package/src/styles/dropdown.css +14 -7
- package/src/styles/empty.css +1 -1
- package/src/styles/feedback.css +25 -16
- package/src/styles/footer.css +15 -6
- package/src/styles/input.css +28 -2
- package/src/styles/layout.css +14 -10
- package/src/styles/loading.css +129 -0
- package/src/styles/motion.css +21 -39
- package/src/styles/nav.css +14 -12
- package/src/styles/reduced-motion.css +21 -0
- package/src/styles/success.css +8 -8
- package/src/styles/table.css +20 -17
- package/src/styles/topbar.css +27 -12
- package/src/tokens/accents.css +10 -14
- package/src/tokens/tokens.css +95 -22
package/src/styles/motion.css
CHANGED
|
@@ -1,24 +1,19 @@
|
|
|
1
|
-
/*
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
* A small, token-driven, framework-agnostic motion system: reusable entrance,
|
|
5
|
-
* micro-interaction, attention, and scroll-reveal effects as plain classes.
|
|
6
|
-
* Every timing reads the brand motion vocabulary (--duration-* / --easing-*,
|
|
7
|
-
* synced from design-system) so motion re-themes and stays consistent.
|
|
1
|
+
/* apliteni-ui — motion library. Reusable entrance, micro-interaction, attention
|
|
2
|
+
* and scroll-reveal effects as plain classes, every timing reading the brand
|
|
3
|
+
* motion vocabulary.
|
|
8
4
|
*
|
|
9
5
|
* Per-effect overrides via custom properties on the element:
|
|
10
|
-
* --m-dur
|
|
11
|
-
* --m-
|
|
12
|
-
*
|
|
13
|
-
*
|
|
6
|
+
* --m-dur duration --m-ease timing function
|
|
7
|
+
* --m-delay start delay --m-dist slide travel (default 16px)
|
|
8
|
+
*
|
|
9
|
+
* Scroll reveals need `initReveal()` from apliteni-ui/motion. Without JS,
|
|
10
|
+
* [data-reveal] content stays fully visible.
|
|
14
11
|
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
12
|
+
* The global prefers-reduced-motion net lives in reduced-motion.css and is NOT
|
|
13
|
+
* @imported from here — the icon gates read each stylesheet on its own and
|
|
14
|
+
* refuse a sheet that pulls in another.
|
|
18
15
|
*
|
|
19
|
-
*
|
|
20
|
-
* the above — plus any component animation in the kit — as the safety net.
|
|
21
|
-
* ========================================================================== */
|
|
16
|
+
* why: docs/specification.md#motion */
|
|
22
17
|
|
|
23
18
|
/* -- Entrances -------------------------------------------------------------
|
|
24
19
|
* `both` fill so the element starts at the "from" frame (hidden) and holds
|
|
@@ -31,7 +26,7 @@
|
|
|
31
26
|
.m-scale-in,
|
|
32
27
|
.m-blur-in {
|
|
33
28
|
animation-duration: var(--m-dur, var(--dur-slow));
|
|
34
|
-
animation-timing-function: var(--m-ease, var(--
|
|
29
|
+
animation-timing-function: var(--m-ease, var(--ease-out));
|
|
35
30
|
animation-delay: var(--m-delay, 0s);
|
|
36
31
|
animation-fill-mode: both;
|
|
37
32
|
}
|
|
@@ -78,7 +73,7 @@
|
|
|
78
73
|
box-shadow: var(--shadow-md);
|
|
79
74
|
}
|
|
80
75
|
.m-press {
|
|
81
|
-
transition: transform var(--
|
|
76
|
+
transition: transform var(--dur-instant) var(--ease-sharp);
|
|
82
77
|
}
|
|
83
78
|
.m-press:active { transform: scale(0.97); }
|
|
84
79
|
|
|
@@ -100,12 +95,12 @@
|
|
|
100
95
|
color-mix(in srgb, var(--text) 12%, transparent),
|
|
101
96
|
transparent
|
|
102
97
|
);
|
|
103
|
-
animation: m-shimmer var(--duration-crawl, 1s)
|
|
98
|
+
animation: m-shimmer var(--duration-crawl, 1s) linear infinite; /* motion: ambient — a skeleton sweeps while the data is away */
|
|
104
99
|
}
|
|
105
100
|
@keyframes m-shimmer { to { transform: translateX(100%); } }
|
|
106
101
|
|
|
107
102
|
/* -- Attention ------------------------------------------------------------- */
|
|
108
|
-
.m-pulse { animation: m-pulse 2s var(--ease) infinite; }
|
|
103
|
+
.m-pulse { animation: m-pulse 2s var(--ease) infinite; } /* motion: ambient — attention loop with no interaction origin */
|
|
109
104
|
@keyframes m-pulse {
|
|
110
105
|
0%, 100% { transform: scale(1); opacity: 1; }
|
|
111
106
|
50% { transform: scale(1.04); opacity: 0.86; }
|
|
@@ -126,7 +121,7 @@
|
|
|
126
121
|
.m-draw [data-draw] {
|
|
127
122
|
stroke-dasharray: var(--m-len, 48);
|
|
128
123
|
stroke-dashoffset: var(--m-len, 48);
|
|
129
|
-
animation: m-draw var(--dur-slow) var(--
|
|
124
|
+
animation: m-draw var(--dur-slow) var(--ease-out) forwards;
|
|
130
125
|
animation-delay: var(--m-delay, 0s);
|
|
131
126
|
}
|
|
132
127
|
@keyframes m-draw { to { stroke-dashoffset: 0; } }
|
|
@@ -140,8 +135,8 @@
|
|
|
140
135
|
opacity: 0;
|
|
141
136
|
transform: translateY(18px);
|
|
142
137
|
transition:
|
|
143
|
-
opacity var(--dur-slow) var(--
|
|
144
|
-
transform var(--dur-slow) var(--
|
|
138
|
+
opacity var(--dur-slow) var(--ease-out),
|
|
139
|
+
transform var(--dur-slow) var(--ease-out);
|
|
145
140
|
transition-delay: calc(var(--reveal-i, 0) * var(--delay-2));
|
|
146
141
|
}
|
|
147
142
|
.js-reveal [data-reveal].is-revealed {
|
|
@@ -149,18 +144,5 @@
|
|
|
149
144
|
transform: none;
|
|
150
145
|
}
|
|
151
146
|
|
|
152
|
-
/*
|
|
153
|
-
*
|
|
154
|
-
* component motion (button loader, badge pulse, feedback check), and smooth
|
|
155
|
-
* scroll. iteration-count:1 lets one-shot animations settle on their final
|
|
156
|
-
* frame (e.g. a checkmark stays drawn) instead of snapping to the start. */
|
|
157
|
-
@media (prefers-reduced-motion: reduce) {
|
|
158
|
-
html { scroll-behavior: auto !important; }
|
|
159
|
-
*, ::before, ::after {
|
|
160
|
-
animation-duration: 0.01ms !important;
|
|
161
|
-
animation-iteration-count: 1 !important;
|
|
162
|
-
transition-duration: 0.01ms !important;
|
|
163
|
-
scroll-behavior: auto !important;
|
|
164
|
-
}
|
|
165
|
-
[data-reveal] { opacity: 1 !important; transform: none !important; }
|
|
166
|
-
}
|
|
147
|
+
/* The global reduced-motion net lives in reduced-motion.css, imported beside this
|
|
148
|
+
* file from src/index.css — it has to reach the React bundle as well. */
|
package/src/styles/nav.css
CHANGED
|
@@ -44,9 +44,9 @@
|
|
|
44
44
|
cursor: pointer;
|
|
45
45
|
text-align: left;
|
|
46
46
|
font-family: inherit;
|
|
47
|
-
transition: background
|
|
47
|
+
transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
|
|
48
48
|
}
|
|
49
|
-
.ui-nav .ui-nav__item { color: var(--text); } /* (0,2,0): a host sheet's a:link is (0,1,1) — why: docs/
|
|
49
|
+
.ui-nav .ui-nav__item { color: var(--text); } /* (0,2,0): a host sheet's a:link is (0,1,1) — why: docs/specification.md#the-page-shell */
|
|
50
50
|
.ui-nav__item:hover { background: var(--surface-2); color: var(--strong); }
|
|
51
51
|
.ui-nav__item.is-active {
|
|
52
52
|
background: var(--surface-3);
|
|
@@ -70,7 +70,7 @@
|
|
|
70
70
|
.ui-nav__item.is-active:focus-visible { box-shadow: var(--ring); }
|
|
71
71
|
|
|
72
72
|
.ui-nav__ic { display: inline-flex; flex: none; }
|
|
73
|
-
.ui-nav__ic svg { width: 17px; height: 17px; stroke: currentColor; fill: none; stroke-width:
|
|
73
|
+
.ui-nav__ic svg { width: 17px; height: 17px; stroke: currentColor; fill: none; stroke-width: 2.2; opacity: 0.72; }
|
|
74
74
|
.ui-nav__item.is-active .ui-nav__ic svg,
|
|
75
75
|
.ui-nav__item.is-current .ui-nav__ic svg { opacity: 1; stroke: var(--accent); }
|
|
76
76
|
.ui-nav__label { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
@@ -82,7 +82,9 @@
|
|
|
82
82
|
/* Tabbing onto it is the same "about to click this" the pointer means. The ring
|
|
83
83
|
says where you are; only this says what the row does. */
|
|
84
84
|
.ui-nav__item.is-danger:focus-visible { background: var(--glow-pink); color: var(--pink); }
|
|
85
|
-
|
|
85
|
+
/* A row that is off. No opacity: the label was already --muted and the fade
|
|
86
|
+
only pulled it toward the rail behind it (#220). */
|
|
87
|
+
.ui-nav__item.is-disabled { color: var(--disabled-ink); cursor: default; pointer-events: none; }
|
|
86
88
|
|
|
87
89
|
/* The current row under the pointer. It rests on --surface-3, which is also what
|
|
88
90
|
a resting row hovers to, so the one row with no hover response was the row the
|
|
@@ -123,7 +125,7 @@
|
|
|
123
125
|
4.08 in dark Nebula, where the flat surface reads 4.92 — and no alpha reaches
|
|
124
126
|
it, the largest that clears being 0.06 in dark Nebula and 0.02 in light
|
|
125
127
|
Emerald. So the accent wash is painted on a base surface, never a raised one.
|
|
126
|
-
See #157 and docs/
|
|
128
|
+
See #157 and docs/specification.md#colour-and-contrast. */
|
|
127
129
|
.ui-nav__item.is-active .ui-nav__badge.is-accent { background: var(--surface-3); color: var(--accent); }
|
|
128
130
|
|
|
129
131
|
/* Collapsible group */
|
|
@@ -134,7 +136,7 @@
|
|
|
134
136
|
border-right: 1.6px solid var(--muted);
|
|
135
137
|
border-bottom: 1.6px solid var(--muted);
|
|
136
138
|
transform: rotate(-45deg);
|
|
137
|
-
transition: transform
|
|
139
|
+
transition: transform var(--dur-fast) var(--ease);
|
|
138
140
|
}
|
|
139
141
|
.ui-nav__group.is-open > .ui-nav__toggle .ui-nav__caret { transform: rotate(45deg); }
|
|
140
142
|
.ui-nav__sub {
|
|
@@ -165,7 +167,7 @@
|
|
|
165
167
|
.ui-nav--side.is-collapsed .ui-nav__caret,
|
|
166
168
|
.ui-nav--side.is-collapsed .ui-nav__sub { display: none; }
|
|
167
169
|
.ui-nav--side.is-collapsed .ui-nav__item { justify-content: center; padding: 11px 0; gap: 0; }
|
|
168
|
-
.ui-nav--side.is-collapsed .ui-nav__ic svg { width: 19px; height: 19px; }
|
|
170
|
+
.ui-nav--side.is-collapsed .ui-nav__ic svg { width: 19px; height: 19px; stroke-width: 2; }
|
|
169
171
|
.ui-nav--side.is-collapsed .ui-nav__item.is-active::before { left: 3px; }
|
|
170
172
|
.ui-nav--side.is-collapsed .ui-nav__foot { text-align: center; }
|
|
171
173
|
|
|
@@ -188,7 +190,7 @@
|
|
|
188
190
|
font-size: 14px;
|
|
189
191
|
font-weight: 500;
|
|
190
192
|
border-radius: 10px 10px 0 0;
|
|
191
|
-
transition: color
|
|
193
|
+
transition: color var(--dur-fast) var(--ease), background var(--dur-fast) var(--ease);
|
|
192
194
|
}
|
|
193
195
|
.ui-nav__tab:hover { color: var(--strong); }
|
|
194
196
|
.ui-nav__tab:focus-visible { outline: none; box-shadow: var(--ring); border-radius: 8px; }
|
|
@@ -204,7 +206,7 @@
|
|
|
204
206
|
background: var(--accent);
|
|
205
207
|
opacity: 0;
|
|
206
208
|
transform: scaleX(0.4);
|
|
207
|
-
transition: opacity
|
|
209
|
+
transition: opacity var(--dur-fast) var(--ease), transform var(--dur-fast) var(--ease);
|
|
208
210
|
}
|
|
209
211
|
.ui-nav--tabs.is-underline .ui-nav__tab.is-active::after { opacity: 1; transform: scaleX(1); }
|
|
210
212
|
|
|
@@ -216,7 +218,7 @@
|
|
|
216
218
|
color: var(--accent);
|
|
217
219
|
}
|
|
218
220
|
|
|
219
|
-
.ui-nav__tab.is-disabled { color: var(--
|
|
221
|
+
.ui-nav__tab.is-disabled { color: var(--disabled-ink); cursor: default; }
|
|
220
222
|
.ui-nav__tab .ui-nav__badge { height: 18px; }
|
|
221
223
|
|
|
222
224
|
/* -- Breadcrumbs --------------------------------------------------------- */
|
|
@@ -239,7 +241,7 @@
|
|
|
239
241
|
border-radius: 7px;
|
|
240
242
|
text-decoration: none;
|
|
241
243
|
font-size: 13px;
|
|
242
|
-
transition: color
|
|
244
|
+
transition: color var(--dur-fast) var(--ease), background var(--dur-fast) var(--ease);
|
|
243
245
|
}
|
|
244
246
|
/* Carries the block's class as well as its own, for the reason .ui-nav__item
|
|
245
247
|
does above: a linked crumb is an <a>, and a host stylesheet's `a:link` is
|
|
@@ -248,4 +250,4 @@
|
|
|
248
250
|
a.ui-nav__crumb:hover { color: var(--strong); background: var(--surface-2); }
|
|
249
251
|
a.ui-nav__crumb:focus-visible { outline: none; box-shadow: var(--ring); }
|
|
250
252
|
.ui-nav__crumb.is-current { color: var(--strong); font-weight: 500; }
|
|
251
|
-
.ui-nav__crumb .ui-nav__ic svg { width: 15px; height: 15px; stroke: currentColor; fill: none; stroke-width:
|
|
253
|
+
.ui-nav__crumb .ui-nav__ic svg { width: 15px; height: 15px; stroke: currentColor; fill: none; stroke-width: 2.5; }
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/* apliteni-ui — reduced-motion net. One file, because it has to reach every
|
|
2
|
+
* bundle the kit publishes and a second copy would drift; a consumer who imports
|
|
3
|
+
* both bundles gets it twice, which costs nothing, since every rule here is
|
|
4
|
+
* idempotent and `!important`.
|
|
5
|
+
*
|
|
6
|
+
* `iteration-count: 1` lets one-shot animations settle on their final frame — a
|
|
7
|
+
* checkmark stays drawn — instead of snapping back to the start.
|
|
8
|
+
*
|
|
9
|
+
* why: docs/specification.md#reduced-motion-travels-with-the-stylesheet
|
|
10
|
+
* why: docs/specification.md#motion */
|
|
11
|
+
|
|
12
|
+
@media (prefers-reduced-motion: reduce) {
|
|
13
|
+
html { scroll-behavior: auto !important; }
|
|
14
|
+
*, ::before, ::after {
|
|
15
|
+
animation-duration: 0.01ms !important;
|
|
16
|
+
animation-iteration-count: 1 !important;
|
|
17
|
+
transition-duration: 0.01ms !important;
|
|
18
|
+
scroll-behavior: auto !important;
|
|
19
|
+
}
|
|
20
|
+
[data-reveal] { opacity: 1 !important; transform: none !important; }
|
|
21
|
+
}
|
package/src/styles/success.css
CHANGED
|
@@ -35,13 +35,13 @@
|
|
|
35
35
|
.ui-sx__glow--a {
|
|
36
36
|
width: 58%; top: -14%; left: 50%; translate: -50% 0;
|
|
37
37
|
background: radial-gradient(circle at center, var(--sx-tint), transparent 68%);
|
|
38
|
-
animation: ui-sx-float 14s ease-in-out infinite alternate;
|
|
38
|
+
animation: ui-sx-float 14s ease-in-out infinite alternate; /* motion: ambient — a background glow that drifts on its own clock; `alternate` needs a symmetric curve, which var(--ease) is not */
|
|
39
39
|
}
|
|
40
40
|
.ui-sx__glow--b {
|
|
41
41
|
width: 52%; bottom: -20%; left: 12%;
|
|
42
42
|
background: radial-gradient(circle at center,
|
|
43
43
|
color-mix(in srgb, var(--accent) 30%, transparent), transparent 68%);
|
|
44
|
-
animation: ui-sx-float 18s ease-in-out -6s infinite alternate;
|
|
44
|
+
animation: ui-sx-float 18s ease-in-out -6s infinite alternate; /* motion: ambient — the second glow, offset in period and phase so the pair never lines up */
|
|
45
45
|
}
|
|
46
46
|
:root[data-theme="light"] .ui-sx__glow { opacity: 0.7; }
|
|
47
47
|
@keyframes ui-sx-float {
|
|
@@ -63,7 +63,7 @@
|
|
|
63
63
|
letter-spacing: -.02em; line-height: 1.2; margin: 0;
|
|
64
64
|
}
|
|
65
65
|
.ui-sx__body {
|
|
66
|
-
color: var(--dim); font-size: 14.5px; line-height: 1.6; margin: 9px 0 0; max-width:
|
|
66
|
+
color: var(--dim); font-size: 14.5px; line-height: 1.6; margin: 9px 0 0; max-width: var(--prose-caption);
|
|
67
67
|
}
|
|
68
68
|
.ui-sx__actions { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 20px; }
|
|
69
69
|
|
|
@@ -104,21 +104,21 @@
|
|
|
104
104
|
/* Soft tinted disc that springs in behind the tick. */
|
|
105
105
|
.ui-sx__disc {
|
|
106
106
|
fill: var(--sx-tint); stroke: var(--sx-track); stroke-width: 1.5;
|
|
107
|
-
transform-origin: center; animation: ui-sx-pop .5s cubic-bezier(.22,1,.3,1) both;
|
|
107
|
+
transform-origin: center; animation: ui-sx-pop .5s cubic-bezier(.22,1,.3,1) both; /* motion: choreographed — first beat of the check: disc, then tick at .28s, then ring at .2s */
|
|
108
108
|
}
|
|
109
109
|
/* The tick, stroked on via dash-offset (path length ~34). */
|
|
110
110
|
.ui-sx__tick {
|
|
111
111
|
fill: none; stroke: var(--sx-green); stroke-width: 5;
|
|
112
112
|
stroke-linecap: round; stroke-linejoin: round;
|
|
113
113
|
stroke-dasharray: 34; stroke-dashoffset: 34;
|
|
114
|
-
animation: ui-sx-draw .5s cubic-bezier(.6,0,.35,1) .28s forwards;
|
|
114
|
+
animation: ui-sx-draw .5s cubic-bezier(.6,0,.35,1) .28s forwards; /* motion: choreographed — the tick draws while the disc is still settling */
|
|
115
115
|
filter: drop-shadow(0 0 5px color-mix(in srgb, var(--green) 55%, transparent));
|
|
116
116
|
}
|
|
117
117
|
/* Burst ring that expands and fades once, framing the moment. */
|
|
118
118
|
.ui-sx__ring {
|
|
119
119
|
fill: none; stroke: var(--sx-green); stroke-width: 2;
|
|
120
120
|
transform-origin: center; opacity: 0;
|
|
121
|
-
animation: ui-sx-burst .7s cubic-bezier(.3,.7,.4,1) .2s forwards;
|
|
121
|
+
animation: ui-sx-burst .7s cubic-bezier(.3,.7,.4,1) .2s forwards; /* motion: choreographed — the ring outlives the tick so the moment ends on the frame */
|
|
122
122
|
}
|
|
123
123
|
|
|
124
124
|
@keyframes ui-sx-pop {
|
|
@@ -137,7 +137,7 @@
|
|
|
137
137
|
.ui-sx__piece {
|
|
138
138
|
position: absolute; top: -8%; width: 8px; height: 8px; border-radius: 2px;
|
|
139
139
|
opacity: 0; transform-origin: center;
|
|
140
|
-
animation: ui-sx-fall 2.4s cubic-bezier(.2,.6,.35,1) var(--sx-d, 0s) forwards;
|
|
140
|
+
animation: ui-sx-fall 2.4s cubic-bezier(.2,.6,.35,1) var(--sx-d, 0s) forwards; /* motion: ambient — fall time is set by the height of the panel, not by an interaction */
|
|
141
141
|
scale: var(--sx-s, 1);
|
|
142
142
|
}
|
|
143
143
|
.ui-sx__piece--a { background: var(--accent); }
|
|
@@ -162,7 +162,7 @@
|
|
|
162
162
|
background: conic-gradient(var(--green) var(--sx-a, 360deg), var(--surface-2) 0);
|
|
163
163
|
mask: radial-gradient(circle, transparent 5px, #000 6px);
|
|
164
164
|
-webkit-mask: radial-gradient(circle, transparent 5px, #000 6px);
|
|
165
|
-
animation: ui-sx-sweep var(--sx-secs, 5s) linear forwards;
|
|
165
|
+
animation: ui-sx-sweep var(--sx-secs, 5s) linear forwards; /* motion: ambient — the caller sets the countdown; the ring just spends it */
|
|
166
166
|
}
|
|
167
167
|
@keyframes ui-sx-sweep { from { --sx-a: 360deg; } to { --sx-a: 0deg; } }
|
|
168
168
|
.ui-sx__count-text { color: var(--muted); font-size: 13px; }
|
package/src/styles/table.css
CHANGED
|
@@ -15,11 +15,11 @@
|
|
|
15
15
|
text-transform: uppercase;
|
|
16
16
|
color: var(--muted);
|
|
17
17
|
font-weight: var(--weight-semibold);
|
|
18
|
-
padding: 0
|
|
18
|
+
padding: 0 var(--space-4) var(--space-3) 0;
|
|
19
19
|
border-bottom: 1px solid var(--border);
|
|
20
20
|
}
|
|
21
21
|
.ui-table td {
|
|
22
|
-
padding:
|
|
22
|
+
padding: var(--space-4) var(--space-4) var(--space-4) 0;
|
|
23
23
|
border-bottom: 1px solid var(--border);
|
|
24
24
|
color: var(--dim);
|
|
25
25
|
vertical-align: middle;
|
|
@@ -39,11 +39,13 @@
|
|
|
39
39
|
* continuous while letting the row ends round; table padding (which only applies
|
|
40
40
|
* in the separate model) insets the rows so the fill clears the container edge.
|
|
41
41
|
* Zebra tables keep the original full-bleed tint (finance ledger), so they're
|
|
42
|
-
* excluded here — their hover rule lives further down.
|
|
42
|
+
* excluded here — their hover rule lives further down.
|
|
43
|
+
* The inset was 6px, which is a tie between --space-1 and --space-2; it rounds
|
|
44
|
+
* up, because what it buys is clearance and clearance rounds away from the edge. */
|
|
43
45
|
.ui-table--hover:not(.ui-table--zebra) {
|
|
44
46
|
border-collapse: separate;
|
|
45
47
|
border-spacing: 0;
|
|
46
|
-
padding: 0
|
|
48
|
+
padding: 0 var(--space-2);
|
|
47
49
|
}
|
|
48
50
|
.ui-table--hover:not(.ui-table--zebra) tbody tr:hover td { background: var(--surface-2); }
|
|
49
51
|
.ui-table--hover:not(.ui-table--zebra) tbody tr:hover td:first-child {
|
|
@@ -51,19 +53,20 @@
|
|
|
51
53
|
.ui-table--hover:not(.ui-table--zebra) tbody tr:hover td:last-child {
|
|
52
54
|
border-top-right-radius: var(--radius-sm); border-bottom-right-radius: var(--radius-sm); }
|
|
53
55
|
|
|
54
|
-
/*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
* Cell helpers: .ui-table__num (right, tabular), .ui-table__code
|
|
60
|
-
*
|
|
61
|
-
|
|
62
|
-
.ui-table--dense
|
|
56
|
+
/* Data-table modifiers, composable: .ui-table--dense --zebra --hover.
|
|
57
|
+
* --dense --space-3 across, --space-2 down — one step in from the base
|
|
58
|
+
* table, and both round DOWN, because the modifier exists to fit
|
|
59
|
+
* more rows and rounding up spends the distinction it is for.
|
|
60
|
+
* --zebra row striping; 2px header rule; the hover tint out-ranks the stripe
|
|
61
|
+
* Cell helpers: .ui-table__num (right, tabular), .ui-table__code.
|
|
62
|
+
* why: docs/specification.md#spacing-and-rhythm
|
|
63
|
+
* held by: stories/table-rhythm.test.js */
|
|
64
|
+
.ui-table--dense th { padding: 0 var(--space-3) var(--space-2) 0; }
|
|
65
|
+
.ui-table--dense td { padding: var(--space-2) var(--space-3); font-size: var(--text-sm); white-space: nowrap; }
|
|
63
66
|
.ui-table--dense th:first-child,
|
|
64
|
-
.ui-table--dense td:first-child { padding-left:
|
|
67
|
+
.ui-table--dense td:first-child { padding-left: var(--space-3); }
|
|
65
68
|
.ui-table--dense th:last-child,
|
|
66
|
-
.ui-table--dense td:last-child { padding-right:
|
|
69
|
+
.ui-table--dense td:last-child { padding-right: var(--space-3); }
|
|
67
70
|
|
|
68
71
|
.ui-table--zebra th { border-bottom-width: 2px; }
|
|
69
72
|
.ui-table--zebra td { border-bottom: 0; }
|
|
@@ -78,9 +81,9 @@
|
|
|
78
81
|
* checkboxes sat flush against the tint with a measured 0px gap.
|
|
79
82
|
* Header and body are inset together, or the columns stop lining up. */
|
|
80
83
|
.ui-table--zebra th:first-child,
|
|
81
|
-
.ui-table--zebra td:first-child { padding-left:
|
|
84
|
+
.ui-table--zebra td:first-child { padding-left: var(--space-3); }
|
|
82
85
|
.ui-table--zebra th:last-child,
|
|
83
|
-
.ui-table--zebra td:last-child { padding-right:
|
|
86
|
+
.ui-table--zebra td:last-child { padding-right: var(--space-3); }
|
|
84
87
|
.ui-table--zebra.ui-table--hover tbody tr:hover td,
|
|
85
88
|
.ui-table--zebra tbody tr:hover td { background: color-mix(in srgb, var(--accent) 8%, transparent); }
|
|
86
89
|
|
package/src/styles/topbar.css
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
}
|
|
15
15
|
.topbar__in {
|
|
16
16
|
width: 100%;
|
|
17
|
-
max-width:
|
|
17
|
+
max-width: var(--container);
|
|
18
18
|
margin: 0 auto;
|
|
19
19
|
padding: 0 clamp(14px, 2.4vw, 26px);
|
|
20
20
|
display: flex;
|
|
@@ -59,7 +59,7 @@
|
|
|
59
59
|
color: var(--muted);
|
|
60
60
|
padding: 4px 13px;
|
|
61
61
|
border-radius: 24px;
|
|
62
|
-
transition: color
|
|
62
|
+
transition: color var(--dur-fast) var(--ease), background var(--dur-fast) var(--ease);
|
|
63
63
|
}
|
|
64
64
|
.dtsw a:hover { color: var(--text); }
|
|
65
65
|
.dtsw a.cur { color: var(--strong); background: var(--surface); box-shadow: var(--shadow-sm); }
|
|
@@ -75,11 +75,14 @@
|
|
|
75
75
|
color: var(--text);
|
|
76
76
|
border: 1px solid var(--border);
|
|
77
77
|
border-radius: 10px;
|
|
78
|
-
transition:
|
|
78
|
+
transition:
|
|
79
|
+
transform var(--dur-fast) var(--ease),
|
|
80
|
+
background var(--dur-fast) var(--ease),
|
|
81
|
+
border-color var(--dur-fast) var(--ease);
|
|
79
82
|
}
|
|
80
83
|
.toggle:hover { transform: translateY(-1px); border-color: var(--border-strong); }
|
|
81
84
|
.toggle .ic { width: 17px; height: 17px; display: inline-block; color: var(--accent); }
|
|
82
|
-
.toggle .ic svg { display: block; width: 100%; height: 100%; }
|
|
85
|
+
.toggle .ic svg { display: block; width: 100%; height: 100%; stroke-width: 2.2; }
|
|
83
86
|
|
|
84
87
|
/* Version switcher */
|
|
85
88
|
.vsw { position: relative; }
|
|
@@ -96,7 +99,7 @@
|
|
|
96
99
|
border: 1px solid var(--border);
|
|
97
100
|
border-radius: 24px;
|
|
98
101
|
padding: 7px 11px 7px 13px;
|
|
99
|
-
transition: border-color
|
|
102
|
+
transition: border-color var(--dur-fast) var(--ease), background var(--dur-fast) var(--ease);
|
|
100
103
|
}
|
|
101
104
|
.vsw__btn:hover { border-color: var(--accent); }
|
|
102
105
|
.vsw__btn .lbl { color: var(--muted); }
|
|
@@ -106,7 +109,7 @@
|
|
|
106
109
|
border-right: 1.6px solid var(--muted);
|
|
107
110
|
border-bottom: 1.6px solid var(--muted);
|
|
108
111
|
transform: rotate(45deg) translateY(-1px);
|
|
109
|
-
transition: transform
|
|
112
|
+
transition: transform var(--dur-fast) var(--ease);
|
|
110
113
|
}
|
|
111
114
|
.vsw.open .vsw__btn .car { transform: rotate(-135deg) translateY(2px); }
|
|
112
115
|
.vsw__menu {
|
|
@@ -122,7 +125,13 @@
|
|
|
122
125
|
opacity: 0;
|
|
123
126
|
visibility: hidden;
|
|
124
127
|
transform: translateY(-6px);
|
|
125
|
-
transition: 0.18s
|
|
128
|
+
/* Named properties, not the bare shorthand: `transition: 0.18s` is `all`, and `all`
|
|
129
|
+
includes visibility — held at the OLD value for the whole duration, so the menu is
|
|
130
|
+
still `hidden` in the frame it opens. */
|
|
131
|
+
transition:
|
|
132
|
+
opacity var(--dur-med) var(--ease),
|
|
133
|
+
transform var(--dur-med) var(--ease),
|
|
134
|
+
visibility var(--dur-med) linear;
|
|
126
135
|
z-index: var(--z-dropdown);
|
|
127
136
|
}
|
|
128
137
|
.vsw.open .vsw__menu { opacity: 1; visibility: visible; transform: translateY(0); }
|
|
@@ -133,7 +142,7 @@
|
|
|
133
142
|
padding: 10px 13px;
|
|
134
143
|
border-radius: 10px;
|
|
135
144
|
cursor: pointer;
|
|
136
|
-
transition: background
|
|
145
|
+
transition: background var(--dur-fast) var(--ease);
|
|
137
146
|
}
|
|
138
147
|
.vopt:hover { background: var(--surface); }
|
|
139
148
|
.vopt .vname { font-family: var(--font-sans); font-size: 12.5px; color: var(--strong); font-weight: 600; letter-spacing: 0.01em; }
|
|
@@ -151,7 +160,9 @@
|
|
|
151
160
|
}
|
|
152
161
|
.vbadge.live { color: var(--chip-success-ink); background: var(--chip-success-fill); }
|
|
153
162
|
.vbadge.arch { color: var(--muted); background: var(--surface); }
|
|
154
|
-
|
|
163
|
+
/* The switcher keeps its glyph and drops its label where the shell folds — the
|
|
164
|
+
same step the rail folds at: docs/specification.md#breakpoints. */
|
|
165
|
+
@media (max-width: 720px) { .vsw__btn .lbl { display: none; } }
|
|
155
166
|
|
|
156
167
|
/* Account — avatar + dropdown. Gated: hidden until the app confirms a session
|
|
157
168
|
and adds `.on` (mirrors the portal's /auth/me reveal). */
|
|
@@ -169,7 +180,7 @@
|
|
|
169
180
|
place-items: center;
|
|
170
181
|
cursor: pointer;
|
|
171
182
|
letter-spacing: 0.02em;
|
|
172
|
-
transition: border-color
|
|
183
|
+
transition: border-color var(--dur-fast) var(--ease);
|
|
173
184
|
}
|
|
174
185
|
.acct .avatar:hover { border-color: var(--accent); }
|
|
175
186
|
.amenu {
|
|
@@ -184,7 +195,11 @@
|
|
|
184
195
|
opacity: 0;
|
|
185
196
|
visibility: hidden;
|
|
186
197
|
transform: translateY(-6px);
|
|
187
|
-
|
|
198
|
+
/* Named properties — see .vsw__menu above. */
|
|
199
|
+
transition:
|
|
200
|
+
opacity var(--dur-med) var(--ease),
|
|
201
|
+
transform var(--dur-med) var(--ease),
|
|
202
|
+
visibility var(--dur-med) linear;
|
|
188
203
|
z-index: var(--z-dropdown);
|
|
189
204
|
}
|
|
190
205
|
.acct.open .amenu { opacity: 1; visibility: visible; transform: translateY(0); }
|
|
@@ -196,7 +211,7 @@
|
|
|
196
211
|
.amenu a { display: flex; align-items: center; gap: 11px; padding: 10px 15px; color: var(--text); text-decoration: none; font-family: var(--font-sans); font-size: 13px; cursor: pointer; }
|
|
197
212
|
.amenu a:hover { background: var(--surface); }
|
|
198
213
|
.amenu a.cur { color: var(--accent); }
|
|
199
|
-
.amenu a svg { width: 19px; height: 19px; flex: none; stroke: currentColor; fill: none; stroke-width:
|
|
214
|
+
.amenu a svg { width: 19px; height: 19px; flex: none; stroke: currentColor; fill: none; stroke-width: 2; opacity: 0.85; }
|
|
200
215
|
.amenu .asep { height: 1px; background: var(--border); margin: 5px 0; }
|
|
201
216
|
.amenu a.aout { color: var(--muted); }
|
|
202
217
|
.amenu a.aout:hover { color: var(--pink); }
|
package/src/tokens/accents.css
CHANGED
|
@@ -1,17 +1,19 @@
|
|
|
1
|
-
/*
|
|
2
|
-
*
|
|
3
|
-
* `data-theme` (dark/light). Set both on <html>:
|
|
1
|
+
/* Accent sub-themes — an orthogonal `data-accent` dimension on top of
|
|
2
|
+
* `data-theme`. Set both on <html>:
|
|
4
3
|
*
|
|
5
4
|
* <html data-theme="dark" data-accent="phoenix">
|
|
6
5
|
*
|
|
7
|
-
* Each sub-theme only re-points the accent family
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
6
|
+
* Each sub-theme only re-points the accent family. Surfaces, text and signal
|
|
7
|
+
* colours (green = live, pink = danger) stay put, so every accent works in
|
|
8
|
+
* light AND dark and every component follows with no component-level change.
|
|
9
|
+
*
|
|
10
|
+
* --ring is NOT here: it is declared once in tokens.css as var(--accent), so
|
|
11
|
+
* re-pointing --accent re-points the focus ring too.
|
|
11
12
|
*
|
|
12
13
|
* Selectors carry two attributes + :root, so they always out-specify the
|
|
13
14
|
* single-attribute theme blocks in tokens.css regardless of import order.
|
|
14
|
-
*
|
|
15
|
+
*
|
|
16
|
+
* why: docs/specification.md#the-focus-ring */
|
|
15
17
|
|
|
16
18
|
/* ---- Phoenix — ember / rising fire (the strategy's namesake) ------------- */
|
|
17
19
|
:root[data-theme="dark"][data-accent="phoenix"] {
|
|
@@ -25,7 +27,6 @@
|
|
|
25
27
|
but not its own wash over a card, which lifts the ground toward the ink. The
|
|
26
28
|
hue is untouched. See issue #157. */
|
|
27
29
|
--glow-purple: rgba(255, 106, 61, 0.15);
|
|
28
|
-
--ring: 0 0 0 3px rgba(255, 106, 61, 0.38);
|
|
29
30
|
--grad-from: #ff7a45;
|
|
30
31
|
--grad-to: #ffcf6a;
|
|
31
32
|
}
|
|
@@ -39,7 +40,6 @@
|
|
|
39
40
|
--accent-strong: var(--accent);
|
|
40
41
|
--accent-contrast: #ffffff;
|
|
41
42
|
--glow-purple: rgba(214, 74, 18, 0.10);
|
|
42
|
-
--ring: 0 0 0 3px rgba(214, 74, 18, 0.28);
|
|
43
43
|
--grad-from: #d64a12;
|
|
44
44
|
--grad-to: #e8992a;
|
|
45
45
|
}
|
|
@@ -55,7 +55,6 @@
|
|
|
55
55
|
/* Thinned from 0.18 for WCAG AA, the same wash-over-a-card pair as dark
|
|
56
56
|
Phoenix and from the same alpha. The hue is untouched. See issue #157. */
|
|
57
57
|
--glow-purple: rgba(59, 157, 255, 0.15);
|
|
58
|
-
--ring: 0 0 0 3px rgba(59, 157, 255, 0.38);
|
|
59
58
|
--grad-from: #3b9dff;
|
|
60
59
|
--grad-to: #20dcf5;
|
|
61
60
|
}
|
|
@@ -83,7 +82,6 @@
|
|
|
83
82
|
rather than the accent — in light a glow tints --purple-light, which
|
|
84
83
|
stories/signal-contrast.test.js holds. See issue #157. */
|
|
85
84
|
--glow-purple: rgba(21, 104, 214, 0.10);
|
|
86
|
-
--ring: 0 0 0 3px rgba(21, 104, 214, 0.28);
|
|
87
85
|
--grad-from: #1568d6;
|
|
88
86
|
--grad-to: #17a2c0;
|
|
89
87
|
}
|
|
@@ -97,7 +95,6 @@
|
|
|
97
95
|
--accent-strong: var(--accent);
|
|
98
96
|
--accent-contrast: #04180f;
|
|
99
97
|
--glow-purple: rgba(22, 201, 138, 0.18);
|
|
100
|
-
--ring: 0 0 0 3px rgba(22, 201, 138, 0.38);
|
|
101
98
|
--grad-from: #16c98a;
|
|
102
99
|
--grad-to: #20dcf5;
|
|
103
100
|
}
|
|
@@ -113,7 +110,6 @@
|
|
|
113
110
|
/* Thinned from 0.10 for WCAG AA, the same grey-panel pair as light Ocean and
|
|
114
111
|
from the same alpha. See issue #157. */
|
|
115
112
|
--glow-purple: rgba(11, 156, 104, 0.08);
|
|
116
|
-
--ring: 0 0 0 3px rgba(11, 156, 104, 0.28);
|
|
117
113
|
--grad-from: #0b9c68;
|
|
118
114
|
--grad-to: #12b0a0;
|
|
119
115
|
}
|