@dataengineeringformachinelearning/viking-ui 1.0.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.
@@ -0,0 +1,460 @@
1
+ // Shared navbar + theme toggle (frontend Angular, marketing Astro, backend Django).
2
+
3
+ .navbar {
4
+ position: sticky;
5
+ top: 0;
6
+ z-index: 50;
7
+ width: 100%;
8
+ min-height: var(--navbar-height, 64px);
9
+ background-color: var(--navbar-bg);
10
+ backdrop-filter: blur(12px);
11
+ -webkit-backdrop-filter: blur(12px);
12
+ border-bottom: 1px solid var(--border-layout);
13
+ display: flex;
14
+ flex-direction: column;
15
+ align-items: stretch;
16
+ padding: 9px 24px;
17
+ box-sizing: border-box;
18
+ }
19
+
20
+ .navbar-brand {
21
+ margin-right: 8px;
22
+ display: inline-flex;
23
+ align-items: center;
24
+ justify-content: center;
25
+ gap: 8px;
26
+ text-decoration: none;
27
+ overflow: visible;
28
+ flex-shrink: 0;
29
+ padding: 0;
30
+ min-height: 36px;
31
+ line-height: 1;
32
+ transition: filter 0.3s ease;
33
+ }
34
+
35
+ .navbar-title {
36
+ font-size: var(--base-font-size);
37
+ font-weight: 700;
38
+ line-height: 1.2;
39
+ color: var(--text-color);
40
+ letter-spacing: -0.02em;
41
+ }
42
+
43
+ .navbar-logo {
44
+ font-size: 28px;
45
+ width: 36px;
46
+ height: 36px;
47
+ line-height: 1;
48
+ color: var(--color-primary);
49
+ overflow: visible;
50
+ flex-shrink: 0;
51
+ display: inline-flex;
52
+ align-items: center;
53
+ justify-content: center;
54
+ }
55
+
56
+ // Angular mat-icon defaults to overflow:hidden — clips ligature glyphs at tight sizes.
57
+ .navbar-brand .navbar-logo.mat-icon,
58
+ .navbar-brand mat-icon.navbar-logo {
59
+ overflow: visible !important;
60
+ width: 36px !important;
61
+ height: 36px !important;
62
+ font-size: 28px !important;
63
+ line-height: 36px !important;
64
+ padding: 0 !important;
65
+ box-sizing: border-box;
66
+ display: inline-flex !important;
67
+ align-items: center !important;
68
+ justify-content: center !important;
69
+ }
70
+
71
+ .navbar-content {
72
+ display: flex;
73
+ align-items: center;
74
+ justify-content: space-between;
75
+ width: 100%;
76
+ max-width: none;
77
+ margin: 0;
78
+ }
79
+
80
+ .navbar-left {
81
+ flex: 1;
82
+ display: flex;
83
+ align-items: center;
84
+ justify-content: flex-start;
85
+ }
86
+
87
+ .navbar-right {
88
+ flex: 1;
89
+ display: flex;
90
+ align-items: center;
91
+ justify-content: flex-end;
92
+ gap: 8px;
93
+ }
94
+
95
+ .navbar-center {
96
+ display: flex;
97
+ justify-content: center;
98
+ }
99
+
100
+ .desktop-nav {
101
+ display: none;
102
+ align-items: center;
103
+ gap: 12px;
104
+ padding: 4px 0;
105
+ }
106
+
107
+ .desktop-auth {
108
+ display: none;
109
+ align-items: center;
110
+ gap: 8px;
111
+ }
112
+
113
+ .nav-btn {
114
+ position: relative;
115
+ font-size: 1rem !important;
116
+ color: var(--nav-link-color, var(--text-muted)) !important;
117
+ font-weight: 600 !important;
118
+ text-transform: uppercase !important;
119
+ letter-spacing: 0.08em !important;
120
+ transition:
121
+ color 0.2s ease,
122
+ background-color 0.2s ease,
123
+ box-shadow 0.2s ease,
124
+ transform 0.2s ease !important;
125
+ border-radius: var(--border-radius-sm) var(--border-radius-sm) 0 0 !important;
126
+ padding: 0 16px !important;
127
+ height: 40px !important;
128
+ line-height: 40px !important;
129
+ display: inline-flex !important;
130
+ align-items: center !important;
131
+ gap: 8px !important;
132
+ text-decoration: none;
133
+ background: transparent;
134
+ border: none;
135
+ cursor: pointer;
136
+ overflow: hidden;
137
+ }
138
+
139
+ .nav-btn .material-icons {
140
+ margin: 0;
141
+ font-size: var(--base-font-size);
142
+ width: 16px;
143
+ height: 16px;
144
+ }
145
+
146
+ .nav-btn::before {
147
+ content: '';
148
+ position: absolute;
149
+ inset: auto 16px 0;
150
+ height: 2px;
151
+ border-radius: 2px;
152
+ background: linear-gradient(
153
+ 90deg,
154
+ transparent,
155
+ color-mix(in srgb, var(--crayola-blue) 80%, transparent),
156
+ transparent
157
+ );
158
+ opacity: 0;
159
+ transform: scaleX(0.4);
160
+ transition:
161
+ opacity 0.25s ease,
162
+ transform 0.25s ease;
163
+ pointer-events: none;
164
+ }
165
+
166
+ .nav-btn:hover {
167
+ color: var(--text-color) !important;
168
+ background-color: color-mix(in srgb, var(--crayola-blue) 10%, transparent) !important;
169
+ transform: translateY(-1px);
170
+ }
171
+
172
+ .nav-btn:hover::before {
173
+ opacity: 1;
174
+ transform: scaleX(1);
175
+ }
176
+
177
+ html[data-theme='light'] {
178
+ --nav-link-color: color-mix(in srgb, var(--jet-black) 88%, var(--white));
179
+
180
+ .nav-btn,
181
+ .mobile-nav-btn,
182
+ .menu-toggle-btn,
183
+ .theme-toggle-btn {
184
+ color: var(--nav-link-color) !important;
185
+ }
186
+
187
+ .nav-btn:hover,
188
+ .mobile-nav-btn:hover {
189
+ background-color: color-mix(in srgb, var(--crayola-blue) 10%, transparent) !important;
190
+ }
191
+ }
192
+
193
+ .nav-btn.active {
194
+ color: var(--text-color) !important;
195
+ background-color: color-mix(in srgb, var(--crayola-blue) 14%, transparent) !important;
196
+ box-shadow:
197
+ inset 0 -2px 0 0 var(--crayola-blue),
198
+ 0 0 12px color-mix(in srgb, var(--crayola-blue) 18%, transparent) !important;
199
+ }
200
+
201
+ .nav-btn.active::before {
202
+ opacity: 1;
203
+ transform: scaleX(1);
204
+ }
205
+
206
+ .navbar .theme-toggle-btn,
207
+ .theme-toggle-btn {
208
+ position: static;
209
+ background: transparent;
210
+ color: var(--text-muted);
211
+ border: none;
212
+ border-radius: 50%;
213
+ width: 48px;
214
+ height: 48px;
215
+ min-width: 48px;
216
+ padding: 0;
217
+ margin: 0;
218
+ display: inline-flex;
219
+ align-items: center;
220
+ justify-content: center;
221
+ cursor: pointer;
222
+ box-shadow: none;
223
+ flex-shrink: 0;
224
+ transition:
225
+ color 0.2s ease,
226
+ transform 0.2s ease,
227
+ background-color 0.2s ease;
228
+ }
229
+
230
+ .navbar .theme-toggle-btn .material-icons,
231
+ .theme-toggle-btn .material-icons {
232
+ font-size: 24px;
233
+ width: 24px;
234
+ height: 24px;
235
+ line-height: 24px;
236
+ }
237
+
238
+ .navbar .theme-toggle-btn:hover,
239
+ .theme-toggle-btn:hover {
240
+ color: var(--text-color);
241
+ transform: rotate(15deg);
242
+ background-color: rgba(33, 118, 255, 0.05);
243
+ box-shadow: none;
244
+ }
245
+
246
+ .navbar .theme-toggle-btn:focus-visible,
247
+ .theme-toggle-btn:focus-visible {
248
+ outline: 2px solid var(--color-primary-container);
249
+ outline-offset: 3px;
250
+ }
251
+
252
+ .menu-toggle-btn {
253
+ display: inline-flex !important;
254
+ color: var(--text-muted) !important;
255
+ transition: color 0.2s;
256
+ background: transparent;
257
+ border: none;
258
+ cursor: pointer;
259
+ align-items: center;
260
+ justify-content: center;
261
+ width: 40px;
262
+ height: 40px;
263
+ border-radius: 50%;
264
+ }
265
+
266
+ .menu-toggle-btn:hover {
267
+ color: var(--text-color) !important;
268
+ }
269
+
270
+ .divider {
271
+ height: 24px;
272
+ width: 0px;
273
+ background-color: var(--border);
274
+ margin: 0 8px;
275
+ }
276
+
277
+ .auth-btn {
278
+ background: var(--color-dark-grey-btn-bg) !important;
279
+ color: var(--color-dark-grey-btn-text) !important;
280
+ font-weight: 600 !important;
281
+ border-radius: 96px !important;
282
+ padding: 0 16px !important;
283
+ box-shadow: var(--shadow-sm) !important;
284
+ text-transform: uppercase !important;
285
+ letter-spacing: 0.1em !important;
286
+ border: 1px solid var(--border) !important;
287
+ transition: var(--transition-smooth) !important;
288
+ height: 40px !important;
289
+ line-height: 40px !important;
290
+ display: inline-flex !important;
291
+ align-items: center !important;
292
+ gap: 8px !important;
293
+ white-space: nowrap !important;
294
+ text-decoration: none;
295
+ cursor: pointer;
296
+ }
297
+
298
+ .auth-btn .material-icons {
299
+ margin: 0;
300
+ font-size: var(--base-font-size);
301
+ width: 16px;
302
+ height: 16px;
303
+ transition: transform 0.3s ease;
304
+ }
305
+
306
+ .auth-btn:hover {
307
+ transform: translateY(-2px) !important;
308
+ background-color: var(--crayola-blue) !important;
309
+ border-color: var(--crayola-blue) !important;
310
+ color: var(--white) !important;
311
+ box-shadow: var(--shadow-md) !important;
312
+ }
313
+
314
+ .auth-btn:hover .material-icons {
315
+ transform: translateX(2px);
316
+ }
317
+
318
+ .mobile-menu {
319
+ display: none;
320
+ flex-direction: column;
321
+ position: absolute;
322
+ top: 64px;
323
+ left: 0;
324
+ right: 0;
325
+ width: auto;
326
+ background-color: var(--card-bg);
327
+ box-shadow: var(--shadow-md);
328
+ border-bottom: 1px solid var(--border);
329
+ padding: 24px;
330
+ box-sizing: border-box;
331
+ z-index: 49;
332
+ gap: 8px;
333
+ transform: translateY(-10px);
334
+ opacity: 0;
335
+ pointer-events: none;
336
+ transition:
337
+ transform 0.25s cubic-bezier(0.16, 1, 0.3, 1),
338
+ opacity 0.25s ease;
339
+ }
340
+
341
+ .mobile-menu.open {
342
+ transform: translateY(0);
343
+ opacity: 1;
344
+ pointer-events: auto;
345
+ display: flex;
346
+ }
347
+
348
+ .mobile-nav-btn {
349
+ width: 100% !important;
350
+ justify-content: flex-start !important;
351
+ font-size: 1rem !important;
352
+ color: var(--text-muted) !important;
353
+ height: 40px !important;
354
+ line-height: 40px !important;
355
+ border-radius: var(--border-radius-sm) !important;
356
+ padding: 0 16px !important;
357
+ display: inline-flex !important;
358
+ align-items: center !important;
359
+ gap: 8px !important;
360
+ text-decoration: none;
361
+ }
362
+
363
+ .mobile-nav-btn .material-icons {
364
+ margin: 0;
365
+ font-size: 20px;
366
+ width: 20px;
367
+ height: 20px;
368
+ }
369
+
370
+ .mobile-nav-btn:hover {
371
+ color: var(--text-color) !important;
372
+ background-color: rgba(33, 118, 255, 0.05) !important;
373
+ }
374
+
375
+ .mobile-nav-btn.active {
376
+ color: var(--text-color) !important;
377
+ background-color: rgba(33, 118, 255, 0.1) !important;
378
+ box-shadow: inset 0 0 0 1px var(--crayola-blue) !important;
379
+ }
380
+
381
+ .mobile-divider {
382
+ height: 0px;
383
+ background-color: var(--border);
384
+ margin: 8px 0;
385
+ }
386
+
387
+ .mobile-auth-btn {
388
+ width: 100% !important;
389
+ height: 40px !important;
390
+ line-height: 40px !important;
391
+ justify-content: center !important;
392
+ border-radius: var(--border-radius-lg) !important;
393
+ background: var(--color-dark-grey-btn-bg) !important;
394
+ color: var(--color-dark-grey-btn-text) !important;
395
+ font-weight: 600 !important;
396
+ border: none !important;
397
+ display: inline-flex !important;
398
+ align-items: center !important;
399
+ gap: 8px !important;
400
+ white-space: nowrap !important;
401
+ text-decoration: none;
402
+ }
403
+
404
+ .navbar-link {
405
+ font-size: 1rem;
406
+ color: var(--text-muted);
407
+ font-weight: 600;
408
+ text-transform: uppercase;
409
+ letter-spacing: 0.08em;
410
+ text-decoration: none;
411
+ transition: var(--transition-smooth);
412
+ }
413
+
414
+ .navbar-link:hover {
415
+ color: var(--text-color);
416
+ }
417
+
418
+ .glowing-icon-sm {
419
+ color: var(--primary-text-color) !important;
420
+ transition: all 0.3s ease;
421
+ }
422
+
423
+ // Glow on the brand link wrapper so mat-icon overflow does not clip the filter.
424
+ .navbar-brand.glowing-icon-sm,
425
+ .navbar-brand:has(.glowing-icon-sm) {
426
+ filter: drop-shadow(0 0 6px color-mix(in srgb, var(--color-primary) 60%, transparent));
427
+ }
428
+
429
+ .navbar-brand.glowing-icon-sm:hover,
430
+ .navbar-brand:has(.glowing-icon-sm):hover {
431
+ filter: drop-shadow(0 0 10px color-mix(in srgb, var(--color-primary) 90%, transparent));
432
+ }
433
+
434
+ .loader-logo.glowing-icon-sm,
435
+ :not(.navbar-brand) > .glowing-icon-sm {
436
+ filter: drop-shadow(0 0 6px color-mix(in srgb, var(--color-primary) 60%, transparent));
437
+ }
438
+
439
+ .loader-logo.glowing-icon-sm:hover,
440
+ :not(.navbar-brand) > .glowing-icon-sm:hover {
441
+ filter: drop-shadow(0 0 10px color-mix(in srgb, var(--color-primary) 90%, transparent));
442
+ }
443
+
444
+ @media (min-width: 768px) {
445
+ .desktop-nav {
446
+ display: flex;
447
+ }
448
+
449
+ .desktop-auth {
450
+ display: flex;
451
+ }
452
+
453
+ .menu-toggle-btn {
454
+ display: none !important;
455
+ }
456
+
457
+ .mobile-menu {
458
+ display: none !important;
459
+ }
460
+ }
@@ -0,0 +1,4 @@
1
+ // Static CSS bundle entry — tokens + page shell + footer + navbar for non-Angular apps.
2
+ @use 'viking-ui' as *;
3
+ @use 'static-navbar' as *;
4
+ @use '../lib/footer/footer' as *;
@@ -0,0 +1,108 @@
1
+ @use 'page-shell';
2
+ @use 'layout-shell';
3
+
4
+ // ============================================================================
5
+ // Viking-UI design tokens
6
+ // ----------------------------------------------------------------------------
7
+ // DEML clinical design system — Flux UI + Spartan-inspired patterns on THEME.md.
8
+ // Lab coat aesthetic: crayola-blue accents, sharp borders, no gradients.
9
+ // 8px grid. 16px main / 14px UI font floors. No colors outside THEME.md.
10
+ // ============================================================================
11
+
12
+ :root {
13
+ /* Accent (Viking "accent" concept -> Material primary) */
14
+ --viking-accent: var(--color-primary, #2176ff);
15
+ --viking-accent-content: var(--color-on-primary, #ffffff);
16
+ --viking-accent-soft: color-mix(in srgb, var(--viking-accent) 12%, transparent);
17
+ --viking-accent-strong: var(--color-primary-container, #33a1fd);
18
+
19
+ /* Surfaces */
20
+ --viking-bg: var(--bg-color, #ffffff);
21
+ --viking-surface: var(--card-bg, #ffffff);
22
+ --viking-surface-alt: var(--color-surface-variant, color-mix(in srgb, #31393c 5%, #ffffff));
23
+ --viking-overlay-backdrop: color-mix(in srgb, var(--jet-black, #31393c) 55%, transparent);
24
+
25
+ /* Text */
26
+ --viking-text: var(--text-color, #31393c);
27
+ --viking-text-muted: var(--text-muted, color-mix(in srgb, #31393c 72%, #ffffff));
28
+ --viking-text-inverted: var(--color-on-primary, #ffffff);
29
+
30
+ /* Borders / focus */
31
+ --viking-border: var(--border, color-mix(in srgb, #31393c 15%, transparent));
32
+ --viking-border-strong: var(--border-layout, color-mix(in srgb, #31393c 25%, transparent));
33
+ --viking-ring: var(--focus-ring-color, #2176ff);
34
+ --viking-ring-width: var(--focus-ring-width, 3px);
35
+ --viking-ring-offset: var(--focus-ring-offset, 2px);
36
+
37
+ /* Status (THEME.md semantic map) */
38
+ --viking-success: var(--color-success, #33a1fd);
39
+ --viking-warning: var(--color-warning, #fdca40);
40
+ --viking-danger: var(--color-error, #f79824);
41
+ --viking-info: var(--color-info, #2176ff);
42
+ /* Danger-tinted TEXT on light surfaces needs deepening for WCAG AA. */
43
+ --viking-danger-text: color-mix(in srgb, var(--viking-danger) 50%, var(--jet-black, #31393c));
44
+ /* Text placed ON danger-filled surfaces (carrot orange requires dark text). */
45
+ --viking-on-danger: var(--jet-black, #31393c);
46
+
47
+ /* Shape (8px grid) */
48
+ --viking-radius: var(--border-radius-md, 8px);
49
+ --viking-radius-lg: var(--border-radius-lg, 16px);
50
+ --viking-radius-pill: var(--border-radius-pill, 999px);
51
+
52
+ /* Elevation — sharp and clinical, no diffuse glows */
53
+ --viking-shadow-sm: var(
54
+ --shadow-sm,
55
+ 0 1px 2px color-mix(in srgb, #31393c 5%, transparent),
56
+ 0 1px 3px color-mix(in srgb, #31393c 10%, transparent)
57
+ );
58
+ --viking-shadow-md: var(
59
+ --shadow-md,
60
+ 0 4px 6px -1px color-mix(in srgb, #31393c 10%, transparent),
61
+ 0 2px 4px -1px color-mix(in srgb, #31393c 6%, transparent)
62
+ );
63
+
64
+ /* Typography — 16px main content, 14px bold/UI chrome */
65
+ --viking-font-family: 'Inter', sans-serif;
66
+ --viking-font-size: max(16px, var(--base-font-size, 16px));
67
+ --viking-font-size-ui: max(14px, var(--ui-font-size, 14px));
68
+ --viking-font-size-lg: max(16px, calc(var(--viking-font-size) * 1.125));
69
+ --viking-font-size-xl: max(16px, calc(var(--viking-font-size) * 1.25));
70
+
71
+ /* Controls (8px grid heights) */
72
+ --viking-control-height: 40px;
73
+ --viking-control-height-sm: 32px;
74
+ --viking-control-height-xs: 24px;
75
+ --viking-control-padding-x: var(--space-2, 16px);
76
+ --viking-btn-min-width: var(--btn-min-width, 120px);
77
+
78
+ /* Spacing */
79
+ --viking-space-1: var(--space-1, 8px);
80
+ --viking-space-2: var(--space-2, 16px);
81
+ --viking-space-3: var(--space-3, 24px);
82
+ --viking-space-4: var(--space-4, 32px);
83
+
84
+ /* Chart axis labels — compact but WCAG-readable on chart surfaces */
85
+ --viking-chart-axis-size: 12px;
86
+
87
+ /* Page shell */
88
+ --viking-container-max-width: var(--container-max-width, 1260px);
89
+
90
+ /* Motion */
91
+ --viking-transition: var(--transition-smooth, all 0.2s cubic-bezier(0.4, 0, 0.2, 1));
92
+
93
+ /* Layering */
94
+ --viking-z-overlay: 1000;
95
+ --viking-z-toast: 1100;
96
+ --viking-z-tooltip: 1200;
97
+ }
98
+
99
+ /* Dark surfaces give the raw danger orange sufficient contrast already. */
100
+ html[data-theme='dark'] {
101
+ --viking-danger-text: var(--viking-danger);
102
+ }
103
+
104
+ @media (prefers-color-scheme: dark) {
105
+ html:not([data-theme='light']) {
106
+ --viking-danger-text: var(--viking-danger);
107
+ }
108
+ }