@flyos/design-system 0.0.1-reserved → 1.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/federation/with-fly-federation.cjs +86 -0
- package/fesm2022/flyos-design-system.mjs +20951 -0
- package/fesm2022/flyos-design-system.mjs.map +1 -0
- package/package.json +53 -4
- package/scss/_app-surface-tokens.scss +366 -0
- package/scss/_app-surface-utilities.scss +82 -0
- package/scss/_business-app-buttons.scss +212 -0
- package/scss/_fly-theme.scss +27 -0
- package/scss/_ink-baseline.scss +29 -0
- package/scss/_menu-anchor.scss +22 -0
- package/scss/_native-select.scss +26 -0
- package/scss/_shell-embed-bridge.scss +81 -0
- package/scss/_theme-auto.scss +6 -0
- package/scss/_theme-dark-vars.scss +56 -0
- package/scss/_theme-dark.scss +204 -0
- package/scss/_theme-light.scss +248 -0
- package/scss/_tokens.scss +119 -0
- package/scss/_vos-button-mixins.scss +28 -0
- package/types/flyos-design-system.d.ts +9955 -0
- package/types/flyos-design-system.d.ts.map +1 -0
- package/ui-fonts/geist-cyrillic.woff2 +0 -0
- package/ui-fonts/geist-latin-ext.woff2 +0 -0
- package/ui-fonts/geist-latin.woff2 +0 -0
- package/ui-fonts/geist-mono-cyrillic.woff2 +0 -0
- package/ui-fonts/geist-mono-latin-ext.woff2 +0 -0
- package/ui-fonts/geist-mono-latin.woff2 +0 -0
- package/ui-fonts/geist.css +61 -0
- package/ui-fonts/primeicons/fonts/primeicons.ttf +0 -0
- package/ui-fonts/primeicons/fonts/primeicons.woff +0 -0
- package/ui-fonts/primeicons/fonts/primeicons.woff2 +0 -0
- package/ui-fonts/primeicons/primeicons.css +1328 -0
- package/README.md +0 -1
package/package.json
CHANGED
|
@@ -1,7 +1,56 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flyos/design-system",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "FlyOS design system —
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"description": "FlyOS design system — shared components, directives, pipes, services, and models for Business App developers.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"flyos",
|
|
7
|
+
"design-system",
|
|
8
|
+
"angular"
|
|
9
|
+
],
|
|
5
10
|
"license": "MIT",
|
|
6
|
-
"
|
|
7
|
-
|
|
11
|
+
"exports": {
|
|
12
|
+
"./federation/with-fly-federation": {
|
|
13
|
+
"require": "./federation/with-fly-federation.cjs",
|
|
14
|
+
"default": "./federation/with-fly-federation.cjs"
|
|
15
|
+
},
|
|
16
|
+
"./federation/*": "./federation/*",
|
|
17
|
+
"./package.json": {
|
|
18
|
+
"default": "./package.json"
|
|
19
|
+
},
|
|
20
|
+
".": {
|
|
21
|
+
"types": "./types/flyos-design-system.d.ts",
|
|
22
|
+
"default": "./fesm2022/flyos-design-system.mjs"
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"cropperjs": "^1.6.2",
|
|
27
|
+
"tslib": "^2.3.0"
|
|
28
|
+
},
|
|
29
|
+
"peerDependencies": {
|
|
30
|
+
"@flyos/design-system-emoji-pack": "*",
|
|
31
|
+
"@angular/animations": "^21.0.0",
|
|
32
|
+
"@angular/cdk": "^21.0.0",
|
|
33
|
+
"@angular/common": "^21.0.0",
|
|
34
|
+
"@angular/core": "^21.0.0",
|
|
35
|
+
"@angular/forms": "^21.0.0",
|
|
36
|
+
"@angular/router": "^21.0.0",
|
|
37
|
+
"@microsoft/signalr": "^10.0.0",
|
|
38
|
+
"primeicons": "^7.0.0",
|
|
39
|
+
"rxjs": "~7.8.0"
|
|
40
|
+
},
|
|
41
|
+
"peerDependenciesMeta": {
|
|
42
|
+
"@microsoft/signalr": {
|
|
43
|
+
"optional": true
|
|
44
|
+
},
|
|
45
|
+
"@flyos/design-system-emoji-pack": {
|
|
46
|
+
"optional": true
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
"publishConfig": {
|
|
50
|
+
"access": "public"
|
|
51
|
+
},
|
|
52
|
+
"module": "fesm2022/flyos-design-system.mjs",
|
|
53
|
+
"typings": "types/flyos-design-system.d.ts",
|
|
54
|
+
"sideEffects": false,
|
|
55
|
+
"type": "module"
|
|
56
|
+
}
|
|
@@ -0,0 +1,366 @@
|
|
|
1
|
+
// ─── App-surface tokens — the BUSINESS-APP content layer ─────────────────────
|
|
2
|
+
// WHY THIS IS A SEPARATE FAMILY FROM `--label-*` / `--surface-*`
|
|
3
|
+
// The DS carries two token families because it dresses two genuinely different
|
|
4
|
+
// surfaces, not because anyone forgot to merge them:
|
|
5
|
+
|
|
6
|
+
// 1. `--label-*` / `--surface-*` / `--window-*` / `--glass-*` (_theme-light/dark)
|
|
7
|
+
// SHELL CHROME. Translucent glass composited over the user's wallpaper.
|
|
8
|
+
// `--surface-card` is a 20%-white LIFT on the window plate — it is only ever
|
|
9
|
+
// meaningful stacked on that plate.
|
|
10
|
+
|
|
11
|
+
// 2. `--ink-*` / `--bg-*` / `--line-*` (this file)
|
|
12
|
+
// BUSINESS-APP CONTENT. An app's own opaque reading surface: white cards on
|
|
13
|
+
// a near-white page in light, dark cards on a darker page in dark. Apps that
|
|
14
|
+
// also embed in the shell re-tint THESE to glass in their own
|
|
15
|
+
// `.fly-shell <app>` block (see Circles' `circles-theme.scss`) — that
|
|
16
|
+
// override layer is the seam, and it only works because the resting values
|
|
17
|
+
// are opaque.
|
|
18
|
+
|
|
19
|
+
// Pointing `--bg-2` at `--surface-card` was evaluated and rejected: standalone,
|
|
20
|
+
// a 20%-white card over a 98.5%-white page stops reading as a card at all. The
|
|
21
|
+
// two families stay distinct on purpose; this comment is the contract.
|
|
22
|
+
|
|
23
|
+
// ADDITIVE ONLY. `tools/ds-compat` classifies re-valuing an existing theme
|
|
24
|
+
// token as MAJOR (it forks the Native Federation shared singleton for every
|
|
25
|
+
// remote), so nothing here may redefine a token another DS partial owns.
|
|
26
|
+
//
|
|
27
|
+
// Three tokens are deliberately ABSENT — they are the consuming app's BRAND and
|
|
28
|
+
// every app already sets them in its own theme file:
|
|
29
|
+
// --accent --accent-soft --focus-ring
|
|
30
|
+
//
|
|
31
|
+
// The other nine platform tokens (--danger* --warning* --purple --scrim
|
|
32
|
+
// --glass-blur) USED to be absent too, on the assumption that the platform layer
|
|
33
|
+
// supplies them. That assumption only holds when an app runs FEDERATED, where
|
|
34
|
+
// the desktop shell emits `_theme-light/dark.scss`. A business app running
|
|
35
|
+
// STANDALONE loads only this file plus its own theme — `@use 'fly-theme'` is
|
|
36
|
+
// commented out in both Circles and Thoughts — so `var(--danger)` resolved to
|
|
37
|
+
// nothing and error text rendered colourless. Confirmed in a live browser, not
|
|
38
|
+
// inferred: 9 of the 12 computed to the empty string on Thoughts standalone.
|
|
39
|
+
//
|
|
40
|
+
// They are now mirrored below at the SAME values `_theme-light/dark.scss` uses.
|
|
41
|
+
// Mirroring (rather than picking new values) is what makes this safe under the
|
|
42
|
+
// cascade: this file's `:root, html.light-theme` selector can tie with the
|
|
43
|
+
// shell's `html.light-theme`, and when the values are identical it does not
|
|
44
|
+
// matter which one wins.
|
|
45
|
+
|
|
46
|
+
// Consumed by the `fly-*` component library in `lib/components/`. Emitted via
|
|
47
|
+
// `_fly-theme.scss`, so `@use 'fly-theme'` is all a consumer needs.
|
|
48
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
49
|
+
|
|
50
|
+
:root,
|
|
51
|
+
html.light-theme {
|
|
52
|
+
// ── Neutrals — text ──────────────────────────────────────────────────────
|
|
53
|
+
--ink: oklch(18% 0.005 250deg); // primary text, primary button fills
|
|
54
|
+
--ink-2: oklch(32% 0.005 250deg); // secondary text
|
|
55
|
+
--ink-3: oklch(50% 0.005 250deg); // tertiary text, icons
|
|
56
|
+
--ink-4: oklch(65% 0.005 250deg); // disabled, muted labels
|
|
57
|
+
--ink-inverse: oklch(99% 0 0deg); // text on dark / gradient fills
|
|
58
|
+
--ink-hover: oklch(28% 0.005 250deg); // hover shade of --ink-filled controls
|
|
59
|
+
|
|
60
|
+
// Label for a fill of `--ink` itself (the primary button). Distinct from
|
|
61
|
+
// `--ink-inverse`, which is a FIXED near-white for coloured/gradient fills and
|
|
62
|
+
// therefore wrong here: `--ink` flips per theme, so its label must flip too.
|
|
63
|
+
//
|
|
64
|
+
// CONTRACT — anything that redefines `--ink` MUST redefine `--on-ink`.
|
|
65
|
+
// It must also be OPAQUE. The shell-embed glass remaps in Circles and Thoughts
|
|
66
|
+
// set `--ink` to white and every surface token to a translucent veil; a
|
|
67
|
+
// translucent label composites into the fill and vanishes.
|
|
68
|
+
--on-ink: var(--ink-inverse);
|
|
69
|
+
|
|
70
|
+
// ── Neutrals — borders ───────────────────────────────────────────────────
|
|
71
|
+
--line: oklch(92% 0.004 250deg); // default borders
|
|
72
|
+
--line-2: oklch(88% 0.004 250deg); // hover borders
|
|
73
|
+
--line-3: oklch(96% 0.003 250deg); // inner row dividers
|
|
74
|
+
|
|
75
|
+
// ── Surfaces (opaque by design — see the header note) ────────────────────
|
|
76
|
+
--bg: oklch(98.5% 0.003 100deg); // app background (warm off-white)
|
|
77
|
+
--bg-2: oklch(100% 0 0deg); // cards, table
|
|
78
|
+
--bg-3: oklch(97% 0.004 100deg); // sidebar, table header
|
|
79
|
+
--bg-hover: oklch(96% 0.005 250deg);
|
|
80
|
+
|
|
81
|
+
// ── Brand primitives ─────────────────────────────────────────────────────
|
|
82
|
+
// `--purple` / `--accent` / `--accent-soft` are platform-owned (_theme-*.scss).
|
|
83
|
+
--teal: oklch(74% 0.13 195deg);
|
|
84
|
+
--grad: linear-gradient(
|
|
85
|
+
135deg,
|
|
86
|
+
oklch(82% 0.12 325deg),
|
|
87
|
+
oklch(60% 0.19 305deg),
|
|
88
|
+
oklch(45% 0.2 285deg)
|
|
89
|
+
);
|
|
90
|
+
--grad-soft: linear-gradient(
|
|
91
|
+
135deg,
|
|
92
|
+
oklch(74% 0.13 195deg / 12%),
|
|
93
|
+
oklch(55% 0.18 295deg / 12%)
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
// ── Accent plate/ink PAIRS ───────────────────────────────────────────────
|
|
97
|
+
// NEVER paint --accent on an --accent-soft plate: that is purple-on-purple,
|
|
98
|
+
// and it is the bug that keeps coming back. Two plates, two inks:
|
|
99
|
+
|
|
100
|
+
// 1. --accent-soft is a TINT the consuming context may redefine (the shell
|
|
101
|
+
// resolves it to `color-mix(… 18%, transparent)`, i.e. a translucent wash
|
|
102
|
+
// over unknowable glass). The only ink correct against it in every mode
|
|
103
|
+
// is the ambient --ink, which each theme already contrasts with its own
|
|
104
|
+
// background.
|
|
105
|
+
--on-accent-soft: var(--ink);
|
|
106
|
+
|
|
107
|
+
// 2. --accent-fill is a SOLID plate we own outright, so its ink is knowable
|
|
108
|
+
// regardless of backdrop — always white. Badges/chips use this pair, so
|
|
109
|
+
// their contrast cannot be broken by a host token override.
|
|
110
|
+
--accent-fill: var(--accent);
|
|
111
|
+
|
|
112
|
+
// Aliased, not a second copy of the same white: "ink on a solid accent plate"
|
|
113
|
+
// and "ink on a dark/gradient fill" are the same requirement, so they must
|
|
114
|
+
// move together if the inverse ink is ever re-tuned.
|
|
115
|
+
--on-accent-fill: var(--ink-inverse);
|
|
116
|
+
|
|
117
|
+
// ── Interaction state layers ─────────────────────────────────────────────
|
|
118
|
+
// Translucent veils layered OVER a surface for hover/press/selected instead
|
|
119
|
+
// of swapping its bg colour — one value reads correctly on any background
|
|
120
|
+
// (the visionOS / Material "state layer" model), so hover looks consistent
|
|
121
|
+
// across cards, rows, chips and glass plates alike.
|
|
122
|
+
--state-hover: oklch(50% 0.03 285deg / 5%);
|
|
123
|
+
--state-press: oklch(50% 0.03 285deg / 9%);
|
|
124
|
+
--state-selected: var(--accent-soft);
|
|
125
|
+
|
|
126
|
+
// Bright top rim that gives a translucent plate physical depth. Inert on
|
|
127
|
+
// opaque surfaces; the shell's glass mode leans on it.
|
|
128
|
+
--edge-highlight: oklch(100% 0 0deg / 50%);
|
|
129
|
+
|
|
130
|
+
// ── Icon size ramp ───────────────────────────────────────────────────────
|
|
131
|
+
// ONE scale for every icon (PrimeIcons + inline SVG). Icons had drifted to
|
|
132
|
+
// ~13 different sizes, which is why they never lined up beside each other.
|
|
133
|
+
--icon-xs: 12px; // dense meta rows, chips
|
|
134
|
+
--icon-sm: 14px; // text buttons, section-header actions
|
|
135
|
+
--icon-md: 16px; // default — icon buttons, rails, nav
|
|
136
|
+
--icon-lg: 20px; // emphasis / empty states
|
|
137
|
+
|
|
138
|
+
// ── Status chips (workflow-generic) ──────────────────────────────────────
|
|
139
|
+
--st-published: oklch(55% 0.13 165deg);
|
|
140
|
+
--st-published-bg: oklch(96% 0.04 165deg);
|
|
141
|
+
--st-approved: oklch(55% 0.15 245deg);
|
|
142
|
+
--st-approved-bg: oklch(96% 0.03 245deg);
|
|
143
|
+
--st-draft: oklch(55% 0.005 250deg);
|
|
144
|
+
--st-draft-bg: oklch(95% 0.003 250deg);
|
|
145
|
+
--st-archived: oklch(55% 0.06 60deg);
|
|
146
|
+
--st-archived-bg: oklch(96% 0.025 80deg);
|
|
147
|
+
|
|
148
|
+
// ── Semantic feedback ────────────────────────────────────────────────────
|
|
149
|
+
// Success has no platform equivalent (`--status-success` is a raw dot colour,
|
|
150
|
+
// not a fg/bg pair), so it ships here, aliased onto the published status chip.
|
|
151
|
+
--success: var(--st-published);
|
|
152
|
+
--success-bg: var(--st-published-bg);
|
|
153
|
+
|
|
154
|
+
// Standalone fallbacks for the platform tokens — see the header. Values are
|
|
155
|
+
// copied verbatim from `_theme-light.scss`; keep them in sync if that file
|
|
156
|
+
// changes, or a standalone app drifts from its federated self.
|
|
157
|
+
--danger: #ff6b6b;
|
|
158
|
+
--danger-bg: rgb(255 59 48 / 20%);
|
|
159
|
+
--danger-line: rgb(255 59 48 / 40%);
|
|
160
|
+
--warning: #febc2e;
|
|
161
|
+
--warning-bg: rgb(254 188 46 / 18%);
|
|
162
|
+
--warning-fg: rgb(255 255 255 / 96%);
|
|
163
|
+
--purple: #9333ea;
|
|
164
|
+
--scrim: rgb(0 0 0 / 50%);
|
|
165
|
+
--glass-blur: 24px;
|
|
166
|
+
|
|
167
|
+
// ── Spacing scale (4px base) ─────────────────────────────────────────────
|
|
168
|
+
--sp-1: 4px;
|
|
169
|
+
--sp-2: 8px;
|
|
170
|
+
--sp-3: 12px;
|
|
171
|
+
--sp-4: 16px;
|
|
172
|
+
--sp-5: 22px;
|
|
173
|
+
--sp-6: 28px;
|
|
174
|
+
--sp-7: 40px;
|
|
175
|
+
--sp-8: 56px;
|
|
176
|
+
|
|
177
|
+
// ── Typography scale ─────────────────────────────────────────────────────
|
|
178
|
+
--text-2xs: 11.5px; // field labels, field errors, footer hints
|
|
179
|
+
--text-xs: 11px; // eyebrows, badges, metric labels
|
|
180
|
+
--text-sm: 12.5px; // meta, hints, crumbs
|
|
181
|
+
--text-md: 13.5px; // body in cards, subtitles
|
|
182
|
+
--text-base: 14px; // controls, table body
|
|
183
|
+
--text-lg: 16px; // page body
|
|
184
|
+
--text-xl: 18px; // card titles, dialog titles
|
|
185
|
+
--text-2xl: 28px; // detail page h1
|
|
186
|
+
--text-3xl: 32px; // listing page h1
|
|
187
|
+
--text-display: 44px; // hero title
|
|
188
|
+
--fw-book: 450; // between regular and medium (segmented buttons)
|
|
189
|
+
--fw-medium: 500;
|
|
190
|
+
--fw-semibold: 600;
|
|
191
|
+
--fw-bold: 700;
|
|
192
|
+
--tracking-tight: -0.02em;
|
|
193
|
+
--tracking-wide: 0.06em;
|
|
194
|
+
|
|
195
|
+
// Type families. `--font-family` / `--font-family-mono` are the platform's
|
|
196
|
+
// names; these are the short aliases the component library reads.
|
|
197
|
+
--font-sans: var(--font-family);
|
|
198
|
+
|
|
199
|
+
// Monospace is retired — the UI is one sans face throughout. Kept (aliased)
|
|
200
|
+
// rather than deleted so existing `var(--font-mono)` consumers keep
|
|
201
|
+
// resolving; the `.mono` utility still contributes tabular-nums, which is
|
|
202
|
+
// what those id/number treatments actually need.
|
|
203
|
+
--font-mono: var(--font-sans);
|
|
204
|
+
|
|
205
|
+
// ── Radii ────────────────────────────────────────────────────────────────
|
|
206
|
+
--r-sm: 6px; // icon buttons, kbd
|
|
207
|
+
--r-md: 8px; // buttons, inputs, nav items
|
|
208
|
+
--r-lg: 12px; // cards, table wrapper, filter panel
|
|
209
|
+
--r-xl: 16px; // reserved
|
|
210
|
+
|
|
211
|
+
// ── Layout ───────────────────────────────────────────────────────────────
|
|
212
|
+
--row-h: 56px; // table row
|
|
213
|
+
|
|
214
|
+
// ── Z-index scale ────────────────────────────────────────────────────────
|
|
215
|
+
--z-sticky: 10;
|
|
216
|
+
--z-bulkbar: 50;
|
|
217
|
+
--z-overlay: 100; // drawers, scrims
|
|
218
|
+
--z-dialog: 110; // centered dialogs / confirms
|
|
219
|
+
--z-toast: 200;
|
|
220
|
+
--z-tooltip: 1000;
|
|
221
|
+
|
|
222
|
+
// ── Shadows ──────────────────────────────────────────────────────────────
|
|
223
|
+
--shadow-card: 0 1px 2px oklch(0% 0 0deg / 4%);
|
|
224
|
+
--shadow-active: 0 1px 2px oklch(0% 0 0deg / 4%), 0 0 0 1px var(--line);
|
|
225
|
+
--shadow-bulk: 0 6px 20px oklch(0% 0 0deg / 10%);
|
|
226
|
+
--shadow-filter: 0 12px 36px oklch(0% 0 0deg / 6%);
|
|
227
|
+
--shadow-panel: var(--shadow-filter), 0 1px 0 oklch(100% 0 0deg) inset;
|
|
228
|
+
--shadow-raised: 0 1px 2px oklch(0% 0 0deg / 8%);
|
|
229
|
+
|
|
230
|
+
// DERIVED off --accent, never a copy of its hex: a hardcoded purple here
|
|
231
|
+
// would not follow a runtime accent override (FlyThemeService.applyAccent),
|
|
232
|
+
// so you would get the new accent with the old glow beside it.
|
|
233
|
+
--shadow-accent: 0 4px 12px color-mix(in srgb, var(--accent) 25%, transparent);
|
|
234
|
+
--shadow-tooltip: 0 4px 16px oklch(0% 0 0deg / 18%);
|
|
235
|
+
--shadow-focus-soft: 0 0 0 3px oklch(0% 0 0deg / 4%);
|
|
236
|
+
--shadow-drawer: -24px 0 64px oklch(0% 0 0deg / 8%); // end-side panel (LTR)
|
|
237
|
+
--shadow-drawer-rtl: 24px 0 64px oklch(0% 0 0deg / 8%); // mirrored under RTL
|
|
238
|
+
--shadow-dialog: 0 24px 64px oklch(18% 0.005 250deg / 18%), 0 8px 24px oklch(18% 0.005 250deg / 10%);
|
|
239
|
+
--shadow-toast: 0 12px 32px oklch(18% 0.005 250deg / 14%), 0 4px 12px oklch(18% 0.005 250deg / 8%);
|
|
240
|
+
|
|
241
|
+
// ── Transitions ──────────────────────────────────────────────────────────
|
|
242
|
+
--t-state: 0.12s ease;
|
|
243
|
+
--t-layout: 0.25s cubic-bezier(0.4, 0, 0.2, 1);
|
|
244
|
+
--t-overlay: 0.18s cubic-bezier(0.2, 0.7, 0.2, 1);
|
|
245
|
+
--t-drawer: 0.32s cubic-bezier(0.32, 0.72, 0.2, 1);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// ── Dark theme ───────────────────────────────────────────────────────────────
|
|
249
|
+
// Sizing, radii, type, spacing, z-index and transition tokens are theme-neutral
|
|
250
|
+
// and inherit the block above unchanged. Alias-based tokens (--success*,
|
|
251
|
+
// --on-accent-*, --state-selected, --font-*) re-resolve through their targets
|
|
252
|
+
// automatically and are NOT redeclared — a second declaration would just be a
|
|
253
|
+
// second place to get it wrong.
|
|
254
|
+
html.dark-theme {
|
|
255
|
+
// The nine platform fallbacks carry the SAME values in both themes upstream,
|
|
256
|
+
// except this one — `_theme-dark.scss` widens the blur. Redeclaring only the
|
|
257
|
+
// token that actually differs keeps the rest inheriting from the block above.
|
|
258
|
+
--glass-blur: 40px;
|
|
259
|
+
|
|
260
|
+
// ── Neutrals (inverted lightness) ────────────────────────────────────────
|
|
261
|
+
--ink: oklch(95% 0.005 250deg);
|
|
262
|
+
--ink-2: oklch(78% 0.005 250deg);
|
|
263
|
+
--ink-3: oklch(62% 0.005 250deg);
|
|
264
|
+
--ink-4: oklch(45% 0.005 250deg);
|
|
265
|
+
--ink-hover: oklch(85% 0.005 250deg);
|
|
266
|
+
// Flips with --ink above: the primary button is a near-white pill here, so its
|
|
267
|
+
// label goes near-black. Aliased to --bg (the darkest opaque surface in this
|
|
268
|
+
// theme) rather than repeating its literal — see the contract on the :root decl.
|
|
269
|
+
--on-ink: var(--bg);
|
|
270
|
+
--line: oklch(22% 0.004 250deg);
|
|
271
|
+
--line-2: oklch(28% 0.004 250deg);
|
|
272
|
+
--line-3: oklch(18% 0.003 250deg);
|
|
273
|
+
--bg: oklch(14% 0.003 250deg);
|
|
274
|
+
--bg-2: oklch(17% 0.003 250deg);
|
|
275
|
+
--bg-3: oklch(20% 0.004 250deg);
|
|
276
|
+
--bg-hover: oklch(24% 0.005 250deg);
|
|
277
|
+
|
|
278
|
+
// ── Brand — higher chroma/lightness to pop on dark ───────────────────────
|
|
279
|
+
--teal: oklch(78% 0.13 195deg);
|
|
280
|
+
--grad: linear-gradient(
|
|
281
|
+
135deg,
|
|
282
|
+
oklch(85% 0.12 325deg),
|
|
283
|
+
oklch(70% 0.19 305deg),
|
|
284
|
+
oklch(60% 0.2 285deg)
|
|
285
|
+
);
|
|
286
|
+
--grad-soft: linear-gradient(
|
|
287
|
+
135deg,
|
|
288
|
+
oklch(78% 0.13 195deg / 18%),
|
|
289
|
+
oklch(68% 0.18 295deg / 18%)
|
|
290
|
+
);
|
|
291
|
+
|
|
292
|
+
// ── Interaction state layers — light veil on dark surfaces ───────────────
|
|
293
|
+
--state-hover: oklch(95% 0.02 285deg / 6%);
|
|
294
|
+
--state-press: oklch(95% 0.02 285deg / 11%);
|
|
295
|
+
--edge-highlight: oklch(100% 0 0deg / 6%);
|
|
296
|
+
|
|
297
|
+
// ── Status chips — dim bg, bright fg ─────────────────────────────────────
|
|
298
|
+
--st-published: oklch(85% 0.13 165deg);
|
|
299
|
+
--st-published-bg: oklch(28% 0.06 165deg);
|
|
300
|
+
--st-approved: oklch(82% 0.15 245deg);
|
|
301
|
+
--st-approved-bg: oklch(28% 0.06 245deg);
|
|
302
|
+
--st-draft: var(--ink-2); // same grey as secondary text on dark
|
|
303
|
+
--st-draft-bg: oklch(24% 0.003 250deg);
|
|
304
|
+
--st-archived: oklch(82% 0.06 60deg);
|
|
305
|
+
--st-archived-bg: oklch(28% 0.05 60deg);
|
|
306
|
+
|
|
307
|
+
// ── Shadows — deeper opacity on dark surfaces ────────────────────────────
|
|
308
|
+
--shadow-card: 0 1px 2px oklch(0% 0 0deg / 35%);
|
|
309
|
+
--shadow-active: 0 1px 2px oklch(0% 0 0deg / 40%), 0 0 0 1px var(--line);
|
|
310
|
+
--shadow-bulk: 0 6px 20px oklch(0% 0 0deg / 55%);
|
|
311
|
+
--shadow-filter: 0 12px 36px oklch(0% 0 0deg / 50%);
|
|
312
|
+
--shadow-panel: var(--shadow-filter), 0 1px 0 oklch(100% 0 0deg / 5%) inset;
|
|
313
|
+
--shadow-accent: 0 4px 12px color-mix(in srgb, var(--accent) 30%, transparent);
|
|
314
|
+
--shadow-focus-soft: 0 0 0 3px oklch(100% 0 0deg / 6%);
|
|
315
|
+
--shadow-drawer: -24px 0 64px oklch(0% 0 0deg / 50%);
|
|
316
|
+
--shadow-drawer-rtl: 24px 0 64px oklch(0% 0 0deg / 50%);
|
|
317
|
+
--shadow-dialog: 0 24px 64px oklch(0% 0 0deg / 60%), 0 8px 24px oklch(0% 0 0deg / 40%);
|
|
318
|
+
--shadow-toast: 0 12px 32px oklch(0% 0 0deg / 50%), 0 4px 12px oklch(0% 0 0deg / 30%);
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
// ── Chrome-token bridge (STANDALONE ONLY) ────────────────────────────────────
|
|
322
|
+
// The older DS components (everything outside lib/app-surface) theme from the
|
|
323
|
+
// SHELL-CHROME family — --label-*, --surface-*, --text-color*, --separator* —
|
|
324
|
+
// and each reference carries a hardcoded literal fallback, e.g.
|
|
325
|
+
// `var(--label-primary, #1d1d1f)` or `var(--surface-card, #fff)`. 211 such
|
|
326
|
+
// fallbacks exist across the library.
|
|
327
|
+
//
|
|
328
|
+
// Those literals are theme-BLIND: a single constant picked by whoever wrote the
|
|
329
|
+
// component. Federated that never shows, because the desktop shell defines the
|
|
330
|
+
// whole chrome family. Standalone, no one does — so a business app got whatever
|
|
331
|
+
// constant each component happened to hardcode, in BOTH light and dark.
|
|
332
|
+
//
|
|
333
|
+
// Aliasing the chrome names onto the app-surface family fixes all 211 sites at
|
|
334
|
+
// once, without touching a single component: the var() resolves through the
|
|
335
|
+
// token and never reaches its literal. The targets are theme-aware, so these
|
|
336
|
+
// follow light/dark automatically.
|
|
337
|
+
//
|
|
338
|
+
// SELECTOR IS LOAD-BEARING: this block is `:root` ALONE — deliberately not
|
|
339
|
+
// `:root, html.light-theme` like the blocks above. The shell declares every one
|
|
340
|
+
// of these under `html.light-theme` / `html.dark-theme` (specificity 0,1,1),
|
|
341
|
+
// which beats a bare `:root` (0,1,0). So federated, the shell's chrome always
|
|
342
|
+
// wins and nothing about the desktop changes; standalone, nothing else declares
|
|
343
|
+
// them and these apply. Widening this selector would create a specificity TIE
|
|
344
|
+
// with the shell and hand the desktop's own chrome to source order.
|
|
345
|
+
:root {
|
|
346
|
+
// Text
|
|
347
|
+
--label-primary: var(--ink);
|
|
348
|
+
--label-secondary: var(--ink-3);
|
|
349
|
+
--label-tertiary: var(--ink-4);
|
|
350
|
+
--text-color: var(--ink);
|
|
351
|
+
--text-color-secondary: var(--ink-3);
|
|
352
|
+
|
|
353
|
+
// Surfaces
|
|
354
|
+
--surface-ground: var(--bg);
|
|
355
|
+
--surface-card: var(--bg-2);
|
|
356
|
+
--surface-section: var(--bg-3);
|
|
357
|
+
--surface-overlay: var(--bg-2);
|
|
358
|
+
--surface-overlay-strong: var(--bg-2);
|
|
359
|
+
|
|
360
|
+
// Lines + interaction states
|
|
361
|
+
--surface-border: var(--line);
|
|
362
|
+
--separator: var(--line);
|
|
363
|
+
--separator-primary: var(--line);
|
|
364
|
+
--surface-hover: var(--bg-hover);
|
|
365
|
+
--surface-active: var(--state-selected);
|
|
366
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
2
|
+
// UI library global utilities (generic). EMITS CSS — import once from the
|
|
3
|
+
// global stylesheet, after _tokens.scss.
|
|
4
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
5
|
+
@use 'shell-embed-bridge';
|
|
6
|
+
|
|
7
|
+
// Class form of the app-surface → shell-glass bridge, for consumers that cannot
|
|
8
|
+
// reach the mixin: a component with INLINE `styles:` (no SCSS pipeline), or a
|
|
9
|
+
// subtree portalled out of its app's stylesheet scope. Prefer the mixin in a
|
|
10
|
+
// real `.scss` file; this exists so the map is never retyped by hand. See
|
|
11
|
+
// `_shell-embed-bridge.scss` for why the bridge is needed at all.
|
|
12
|
+
.fly-app-surface-on-glass {
|
|
13
|
+
@include shell-embed-bridge.app-surface-on-glass;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// Tabular numerals / code — reusable in templates without restyling a component.
|
|
17
|
+
.mono {
|
|
18
|
+
font-family: var(--font-mono);
|
|
19
|
+
font-variant-numeric: tabular-nums;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// ── Tooltip (CSS-only, no JS dependency) ─────────────────────────────────────
|
|
23
|
+
// Add `data-tooltip="text"` to any element to show a floating label on hover or
|
|
24
|
+
// keyboard focus. Always pair with `aria-label` for screen-reader users —
|
|
25
|
+
// data-tooltip is a *visual* affordance only (the flyTooltip directive wires
|
|
26
|
+
// both together). Consumers should use `data-tooltip` *instead of* `title`.
|
|
27
|
+
[data-tooltip] {
|
|
28
|
+
position: relative;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
[data-tooltip]::before,
|
|
32
|
+
[data-tooltip]::after {
|
|
33
|
+
position: absolute;
|
|
34
|
+
left: 50%;
|
|
35
|
+
pointer-events: none;
|
|
36
|
+
opacity: 0;
|
|
37
|
+
transition: opacity 0.14s ease, transform 0.14s ease;
|
|
38
|
+
z-index: var(--z-tooltip);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
[data-tooltip]::before {
|
|
42
|
+
content: attr(data-tooltip);
|
|
43
|
+
bottom: calc(100% + 8px);
|
|
44
|
+
transform: translateX(-50%) translateY(3px);
|
|
45
|
+
background: var(--ink);
|
|
46
|
+
color: var(--ink-inverse);
|
|
47
|
+
font-family: var(--font-sans, system-ui, sans-serif);
|
|
48
|
+
font-size: var(--text-xs);
|
|
49
|
+
font-weight: var(--fw-medium);
|
|
50
|
+
line-height: 1.3;
|
|
51
|
+
letter-spacing: 0;
|
|
52
|
+
padding: 5px 9px;
|
|
53
|
+
border-radius: var(--r-sm);
|
|
54
|
+
white-space: nowrap;
|
|
55
|
+
box-shadow: var(--shadow-tooltip);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
[data-tooltip]::after {
|
|
59
|
+
content: '';
|
|
60
|
+
bottom: calc(100% + 3px);
|
|
61
|
+
transform: translateX(-50%) translateY(3px);
|
|
62
|
+
width: 0;
|
|
63
|
+
height: 0;
|
|
64
|
+
border-left: 5px solid transparent;
|
|
65
|
+
border-right: 5px solid transparent;
|
|
66
|
+
border-top: 5px solid var(--ink);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
[data-tooltip]:hover::before,
|
|
70
|
+
[data-tooltip]:hover::after,
|
|
71
|
+
[data-tooltip]:focus-visible::before,
|
|
72
|
+
[data-tooltip]:focus-visible::after {
|
|
73
|
+
opacity: 1;
|
|
74
|
+
transform: translateX(-50%) translateY(0);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// ── CDK overlay container ────────────────────────────────────────────────────
|
|
78
|
+
// Styled entirely by @angular/cdk/overlay-prebuilt.css (imported by the global
|
|
79
|
+
// stylesheet). Its default z-index 1000 is correct here: a connected dropdown
|
|
80
|
+
// (fly-action-menu) is the topmost transient and every library layer sits
|
|
81
|
+
// below 1000. Do NOT re-pin it — the container is shared with the federated
|
|
82
|
+
// shell, so an override leaks into the host's overlays.
|