procode-vs-theme 2.1.0 → 2.4.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.
Files changed (68) hide show
  1. package/CHANGELOG.md +214 -45
  2. package/dist/components.esm.js +28 -4
  3. package/dist/components.esm.js.map +1 -1
  4. package/dist/components.js +35 -3
  5. package/dist/components.js.map +1 -1
  6. package/dist/index.esm.js +41 -5
  7. package/dist/index.esm.js.map +1 -1
  8. package/dist/index.js +41 -5
  9. package/dist/index.js.map +1 -1
  10. package/dist/src/base/_border.scss +21 -12
  11. package/dist/src/base/_color.scss +106 -47
  12. package/dist/src/base/_custom-properties.scss +166 -111
  13. package/dist/src/base/_font.scss +61 -37
  14. package/dist/src/base/_size.scss +30 -17
  15. package/dist/src/base/_space.scss +53 -33
  16. package/dist/src/base/_variants.scss +128 -0
  17. package/dist/src/components/_alert.scss +83 -0
  18. package/dist/src/components/_badge.scss +100 -0
  19. package/dist/src/components/_buttons.scss +189 -420
  20. package/dist/src/components/_cards.scss +130 -0
  21. package/dist/src/components/_input.scss +186 -32
  22. package/dist/src/components/_link.scss +34 -0
  23. package/dist/src/components/_page.scss +87 -0
  24. package/dist/src/components/_pagination.scss +71 -0
  25. package/dist/src/components/_table.scss +171 -0
  26. package/dist/src/components/_tabs.scss +77 -0
  27. package/dist/src/components.ts +47 -23
  28. package/dist/src/index.scss +82 -71
  29. package/dist/src/utilities/_interaction.scss +72 -0
  30. package/dist/src/utilities/background-color/index.scss +13 -0
  31. package/dist/src/utilities/border/_border-color.scss +2 -0
  32. package/dist/src/utilities/box-shadow/index.scss +8 -8
  33. package/dist/src/utilities/spaces/_gap.scss +21 -2
  34. package/dist/src/utilities/typography/_color.scss +38 -34
  35. package/dist/src/variables.ts +38 -35
  36. package/dist/types/components.d.ts +18 -2
  37. package/dist/types/variables.d.ts +2 -0
  38. package/dist/variables.esm.js +4 -1
  39. package/dist/variables.esm.js.map +1 -1
  40. package/dist/variables.js +4 -0
  41. package/dist/variables.js.map +1 -1
  42. package/package.json +84 -84
  43. package/src/base/_border.scss +21 -12
  44. package/src/base/_color.scss +106 -47
  45. package/src/base/_custom-properties.scss +166 -111
  46. package/src/base/_font.scss +61 -37
  47. package/src/base/_size.scss +30 -17
  48. package/src/base/_space.scss +53 -33
  49. package/src/base/_variants.scss +128 -0
  50. package/src/components/_alert.scss +83 -0
  51. package/src/components/_badge.scss +100 -0
  52. package/src/components/_buttons.scss +189 -420
  53. package/src/components/_cards.scss +130 -0
  54. package/src/components/_input.scss +186 -32
  55. package/src/components/_link.scss +34 -0
  56. package/src/components/_page.scss +87 -0
  57. package/src/components/_pagination.scss +71 -0
  58. package/src/components/_table.scss +171 -0
  59. package/src/components/_tabs.scss +77 -0
  60. package/src/components.ts +47 -23
  61. package/src/index.scss +82 -71
  62. package/src/utilities/_interaction.scss +72 -0
  63. package/src/utilities/background-color/index.scss +13 -0
  64. package/src/utilities/border/_border-color.scss +2 -0
  65. package/src/utilities/box-shadow/index.scss +8 -8
  66. package/src/utilities/spaces/_gap.scss +21 -2
  67. package/src/utilities/typography/_color.scss +38 -34
  68. package/src/variables.ts +38 -35
