@apliteni/apliteni-ui 0.4.0 → 0.6.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/package.json +8 -3
- package/src/assets/brand.generated/apliteni-logo-dark.svg +27 -0
- package/src/assets/brand.generated/apliteni-logo.svg +27 -0
- package/src/assets/brand.generated/apliteni-mark.svg +19 -0
- package/src/assets/brand.generated/index.js +5 -0
- package/src/assets/icons.js +106 -24
- package/src/assets/illustrations.js +68 -0
- package/src/components/drawer.js +200 -0
- package/src/components/dropdown.js +229 -0
- package/src/components/feedback.js +6 -0
- package/src/components/footer.js +95 -0
- package/src/components/index.js +46 -26
- package/src/components/nav.js +190 -0
- package/src/components/success.js +126 -0
- package/src/components/toasts.js +94 -0
- package/src/components/topbar.js +16 -15
- package/src/index.css +8 -1
- package/src/index.js +5 -0
- package/src/inline.js +19 -5
- package/src/motion.js +68 -0
- package/src/styles/base.css +0 -6
- package/src/styles/button.css +40 -11
- package/src/styles/callout.css +79 -12
- package/src/styles/drawer.css +166 -0
- package/src/styles/dropdown.css +133 -0
- package/src/styles/empty.css +84 -0
- package/src/styles/feedback.css +1 -1
- package/src/styles/footer.css +123 -0
- package/src/styles/motion.css +166 -0
- package/src/styles/nav.css +218 -0
- package/src/styles/success.css +189 -0
- package/src/styles/table.css +2 -15
- package/src/tokens/brand.generated.css +121 -0
- package/src/tokens/tokens.css +18 -5
- package/src/styles/aurora.css +0 -93
package/src/styles/callout.css
CHANGED
|
@@ -26,28 +26,95 @@
|
|
|
26
26
|
.ui-callout--danger { background: var(--glow-pink); }
|
|
27
27
|
.ui-callout--danger .ui-callout__icon { color: var(--pink); }
|
|
28
28
|
|
|
29
|
-
/*
|
|
29
|
+
/* ----------------------------------------------------------------------------
|
|
30
|
+
* Toast — a floating, dismissible notification.
|
|
31
|
+
* A status (colour) × style (surface) matrix, entirely token-driven:
|
|
32
|
+
* status success · danger · warn · info · neutral → sets --toast-accent/-glow/-on
|
|
33
|
+
* style soft (tinted) · solid (filled) · outline (bordered)
|
|
34
|
+
* -------------------------------------------------------------------------- */
|
|
30
35
|
.ui-toast {
|
|
36
|
+
position: relative;
|
|
31
37
|
display: flex;
|
|
32
|
-
align-items:
|
|
38
|
+
align-items: flex-start;
|
|
33
39
|
gap: 12px;
|
|
34
|
-
padding: 13px
|
|
40
|
+
padding: 13px 15px;
|
|
35
41
|
border-radius: var(--radius-md);
|
|
36
|
-
background: var(--bg-elevated);
|
|
37
|
-
box-shadow: var(--shadow-lg);
|
|
38
42
|
color: var(--text);
|
|
39
43
|
font-size: var(--text-base);
|
|
40
|
-
|
|
44
|
+
width: 100%;
|
|
45
|
+
max-width: 400px;
|
|
46
|
+
overflow: hidden; /* clips the timer bar + left marker to the rounded corners */
|
|
47
|
+
animation: ui-toast-in 0.28s cubic-bezier(0.22, 1, 0.36, 1) both;
|
|
41
48
|
}
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
.ui-toast--
|
|
46
|
-
.ui-
|
|
49
|
+
|
|
50
|
+
/* status → the paint tokens every style below consumes (--toast-on = the ink
|
|
51
|
+
that reads on the accent when it becomes a fill) */
|
|
52
|
+
.ui-toast--success { --toast-accent: var(--green); --toast-glow: var(--glow-green); --toast-on: #0c0c0c; }
|
|
53
|
+
.ui-toast--danger { --toast-accent: var(--pink); --toast-glow: var(--glow-pink); --toast-on: #ffffff; }
|
|
54
|
+
.ui-toast--warn { --toast-accent: var(--amber); --toast-glow: color-mix(in srgb, var(--amber) 14%, transparent); --toast-on: #0c0c0c; }
|
|
55
|
+
.ui-toast--info { --toast-accent: var(--cyan); --toast-glow: var(--glow-cyan); --toast-on: #0c0c0c; }
|
|
56
|
+
.ui-toast--neutral { --toast-accent: var(--muted); --toast-glow: var(--surface-2); --toast-on: var(--strong); }
|
|
57
|
+
|
|
58
|
+
/* left status marker (soft + outline; solid is already a full fill) */
|
|
59
|
+
.ui-toast--soft::before,
|
|
60
|
+
.ui-toast--outline::before {
|
|
61
|
+
content: ''; position: absolute; left: 0; top: 0; bottom: 0;
|
|
62
|
+
width: 3px; background: var(--toast-accent);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
.ui-toast__icon { width: 22px; height: 22px; flex: none; margin-top: 1px; display: grid; place-items: center; border-radius: 50%; background: var(--toast-accent); color: var(--toast-on); }
|
|
66
|
+
.ui-toast__icon svg { width: 13px; height: 13px; stroke: currentColor; fill: none; stroke-width: 2; }
|
|
67
|
+
.ui-toast__body { flex: 1; min-width: 0; }
|
|
47
68
|
.ui-toast__title { font-weight: var(--weight-medium); color: var(--strong); }
|
|
48
|
-
.ui-
|
|
69
|
+
.ui-toast__text { color: var(--dim); }
|
|
70
|
+
|
|
71
|
+
/* trailing action ("Undo" / "Retry") */
|
|
72
|
+
.ui-toast__action { flex: none; align-self: center; background: none; border: 0; padding: 4px 9px; border-radius: var(--radius-xs); font: inherit; font-weight: var(--weight-medium); color: var(--toast-accent); cursor: pointer; }
|
|
73
|
+
.ui-toast__action:hover { background: color-mix(in srgb, var(--toast-accent) 14%, transparent); }
|
|
74
|
+
|
|
75
|
+
.ui-toast__close { flex: none; align-self: flex-start; background: none; border: 0; color: var(--muted); cursor: pointer; padding: 2px; display: grid; place-items: center; }
|
|
76
|
+
.ui-toast__close svg { width: 15px; height: 15px; stroke: currentColor; fill: none; stroke-width: 1.8; }
|
|
49
77
|
.ui-toast__close:hover { color: var(--text); }
|
|
50
78
|
|
|
79
|
+
/* auto-dismiss progress bar — .is-running is added by wireToastStack() */
|
|
80
|
+
.ui-toast__timer { position: absolute; left: 0; bottom: 0; height: 3px; width: 100%; background: var(--toast-accent); opacity: 0.85; transform-origin: left; }
|
|
81
|
+
.ui-toast__timer.is-running { animation: ui-toast-timer var(--toast-dur, 5s) linear forwards; }
|
|
82
|
+
|
|
83
|
+
/* style: soft — tinted surface */
|
|
84
|
+
.ui-toast--soft { background: var(--toast-glow); box-shadow: var(--shadow-sm); }
|
|
85
|
+
|
|
86
|
+
/* style: solid — filled accent, ink flips to --toast-on */
|
|
87
|
+
.ui-toast--solid { background: var(--toast-accent); color: var(--toast-on); box-shadow: var(--shadow-lg); }
|
|
88
|
+
.ui-toast--solid .ui-toast__title,
|
|
89
|
+
.ui-toast--solid .ui-toast__text { color: var(--toast-on); }
|
|
90
|
+
.ui-toast--solid .ui-toast__text { opacity: 0.82; }
|
|
91
|
+
.ui-toast--solid .ui-toast__icon { background: color-mix(in srgb, var(--toast-on) 22%, transparent); color: var(--toast-on); }
|
|
92
|
+
.ui-toast--solid .ui-toast__action { color: var(--toast-on); }
|
|
93
|
+
.ui-toast--solid .ui-toast__action:hover { background: color-mix(in srgb, var(--toast-on) 18%, transparent); }
|
|
94
|
+
.ui-toast--solid .ui-toast__close { color: color-mix(in srgb, var(--toast-on) 68%, transparent); }
|
|
95
|
+
.ui-toast--solid .ui-toast__close:hover { color: var(--toast-on); }
|
|
96
|
+
.ui-toast--solid .ui-toast__timer { background: color-mix(in srgb, var(--toast-on) 55%, transparent); }
|
|
97
|
+
|
|
98
|
+
/* style: outline — elevated card with a status-tinted border */
|
|
99
|
+
.ui-toast--outline { background: var(--bg-elevated); box-shadow: var(--shadow-md); border: 1px solid color-mix(in srgb, var(--toast-accent) 40%, transparent); }
|
|
100
|
+
|
|
101
|
+
/* compact — single line, no body text */
|
|
102
|
+
.ui-toast--compact { align-items: center; padding-top: 10px; padding-bottom: 10px; }
|
|
103
|
+
.ui-toast--compact .ui-toast__icon { margin-top: 0; }
|
|
104
|
+
|
|
105
|
+
@keyframes ui-toast-in { from { opacity: 0; transform: translateX(18px); } to { opacity: 1; transform: none; } }
|
|
106
|
+
@keyframes ui-toast-out { to { opacity: 0; transform: translateX(24px); } }
|
|
107
|
+
@keyframes ui-toast-timer { from { transform: scaleX(1); } to { transform: scaleX(0); } }
|
|
108
|
+
.ui-toast.is-leaving { animation: ui-toast-out 0.2s ease forwards; }
|
|
109
|
+
|
|
110
|
+
@media (prefers-reduced-motion: reduce) {
|
|
111
|
+
.ui-toast, .ui-toast.is-leaving { animation: none; }
|
|
112
|
+
.ui-toast__timer.is-running { animation: none; }
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/* stack container for queued toasts */
|
|
116
|
+
.ui-toast-stack { display: flex; flex-direction: column; gap: 12px; width: 400px; max-width: 100%; }
|
|
117
|
+
|
|
51
118
|
/* Success panel — centered confirmation, used after form submit */
|
|
52
119
|
.ui-success {
|
|
53
120
|
border-radius: var(--radius-lg);
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
/* ============================================================================
|
|
2
|
+
* Drawer — edge-anchored overlay panel (Sheet / Slide-over): a panel that
|
|
3
|
+
* slides in from any screen edge over a scrim. Fully token-driven so it
|
|
4
|
+
* re-themes across accents + light/dark. Shares its scrim + focus-trap concept
|
|
5
|
+
* with a future Modal (see drawer.js). `prefers-reduced-motion` drops the slide
|
|
6
|
+
* for a plain fade.
|
|
7
|
+
*
|
|
8
|
+
* Local tokens (surface/shadow/scrim) so the panel + scrim re-theme cleanly:
|
|
9
|
+
* --drawer-surface panel background --drawer-shadow panel elevation
|
|
10
|
+
* --drawer-scrim backdrop colour (overridden for light below)
|
|
11
|
+
* ========================================================================== */
|
|
12
|
+
|
|
13
|
+
.ui-drawer {
|
|
14
|
+
--drawer-surface: var(--surface-2);
|
|
15
|
+
--drawer-shadow: var(--shadow-lg);
|
|
16
|
+
--drawer-scrim: rgba(0, 0, 0, 0.58);
|
|
17
|
+
--drawer-w: 420px; /* left|right panels: width */
|
|
18
|
+
--drawer-h: 45vh; /* top|bottom panels: height */
|
|
19
|
+
|
|
20
|
+
position: fixed;
|
|
21
|
+
inset: 0;
|
|
22
|
+
z-index: var(--z-overlay);
|
|
23
|
+
pointer-events: none; /* container never blocks; scrim/panel opt back in */
|
|
24
|
+
}
|
|
25
|
+
:root[data-theme="light"] .ui-drawer { --drawer-scrim: rgba(20, 22, 40, 0.38); }
|
|
26
|
+
|
|
27
|
+
/* Scrim — fades in; visibility trails the fade so the panel can animate out. */
|
|
28
|
+
.ui-drawer__scrim {
|
|
29
|
+
position: absolute;
|
|
30
|
+
inset: 0;
|
|
31
|
+
background: var(--drawer-scrim);
|
|
32
|
+
pointer-events: auto;
|
|
33
|
+
opacity: 0;
|
|
34
|
+
visibility: hidden;
|
|
35
|
+
transition: opacity var(--dur-med) var(--ease), visibility var(--dur-med) var(--ease);
|
|
36
|
+
}
|
|
37
|
+
.ui-drawer.is-open .ui-drawer__scrim { opacity: 1; visibility: visible; }
|
|
38
|
+
|
|
39
|
+
/* Panel — the sliding surface. Flex column: header / scrollable body / footer. */
|
|
40
|
+
.ui-drawer__panel {
|
|
41
|
+
position: absolute;
|
|
42
|
+
display: flex;
|
|
43
|
+
flex-direction: column;
|
|
44
|
+
background: var(--drawer-surface);
|
|
45
|
+
box-shadow: var(--drawer-shadow);
|
|
46
|
+
pointer-events: auto;
|
|
47
|
+
opacity: 1;
|
|
48
|
+
visibility: hidden;
|
|
49
|
+
transition:
|
|
50
|
+
transform var(--dur-med) var(--ease),
|
|
51
|
+
opacity var(--dur-med) var(--ease),
|
|
52
|
+
visibility var(--dur-med) var(--ease);
|
|
53
|
+
}
|
|
54
|
+
.ui-drawer__panel:focus-visible { outline: none; box-shadow: var(--drawer-shadow), var(--ring); }
|
|
55
|
+
.ui-drawer.is-open .ui-drawer__panel { visibility: visible; transform: none; }
|
|
56
|
+
|
|
57
|
+
/* -- Edge anchoring + slide-in direction ---------------------------------- */
|
|
58
|
+
.ui-drawer--right .ui-drawer__panel,
|
|
59
|
+
.ui-drawer--left .ui-drawer__panel {
|
|
60
|
+
top: 0; bottom: 0;
|
|
61
|
+
width: min(var(--drawer-w), 100vw);
|
|
62
|
+
max-width: 100vw;
|
|
63
|
+
}
|
|
64
|
+
.ui-drawer--right .ui-drawer__panel {
|
|
65
|
+
right: 0;
|
|
66
|
+
border-left: 1px solid var(--border);
|
|
67
|
+
transform: translateX(100%);
|
|
68
|
+
}
|
|
69
|
+
.ui-drawer--left .ui-drawer__panel {
|
|
70
|
+
left: 0;
|
|
71
|
+
border-right: 1px solid var(--border);
|
|
72
|
+
transform: translateX(-100%);
|
|
73
|
+
}
|
|
74
|
+
.ui-drawer--top .ui-drawer__panel,
|
|
75
|
+
.ui-drawer--bottom .ui-drawer__panel {
|
|
76
|
+
left: 0; right: 0;
|
|
77
|
+
height: min(var(--drawer-h), 100vh);
|
|
78
|
+
max-height: 100vh;
|
|
79
|
+
}
|
|
80
|
+
.ui-drawer--top .ui-drawer__panel {
|
|
81
|
+
top: 0;
|
|
82
|
+
border-bottom: 1px solid var(--border);
|
|
83
|
+
transform: translateY(-100%);
|
|
84
|
+
}
|
|
85
|
+
.ui-drawer--bottom .ui-drawer__panel {
|
|
86
|
+
bottom: 0;
|
|
87
|
+
border-top: 1px solid var(--border);
|
|
88
|
+
transform: translateY(100%);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/* -- Sizes ----------------------------------------------------------------- */
|
|
92
|
+
/* left|right → width; top|bottom → height. Same names, axis chosen by side. */
|
|
93
|
+
.ui-drawer--right.ui-drawer--sm, .ui-drawer--left.ui-drawer--sm { --drawer-w: 320px; }
|
|
94
|
+
.ui-drawer--right.ui-drawer--md, .ui-drawer--left.ui-drawer--md { --drawer-w: 420px; }
|
|
95
|
+
.ui-drawer--right.ui-drawer--lg, .ui-drawer--left.ui-drawer--lg { --drawer-w: 560px; }
|
|
96
|
+
.ui-drawer--top.ui-drawer--sm, .ui-drawer--bottom.ui-drawer--sm { --drawer-h: 30vh; }
|
|
97
|
+
.ui-drawer--top.ui-drawer--md, .ui-drawer--bottom.ui-drawer--md { --drawer-h: 45vh; }
|
|
98
|
+
.ui-drawer--top.ui-drawer--lg, .ui-drawer--bottom.ui-drawer--lg { --drawer-h: 72vh; }
|
|
99
|
+
|
|
100
|
+
/* -- Slots ----------------------------------------------------------------- */
|
|
101
|
+
.ui-drawer__header {
|
|
102
|
+
display: flex;
|
|
103
|
+
align-items: center;
|
|
104
|
+
justify-content: space-between;
|
|
105
|
+
gap: 12px;
|
|
106
|
+
padding: 18px 20px;
|
|
107
|
+
border-bottom: 1px solid var(--border);
|
|
108
|
+
flex: none;
|
|
109
|
+
}
|
|
110
|
+
.ui-drawer__title {
|
|
111
|
+
margin: 0;
|
|
112
|
+
font-family: var(--font-sans);
|
|
113
|
+
font-size: 15px;
|
|
114
|
+
font-weight: 600;
|
|
115
|
+
letter-spacing: 0.01em;
|
|
116
|
+
color: var(--strong);
|
|
117
|
+
}
|
|
118
|
+
.ui-drawer__close {
|
|
119
|
+
display: inline-flex;
|
|
120
|
+
align-items: center;
|
|
121
|
+
justify-content: center;
|
|
122
|
+
width: 30px; height: 30px;
|
|
123
|
+
flex: none;
|
|
124
|
+
cursor: pointer;
|
|
125
|
+
color: var(--muted);
|
|
126
|
+
background: transparent;
|
|
127
|
+
border: 1px solid transparent;
|
|
128
|
+
border-radius: var(--radius-sm);
|
|
129
|
+
transition: color 0.15s ease, background 0.15s ease, border-color 0.15s ease;
|
|
130
|
+
}
|
|
131
|
+
.ui-drawer__close:hover { color: var(--strong); background: var(--surface); }
|
|
132
|
+
.ui-drawer__close:focus-visible { outline: none; box-shadow: var(--ring); border-color: var(--accent); }
|
|
133
|
+
.ui-drawer__close svg { width: 18px; height: 18px; stroke: currentColor; fill: none; stroke-width: 1.8; }
|
|
134
|
+
|
|
135
|
+
.ui-drawer__body {
|
|
136
|
+
flex: 1 1 auto;
|
|
137
|
+
min-height: 0;
|
|
138
|
+
overflow-y: auto;
|
|
139
|
+
padding: 20px;
|
|
140
|
+
color: var(--text);
|
|
141
|
+
font-family: var(--font-sans);
|
|
142
|
+
font-size: 13px;
|
|
143
|
+
line-height: 1.55;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
.ui-drawer__footer {
|
|
147
|
+
display: flex;
|
|
148
|
+
align-items: center;
|
|
149
|
+
justify-content: flex-end;
|
|
150
|
+
gap: 10px;
|
|
151
|
+
padding: 16px 20px;
|
|
152
|
+
border-top: 1px solid var(--border);
|
|
153
|
+
background: var(--surface-2);
|
|
154
|
+
flex: none;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/* -- Reduced motion: no slide, just a fade -------------------------------- */
|
|
158
|
+
@media (prefers-reduced-motion: reduce) {
|
|
159
|
+
.ui-drawer__panel {
|
|
160
|
+
transform: none !important;
|
|
161
|
+
opacity: 0;
|
|
162
|
+
transition: opacity var(--dur-fast) linear, visibility var(--dur-fast) linear;
|
|
163
|
+
}
|
|
164
|
+
.ui-drawer.is-open .ui-drawer__panel { opacity: 1; }
|
|
165
|
+
.ui-drawer__scrim { transition: opacity var(--dur-fast) linear, visibility var(--dur-fast) linear; }
|
|
166
|
+
}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/* ============================================================================
|
|
2
|
+
* Dropdown — the kit's popover-list primitive (trigger + panel + item rows).
|
|
3
|
+
* Fully token-driven so it re-themes across accents + light/dark. Shares its
|
|
4
|
+
* open/close JS with the topbar's version switcher and account menu, which keep
|
|
5
|
+
* their own bespoke classes; this file styles the standalone `dropdown()`.
|
|
6
|
+
* ========================================================================== */
|
|
7
|
+
|
|
8
|
+
.ui-dropdown { position: relative; display: inline-flex; }
|
|
9
|
+
|
|
10
|
+
/* Trigger — pill button: [pre] [value] [chevron] */
|
|
11
|
+
.ui-dropdown__trigger {
|
|
12
|
+
display: inline-flex;
|
|
13
|
+
align-items: center;
|
|
14
|
+
gap: 8px;
|
|
15
|
+
cursor: pointer;
|
|
16
|
+
font-family: var(--font-sans);
|
|
17
|
+
font-size: 12.5px;
|
|
18
|
+
font-weight: 500;
|
|
19
|
+
color: var(--text);
|
|
20
|
+
background: var(--surface);
|
|
21
|
+
border: 1px solid var(--border);
|
|
22
|
+
border-radius: var(--radius-pill);
|
|
23
|
+
padding: 7px 11px 7px 13px;
|
|
24
|
+
transition: border-color 0.2s ease, background 0.2s ease;
|
|
25
|
+
}
|
|
26
|
+
.ui-dropdown__trigger:hover { border-color: var(--accent); }
|
|
27
|
+
.ui-dropdown__trigger:focus-visible { outline: none; box-shadow: var(--ring); border-color: var(--accent); }
|
|
28
|
+
.ui-dropdown__pre { color: var(--muted); }
|
|
29
|
+
.ui-dropdown__value { color: var(--strong); font-weight: 600; letter-spacing: 0.01em; }
|
|
30
|
+
|
|
31
|
+
/* Chevron — border caret that flips when the container is .open */
|
|
32
|
+
.ui-dropdown__chevron {
|
|
33
|
+
width: 8px; height: 8px;
|
|
34
|
+
border-right: 1.6px solid var(--muted);
|
|
35
|
+
border-bottom: 1.6px solid var(--muted);
|
|
36
|
+
transform: rotate(45deg) translateY(-1px);
|
|
37
|
+
transition: transform 0.2s ease;
|
|
38
|
+
flex: none;
|
|
39
|
+
}
|
|
40
|
+
.ui-dropdown.open .ui-dropdown__chevron { transform: rotate(-135deg) translateY(2px); }
|
|
41
|
+
|
|
42
|
+
/* Panel — the popover surface */
|
|
43
|
+
.ui-dropdown__panel {
|
|
44
|
+
position: absolute;
|
|
45
|
+
top: calc(100% + 9px);
|
|
46
|
+
left: 0;
|
|
47
|
+
min-width: 240px;
|
|
48
|
+
background: var(--surface-2);
|
|
49
|
+
border: 1px solid var(--border);
|
|
50
|
+
border-radius: var(--radius-lg);
|
|
51
|
+
padding: 6px;
|
|
52
|
+
box-shadow: var(--shadow-lg);
|
|
53
|
+
opacity: 0;
|
|
54
|
+
visibility: hidden;
|
|
55
|
+
transform: translateY(-6px);
|
|
56
|
+
transition: opacity 0.18s ease, transform 0.18s ease, visibility 0.18s ease;
|
|
57
|
+
z-index: var(--z-dropdown);
|
|
58
|
+
}
|
|
59
|
+
.ui-dropdown__panel.is-end { left: auto; right: 0; }
|
|
60
|
+
.ui-dropdown__panel.is-scroll { max-height: 300px; overflow-y: auto; }
|
|
61
|
+
.ui-dropdown.open .ui-dropdown__panel { opacity: 1; visibility: visible; transform: translateY(0); }
|
|
62
|
+
|
|
63
|
+
/* Item row — [icon] [main: label + desc] [badge] [tick] */
|
|
64
|
+
.ui-dropdown__item {
|
|
65
|
+
display: flex;
|
|
66
|
+
gap: 11px;
|
|
67
|
+
align-items: center;
|
|
68
|
+
padding: 9px 12px;
|
|
69
|
+
border-radius: var(--radius-sm);
|
|
70
|
+
cursor: pointer;
|
|
71
|
+
text-decoration: none;
|
|
72
|
+
color: var(--text);
|
|
73
|
+
transition: background 0.15s ease;
|
|
74
|
+
}
|
|
75
|
+
.ui-dropdown__item:hover { background: var(--surface); }
|
|
76
|
+
.ui-dropdown__item:focus-visible { outline: none; background: var(--surface); box-shadow: var(--ring); }
|
|
77
|
+
.ui-dropdown__main { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
|
|
78
|
+
.ui-dropdown__label { font-family: var(--font-sans); font-size: 12.5px; color: var(--strong); font-weight: 600; letter-spacing: 0.01em; }
|
|
79
|
+
.ui-dropdown__desc { font-size: 11px; color: var(--muted); line-height: 1.35; }
|
|
80
|
+
.ui-dropdown__ic { display: inline-flex; flex: none; color: var(--muted); }
|
|
81
|
+
.ui-dropdown__ic svg { width: 18px; height: 18px; stroke: currentColor; fill: none; stroke-width: 1.8; }
|
|
82
|
+
|
|
83
|
+
/* Trailing selected tick (listbox variant) */
|
|
84
|
+
.ui-dropdown__tick { margin-left: auto; flex: none; display: none; color: var(--accent); }
|
|
85
|
+
.ui-dropdown__tick svg { width: 16px; height: 16px; stroke: currentColor; fill: none; stroke-width: 2.2; }
|
|
86
|
+
.ui-dropdown__item.is-selected .ui-dropdown__tick { display: inline-flex; }
|
|
87
|
+
.ui-dropdown__item.is-selected .ui-dropdown__label { color: var(--accent); }
|
|
88
|
+
|
|
89
|
+
/* When a row has both a badge and a tick, keep the badge from eating the margin */
|
|
90
|
+
.ui-dropdown__badge + .ui-dropdown__tick { margin-left: 8px; }
|
|
91
|
+
|
|
92
|
+
/* Trailing status badge */
|
|
93
|
+
.ui-dropdown__badge {
|
|
94
|
+
font-size: 9.5px;
|
|
95
|
+
letter-spacing: 0.12em;
|
|
96
|
+
text-transform: uppercase;
|
|
97
|
+
font-weight: 700;
|
|
98
|
+
padding: 2px 7px;
|
|
99
|
+
border-radius: var(--radius-pill);
|
|
100
|
+
margin-left: auto;
|
|
101
|
+
flex: none;
|
|
102
|
+
color: var(--muted);
|
|
103
|
+
background: var(--surface);
|
|
104
|
+
}
|
|
105
|
+
.ui-dropdown__badge.is-live { color: var(--green); background: var(--glow-green); }
|
|
106
|
+
.ui-dropdown__badge.is-accent { color: var(--accent); background: color-mix(in srgb, var(--accent) 14%, transparent); }
|
|
107
|
+
|
|
108
|
+
/* Disabled + danger rows */
|
|
109
|
+
.ui-dropdown__item.is-disabled { opacity: 0.45; cursor: not-allowed; pointer-events: none; }
|
|
110
|
+
.ui-dropdown__item.is-danger .ui-dropdown__label { color: var(--muted); }
|
|
111
|
+
.ui-dropdown__item.is-danger:hover .ui-dropdown__label { color: var(--accent); }
|
|
112
|
+
|
|
113
|
+
/* Grouped sections */
|
|
114
|
+
.ui-dropdown__section + .ui-dropdown__section { border-top: 1px solid var(--border); margin-top: 5px; padding-top: 5px; }
|
|
115
|
+
.ui-dropdown__group {
|
|
116
|
+
font-size: 10px;
|
|
117
|
+
letter-spacing: 0.1em;
|
|
118
|
+
text-transform: uppercase;
|
|
119
|
+
font-weight: 700;
|
|
120
|
+
color: var(--muted);
|
|
121
|
+
padding: 7px 12px 4px;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/* Separator */
|
|
125
|
+
.ui-dropdown__sep { height: 1px; background: var(--border); margin: 5px 4px; }
|
|
126
|
+
|
|
127
|
+
/* Optional pinned header/footer blocks */
|
|
128
|
+
.ui-dropdown__panel > .ui-dropdown__head {
|
|
129
|
+
padding: 11px 13px;
|
|
130
|
+
margin: -6px -6px 5px;
|
|
131
|
+
border-bottom: 1px solid var(--border);
|
|
132
|
+
border-radius: var(--radius-lg) var(--radius-lg) 0 0;
|
|
133
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/* ============================================================================
|
|
2
|
+
* Empty state — the placeholder shown when a list, table or page has no rows.
|
|
3
|
+
* A duotone spot illustration (in the active accent, with a brand-green spark),
|
|
4
|
+
* a title, an optional line of guidance, and an optional action.
|
|
5
|
+
*
|
|
6
|
+
* Markup:
|
|
7
|
+
* <div class="ui-empty">
|
|
8
|
+
* <div class="ui-empty__art"><svg class="ui-illo">…</svg></div>
|
|
9
|
+
* <div class="ui-empty__title">No people yet</div>
|
|
10
|
+
* <div class="ui-empty__sub">Contractors and staff you add show up here.</div>
|
|
11
|
+
* <div class="ui-empty__actions"><button class="ui-btn ui-btn--primary">…</button></div>
|
|
12
|
+
* </div>
|
|
13
|
+
*
|
|
14
|
+
* Illustrations live in assets/illustrations.js; emptyState() in components
|
|
15
|
+
* assembles the block. The legacy line-icon slot (.ui-empty__icon) still works.
|
|
16
|
+
* ========================================================================== */
|
|
17
|
+
|
|
18
|
+
.ui-empty {
|
|
19
|
+
display: flex;
|
|
20
|
+
flex-direction: column;
|
|
21
|
+
align-items: center;
|
|
22
|
+
text-align: center;
|
|
23
|
+
gap: 8px;
|
|
24
|
+
padding: 48px 24px;
|
|
25
|
+
color: var(--muted);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/* Duotone illustration slot. */
|
|
29
|
+
.ui-empty__art {
|
|
30
|
+
margin-bottom: 4px;
|
|
31
|
+
}
|
|
32
|
+
.ui-illo {
|
|
33
|
+
display: block;
|
|
34
|
+
}
|
|
35
|
+
.ui-illo__stroke {
|
|
36
|
+
stroke: var(--accent);
|
|
37
|
+
stroke-width: 2.4;
|
|
38
|
+
fill: none;
|
|
39
|
+
stroke-linecap: round;
|
|
40
|
+
stroke-linejoin: round;
|
|
41
|
+
}
|
|
42
|
+
.ui-illo__fill {
|
|
43
|
+
fill: color-mix(in srgb, var(--accent) 13%, transparent);
|
|
44
|
+
stroke: none;
|
|
45
|
+
}
|
|
46
|
+
.ui-illo__spark {
|
|
47
|
+
fill: var(--illo-spark, #12a150);
|
|
48
|
+
stroke: none;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.ui-empty__title {
|
|
52
|
+
color: var(--text);
|
|
53
|
+
font-size: var(--text-md);
|
|
54
|
+
font-weight: var(--weight-medium);
|
|
55
|
+
margin: 2px 0 0;
|
|
56
|
+
}
|
|
57
|
+
.ui-empty__sub {
|
|
58
|
+
font-size: var(--text-sm);
|
|
59
|
+
max-width: 340px;
|
|
60
|
+
margin: 0;
|
|
61
|
+
line-height: 1.55;
|
|
62
|
+
}
|
|
63
|
+
.ui-empty__actions {
|
|
64
|
+
display: flex;
|
|
65
|
+
gap: 10px;
|
|
66
|
+
justify-content: center;
|
|
67
|
+
margin-top: 12px;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/* Legacy line-icon slot — kept so existing .ui-empty__icon markup still works. */
|
|
71
|
+
.ui-empty__icon {
|
|
72
|
+
width: 44px;
|
|
73
|
+
height: 44px;
|
|
74
|
+
margin: 0 auto 14px;
|
|
75
|
+
color: var(--muted);
|
|
76
|
+
opacity: 0.6;
|
|
77
|
+
}
|
|
78
|
+
.ui-empty__icon svg {
|
|
79
|
+
width: 100%;
|
|
80
|
+
height: 100%;
|
|
81
|
+
stroke: currentColor;
|
|
82
|
+
fill: none;
|
|
83
|
+
stroke-width: 1.5;
|
|
84
|
+
}
|
package/src/styles/feedback.css
CHANGED
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
font-family: var(--font-sans); font-size: 13px; font-weight: var(--weight-semibold); letter-spacing: .01em;
|
|
26
26
|
padding: 9px 17px 9px 15px; border-radius: 999px; cursor: pointer; white-space: nowrap; overflow: hidden;
|
|
27
27
|
box-shadow: 0 10px 26px var(--ui-fb-pill-glow), 0 2px 6px rgba(0,0,0,.28), inset 0 1px 0 rgba(255,255,255,.28);
|
|
28
|
-
transition: transform .2s cubic-bezier(.34,1.56,.64,1), opacity .16s ease, box-shadow .2s ease;
|
|
28
|
+
transition: transform .2s var(--easing-spring, cubic-bezier(.34,1.56,.64,1)), opacity .16s ease, box-shadow .2s ease;
|
|
29
29
|
}
|
|
30
30
|
.ui-fbpill.show { opacity: 1; pointer-events: auto; transform: translate(-50%, -100%) translateY(-9px) scale(1); }
|
|
31
31
|
.ui-fbpill:hover { box-shadow: 0 14px 34px var(--ui-fb-pill-glow), 0 3px 9px rgba(0,0,0,.3), inset 0 1px 0 rgba(255,255,255,.34); }
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/* ============================================================================
|
|
2
|
+
* Footer — the canonical site/app footer (brand lockup, grouped link columns,
|
|
3
|
+
* legal/copyright row, optional social icons + theme/accent switcher slot).
|
|
4
|
+
* Three variants: full (marketing), slim (single legal row), app (in-product).
|
|
5
|
+
* Local --footer-* tokens map to the global scale, so it re-themes across every
|
|
6
|
+
* accent + light/dark and a host can override just the footer if it needs to.
|
|
7
|
+
* ========================================================================== */
|
|
8
|
+
|
|
9
|
+
.ui-footer {
|
|
10
|
+
--footer-surface: transparent;
|
|
11
|
+
--footer-border: var(--border);
|
|
12
|
+
--footer-link: var(--muted);
|
|
13
|
+
--footer-link-hover: var(--strong);
|
|
14
|
+
--footer-title: var(--strong);
|
|
15
|
+
--footer-text: var(--dim);
|
|
16
|
+
|
|
17
|
+
background: var(--footer-surface);
|
|
18
|
+
border-top: 1px solid var(--footer-border);
|
|
19
|
+
color: var(--footer-text);
|
|
20
|
+
font-family: var(--font-sans);
|
|
21
|
+
}
|
|
22
|
+
.ui-footer__in {
|
|
23
|
+
width: 100%;
|
|
24
|
+
max-width: 1180px;
|
|
25
|
+
margin: 0 auto;
|
|
26
|
+
padding: 40px clamp(14px, 2.4vw, 26px) 30px;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/* Top block: brand + tagline + social on the left, link columns on the right. */
|
|
30
|
+
.ui-footer__top {
|
|
31
|
+
display: flex;
|
|
32
|
+
justify-content: space-between;
|
|
33
|
+
gap: 40px 60px;
|
|
34
|
+
flex-wrap: wrap;
|
|
35
|
+
padding-bottom: 30px;
|
|
36
|
+
}
|
|
37
|
+
.ui-footer__brand { max-width: 300px; }
|
|
38
|
+
.ui-footer .ui-footer__brand .brand { font-size: 15px; }
|
|
39
|
+
.ui-footer__tagline {
|
|
40
|
+
margin: 12px 0 0;
|
|
41
|
+
font-size: 13px;
|
|
42
|
+
line-height: 1.6;
|
|
43
|
+
color: var(--footer-text);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/* Social row */
|
|
47
|
+
.ui-footer__socials { display: flex; gap: 10px; margin-top: 16px; }
|
|
48
|
+
.ui-footer__social {
|
|
49
|
+
width: 34px; height: 34px;
|
|
50
|
+
display: grid; place-items: center;
|
|
51
|
+
border-radius: 10px;
|
|
52
|
+
border: 1px solid var(--footer-border);
|
|
53
|
+
color: var(--footer-link);
|
|
54
|
+
background: var(--surface);
|
|
55
|
+
transition: color 0.15s ease, border-color 0.15s ease, transform 0.15s ease;
|
|
56
|
+
}
|
|
57
|
+
.ui-footer__social:hover { color: var(--accent); border-color: var(--accent); transform: translateY(-1px); }
|
|
58
|
+
.ui-footer__social svg { width: 17px; height: 17px; display: block; }
|
|
59
|
+
|
|
60
|
+
/* Link columns */
|
|
61
|
+
.ui-footer__nav {
|
|
62
|
+
display: grid;
|
|
63
|
+
grid-template-columns: repeat(auto-fit, minmax(140px, max-content));
|
|
64
|
+
gap: 30px 56px;
|
|
65
|
+
}
|
|
66
|
+
.ui-footer__col-title {
|
|
67
|
+
font-size: 11px;
|
|
68
|
+
font-weight: 700;
|
|
69
|
+
letter-spacing: 0.1em;
|
|
70
|
+
text-transform: uppercase;
|
|
71
|
+
color: var(--footer-text);
|
|
72
|
+
margin: 0 0 14px;
|
|
73
|
+
}
|
|
74
|
+
.ui-footer__links { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 11px; }
|
|
75
|
+
.ui-footer__links a {
|
|
76
|
+
font-size: 13.5px;
|
|
77
|
+
color: var(--footer-link);
|
|
78
|
+
text-decoration: none;
|
|
79
|
+
transition: color 0.15s ease;
|
|
80
|
+
}
|
|
81
|
+
.ui-footer__links a:hover { color: var(--footer-link-hover); }
|
|
82
|
+
|
|
83
|
+
/* Legal bar — shared by every variant */
|
|
84
|
+
.ui-footer__bar {
|
|
85
|
+
display: flex;
|
|
86
|
+
align-items: center;
|
|
87
|
+
justify-content: space-between;
|
|
88
|
+
gap: 16px 22px;
|
|
89
|
+
flex-wrap: wrap;
|
|
90
|
+
padding-top: 22px;
|
|
91
|
+
border-top: 1px solid var(--footer-border);
|
|
92
|
+
font-size: 13px;
|
|
93
|
+
color: var(--footer-link);
|
|
94
|
+
}
|
|
95
|
+
.ui-footer__legal { color: var(--footer-link); }
|
|
96
|
+
.ui-footer__legal-links { display: flex; gap: 22px; flex-wrap: wrap; }
|
|
97
|
+
.ui-footer__legal-links a { color: var(--footer-link); text-decoration: none; transition: color 0.15s ease; }
|
|
98
|
+
.ui-footer__legal-links a:hover { color: var(--footer-link-hover); }
|
|
99
|
+
.ui-footer__switcher { display: inline-flex; align-items: center; gap: 12px; margin-left: auto; }
|
|
100
|
+
|
|
101
|
+
/* slim — a single legal row, no divider above it. */
|
|
102
|
+
.ui-footer--slim .ui-footer__in { padding-top: 24px; padding-bottom: 24px; }
|
|
103
|
+
.ui-footer--slim .ui-footer__bar { padding-top: 0; border-top: 0; }
|
|
104
|
+
|
|
105
|
+
/* app — compact, in-product: surface background + tighter padding. */
|
|
106
|
+
.ui-footer--app {
|
|
107
|
+
--footer-surface: var(--surface);
|
|
108
|
+
border-top: 1px solid var(--footer-border);
|
|
109
|
+
}
|
|
110
|
+
.ui-footer--app .ui-footer__in { max-width: none; padding: 12px clamp(14px, 2.4vw, 22px); }
|
|
111
|
+
.ui-footer--app .ui-footer__bar { padding-top: 0; border-top: 0; font-size: 12.5px; }
|
|
112
|
+
|
|
113
|
+
/* Responsive — columns collapse to a stacked layout on narrow screens. */
|
|
114
|
+
@media (max-width: 720px) {
|
|
115
|
+
.ui-footer__top { flex-direction: column; gap: 30px; }
|
|
116
|
+
.ui-footer__nav { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 26px 30px; }
|
|
117
|
+
.ui-footer__brand { max-width: none; }
|
|
118
|
+
}
|
|
119
|
+
@media (max-width: 460px) {
|
|
120
|
+
.ui-footer__nav { grid-template-columns: 1fr; }
|
|
121
|
+
.ui-footer__bar { flex-direction: column; align-items: flex-start; }
|
|
122
|
+
.ui-footer__switcher { margin-left: 0; }
|
|
123
|
+
}
|