@visns-studio/visns-components 6.0.4 → 6.0.5

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.
@@ -11,7 +11,11 @@
11
11
  padding: 0;
12
12
  margin: 0;
13
13
  line-height: 1.45;
14
- margin-right: 1rem;
14
+ /* The mark and the navigation were butted together, reading as one
15
+ run of items. A hairline gives the logo its own territory. */
16
+ margin-right: var(--spacing-md);
17
+ padding-right: var(--spacing-md);
18
+ border-right: 1px solid rgba(255, 255, 255, 0.18);
15
19
 
16
20
  .logoButton {
17
21
  background: none;
@@ -101,19 +105,24 @@
101
105
  a,
102
106
  span,
103
107
  button {
104
- font-size: 0.9rem;
108
+ font-size: var(--font-size-sm);
109
+ font-weight: var(--font-weight-medium);
105
110
  display: flex;
106
111
  flex-wrap: nowrap;
107
112
  align-items: center;
108
- gap: 0.25rem;
113
+ gap: 0.35rem;
109
114
  box-sizing: border-box;
110
- padding: 0.35em 0.5em;
115
+ /* Was 0.35em/0.5em — a tap target under the 44px guideline and
116
+ visually cramped against the taller header. */
117
+ padding: 0.55rem 0.7rem;
111
118
  margin: 0;
112
119
  line-height: 1;
113
120
  text-decoration: none;
114
- outline: none;
115
- border-radius: var(--br);
116
- transition: all 0.15s cubic-bezier(0.25, 0.8, 0.25, 1);
121
+ border-radius: var(--radius-sm);
122
+ /* `all` also animated layout properties. Only what changes. */
123
+ transition:
124
+ background-color var(--speed) var(--ease),
125
+ color var(--speed) var(--ease);
117
126
  background: none;
118
127
  border: none;
119
128
  cursor: pointer;
@@ -124,7 +133,16 @@
124
133
  a,
125
134
  span,
126
135
  button {
127
- color: var(--tertiary-color);
136
+ color: rgba(255, 255, 255, 0.82);
137
+ }
138
+
139
+ /* Nothing responded to the pointer unless it was already the
140
+ active page, so the bar felt inert. */
141
+ &:not(.active):hover a,
142
+ &:not(.active):hover span,
143
+ &:not(.active):hover button {
144
+ background: rgba(255, 255, 255, 0.12);
145
+ color: #fff;
128
146
  }
129
147
 
130
148
  svg {
@@ -133,19 +151,21 @@
133
151
  visibility: hidden;
134
152
  }
135
153
 
136
- &:hover a,
154
+ /* Only the current page wears the brand red. Hover shared it
155
+ before, so pointing at any item made it look selected and the
156
+ real active item was impossible to pick out while moving the
157
+ mouse across the bar. Hover is handled above, as a quiet lift. */
137
158
  &.active a,
138
- &:hover span,
139
159
  &.active span,
140
- &:hover button,
141
160
  &.active button {
142
- background: rgba(var(--secondary-rgb), 1);
143
- color: var(--tertiary-color);
161
+ background: var(--secondary-color);
162
+ color: #fff;
163
+ font-weight: var(--font-weight-semibold);
144
164
  }
145
165
 
146
- &:hover svg,
147
- &.active svg {
148
- color: var(--tertiary-color);
166
+ &.active svg,
167
+ &:hover svg {
168
+ color: #fff;
149
169
  }
150
170
 
151
171
  > ul {
@@ -330,11 +350,34 @@
330
350
  justify-self: end;
331
351
  position: relative;
332
352
  z-index: 1000; // Higher z-index to stay above sticky header
353
+ /* Account actions are a different kind of thing from page navigation, so
354
+ a hairline separates them rather than leaving one undifferentiated row
355
+ of targets. */
356
+ padding-left: var(--spacing-md);
357
+ margin-left: var(--spacing-sm);
333
358
 
334
359
  > ul {
335
360
  list-style: none;
336
361
  display: flex;
337
- padding: 0;
362
+ /* A faint inset holds the icons together as one group rather than
363
+ leaving them as loose targets floating in the bar.
364
+ Deliberately count-agnostic: projects mount a different number of
365
+ actions here, so this is padding and a pill radius rather than
366
+ anything sized to a fixed set. If a project mounts more than fits,
367
+ the group scrolls instead of pushing the navigation. */
368
+ background: rgba(255, 255, 255, 0.1);
369
+ border-radius: var(--radius-pill);
370
+ /* An even ring around the chips; any more and the group reads as a
371
+ separate control rather than a container for them. */
372
+ padding: 4px;
373
+ max-width: 100%;
374
+ overflow-x: auto;
375
+ scrollbar-width: none;
376
+
377
+ &::-webkit-scrollbar {
378
+ display: none;
379
+ }
380
+
338
381
  margin: 0;
339
382
  flex-wrap: nowrap;
340
383
  flex-direction: row;
@@ -356,39 +399,85 @@
356
399
  z-index: 1002;
357
400
  }
358
401
 
359
- a {
402
+ a,
403
+ button {
360
404
  color: var(--tertiary-color);
361
405
  box-sizing: border-box;
362
- padding: 0.35rem;
363
406
  text-decoration: none;
364
407
  background: none;
365
- border: 1px solid var(--primary-color);
366
- border-radius: 100%;
367
- transition: all 0.25s cubic-bezier(0.25, 0.8, 0.25, 1); // Reduced duration
408
+ font: inherit;
409
+ padding: 0;
410
+ /* Was a 1px border in the header's own colour — invisible, but it
411
+ still consumed the ring of space that would have made these
412
+ read as buttons. */
413
+ border: none;
414
+ /* Circular, so each chip nests inside the pill-shaped group at any
415
+ position — a rounded square cut across the container's curve at
416
+ the two ends. Also stays correct however many actions a project
417
+ mounts, since no chip is styled by its position. */
418
+ border-radius: var(--radius-pill);
419
+ /* `all` animated layout too; and the hover scale made the icons
420
+ wobble against a static header. Colour alone is enough feedback
421
+ on a 36px target. */
422
+ transition: background-color var(--speed) var(--ease);
368
423
  display: flex;
369
424
  align-items: center;
370
425
  justify-content: center;
371
- width: 32px; // Reduced from 36px
372
- height: 32px; // Reduced from 36px
426
+ /* 32px was below the 44px guideline and awkward to hit. */
427
+ width: 36px;
428
+ height: 36px;
373
429
  position: relative;
374
430
  z-index: 1003;
375
- transform: translateZ(0) translateX(0) translateY(0); // Force compositor layer
376
- will-change: transform, background-color; // Optimize for animations
377
- /* Remove contain: layout to prevent rendering optimization conflicts */
378
- outline: none;
379
431
  appearance: none;
380
- backface-visibility: hidden; // Prevent rendering glitches
381
- -webkit-backface-visibility: hidden;
382
- /* Force onto own layer to prevent culling */
383
- isolation: isolate;
384
432
 
433
+ /* Brand red on hover, matching the rest of the bar. A neutral
434
+ white lift read as a system default rather than a Prime
435
+ control, and left this cluster looking unrelated to everything
436
+ around it. */
385
437
  &:hover,
386
438
  &.active {
387
- background: var(--primary-color);
388
- transform: translateZ(0) scale(1.05); // Slight scale on hover
439
+ background: var(--secondary-color);
389
440
 
390
441
  svg {
391
- color: var(--secondary-color);
442
+ color: #fff !important;
443
+ }
444
+ }
445
+
446
+ svg {
447
+ /* Components mounted here (notifications, switch account)
448
+ colour their own icons, which is why they hovered
449
+ differently from the plain links beside them. */
450
+ color: var(--tertiary-color);
451
+ }
452
+ }
453
+
454
+ /* Components mounted into this cluster ship their own trigger styles —
455
+ the notification bell is 40px with its own hover fill and a scale
456
+ transform, against 36px flat siblings. Rather than chase each one by
457
+ name, normalise any button nested inside a wrapper element so the
458
+ cluster stays uniform however a project fills it. */
459
+ li > div,
460
+ li > span {
461
+ display: flex;
462
+ align-items: center;
463
+ }
464
+
465
+ li button {
466
+ width: 36px;
467
+ height: 36px;
468
+ min-width: 36px;
469
+ padding: 0;
470
+ border-radius: var(--radius-pill) !important;
471
+ background: none;
472
+ transform: none !important;
473
+ color: var(--tertiary-color);
474
+
475
+ &:hover {
476
+ background: var(--secondary-color) !important;
477
+ color: #fff;
478
+
479
+ svg {
480
+ color: #fff !important;
392
481
  }
393
482
  }
394
483
  }
@@ -1,3 +1,8 @@
1
+ @use 'controls' as *;
2
+
3
+ .btn {
4
+ @include button-primary;
5
+ }
1
6
  /* Profile.module.scss */
2
7
 
3
8
  /* Form field label animation */
@@ -295,33 +300,7 @@ select:focus + .fi__span {
295
300
  }
296
301
  }
297
302
 
298
- .btn {
299
- width: max-content;
300
- display: inline-block;
301
- position: relative;
302
- padding: 0.65rem 1rem;
303
- cursor: pointer;
304
- font-size: 1rem;
305
- color: var(--secondary-color);
306
- text-decoration: none;
307
- overflow: hidden;
308
- background: var(--primary-color);
309
- border: 1px solid rgba(var(--primary-rgb), 1.1);
310
- border-radius: var(--br);
311
- outline: none;
312
- transition: all 0.2s cubic-bezier(0.85, 0, 0.15, 1) 0s;
313
303
 
314
- &:hover:not(:disabled) {
315
- color: var(--tertiary-color);
316
- background: var(--secondary-color);
317
- border: 1px solid rgba(var(--secondary-color-rgb), 1.1);
318
- }
319
-
320
- &:disabled {
321
- opacity: 0.6;
322
- cursor: not-allowed;
323
- }
324
- }
325
304
 
326
305
  .inputError {
327
306
  border-color: red !important;
@@ -1,14 +1,17 @@
1
1
  .quickActions {
2
2
  width: 100%;
3
- background: rgba(var(--bg-rgb), 0.98);
4
- padding: 0.75rem var(--padding);
5
- border-top: solid 3px rgba(var(--primary-rgb), 0.1);
6
- border-bottom: solid 1px rgba(var(--primary-rgb), 0.15);
3
+ background: var(--surface-color);
4
+ padding: var(--spacing-sm) clamp(var(--spacing-md), 3vw, var(--spacing-xl));
5
+ /* Was a 3px tinted top rule plus a 1px bottom rule plus a shadow — three
6
+ separators stacked on one strip, which made it read as a heavier
7
+ element than the header above it. One hairline is enough. */
8
+ border-top: none;
9
+ border-bottom: 1px solid var(--border-color);
7
10
  color: var(--paragraph-color);
8
11
  display: flex;
9
12
  flex-wrap: wrap;
10
13
  align-items: center;
11
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
14
+ box-shadow: none;
12
15
  overflow: visible; /* Ensure dropdowns are visible */
13
16
  position: relative; /* Create a stacking context */
14
17
  z-index: 100; /* Ensure proper stacking */
@@ -20,49 +23,51 @@
20
23
  display: flex;
21
24
  align-items: center;
22
25
  justify-content: center;
23
- background-color: rgba(var(--primary-rgb), 0.08);
24
- border-radius: 50%;
25
- margin-right: 0.75rem;
26
+ /* A label, not a control — it does nothing when clicked, so a filled
27
+ circle that lights up on hover was promising an action it does not
28
+ have. */
29
+ background: none;
30
+ border-radius: var(--radius-sm);
31
+ margin-right: var(--spacing-sm);
32
+ padding-right: var(--spacing-sm);
26
33
  position: relative;
27
- color: rgba(var(--primary-rgb), 0.8);
28
- transition: all 0.2s ease;
29
-
30
- &:hover {
31
- background-color: rgba(var(--primary-rgb), 0.12);
32
- transform: scale(1.05);
33
- }
34
+ color: var(--muted-color);
35
+ flex: none;
34
36
 
35
37
  &::after {
36
38
  content: '';
37
39
  position: absolute;
38
- right: -0.5rem;
40
+ right: 0;
39
41
  top: 50%;
40
42
  transform: translateY(-50%);
41
43
  height: 60%;
42
44
  width: 1px;
43
- background-color: rgba(var(--primary-rgb), 0.15);
45
+ background-color: var(--border-color);
44
46
  }
45
47
  }
46
48
 
47
49
  > button {
48
50
  appearance: none;
49
- border: 1px solid rgba(var(--primary-rgb), 0.2);
50
- border-radius: var(--br, 4px);
51
- background: rgba(var(--bg-rgb), 1);
51
+ border: 1px solid var(--border-color);
52
+ border-radius: var(--radius-sm);
53
+ background: var(--surface-color);
52
54
  width: max-content;
53
- color: var(--paragraph-color);
54
- padding: 0.4rem 0.8rem;
55
- margin: 0 0.2rem;
56
- font-size: 0.85rem;
57
- font-weight: 500;
58
- transition: all 0.2s ease;
59
- box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
55
+ color: var(--text-color);
56
+ padding: 0 var(--spacing-md);
57
+ margin: 0;
58
+ /* Matches the button mixin used everywhere else, so quick actions and
59
+ page buttons are the same size and weight. */
60
+ font-size: var(--font-size-sm);
61
+ font-weight: var(--font-weight-semibold);
62
+ transition:
63
+ background-color var(--speed) var(--ease),
64
+ border-color var(--speed) var(--ease);
65
+ box-shadow: none;
60
66
  display: flex;
61
67
  align-items: center;
62
68
  justify-content: center;
63
- min-height: 32px;
69
+ min-height: 2.5rem;
64
70
  position: relative;
65
- overflow: hidden;
66
71
 
67
72
  &::before {
68
73
  content: '';
@@ -0,0 +1,139 @@
1
+ /**
2
+ * Shared control definitions.
3
+ *
4
+ * `.btn` was copy-pasted into ten stylesheets and had drifted into seven
5
+ * different definitions — different paddings, font sizes, borders and hover
6
+ * behaviour, all called the same thing. CSS modules hash each class per file,
7
+ * so a single global `.btn` cannot reach them; a mixin can, and each file
8
+ * keeps its own scoped class while the definition lives in one place.
9
+ *
10
+ * Every variant shares a height, radius, weight and focus treatment, so they
11
+ * line up when placed side by side.
12
+ */
13
+
14
+ @mixin button-base {
15
+ display: inline-flex;
16
+ align-items: center;
17
+ justify-content: center;
18
+ gap: 0.4rem;
19
+ width: max-content;
20
+ min-height: 2.5rem;
21
+ padding: 0 var(--spacing-md);
22
+ border: 1px solid transparent;
23
+ border-radius: var(--radius-sm);
24
+ font-family: var(--font-family);
25
+ // Was 1rem against 15px body text, so buttons shouted slightly.
26
+ font-size: var(--font-size-sm);
27
+ font-weight: var(--font-weight-semibold);
28
+ line-height: 1;
29
+ text-decoration: none;
30
+ white-space: nowrap;
31
+ cursor: pointer;
32
+ // Was `all 0.2s`, which animates layout properties too and makes hover
33
+ // feel laggy. Only what actually changes.
34
+ transition:
35
+ background-color var(--speed) var(--ease),
36
+ border-color var(--speed) var(--ease),
37
+ color var(--speed) var(--ease);
38
+
39
+ &:disabled,
40
+ &[aria-disabled='true'] {
41
+ opacity: 0.55;
42
+ cursor: not-allowed;
43
+ }
44
+
45
+ // Focus is handled globally by the app's _focus.scss; nothing here removes
46
+ // the outline, which is what created the accessibility gap in the first
47
+ // place.
48
+ }
49
+
50
+ @mixin button-primary {
51
+ @include button-base;
52
+
53
+ background: var(--primary-color);
54
+ border-color: var(--primary-color);
55
+ color: #fff;
56
+
57
+ &:hover:not(:disabled) {
58
+ background: var(--primary-color-darker);
59
+ border-color: var(--primary-color-darker);
60
+ // Was a light-blue fill with navy text, which dropped below a legible
61
+ // contrast on hover — the one state where feedback matters most.
62
+ color: #fff;
63
+ }
64
+ }
65
+
66
+ @mixin button-secondary {
67
+ @include button-base;
68
+
69
+ background: var(--paper);
70
+ border-color: var(--border-color);
71
+ color: var(--text-color);
72
+
73
+ &:hover:not(:disabled) {
74
+ border-color: var(--border-color-dark);
75
+ background: var(--hover-color);
76
+ }
77
+ }
78
+
79
+ @mixin button-ghost {
80
+ @include button-base;
81
+
82
+ background: none;
83
+ border-color: transparent;
84
+ color: var(--primary-color);
85
+
86
+ &:hover:not(:disabled) {
87
+ background: var(--primary-color-light);
88
+ }
89
+ }
90
+
91
+ @mixin button-danger {
92
+ @include button-base;
93
+
94
+ background: none;
95
+ border-color: transparent;
96
+ color: var(--danger-color);
97
+
98
+ &:hover:not(:disabled) {
99
+ background: var(--danger-light);
100
+ border-color: var(--danger-color);
101
+ }
102
+ }
103
+
104
+ @mixin button-small {
105
+ min-height: 2rem;
106
+ padding: 0 var(--spacing-sm);
107
+ font-size: var(--font-size-xs);
108
+ }
109
+
110
+ /* --- Inputs -------------------------------------------------------------- */
111
+
112
+ @mixin input-base {
113
+ width: 100%;
114
+ min-height: 2.5rem;
115
+ padding: 0 0.65rem;
116
+ border: 1px solid var(--border-color);
117
+ border-radius: var(--radius-sm);
118
+ background: var(--paper);
119
+ font-family: var(--font-family);
120
+ font-size: var(--font-size-md);
121
+ color: var(--text-color);
122
+ transition:
123
+ border-color var(--speed) var(--ease),
124
+ box-shadow var(--speed) var(--ease);
125
+
126
+ &::placeholder {
127
+ color: var(--muted-color);
128
+ }
129
+
130
+ &:hover:not(:disabled) {
131
+ border-color: var(--border-color-dark);
132
+ }
133
+
134
+ &:disabled {
135
+ background: var(--bg-color-secondary);
136
+ color: var(--disabled-color);
137
+ cursor: not-allowed;
138
+ }
139
+ }
@@ -10,24 +10,26 @@
10
10
 
11
11
  html,
12
12
  body {
13
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
14
- Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji',
15
- 'Segoe UI Symbol';
13
+ /* Was a hardcoded system stack, which overrode the app's font because this
14
+ file is injected after the entry stylesheet. Through the token it
15
+ follows whatever the app defines. */
16
+ font-family: var(--font-family, system-ui, sans-serif);
16
17
  height: 100%;
17
- text-rendering: geometricPrecision;
18
- font-stretch: 75% 125%;
18
+ text-rendering: optimizeLegibility;
19
19
  }
20
20
 
21
21
  body {
22
22
  background: var(--bg-color);
23
23
  font-weight: var(--para-weight);
24
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
25
- Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji',
26
- 'Segoe UI Symbol';
24
+ font-family: var(--font-family, system-ui, sans-serif);
27
25
  font-style: normal;
28
26
  overflow-x: hidden;
29
27
  overscroll-behavior: none;
30
- font-size: 0.85rem;
28
+ /* Was 0.85rem (13.6px) — small enough that every component had to size up
29
+ from it. Now the body step of the scale. */
30
+ font-size: var(--font-size-md, 0.9375rem);
31
+ line-height: var(--para-height, 1.6);
32
+ color: var(--text-color, #1f2a37);
31
33
  }
32
34
 
33
35
  input,
@@ -130,24 +132,61 @@ select {
130
132
  appearance: none;
131
133
  }
132
134
 
135
+ /* A real scale. These carried colour and weight but no size, so every heading
136
+ fell back to the browser default — a hierarchy inherited rather than chosen,
137
+ and unrelated to the body size beneath it. Sizes come from the tokens, with
138
+ fallbacks so this file still stands alone. */
133
139
  h1,
134
140
  h2,
135
141
  h3,
136
142
  h4,
137
143
  h5,
138
144
  h6 {
139
- color: var(--header-color);
140
- font-weight: var(--title-weight);
141
- line-height: var(--title-height);
142
- letter-spacing: 0.015rem;
145
+ color: var(--heading-color, #10192a);
146
+ font-weight: var(--font-weight-bold, 700);
147
+ line-height: var(--title-height, 1.25);
148
+ /* Was +0.015rem. Barlow opens up as it scales, so the display sizes want
149
+ pulling in, not pushing apart. */
150
+ letter-spacing: -0.01em;
151
+ margin: 0 0 var(--spacing-sm, 0.5rem);
152
+ }
153
+
154
+ h1 {
155
+ font-size: var(--font-size-2xl, 1.75rem);
156
+ letter-spacing: -0.02em;
157
+ }
158
+
159
+ h2 {
160
+ font-size: var(--font-size-xl, 1.375rem);
161
+ }
162
+
163
+ h3 {
164
+ font-size: var(--font-size-lg, 1.125rem);
165
+ }
166
+
167
+ h4 {
168
+ font-size: var(--font-size-md, 0.9375rem);
169
+ font-weight: var(--font-weight-semibold, 600);
170
+ letter-spacing: 0;
171
+ }
172
+
173
+ h5,
174
+ h6 {
175
+ font-size: var(--font-size-sm, 0.8125rem);
176
+ font-weight: var(--font-weight-semibold, 600);
177
+ letter-spacing: 0.02em;
178
+ text-transform: uppercase;
179
+ color: var(--muted-color, #6b7688);
143
180
  }
144
181
 
145
182
  p {
146
- font-size: clamp(1rem, 2vw, 1.25rem);
183
+ /* Was clamp(1rem, 2vw, 1.25rem) — up to 20px, larger than the body text
184
+ around it, which inverted the hierarchy on every screen. */
185
+ font-size: inherit;
147
186
  color: var(--paragraph-color);
148
187
  font-weight: var(--para-weight);
149
188
  line-height: var(--para-height);
150
- margin-bottom: 1rem;
189
+ margin-bottom: var(--spacing-md, 1rem);
151
190
 
152
191
  @media (max-width: 1024px) {
153
192
  font-size: clamp(0.85rem, 2vw, 0.95rem);