@@ -0,0 +1,130 @@
1
+ @use "sass:map";
2
+ @use "../base/color" as cl;
3
+ @use "../base/border" as bo;
4
+ @use "../base/font" as ft;
5
+ @use "../base/space" as sp;
6
+ @use "../base/variants" as vr;
7
+
8
+ // Cards
9
+ //
10
+ // <div class="qo-card"> … </div>
11
+ // <div class="qo-card qo-card-hover qo-card-primary"> … </div>
12
+
13
+ .qo-card {
14
+ display: block;
15
+ padding: sp.$space-3 sp.$space-4;
16
+ background-color: cl.$background-default;
17
+ border: bo.$border-width-sm solid cl.$border-default;
18
+ border-radius: bo.$border-radius-md;
19
+ box-shadow: cl.$shadow-sm;
20
+ transition: box-shadow 0.2s ease, border-color 0.2s ease;
21
+
22
+ &.qo-card-flat { box-shadow: none; }
23
+ &.qo-card-soft { border-color: cl.$border-light; }
24
+ &.qo-card-plain { border: 0; box-shadow: none; }
25
+ &.qo-card-pad-0 { padding: 0; }
26
+ &.qo-card-pad-sm { padding: sp.$space-2 sp.$space-3; }
27
+ &.qo-card-pad-lg { padding: sp.$space-4 sp.$space-5; }
28
+
29
+ // Only an interactive card gets hover/focus affordance.
30
+ &.qo-card-hover {
31
+ cursor: pointer;
32
+ &:hover { box-shadow: cl.$shadow-md; border-color: cl.$border-secondary; }
33
+ &:focus-visible { outline: 0; box-shadow: cl.$focus-ring; }
34
+ }
35
+
36
+ // A left accent stripe in any semantic colour.
37
+ @each $name, $spec in vr.$variants {
38
+ &.qo-card-#{$name} {
39
+ border-left: bo.$border-width-lg solid map.get($spec, base);
40
+ }
41
+ }
42
+ }
43
+
44
+ .qo-card-header {
45
+ padding-bottom: sp.$space-3;
46
+ margin-bottom: sp.$space-3;
47
+ border-bottom: bo.$border-width-sm solid cl.$border-light;
48
+ color: cl.$text-darker;
49
+ font-size: ft.$font-size-lg;
50
+ font-weight: ft.$font-weight-semibold;
51
+ }
52
+
53
+ .qo-card-body { display: block; }
54
+
55
+ .qo-card-footer {
56
+ padding-top: sp.$space-3;
57
+ margin-top: sp.$space-3;
58
+ border-top: bo.$border-width-sm solid cl.$border-light;
59
+ }
60
+
61
+ // Metric / count card — icon chip, label, value, helper.
62
+ .qo-metric-card {
63
+ min-height: 88px;
64
+ padding: sp.$space-3 sp.$space-4;
65
+ display: flex;
66
+ align-items: center;
67
+ gap: sp.$space-3;
68
+ background-color: cl.$background-default;
69
+ border: bo.$border-width-sm solid cl.$border-default;
70
+ border-radius: bo.$border-radius-md;
71
+ box-shadow: cl.$shadow-sm;
72
+ }
73
+
74
+ .qo-metric-icon {
75
+ width: 38px;
76
+ height: 38px;
77
+ flex: 0 0 38px;
78
+ display: inline-flex;
79
+ align-items: center;
80
+ justify-content: center;
81
+ border-radius: bo.$border-radius-full;
82
+ background-color: cl.$background-primary-soft;
83
+ color: cl.$text-primary;
84
+ font-size: ft.$font-size-xl;
85
+
86
+ // Every tint variant, so a metric chip can be any status colour.
87
+ @each $name, $spec in vr.$tint-variants {
88
+ &.qo-metric-icon-#{$name} {
89
+ background-color: map.get($spec, soft);
90
+ color: map.get($spec, ink);
91
+ }
92
+ }
93
+ }
94
+
95
+ .qo-metric-label {
96
+ margin: 0 0 2px;
97
+ color: cl.$text-darker;
98
+ font-size: ft.$font-size-sm;
99
+ font-weight: ft.$font-weight-medium;
100
+ line-height: ft.$line-height-xxs;
101
+ }
102
+
103
+ .qo-metric-value {
104
+ margin: 0;
105
+ color: cl.$text-darker;
106
+ font-size: 24px;
107
+ font-weight: ft.$font-weight-bold;
108
+ line-height: 1.05;
109
+ }
110
+
111
+ .qo-metric-helper {
112
+ margin-top: 3px;
113
+ color: cl.$text-secondary;
114
+ font-size: ft.$font-size-xs;
115
+ font-weight: ft.$font-weight-regular;
116
+ }
117
+
118
+ // Responsive metric row: 5 → 3 → 1 columns.
119
+ .qo-metrics-grid {
120
+ display: grid;
121
+ grid-template-columns: repeat(5, minmax(150px, 1fr));
122
+ gap: sp.$space-3;
123
+
124
+ @media (max-width: 1200px) {
125
+ grid-template-columns: repeat(3, minmax(180px, 1fr));
126
+ }
127
+ @media (max-width: 768px) {
128
+ grid-template-columns: 1fr;
129
+ }
130
+ }
@@ -1,32 +1,186 @@
1
- @use "../base/mixins/font_size-mx" as mx;
2
- @use "../base/font" as ft;
3
- @use "../base/color" as cl;
4
- @use "../base/border" as bo;
5
-
6
- $input-padding-xs: 5.5px !default;
7
- $input-padding-md: 8px !default;
8
- $input-padding-xl: 16px !default;
9
-
10
- .qo-input {
11
- display: inline-block;
12
- border-radius: bo.$border-radius-sm;
13
- }
14
- .qo-input-full {
15
- display: block;
16
- border-radius: bo.$border-radius-sm;
17
- width: 100%;
18
- padding: $input-padding-xl;
19
- @include mx.font-size(ft.$font-size-md, ft.$line-height-md);
20
- }
21
- .qo-input-xs {
22
- padding: $input-padding-xs;
23
- @include mx.font-size(ft.$font-size-xs, ft.$line-height-xs);
24
- }
25
- .qo-input-md {
26
- padding: $input-padding-md;
27
- @include mx.font-size(ft.$font-size-md, ft.$line-height-md);
28
- }
29
- .qo-input-default {
30
- background-color: cl.$background-default;
31
- border: bo.$border-width-sm solid cl.$border-default;
32
- }
1
+ @use "sass:map";
2
+ @use "../base/color" as cl;
3
+ @use "../base/border" as bo;
4
+ @use "../base/font" as ft;
5
+ @use "../base/space" as sp;
6
+ @use "../base/size" as sz;
7
+ @use "../base/variants" as vr;
8
+
9
+ // Form controls
10
+ //
11
+ // <input class="qo-input" />
12
+ // <input class="qo-input qo-input-sm qo-input-danger" />
13
+ //
14
+ // One class carries rest, :hover, :focus, :disabled and :read-only. The focus
15
+ // ring is the theme's single `$focus-ring` token, so every control on a screen
16
+ // focuses identically.
17
+
18
+ $input-sizes: (
19
+ xs: (24px, sp.$space-2, ft.$font-size-xs),
20
+ sm: (sz.$control-height-sm, sp.$space-2, ft.$font-size-sm),
21
+ md: (sz.$control-height, sp.$space-3, ft.$font-size-md),
22
+ lg: (48px, sp.$space-4, ft.$font-size-lg),
23
+ ) !default;
24
+
25
+ .qo-input {
26
+ width: 100%;
27
+ height: sz.$control-height;
28
+ padding: 0 sp.$space-3;
29
+ display: inline-flex;
30
+ align-items: center;
31
+ border: bo.$border-width-sm solid cl.$border-default;
32
+ border-radius: bo.$border-radius-md;
33
+ background-color: cl.$background-default;
34
+ color: cl.$text-dark;
35
+ font-family: ft.$font-family-primary;
36
+ font-size: ft.$font-size-md;
37
+ font-weight: ft.$font-weight-regular;
38
+ line-height: 1;
39
+ transition: border-color 0.2s ease, box-shadow 0.2s ease;
40
+
41
+ &::placeholder {
42
+ color: cl.$text-placeholder;
43
+ font-family: ft.$font-family-primary;
44
+ font-weight: ft.$font-weight-regular;
45
+ // Explicit colour, never reduced opacity — opacity renders inconsistently
46
+ // across Chrome/Edge/Firefox.
47
+ opacity: 1;
48
+ }
49
+
50
+ &:hover:not(:disabled):not([readonly]) { border-color: cl.$border-secondary; }
51
+
52
+ &:focus,
53
+ &:focus-visible {
54
+ outline: 0;
55
+ border-color: cl.$border-primary;
56
+ box-shadow: cl.$focus-ring;
57
+ }
58
+
59
+ &:disabled,
60
+ &.qo-disabled {
61
+ background-color: cl.$background-disabled;
62
+ color: cl.$text-default;
63
+ cursor: not-allowed;
64
+ }
65
+
66
+ &[readonly] {
67
+ background-color: cl.$background-light;
68
+ cursor: default;
69
+ }
70
+
71
+ @each $name, $spec in $input-sizes {
72
+ &.qo-input-#{$name} {
73
+ height: nth($spec, 1);
74
+ padding: 0 nth($spec, 2);
75
+ font-size: nth($spec, 3);
76
+ }
77
+ }
78
+
79
+ &.qo-input-full { display: flex; width: 100%; }
80
+ &.qo-input-auto { width: auto; }
81
+ &.qo-input-pill { border-radius: bo.$border-radius-pill; }
82
+
83
+ // Validation states. Each re-colours the border and its own focus ring so
84
+ // the ring never contradicts the state.
85
+ @each $name in (success, warning, danger, info) {
86
+ &.qo-input-#{$name} {
87
+ border-color: map.get(map.get(vr.$variants, $name), base);
88
+ &:focus,
89
+ &:focus-visible {
90
+ border-color: map.get(map.get(vr.$variants, $name), base);
91
+ box-shadow: 0 0 0 3px rgba(0, 0, 0, 0);
92
+ outline: 2px solid map.get(map.get(vr.$variants, $name), soft);
93
+ outline-offset: 0;
94
+ }
95
+ }
96
+ }
97
+
98
+ // A textarea keeps the ramp but must not be pinned to a control height.
99
+ &.qo-input-textarea {
100
+ height: auto;
101
+ min-height: 80px;
102
+ padding: sp.$space-2 sp.$space-3;
103
+ line-height: ft.$line-height-md;
104
+ }
105
+ }
106
+
107
+ // Retained from 2.2.0 — `qo-input-default` was the only way to get a bordered
108
+ // input before `.qo-input` carried its own border.
109
+ .qo-input-default {
110
+ background-color: cl.$background-default;
111
+ border: bo.$border-width-sm solid cl.$border-default;
112
+ }
113
+
114
+ // Label + help + error, so a field is one block rather than three guesses.
115
+ .qo-label {
116
+ display: inline-block;
117
+ margin-bottom: sp.$space-1;
118
+ color: cl.$text-darker;
119
+ font-family: ft.$font-family-primary;
120
+ font-size: ft.$font-size-sm;
121
+ font-weight: ft.$font-weight-semibold;
122
+
123
+ &.qo-label-required::after {
124
+ content: " *";
125
+ color: cl.$text-danger;
126
+ }
127
+ }
128
+
129
+ .qo-help {
130
+ display: block;
131
+ margin-top: sp.$space-1;
132
+ color: cl.$text-secondary;
133
+ font-size: ft.$font-size-xs;
134
+ }
135
+
136
+ .qo-field {
137
+ display: block;
138
+ & + & { margin-top: sp.$space-3; }
139
+ }
140
+
141
+ // An input with a leading or trailing icon. The icon is positioned, not
142
+ // padded in by hand, so it cannot drift out of the control.
143
+ .qo-input-group {
144
+ position: relative;
145
+ display: flex;
146
+ align-items: center;
147
+ width: 100%;
148
+
149
+ > .qo-input-icon {
150
+ position: absolute;
151
+ top: 50%;
152
+ transform: translateY(-50%);
153
+ color: cl.$text-default;
154
+ font-size: ft.$font-size-md;
155
+ pointer-events: none;
156
+ }
157
+
158
+ > .qo-input-icon-start { left: sp.$space-3; }
159
+ > .qo-input-icon-end { right: sp.$space-3; }
160
+
161
+ > .qo-input-icon-start ~ .qo-input { padding-left: 38px; }
162
+ > .qo-input:has(~ .qo-input-icon-end) { padding-right: 38px; }
163
+
164
+ // Search is the listing page's most common group: the magnifier is primary
165
+ // coloured and the control is the full-height one.
166
+ &.qo-input-group-search > .qo-input-icon { color: cl.$text-primary; }
167
+ }
168
+
169
+ // Checkbox / radio — sized and coloured, not restyled from scratch.
170
+ .qo-check {
171
+ width: 16px;
172
+ height: 16px;
173
+ margin: 0;
174
+ accent-color: cl.$background-primary;
175
+ cursor: pointer;
176
+
177
+ &:focus-visible { outline: 0; box-shadow: cl.$focus-ring; }
178
+ &:disabled { cursor: not-allowed; opacity: 0.45; }
179
+ }
180
+
181
+ // Native select needs the control ramp plus room for its own arrow.
182
+ .qo-select {
183
+ @extend .qo-input;
184
+ padding-right: sp.$space-6;
185
+ cursor: pointer;
186
+ }
@@ -0,0 +1,34 @@
1
+ @use "sass:map";
2
+ @use "../base/color" as cl;
3
+ @use "../base/border" as bo;
4
+ @use "../base/variants" as vr;
5
+
6
+ // Links — one class carrying rest, hover, active and focus.
7
+ .qo-link {
8
+ color: cl.$text-primary;
9
+ text-decoration: none;
10
+ cursor: pointer;
11
+ transition: color 0.2s ease;
12
+
13
+ &:hover { color: cl.$text-primary-hover; text-decoration: underline; }
14
+ &:focus-visible {
15
+ outline: 0;
16
+ box-shadow: cl.$focus-ring;
17
+ border-radius: bo.$border-radius-sm;
18
+ }
19
+
20
+ &.qo-link-muted {
21
+ color: cl.$text-secondary;
22
+ &:hover { color: cl.$text-dark; }
23
+ }
24
+
25
+ &.qo-link-underline { text-decoration: underline; }
26
+ &.qo-link-plain:hover { text-decoration: none; }
27
+
28
+ @each $name, $spec in vr.$variants {
29
+ &.qo-link-#{$name} {
30
+ color: map.get($spec, ink);
31
+ &:hover { color: map.get($spec, hover); }
32
+ }
33
+ }
34
+ }
@@ -0,0 +1,87 @@
1
+ @use "../base/color" as cl;
2
+ @use "../base/border" as bo;
3
+ @use "../base/font" as ft;
4
+ @use "../base/space" as sp;
5
+
6
+ // Page shell, header and toolbar — the listing-page layout primitives.
7
+ //
8
+ // <section class="qo-page">
9
+ // <header class="qo-page-header"> … </header>
10
+ // <div class="qo-toolbar"> … </div>
11
+ // </section>
12
+
13
+ .qo-page {
14
+ min-height: 100%;
15
+ padding: sp.$space-4 sp.$space-5 sp.$space-5;
16
+ background-color: cl.$background-light;
17
+ color: cl.$text-dark;
18
+ font-family: ft.$font-family-primary;
19
+ font-size: ft.$font-size-base;
20
+ line-height: ft.$line-height-base;
21
+
22
+ @media (max-width: 768px) { padding: sp.$space-3; }
23
+ }
24
+
25
+ .qo-page-header {
26
+ min-height: 56px;
27
+ padding: 0 sp.$space-4;
28
+ display: grid;
29
+ grid-template-columns: 1fr auto 1fr;
30
+ align-items: center;
31
+ background-color: cl.$background-default;
32
+ border: bo.$border-width-sm solid cl.$border-light;
33
+ border-radius: bo.$border-radius-md bo.$border-radius-md 0 0;
34
+
35
+ @media (max-width: 768px) {
36
+ grid-template-columns: 1fr auto;
37
+ row-gap: sp.$space-2;
38
+ padding: sp.$space-2 sp.$space-3;
39
+ }
40
+ }
41
+
42
+ .qo-page-title {
43
+ margin: 0;
44
+ color: cl.$text-darker;
45
+ font-size: ft.$font-size-xxl;
46
+ font-weight: ft.$font-weight-bold;
47
+ line-height: ft.$line-height-xxs;
48
+ }
49
+
50
+ .qo-page-subtitle {
51
+ margin: 0;
52
+ color: cl.$text-secondary;
53
+ font-size: ft.$font-size-sm;
54
+ font-weight: ft.$font-weight-regular;
55
+ }
56
+
57
+ .qo-page-action { justify-self: end; }
58
+
59
+ // Toolbar — search + actions, wrapping to its own row when narrow.
60
+ .qo-toolbar {
61
+ display: flex;
62
+ align-items: center;
63
+ gap: sp.$space-2;
64
+
65
+ &.qo-toolbar-between { justify-content: space-between; }
66
+ &.qo-toolbar-end { justify-content: flex-end; }
67
+ &.qo-toolbar-wrap { flex-wrap: wrap; }
68
+
69
+ @media (max-width: 1200px) { flex-wrap: wrap; }
70
+
71
+ @media (max-width: 768px) {
72
+ align-items: stretch;
73
+ // A text button stretches to fill the row; an icon button keeps its square.
74
+ > .qo-btn:not(.qo-btn-icon) { flex: 1 1 auto; }
75
+ }
76
+ }
77
+
78
+ // The flexible search region inside a toolbar.
79
+ .qo-toolbar-search {
80
+ position: relative;
81
+ flex: 1 1 auto;
82
+ min-width: 280px;
83
+
84
+ @media (max-width: 1200px) { flex-basis: 100%; }
85
+ }
86
+
87
+ .qo-toolbar-spacer { flex: 1 1 auto; }
@@ -0,0 +1,71 @@
1
+ @use "../base/color" as cl;
2
+ @use "../base/border" as bo;
3
+ @use "../base/font" as ft;
4
+ @use "../base/space" as sp;
5
+ @use "../base/size" as sz;
6
+
7
+ // Pagination
8
+ //
9
+ // <nav class="qo-pagination">
10
+ // <button class="qo-page-btn">‹</button>
11
+ // <button class="qo-page-btn qo-page-btn-active">1</button>
12
+ // </nav>
13
+
14
+ .qo-pagination {
15
+ display: flex;
16
+ align-items: center;
17
+ gap: sp.$space-1;
18
+ }
19
+
20
+ .qo-page-btn {
21
+ height: sz.$control-height-sm;
22
+ min-width: sz.$control-height-sm;
23
+ padding: 0 9px;
24
+ display: inline-flex;
25
+ align-items: center;
26
+ justify-content: center;
27
+ border: bo.$border-width-sm solid cl.$border-light;
28
+ border-radius: bo.$border-radius-sm;
29
+ background-color: cl.$background-default;
30
+ color: cl.$text-dark;
31
+ font-family: ft.$font-family-primary;
32
+ font-size: ft.$font-size-sm;
33
+ cursor: pointer;
34
+ transition: background-color 0.2s ease, border-color 0.2s ease, color 0.2s ease;
35
+
36
+ &:hover:not(:disabled) {
37
+ background-color: cl.$background-primary-soft;
38
+ border-color: cl.$border-primary-soft;
39
+ color: cl.$text-primary;
40
+ }
41
+
42
+ &:focus-visible { outline: 0; box-shadow: cl.$focus-ring; }
43
+
44
+ &:disabled {
45
+ opacity: 0.48;
46
+ cursor: not-allowed;
47
+ }
48
+
49
+ &.qo-page-btn-active {
50
+ border-color: cl.$border-primary-soft;
51
+ background-color: cl.$background-primary-soft;
52
+ color: cl.$text-primary;
53
+ font-weight: ft.$font-weight-semibold;
54
+ }
55
+ }
56
+
57
+ // The rows-per-page select sits in the same ramp as the page buttons.
58
+ .qo-page-size {
59
+ height: sz.$control-height-sm;
60
+ min-width: sz.$control-height-sm;
61
+ padding: 0 9px;
62
+ border: bo.$border-width-sm solid cl.$border-light;
63
+ border-radius: bo.$border-radius-sm;
64
+ background-color: cl.$background-default;
65
+ color: cl.$text-dark;
66
+ font-family: ft.$font-family-primary;
67
+ font-size: ft.$font-size-sm;
68
+ cursor: pointer;
69
+
70
+ &:focus-visible { outline: 0; box-shadow: cl.$focus-ring; }
71
+ }