@meshmakers/octo-ui 3.4.1100 → 3.4.1120

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.
@@ -0,0 +1,484 @@
1
+ // ============================================================================
2
+ // RUNTIME BROWSER - Theme tokens (dark default + light)
3
+ //
4
+ // `_variables.scss` defines the LCARS brand palette and *consumes* the
5
+ // semantic `--theme-*` tokens with dark fallbacks. This file is where those
6
+ // semantic tokens are actually defined, for both themes, so that every host
7
+ // app resolves them identically instead of maintaining its own copy.
8
+ //
9
+ // Usage in a host app's global stylesheet:
10
+ //
11
+ // @use "styles/_with-kendo.scss" as octo; // or _index.scss when the host
12
+ // // imports Kendo itself
13
+ // @include octo.theme(); // :root tokens, both themes
14
+ // @include octo.styles(); // component styles
15
+ //
16
+ // Dark is the default. Light is applied either by OS preference (when the
17
+ // host has not forced dark) or by an explicit `data-theme="light"` on the
18
+ // root element — see ThemeService in @meshmakers/octo-ui/branding.
19
+ // ============================================================================
20
+
21
+ @use "variables" as vars;
22
+
23
+ // ----------------------------------------------------------------------------
24
+ // DARK THEME (default)
25
+ // ----------------------------------------------------------------------------
26
+ @mixin dark-theme-tokens {
27
+ // Surfaces & backgrounds
28
+ --theme-bg-app: #07172b;
29
+ --theme-bg-app-end: #07172b;
30
+ --theme-bg-surface: #394555;
31
+ --theme-bg-elevated: #1f2e40;
32
+ --theme-bg-overlay: rgba(31, 46, 64, 0.4);
33
+ --theme-bg-input: #1f2e40;
34
+
35
+ // Text
36
+ --theme-text-primary: #ffffff;
37
+ --theme-text-secondary: #9292a6;
38
+ --theme-text-muted: #6b7689;
39
+ --theme-text-on-accent: #07172b;
40
+ --theme-text-accent: #64ceb9;
41
+
42
+ // Borders
43
+ --theme-border-subtle: rgba(100, 206, 185, 0.2);
44
+ --theme-border-strong: rgba(100, 206, 185, 0.45);
45
+ --theme-border-divider: rgba(255, 255, 255, 0.08);
46
+
47
+ // Effects
48
+ --theme-glow-primary: 0 0 10px rgba(100, 206, 185, 0.4);
49
+ --theme-glow-accent: 0 0 15px rgba(100, 206, 185, 0.5);
50
+ --theme-shadow-panel: 0 4px 30px rgba(0, 0, 0, 0.3);
51
+ --theme-shadow-popup: 0 8px 32px rgba(0, 0, 0, 0.5);
52
+
53
+ // Gradients
54
+ --theme-gradient-page: linear-gradient(180deg, rgba(7, 23, 43, 0.95), rgba(7, 23, 43, 1));
55
+ --theme-gradient-header: linear-gradient(180deg, #394555, #1f2e40);
56
+ --theme-accent-bar: linear-gradient(180deg, var(--octo-mint), var(--neo-cyan));
57
+ --theme-accent-line: linear-gradient(90deg, var(--octo-mint), var(--neo-cyan), transparent);
58
+ --theme-panel-rule: linear-gradient(90deg, var(--octo-mint), var(--neo-cyan), var(--royal-violet));
59
+
60
+ // Status (semantic)
61
+ --theme-status-success: #37b400;
62
+ --theme-status-warning: #da9162;
63
+ --theme-status-error: #ec658f;
64
+ --theme-status-info: #00a8dc;
65
+
66
+ // Chart palette (8 series)
67
+ --theme-chart-1: #64ceb9;
68
+ --theme-chart-2: #00a8dc;
69
+ --theme-chart-3: #6c4da8;
70
+ --theme-chart-4: #da9162;
71
+ --theme-chart-5: #ec658f;
72
+ --theme-chart-6: #c861d6;
73
+ --theme-chart-7: #546fbd;
74
+ --theme-chart-8: #9292a6;
75
+
76
+ // Kendo bridge
77
+ --kendo-color-on-base: #c8cdd3;
78
+ --kendo-color-on-primary: #07172b;
79
+ --kendo-color-base-on-surface: #c8cdd3;
80
+
81
+ // Kendo's Material default --kendo-color-base is the Ash-Blue #9292a6,
82
+ // which lands as a washed-out medium-grey on the LCARS dark surfaces and
83
+ // is the source of the low-contrast "Copy ID" / kendo-dropdownbutton look
84
+ // (white-ish text on light-ish grey, hard to read against the deep-sea bg).
85
+ // Repoint --kendo-color-base and its subtle/emphasis siblings at the LCARS
86
+ // surface palette so every solid-base button (kendo-dropdownbutton, menu
87
+ // buttons, .k-button-solid-base) blends with the surrounding panels while
88
+ // keeping enough contrast against the page background.
89
+ --kendo-color-base: #394555; // = iron-navy / theme-bg-surface
90
+ --kendo-color-base-subtle: #1f2e40; // = surface-elevated / theme-bg-elevated
91
+ --kendo-color-base-emphasis: #4a5970; // one notch brighter for hover/active
92
+ --kendo-color-base-hover: #475569; // explicit hover override (Material derives it from --base otherwise, which Kendo computes as still-too-light)
93
+ --kendo-color-base-active: #4a5970;
94
+ }
95
+
96
+ // ----------------------------------------------------------------------------
97
+ // LIGHT THEME (single source of truth — used by both the OS-preference media
98
+ // query and the explicit [data-theme="light"] override).
99
+ // ----------------------------------------------------------------------------
100
+ @mixin light-theme-tokens {
101
+ // The page needs to sit BELOW the cards, or there is no depth at all:
102
+ // #ffffff on #f3f6fa measured 1.08:1 — card and page were the same surface.
103
+ // #e9edf3 puts it at 1.35:1, which is what the dark theme has (1.85:1).
104
+ --theme-bg-app: #e9edf3;
105
+ --theme-bg-app-end: #e9edf3;
106
+ --theme-bg-surface: #ffffff;
107
+ --theme-bg-elevated: #f4f7fa;
108
+ --theme-bg-overlay: rgba(255, 255, 255, 0.92);
109
+ --theme-bg-input: #ffffff;
110
+
111
+ --theme-text-primary: #07172b;
112
+ --theme-text-secondary: #4b576b;
113
+ --theme-text-muted: #6b7689;
114
+ --theme-text-on-accent: #ffffff;
115
+ --theme-text-accent: #2e8473;
116
+
117
+ // Neutral, not mint. A mint hairline measures 1.12:1 on a light ground —
118
+ // it is not a subtle border, it is an invisible one.
119
+ --theme-border-subtle: rgba(7, 23, 43, 0.12);
120
+ --theme-border-strong: rgba(7, 23, 43, 0.22);
121
+ --theme-border-divider: rgba(7, 23, 43, 0.1);
122
+
123
+ // A glow needs a dark room. On a light ground it only muddies the edge.
124
+ --theme-glow-primary: none;
125
+ --theme-glow-accent: none;
126
+ --theme-shadow-panel: 0 2px 8px rgba(7, 23, 43, 0.08);
127
+ --theme-shadow-popup: 0 8px 24px rgba(7, 23, 43, 0.15);
128
+
129
+ --theme-gradient-page: linear-gradient(180deg, #f3f6fa, #ffffff);
130
+ --theme-gradient-header: linear-gradient(180deg, #ffffff, #eef2f7);
131
+ --theme-accent-line: linear-gradient(90deg, #2e8473, #0288b8, transparent);
132
+ // accent-bar and panel-rule keep the brand gradient (defined in the dark
133
+ // block, which always runs first, and deliberately not redefined here).
134
+
135
+ --theme-status-success: #2e8b00;
136
+ --theme-status-warning: #b56b3c;
137
+ --theme-status-error: #c63d6a;
138
+ --theme-status-info: #0277a6;
139
+
140
+ --theme-chart-1: #2e8473;
141
+ --theme-chart-2: #0277a6;
142
+ --theme-chart-3: #553a85;
143
+ --theme-chart-4: #b56b3c;
144
+ --theme-chart-5: #c63d6a;
145
+ --theme-chart-6: #9c4ba8;
146
+ --theme-chart-7: #3f5394;
147
+ --theme-chart-8: #6b7689;
148
+
149
+ --kendo-color-on-base: #07172b;
150
+ --kendo-color-on-primary: #ffffff;
151
+ --kendo-color-base-on-surface: #07172b;
152
+
153
+ // Light-theme counterparts to the LCARS dark-theme overrides above.
154
+ // Light buttons should sit on a pale neutral that reads against the
155
+ // off-white app background without disappearing into it.
156
+ --kendo-color-base: #eef2f7; // = theme-bg-elevated (light)
157
+ --kendo-color-base-subtle: #f3f6fa; // = theme-bg-app (lightest)
158
+ --kendo-color-base-emphasis: #d8e0ea; // one notch darker for hover/active
159
+ --kendo-color-base-hover: #d8e0ea;
160
+ --kendo-color-base-active: #c8d2dd;
161
+ }
162
+
163
+ // ----------------------------------------------------------------------------
164
+ // Light-theme button contrast — the library's primary/base button gradients
165
+ // (mint at 15–30% alpha) read fine on dark surfaces but wash out on white,
166
+ // leaving confirmation-dialog buttons hard to tell apart and the secondary
167
+ // button looking disabled. Apply solid theme-token fills in light mode.
168
+ //
169
+ // Dialog/window action buttons are styled by the lcars-button mixin scoped to
170
+ // `.k-dialog .k-dialog-actions` (and friends), which has specificity (0,4,0).
171
+ // These selectors have to match or beat that — they land at (0,5,1).
172
+ // ----------------------------------------------------------------------------
173
+ @mixin light-theme-button-primary {
174
+ background: var(--theme-text-accent);
175
+ border-color: var(--theme-text-accent);
176
+ color: #ffffff;
177
+
178
+ .k-svg-icon,
179
+ .k-icon,
180
+ svg {
181
+ fill: #ffffff;
182
+ color: #ffffff;
183
+ }
184
+
185
+ &:hover:not(:disabled) {
186
+ background: color-mix(in srgb, var(--theme-text-accent) 88%, black);
187
+ border-color: color-mix(in srgb, var(--theme-text-accent) 88%, black);
188
+ box-shadow: var(--theme-glow-accent);
189
+ }
190
+
191
+ &:active:not(:disabled) {
192
+ background: color-mix(in srgb, var(--theme-text-accent) 75%, black);
193
+ }
194
+ }
195
+
196
+ @mixin light-theme-button-base {
197
+ background: var(--theme-bg-elevated);
198
+ border-color: var(--theme-border-strong);
199
+ color: var(--theme-text-primary);
200
+
201
+ .k-svg-icon,
202
+ .k-icon,
203
+ svg {
204
+ fill: var(--theme-text-primary);
205
+ color: var(--theme-text-primary);
206
+ }
207
+
208
+ &:hover:not(:disabled) {
209
+ background: color-mix(in srgb, var(--theme-text-accent) 12%, var(--theme-bg-elevated));
210
+ border-color: var(--theme-text-accent);
211
+ }
212
+
213
+ &:active:not(:disabled) {
214
+ background: color-mix(in srgb, var(--theme-text-accent) 20%, var(--theme-bg-elevated));
215
+ }
216
+ }
217
+
218
+ // ----------------------------------------------------------------------------
219
+ // Light-theme structure.
220
+ //
221
+ // The LCARS palette is built to glow, and glowing means light. Ported to a
222
+ // light ground by inverting lightness alone, every role it plays collapses:
223
+ // octo-mint carries 9.49:1 as text on #07172b and 1.75:1 on #f3f6fa, and the
224
+ // mint tints that draw every panel edge fall from 1.53:1 to 1.12:1.
225
+ //
226
+ // So the ROLE changes with the theme, not just the value: in dark, colour is
227
+ // the figure — thin bright lines and glowing text. In light, colour becomes
228
+ // the ground — solid brand blocks carrying dark text, structure carried by
229
+ // surface elevation and neutral rules. That is also closer to real LCARS,
230
+ // which is built from coloured blocks rather than hairlines. The proof is in
231
+ // the same number: #07172b on #64ceb9 is again 9.49:1 — one pair, two roles.
232
+ // ----------------------------------------------------------------------------
233
+ @mixin light-theme-surface-overrides {
234
+ // Cards lift off the ground again.
235
+ .k-grid,
236
+ .lcars-content-panel,
237
+ .lcars-panel {
238
+ background: #ffffff;
239
+ border: 1px solid rgba(7, 23, 43, 0.1);
240
+ box-shadow: 0 1px 3px rgba(7, 23, 43, 0.07);
241
+ }
242
+
243
+ // A grid inside a content panel must not become a second card: the panel
244
+ // already supplies the border, the radius and the surface. Two nested cards
245
+ // is what left the toolbar's rounded top corners floating inside a white
246
+ // sheet, with a transparent filter strip wedged between them.
247
+ .lcars-content-panel .k-grid {
248
+ border: none;
249
+ border-radius: 0;
250
+ box-shadow: none;
251
+ }
252
+
253
+ // Table chrome. In dark the header/toolbar/pager band is LIGHTER than the
254
+ // data; on a light ground it has to be darker, or the table loses its frame
255
+ // and reads as a borderless white slab.
256
+ .k-grid .k-grid-header,
257
+ .k-grid-toolbar,
258
+ .k-toolbar,
259
+ .k-pager,
260
+ .k-grid-pager {
261
+ background: #d7ebe5;
262
+ border-color: rgba(46, 132, 115, 0.3);
263
+ }
264
+
265
+ .k-grid .k-grid-header {
266
+ border-bottom: 2px solid rgba(46, 132, 115, 0.45);
267
+ }
268
+
269
+ .k-pager,
270
+ .k-grid-pager {
271
+ border-top: 1px solid rgba(46, 132, 115, 0.3);
272
+ }
273
+
274
+ .k-grid .k-grid-content {
275
+ background: #ffffff;
276
+ }
277
+
278
+ // Uppercase plus letter-spacing costs width and legibility in a dense table,
279
+ // and mint column headers are unreadable on a light band anyway.
280
+ .k-grid .k-grid-header th {
281
+ color: var(--theme-text-primary);
282
+ text-transform: none;
283
+ letter-spacing: 0;
284
+ font-weight: 600;
285
+ }
286
+
287
+ .k-label,
288
+ kendo-label,
289
+ .section-title {
290
+ text-transform: none;
291
+ letter-spacing: 0;
292
+ }
293
+
294
+ // Brand as block, never as ink.
295
+ .lcars-header-accent {
296
+ background: var(--octo-mint);
297
+ border-radius: 4px;
298
+ box-shadow: none;
299
+ }
300
+
301
+ .page-title .title-prefix {
302
+ background: var(--octo-mint);
303
+ color: #07172b;
304
+ padding: 3px 10px;
305
+ border-radius: 3px;
306
+ font-weight: 700;
307
+ }
308
+
309
+ .page-title .title-main {
310
+ color: var(--theme-text-primary);
311
+ }
312
+
313
+ .lcars-header-line {
314
+ background: rgba(7, 23, 43, 0.1);
315
+ height: 1px;
316
+ }
317
+
318
+ .k-drawer .k-drawer-item.k-selected {
319
+ background: var(--octo-mint);
320
+ color: #07172b;
321
+ border-left: none;
322
+ font-weight: 600;
323
+
324
+ // The count badge is mint-on-mint once the row itself is a mint block.
325
+ .drawer-badge {
326
+ color: #07172b;
327
+ background: rgba(255, 255, 255, 0.8);
328
+ border-color: rgba(7, 23, 43, 0.18);
329
+ }
330
+ }
331
+
332
+ // The app bar carried four treatments on one edge: a 1px mint border
333
+ // (1.18:1 — invisible), the 2px gradient ::after the host draws, a
334
+ // dark-theme drop shadow, and the host's breadcrumb wash. Keep the gradient
335
+ // as the single statement.
336
+ .k-appbar {
337
+ border-bottom: none;
338
+ box-shadow: 0 1px 2px rgba(7, 23, 43, 0.08);
339
+ }
340
+
341
+ // Decoration that carries the theme in dark and carries nothing in light.
342
+ .lcars-status-bar,
343
+ .lcars-footer .footer-bar {
344
+ display: none;
345
+ }
346
+ }
347
+
348
+ @mixin light-theme-button-overrides {
349
+ // Dialog action buttons (kendo-dialog-actions used by ConfirmationService etc.)
350
+ .k-dialog .k-dialog-actions,
351
+ .k-window > .k-actions {
352
+ .k-button.k-button-solid-primary,
353
+ .k-button.k-button-primary,
354
+ .k-button[themecolor="primary"] {
355
+ @include light-theme-button-primary;
356
+ }
357
+
358
+ // Base/default button (the "No"/"Cancel"/secondary action)
359
+ .k-button:not(.k-button-primary):not(.k-button-solid-primary):not([themecolor="primary"]):not(.k-button-flat):not(.k-button-outline):not([themecolor="error"]) {
360
+ @include light-theme-button-base;
361
+ }
362
+ }
363
+
364
+ // General-purpose primary/base buttons outside dialogs (top-level scope so
365
+ // host-app pages get the same emphasis without each page having to opt in)
366
+ .k-button.k-button-solid-primary {
367
+ @include light-theme-button-primary;
368
+ }
369
+
370
+ .k-button.k-button-solid-base {
371
+ @include light-theme-button-base;
372
+ }
373
+ }
374
+
375
+ // ----------------------------------------------------------------------------
376
+ // Public entry point: emits the :root token blocks for both themes.
377
+ // Include this ONCE per app, before `styles()`.
378
+ // ----------------------------------------------------------------------------
379
+ // ----------------------------------------------------------------------------
380
+ // Kendo colour bridge.
381
+ //
382
+ // `_kendo-theme.scss` (the library's SLIM Kendo build) already binds Kendo's
383
+ // $kendo-colors to our tokens, so hosts using `_with-kendo.scss` are covered.
384
+ // A host that imports the FULL @progress/kendo-theme-material itself is not:
385
+ // it gets Material's light defaults, which is why the Meshmakers App's grid
386
+ // and toolbars rendered white on the dark theme. Declaring the same bridge as
387
+ // :root custom properties covers both entry points and, unlike a compiled
388
+ // $kendo-colors merge, follows the active theme at runtime.
389
+ //
390
+ // Values deliberately resolve to what the slim theme already produced, so this
391
+ // changes nothing for hosts that were already on it.
392
+ // ----------------------------------------------------------------------------
393
+ @mixin kendo-bridge {
394
+ --kendo-color-surface: var(--theme-bg-surface);
395
+ --kendo-color-surface-alt: var(--theme-bg-elevated);
396
+ --kendo-color-on-surface: var(--kendo-color-base-on-surface);
397
+ --kendo-color-subtle: var(--theme-text-secondary);
398
+ --kendo-color-border: var(--theme-border-divider);
399
+
400
+ // Kendo derives every `*-on-subtle` ink from its own `*-subtle` surface,
401
+ // assuming that surface is light. We repoint --kendo-color-base-subtle at a
402
+ // dark elevated surface, but the derived ink stayed near-black (#131316) —
403
+ // which is what made chips (assigned roles and groups on the identity pages)
404
+ // render as dark text on a dark pill. The other `*-subtle` surfaces are left
405
+ // at Kendo's light values, so their inks stay correct and are not touched.
406
+ --kendo-color-base-on-subtle: var(--kendo-color-base-on-surface);
407
+
408
+ --kendo-color-secondary: var(--neo-cyan);
409
+ --kendo-color-tertiary: var(--toffee);
410
+ --kendo-color-info: var(--indigogo);
411
+ --kendo-color-success: var(--theme-status-success);
412
+ --kendo-color-warning: var(--theme-status-warning);
413
+ --kendo-color-error: var(--theme-status-error);
414
+ }
415
+
416
+ // ----------------------------------------------------------------------------
417
+ // Ink overlays — "one step raised off the page".
418
+ //
419
+ // The idiom a dark-only stylesheet writes as `rgba(255,255,255,.03)` cannot be
420
+ // expressed with a surface colour that works in both themes: alpha-blending a
421
+ // light surface over a light page yields no contrast. Tinting with the TEXT
422
+ // colour does work — white-ish over dark lightens, near-black over light
423
+ // darkens — so these derive from --theme-text-primary and flip with the theme.
424
+ //
425
+ // Ready-made steps rather than a color-mix() at every call site: the same few
426
+ // values recur across dozens of declarations and the long form pushes
427
+ // component stylesheets against their style budget.
428
+ // ----------------------------------------------------------------------------
429
+ @mixin ink-overlays {
430
+ --theme-ink-02: color-mix(in srgb, var(--theme-text-primary) 2%, transparent);
431
+ --theme-ink-03: color-mix(in srgb, var(--theme-text-primary) 3%, transparent);
432
+ --theme-ink-04: color-mix(in srgb, var(--theme-text-primary) 4%, transparent);
433
+ --theme-ink-06: color-mix(in srgb, var(--theme-text-primary) 6%, transparent);
434
+ --theme-ink-08: color-mix(in srgb, var(--theme-text-primary) 8%, transparent);
435
+ --theme-ink-09: color-mix(in srgb, var(--theme-text-primary) 9%, transparent);
436
+ --theme-ink-12: color-mix(in srgb, var(--theme-text-primary) 12%, transparent);
437
+ --theme-ink-15: color-mix(in srgb, var(--theme-text-primary) 15%, transparent);
438
+ --theme-ink-70: color-mix(in srgb, var(--theme-text-primary) 70%, transparent);
439
+ }
440
+
441
+ @mixin theme {
442
+ :root {
443
+ @include vars.variables;
444
+ @include dark-theme-tokens;
445
+ @include kendo-bridge;
446
+ @include ink-overlays;
447
+ }
448
+
449
+ // ----- LIGHT THEME via OS preference (when no force-dark override) -----
450
+ @media (prefers-color-scheme: light) {
451
+ :root:not([data-theme="dark"]) {
452
+ @include light-theme-tokens;
453
+ }
454
+ }
455
+
456
+ // ----- LIGHT THEME via explicit override -----
457
+ :root[data-theme="light"] {
458
+ @include light-theme-tokens;
459
+ }
460
+ }
461
+
462
+ // ----------------------------------------------------------------------------
463
+ // Public entry point: emits the light-theme button overrides.
464
+ //
465
+ // Include this in a host's GLOBAL stylesheet, AFTER `styles()` — the lcars
466
+ // button mixin styles dialog action buttons at specificity (0,4,0), so these
467
+ // rules must both outrank it and come later in source order. Deliberately not
468
+ // part of `styles()`: that mixin is also included from component stylesheets,
469
+ // where :root-scoped rules do not belong and would inflate every component's
470
+ // style budget.
471
+ // ----------------------------------------------------------------------------
472
+ @mixin theme-overrides {
473
+ @media (prefers-color-scheme: light) {
474
+ :root:not([data-theme="dark"]) {
475
+ @include light-theme-surface-overrides;
476
+ @include light-theme-button-overrides;
477
+ }
478
+ }
479
+
480
+ :root[data-theme="light"] {
481
+ @include light-theme-surface-overrides;
482
+ @include light-theme-button-overrides;
483
+ }
484
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@meshmakers/octo-ui",
3
- "version": "3.4.1100",
3
+ "version": "3.4.1120",
4
4
  "peerDependencies": {
5
5
  "@ngx-translate/core": "^17.0.0 || ^18.0.0",
6
6
  "@angular/animations": "^22.0.0",