oat-glassed 0.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/css/form.css ADDED
@@ -0,0 +1,264 @@
1
+ @layer base {
2
+ label {
3
+ display: block;
4
+ font-size: var(--text-7);
5
+ font-weight: var(--font-medium);
6
+
7
+ &:has(input:where([type=checkbox], [type=radio])) {
8
+ display: inline-flex;
9
+ align-items: center;
10
+ gap: var(--space-2);
11
+ font-weight: var(--font-normal);
12
+ }
13
+ }
14
+
15
+ :where(input:not([type=checkbox], [type=radio], [type=range], [type=file], [type=color]), textarea, select) {
16
+ width: 100%;
17
+ margin-block-start: var(--space-1);
18
+ padding: var(--space-2) var(--space-3);
19
+ font-size: var(--text-7);
20
+ line-height: var(--leading-normal);
21
+ background-color: light-dark(rgb(255 255 255 / 0.45), rgb(255 255 255 / 0.04));
22
+ color: var(--foreground);
23
+ border: 1px solid var(--input);
24
+ border-radius: var(--radius-medium);
25
+ box-shadow: inset 0 1px 0 light-dark(rgb(255 255 255 / 0.6), rgb(255 255 255 / 0.04));
26
+ transition: border-color var(--transition-fast), box-shadow var(--transition-fast), background-color var(--transition-fast);
27
+
28
+ &::placeholder {
29
+ color: var(--muted-foreground);
30
+ }
31
+
32
+ &:focus {
33
+ outline: none;
34
+ border-color: var(--ring);
35
+ background-color: light-dark(rgb(255 255 255 / 0.6), rgb(255 255 255 / 0.06));
36
+ box-shadow:
37
+ 0 0 0 3px rgb(from var(--ring) r g b / 0.12),
38
+ inset 0 1px 0 light-dark(rgb(255 255 255 / 0.5), rgb(255 255 255 / 0.03));
39
+ z-index: 1;
40
+ }
41
+
42
+ &:disabled {
43
+ background-color: var(--muted);
44
+ }
45
+
46
+ &:is([aria-invalid=true], :user-invalid) {
47
+ border-color: var(--danger);
48
+
49
+ &:focus {
50
+ box-shadow:
51
+ 0 0 0 3px rgb(from var(--danger) r g b / 0.12),
52
+ inset 0 1px 0 light-dark(rgb(255 255 255 / 0.5), rgb(255 255 255 / 0.03));
53
+ }
54
+ }
55
+ }
56
+
57
+ textarea {
58
+ height: auto;
59
+ min-height: 5rem;
60
+ padding: var(--space-3);
61
+ resize: vertical;
62
+ }
63
+
64
+ select {
65
+ appearance: none;
66
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%2371717a' stroke-width='2'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
67
+ background-repeat: no-repeat;
68
+ background-position: right var(--space-2) center;
69
+ padding-inline-end: var(--space-6);
70
+ }
71
+
72
+ input:where([type=checkbox], [type=radio]) {
73
+ appearance: none;
74
+ width: 1rem;
75
+ height: 1rem;
76
+ margin: 0;
77
+ position: relative;
78
+ background-color: var(--background);
79
+ border: 1px solid var(--input);
80
+ transition: background-color var(--transition-fast), border-color var(--transition-fast);
81
+
82
+ &:checked {
83
+ background-color: var(--primary);
84
+ border-color: var(--primary);
85
+
86
+ &::after {
87
+ content: "";
88
+ position: absolute;
89
+ inset: 0;
90
+ background-color: var(--primary-foreground);
91
+ mask-position: center;
92
+ mask-repeat: no-repeat;
93
+ mask-size: 100%;
94
+ }
95
+ }
96
+ }
97
+
98
+ input[type=checkbox] {
99
+ border-radius: var(--radius-small);
100
+
101
+ &:checked::after {
102
+ mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='4'%3E%3Cpolyline points='20 6 9 17 4 12'/%3E%3C/svg%3E");
103
+ }
104
+
105
+ &[role=switch] {
106
+ --switch-height: calc(var(--bar-height) * 3);
107
+ --switch-inset: 2px;
108
+ --switch-thumb: calc(var(--switch-height) - var(--switch-inset) * 3);
109
+
110
+ width: calc(var(--switch-height) * 2);
111
+ height: var(--switch-height);
112
+ border-radius: var(--radius-full);
113
+ background-color: var(--input);
114
+
115
+ &::before {
116
+ content: "";
117
+ position: absolute;
118
+ top: 50%;
119
+ left: var(--switch-inset);
120
+ transform: translateY(-50%);
121
+ width: var(--switch-thumb);
122
+ height: var(--switch-thumb);
123
+ background-color: var(--background);
124
+ border-radius: var(--radius-full);
125
+ transition: transform var(--transition);
126
+ box-shadow: var(--shadow-small);
127
+ }
128
+
129
+ &:checked {
130
+ background-color: var(--primary);
131
+
132
+ &::after {
133
+ content: none;
134
+ }
135
+
136
+ &::before {
137
+ transform: translateY(-50%) translateX(var(--switch-height));
138
+ }
139
+ }
140
+ }
141
+ }
142
+
143
+ input[type=radio] {
144
+ border-radius: var(--radius-full);
145
+
146
+ &:checked::after {
147
+ mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Ccircle cx='8' cy='8' r='4' fill='currentColor'/%3E%3C/svg%3E");
148
+ }
149
+ }
150
+
151
+ :where(input:where([type=checkbox], [type=radio], [type=range]), select):not(:disabled),
152
+ label:has(input:where([type=checkbox], [type=radio]):not(:disabled)) {
153
+ cursor: pointer;
154
+ }
155
+
156
+ input[type=range] {
157
+ width: 100%;
158
+ height: var(--bar-height);
159
+ appearance: none;
160
+ background: var(--muted);
161
+ border-radius: var(--radius-full);
162
+
163
+ &::-webkit-slider-thumb {
164
+ appearance: none;
165
+ width: 1.25rem;
166
+ height: 1.25rem;
167
+ background: var(--primary);
168
+ border-radius: var(--radius-full);
169
+ transition: transform var(--transition-fast);
170
+
171
+ &:hover {
172
+ transform: scale(1.1);
173
+ }
174
+ }
175
+
176
+ &::-moz-range-thumb {
177
+ width: 1.25rem;
178
+ height: 1.25rem;
179
+ background: var(--primary);
180
+ border: none;
181
+ border-radius: var(--radius-full);
182
+ }
183
+ }
184
+
185
+ fieldset {
186
+ border: 1px solid var(--border);
187
+ border-radius: var(--radius-medium);
188
+ padding: var(--space-4);
189
+ margin-block-end: var(--space-4);
190
+ content-visibility: auto;
191
+ }
192
+
193
+ legend {
194
+ font-size: var(--text-7);
195
+ font-weight: var(--font-medium);
196
+ padding: 0 var(--space-2);
197
+ }
198
+ }
199
+
200
+ @layer components {
201
+ fieldset.group {
202
+ display: flex;
203
+ align-items: stretch;
204
+ border: none;
205
+ padding: 0;
206
+ margin: 0;
207
+
208
+ & > :is(input, textarea, select) {
209
+ flex: 1;
210
+ margin-block-start: 0;
211
+
212
+ &:not(:focus):not(:last-child) {
213
+ border-inline-end-color: transparent;
214
+ }
215
+ }
216
+
217
+ & > :is(input, textarea, select, button) {
218
+ border-radius: 0;
219
+ &:first-child {
220
+ border-radius: var(--radius-medium) 0 0 var(--radius-medium);
221
+ }
222
+
223
+ &:last-child {
224
+ border-radius: 0 var(--radius-medium) var(--radius-medium) 0;
225
+ }
226
+ }
227
+
228
+ & > legend {
229
+ float: inline-start;
230
+ display: inline-flex;
231
+ align-items: center;
232
+ padding: 0 var(--space-3);
233
+ line-height: var(--leading-normal);
234
+ font-weight: var(--font-normal);
235
+ color: var(--muted-foreground);
236
+ background-color: var(--muted);
237
+ border: 1px solid var(--input);
238
+ border-inline-end: none;
239
+ border-radius: var(--radius-medium) 0 0 var(--radius-medium);
240
+ }
241
+ }
242
+
243
+ [data-field] {
244
+ margin-block-end: var(--space-4);
245
+
246
+ /* Hint text that succeeds an input with aria-describedby */
247
+ [data-hint], .error {
248
+ font-size: var(--text-8);
249
+ font-weight: var(--font-normal);
250
+ color: var(--muted-foreground);
251
+ margin-block-start: var(--space-1);
252
+ }
253
+
254
+ .error {
255
+ display: none;
256
+ }
257
+
258
+ /* Reveal error on data-field="error" */
259
+ &[data-field="error"] .error {
260
+ display: block;
261
+ color: var(--danger);
262
+ }
263
+ }
264
+ }
package/css/grid.css ADDED
@@ -0,0 +1,65 @@
1
+ @layer components {
2
+ :root {
3
+ --grid-cols: 12;
4
+ --grid-gap: 1.5rem;
5
+ --container-max: 1280px;
6
+ --container-pad: 1rem;
7
+ }
8
+
9
+ .container {
10
+ width: 100%;
11
+ max-width: var(--container-max);
12
+ margin-inline: auto;
13
+ padding-inline: var(--container-pad);
14
+ }
15
+
16
+ .row {
17
+ display: grid;
18
+ grid-template-columns: repeat(var(--grid-cols), 1fr);
19
+ gap: var(--grid-gap);
20
+ width: 100%;
21
+ }
22
+
23
+ /* Column spans using CSS custom property */
24
+ .col, [class*="col-"] { grid-column-end: span var(--span, var(--grid-cols)); }
25
+
26
+ .col-1 { --span: 1; }
27
+ .col-2 { --span: 2; }
28
+ .col-3 { --span: 3; }
29
+ .col-4 { --span: 4; }
30
+ .col-5 { --span: 5; }
31
+ .col-6 { --span: 6; }
32
+ .col-7 { --span: 7; }
33
+ .col-8 { --span: 8; }
34
+ .col-9 { --span: 9; }
35
+ .col-10 { --span: 10; }
36
+ .col-11 { --span: 11; }
37
+ .col-12 { --span: 12; }
38
+
39
+ /* Offsets via grid-column-start */
40
+ .offset-1 { grid-column-start: 2; }
41
+ .offset-2 { grid-column-start: 3; }
42
+ .offset-3 { grid-column-start: 4; }
43
+ .offset-4 { grid-column-start: 5; }
44
+ .offset-5 { grid-column-start: 6; }
45
+ .offset-6 { grid-column-start: 7; }
46
+
47
+ .col-end {
48
+ grid-column-start: span var(--span, 1);
49
+ grid-column-end: -1;
50
+ }
51
+
52
+ /* Responsive: stack on mobile */
53
+ @media (max-width: 768px) {
54
+ .row {
55
+ --grid-cols: 4;
56
+ --grid-gap: 1rem;
57
+ }
58
+ .col, [class*="col-"] {
59
+ --span: 4;
60
+ }
61
+ [class*="offset-"] {
62
+ grid-column-start: auto;
63
+ }
64
+ }
65
+ }
package/css/nav.css ADDED
@@ -0,0 +1,89 @@
1
+ @layer components {
2
+ [data-nav] {
3
+ font-size: var(--text-7);
4
+ display: flex;
5
+ flex-direction: column;
6
+ gap: var(--space-1);
7
+
8
+ /* Section labels */
9
+ & > small {
10
+ display: block;
11
+ padding: var(--space-2) var(--space-3);
12
+ font-size: var(--text-8);
13
+ font-weight: var(--font-semibold);
14
+ color: var(--muted-foreground);
15
+ text-transform: uppercase;
16
+ letter-spacing: 0.05em;
17
+
18
+ &:not(:first-child) {
19
+ margin-block-start: var(--space-3);
20
+ }
21
+ }
22
+
23
+ a {
24
+ display: flex;
25
+ align-items: center;
26
+ gap: var(--space-2);
27
+ padding: var(--space-2) var(--space-3);
28
+ color: var(--foreground);
29
+ text-decoration: none;
30
+ border-radius: var(--radius-small);
31
+ transition: background-color var(--transition-fast);
32
+
33
+ &:hover {
34
+ background-color: var(--accent);
35
+ }
36
+
37
+ &[aria-current] {
38
+ background-color: var(--accent);
39
+ font-weight: var(--font-medium);
40
+ }
41
+
42
+ & > .badge {
43
+ margin-inline-start: auto;
44
+ font-size: 0.625rem;
45
+ }
46
+ }
47
+
48
+ svg, img:not(.avatar img) {
49
+ width: 1rem;
50
+ height: 1rem;
51
+ flex-shrink: 0;
52
+ opacity: 0.7;
53
+ }
54
+
55
+ /* Collapsible sections */
56
+ details {
57
+ border: none;
58
+ background: none;
59
+ overflow: visible;
60
+
61
+ & + details { margin-top: 0; }
62
+ &[open] summary { border-bottom: none; }
63
+
64
+ > :not(summary) {
65
+ margin: 0;
66
+ padding-inline-start: var(--space-6);
67
+ }
68
+ }
69
+
70
+ summary {
71
+ justify-content: flex-start;
72
+ padding: var(--space-2) var(--space-3);
73
+ border-radius: var(--radius-small);
74
+ font-size: var(--text-7);
75
+
76
+ &::after {
77
+ width: 0.75rem;
78
+ height: 0.75rem;
79
+ margin-inline-start: auto;
80
+ }
81
+ }
82
+
83
+ hr {
84
+ margin: var(--space-2) var(--space-3);
85
+ border: none;
86
+ border-top: 1px solid var(--border);
87
+ }
88
+ }
89
+ }
@@ -0,0 +1,75 @@
1
+ @layer base {
2
+ progress {
3
+ appearance: none;
4
+ width: 100%;
5
+ height: var(--bar-height);
6
+ border: none;
7
+ border-radius: var(--radius-full);
8
+ overflow: hidden;
9
+ background-color: var(--muted);
10
+
11
+ &::-webkit-progress-bar {
12
+ background-color: var(--muted);
13
+ border-radius: var(--radius-full);
14
+ }
15
+
16
+ &::-webkit-progress-value {
17
+ background-color: var(--primary);
18
+ border-radius: var(--radius-full);
19
+ transition: width var(--transition);
20
+ }
21
+
22
+ &::-moz-progress-bar {
23
+ background-color: var(--primary);
24
+ border-radius: var(--radius-full);
25
+ }
26
+ }
27
+
28
+ meter {
29
+ appearance: none;
30
+ width: 100%;
31
+ height: var(--bar-height);
32
+ border: none;
33
+ border-radius: var(--radius-full);
34
+ overflow: hidden;
35
+ background: var(--muted);
36
+
37
+ &::-webkit-meter-bar {
38
+ background: var(--muted);
39
+ border: none;
40
+ border-radius: var(--radius-full);
41
+ height: var(--bar-height);
42
+ }
43
+
44
+ &::-webkit-meter-optimum-value,
45
+ &::-webkit-meter-suboptimum-value,
46
+ &::-webkit-meter-even-less-good-value {
47
+ border-radius: var(--radius-full);
48
+ }
49
+
50
+ &::-webkit-meter-optimum-value {
51
+ background: var(--success);
52
+ }
53
+
54
+ &::-webkit-meter-suboptimum-value {
55
+ background: var(--warning);
56
+ }
57
+
58
+ &::-webkit-meter-even-less-good-value {
59
+ background: var(--danger);
60
+ }
61
+
62
+ &::-moz-meter-bar {
63
+ background: var(--success);
64
+ border-radius: var(--radius-full);
65
+ }
66
+
67
+ &:-moz-meter-sub-optimum::-moz-meter-bar {
68
+ background: var(--warning);
69
+ }
70
+
71
+ &:-moz-meter-sub-sub-optimum::-moz-meter-bar {
72
+ background: var(--danger);
73
+ }
74
+ }
75
+ }
@@ -0,0 +1,189 @@
1
+ @layer components {
2
+ [data-sidebar-layout] {
3
+ display: grid;
4
+ grid-template-columns: 14rem 1fr;
5
+ grid-template-rows: auto 1fr;
6
+ height: 100dvh;
7
+
8
+ > main {
9
+ grid-row: 2;
10
+ min-width: 0;
11
+ overflow-y: auto;
12
+ }
13
+
14
+ > aside[data-sidebar] {
15
+ grid-row: 2;
16
+ min-height: 0;
17
+ z-index: 1;
18
+ background-color: light-dark(rgb(248 250 252 / 0.55), rgb(2 6 23 / 0.55));
19
+ backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate));
20
+ -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate));
21
+ will-change: transform;
22
+ contain: layout style paint;
23
+ border-inline-end: 1px solid var(--border);
24
+ display: flex;
25
+ flex-direction: column;
26
+
27
+ > :is(header, footer) {
28
+ flex-shrink: 0;
29
+ padding: var(--space-3);
30
+ }
31
+
32
+ > footer {
33
+ margin-block-start: auto;
34
+ }
35
+
36
+ > nav {
37
+ flex: 1;
38
+ min-height: 0;
39
+ overflow-y: auto;
40
+ padding: var(--space-3) var(--space-2);
41
+ font-size: var(--text-7);
42
+
43
+ ul {
44
+ list-style: none;
45
+ padding: 0;
46
+ margin: 0;
47
+ display: flex;
48
+ flex-direction: column;
49
+ gap: var(--space-1);
50
+
51
+ li {
52
+ margin: 0;
53
+ }
54
+ }
55
+
56
+ a {
57
+ display: flex;
58
+ gap: var(--space-2);
59
+ padding: var(--space-1) var(--space-3);
60
+ color: var(--foreground);
61
+ text-decoration: none;
62
+ border-radius: var(--radius-small);
63
+ transition: background-color var(--transition-fast);
64
+
65
+ &:is(:hover, [aria-current]) {
66
+ background-color: var(--accent);
67
+ }
68
+ }
69
+
70
+ details {
71
+ border: none;
72
+ overflow: visible;
73
+ background: none;
74
+
75
+ & + details { margin-top: 0; }
76
+ &[open] summary { border-bottom: none; }
77
+ > ul { margin-inline-start: var(--space-4); padding: var(--space-1) 0; }
78
+ }
79
+
80
+ summary {
81
+ justify-content: flex-start;
82
+ padding: var(--space-2) var(--space-3);
83
+ border-radius: var(--radius-small);
84
+
85
+ &::after {
86
+ width: 0.75rem;
87
+ height: 0.75rem;
88
+ margin-inline-start: auto;
89
+ }
90
+ }
91
+ }
92
+ }
93
+
94
+ > nav[data-topnav] {
95
+ grid-column: 1 / -1;
96
+ }
97
+ }
98
+
99
+ nav[data-topnav] {
100
+ position: sticky;
101
+ top: 0;
102
+ z-index: 5;
103
+ display: flex;
104
+ align-items: center;
105
+ gap: var(--space-3);
106
+ padding: var(--space-2) var(--space-4);
107
+ background-color: light-dark(rgb(248 250 252 / 0.55), rgb(2 6 23 / 0.55));
108
+ backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate));
109
+ -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate));
110
+ will-change: transform;
111
+ contain: layout style paint;
112
+ border-bottom: 1px solid var(--glass-border);
113
+
114
+ a {
115
+ text-decoration: none;
116
+ }
117
+ }
118
+
119
+ :is([data-sidebar-toggle], [data-sidebar-header]) {
120
+ display: none;
121
+ }
122
+
123
+ [data-sidebar-toggle] {
124
+ padding: 0 var(--space-1);
125
+ background: none;
126
+ border: 1px solid var(--border);
127
+ border-radius: var(--radius-small);
128
+ }
129
+
130
+ @media (min-width: 769px) {
131
+ [data-sidebar-layout="always"] {
132
+ transition: grid-template-columns var(--transition);
133
+
134
+ [data-sidebar-toggle] {
135
+ display: inline-block;
136
+ }
137
+
138
+ > aside[data-sidebar] {
139
+ transform: translateX(0);
140
+ opacity: 1;
141
+ }
142
+
143
+ &[data-sidebar-open] {
144
+ grid-template-columns: 0px 1fr;
145
+ gap: 0;
146
+
147
+ > aside[data-sidebar] {
148
+ overflow: hidden;
149
+ min-width: 0;
150
+ transform: translateX(-100%);
151
+ opacity: 0;
152
+ visibility: hidden;
153
+ border-inline-end: none;
154
+ }
155
+ }
156
+ }
157
+ }
158
+
159
+ @media (max-width: 768px) {
160
+ [data-sidebar-layout] {
161
+ grid-template-columns: 1fr;
162
+
163
+ > main {
164
+ grid-column: 1;
165
+ }
166
+
167
+ > aside[data-sidebar] {
168
+ grid-column: 1;
169
+ z-index: 2;
170
+ width: 16rem;
171
+ transform: translateX(-100%);
172
+ box-shadow: var(--shadow-large);
173
+ }
174
+
175
+ &[data-sidebar-open] > aside[data-sidebar] {
176
+ transform: translateX(0);
177
+ }
178
+ }
179
+ [data-sidebar-toggle] { display: inline-block; }
180
+
181
+ [data-sidebar-header] {
182
+ display: flex;
183
+ align-items: center;
184
+ gap: var(--space-3);
185
+ padding: var(--space-3) var(--space-4);
186
+ border-bottom: 1px solid var(--border);
187
+ }
188
+ }
189
+ }
@@ -0,0 +1,39 @@
1
+ @layer components {
2
+ [role="status"].skeleton {
3
+ --_c: light-dark(
4
+ color-mix(in srgb, var(--muted) 30%, white),
5
+ color-mix(in srgb, var(--muted) 90%, var(--foreground))
6
+ );
7
+
8
+ margin-block-end: var(--space-3);
9
+ background: var(--muted);
10
+ border-radius: var(--radius-small);
11
+ animation: anim 2s infinite;
12
+ background-size: 200% 100%;
13
+ background-image: linear-gradient(
14
+ 90deg,
15
+ var(--muted) 0%,
16
+ var(--_c) 50%,
17
+ var(--muted) 100%
18
+ );
19
+
20
+ &.box {
21
+ width: 4rem;
22
+ height: 4rem;
23
+ }
24
+
25
+ &.line {
26
+ height: 1rem;
27
+ width: 100%;
28
+ }
29
+ }
30
+
31
+ [role="status"].skeleton:last-child {
32
+ margin-block-end: 0;
33
+ }
34
+
35
+ @keyframes anim {
36
+ from { background-position: 200% 0; }
37
+ to { background-position: -200% 0; }
38
+ }
39
+ }