@axiapps/axi-design 1.16.0 → 1.17.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/README.md +3 -0
- package/dist/axi.css +139 -0
- package/dist/themes/glass.css +1 -0
- package/package.json +1 -1
- package/src/primitives.css +16 -0
- package/src/shells.css +101 -0
- package/src/tokens.css +22 -0
package/README.md
CHANGED
|
@@ -138,6 +138,9 @@ not "what does the system look like". Everything else is
|
|
|
138
138
|
| `--axi-check-size` | the size of an `.axi-check` or `.axi-radio` box | `22px` | `<input type="checkbox" class="axi-check" style="--axi-check-size: 16px">` |
|
|
139
139
|
| `--axi-check-fill` | the fill a checked `.axi-check` takes, and the colour of a checked `.axi-radio`'s diamond | `var(--axi-accent)` | `<input type="checkbox" class="axi-check" style="--axi-check-fill: var(--axi-danger)">` |
|
|
140
140
|
| `--axi-textarea-h` | the minimum height of a `<textarea class="axi-input">` | `90px` | `<textarea class="axi-input" style="--axi-textarea-h: 200px">` |
|
|
141
|
+
| `--axi-well-pad` | the padding inside an `.axi-well` | `10px` | `<div class="axi-well" style="--axi-well-pad: 18px">` |
|
|
142
|
+
| `--axi-rail-w` | an `.axi-rail`'s width, for labels longer than the default holds | `208px` | `<aside class="axi-rail" style="--axi-rail-w: 260px">` |
|
|
143
|
+
| `--axi-rail-pad` | the padding inside an `.axi-rail` | `10px` | `<aside class="axi-rail" style="--axi-rail-pad: 6px">` |
|
|
141
144
|
| `--axi-avatar-size` | the size of an `.axi-avatar` square | `40px` | `<span class="axi-avatar" style="--axi-avatar-size: 28px">MS</span>` |
|
|
142
145
|
| `--axi-modal-width` | the maximum width of an `.axi-modal`, before the viewport clamp | `560px` | `<dialog class="axi-modal" style="--axi-modal-width: 760px">` |
|
|
143
146
|
| `--axi-card-strip` | the colour of `.axi-card--strip`'s top strip | `var(--axi-accent)` | `<a class="axi-card axi-card--strip" style="--axi-card-strip: var(--axi-ok)">` |
|
package/dist/axi.css
CHANGED
|
@@ -43,6 +43,28 @@
|
|
|
43
43
|
--axi-ink-on-fill below, on the other side of the same token. */
|
|
44
44
|
--axi-ground-deep: var(--axi-ink-line);
|
|
45
45
|
--axi-rule: #3a4250; /* internal rules, inside an outlined panel */
|
|
46
|
+
/* --- the well --- */
|
|
47
|
+
/* A field sunk INTO a surface rather than raised off one: a table picker's
|
|
48
|
+
list, a bar's trough, a column of cards standing on the page. The language
|
|
49
|
+
had no name for it, and every consumer that needed one reached for a second
|
|
50
|
+
.axi-panel inside the first - two identical fills parted by a line, which
|
|
51
|
+
reads as one field with a stray rule through it.
|
|
52
|
+
|
|
53
|
+
Two tokens because a well is the exact inverse of a panel on both counts.
|
|
54
|
+
The fill is a SUBTRACTION from whatever is behind it, not a colour of its
|
|
55
|
+
own: spelled as --axi-ground it is right in this theme, where surfaces are
|
|
56
|
+
opaque and the page really is what shows through a hole in one, and wrong
|
|
57
|
+
in a glass theme, where an opaque page colour inside a translucent pane is
|
|
58
|
+
a black patch rather than a recess. A theme restates it as a darkening at
|
|
59
|
+
alpha and the panel's own tint carries through.
|
|
60
|
+
|
|
61
|
+
The line is --axi-rule and not --axi-ink-line, because ink only reads
|
|
62
|
+
against a fill lighter than itself. Every outline in this language is
|
|
63
|
+
near-black on the assumption of a ground the lines can be darker than; a
|
|
64
|
+
well IS at ground level, so an ink edge round one is a black line on a
|
|
65
|
+
black field. Raised takes ink, sunk takes the rule. */
|
|
66
|
+
--axi-well-fill: var(--axi-ground);
|
|
67
|
+
--axi-well-line: var(--axi-rule);
|
|
46
68
|
--axi-text: #f4f6f9;
|
|
47
69
|
--axi-text-dim: #a7b0be;
|
|
48
70
|
--axi-text-faint: #7c8695;
|
|
@@ -251,6 +273,22 @@ a { color: inherit; }
|
|
|
251
273
|
padding: var(--axi-panel-pad, 26px);
|
|
252
274
|
}
|
|
253
275
|
|
|
276
|
+
/* ---------- well ---------- */
|
|
277
|
+
/* The panel's inverse: a field sunk into the surface around it rather than
|
|
278
|
+
raised off it. No block, because a recess casts nothing, and the rule rather
|
|
279
|
+
than the ink for its edge - see --axi-well-fill in src/tokens.css for why
|
|
280
|
+
both of those follow from the same fact. Reach for this wherever a second
|
|
281
|
+
panel inside a panel was the instinct: a picker list beside a table, a column
|
|
282
|
+
of cards standing on the page, a trough a bar fills. */
|
|
283
|
+
.axi-well {
|
|
284
|
+
background: var(--axi-well-fill);
|
|
285
|
+
border: var(--axi-border-control) solid var(--axi-well-line);
|
|
286
|
+
border-radius: var(--axi-radius);
|
|
287
|
+
/* Tighter than a panel's 26px: a well is a container for objects that carry
|
|
288
|
+
their own padding, not a page margin. */
|
|
289
|
+
padding: var(--axi-well-pad, 10px);
|
|
290
|
+
}
|
|
291
|
+
|
|
254
292
|
/* ---------- button ---------- */
|
|
255
293
|
.axi-btn {
|
|
256
294
|
display: inline-flex; align-items: center; gap: 8px;
|
|
@@ -935,6 +973,107 @@ textarea.axi-input {
|
|
|
935
973
|
}
|
|
936
974
|
.axi-tabs .axi-tabs__close:hover { color: var(--axi-text); border-color: transparent; }
|
|
937
975
|
|
|
976
|
+
/* ---------- rail ---------- */
|
|
977
|
+
/* Vertical navigation, for a set too large for a tab strip to hold. Same
|
|
978
|
+
grammar as .axi-tabs deliberately - the item you are on is filled with the
|
|
979
|
+
accent and blocked, the rest are transparent until hovered - because "where
|
|
980
|
+
am I" is one question and should have one answer however the app happens to
|
|
981
|
+
be laying it out.
|
|
982
|
+
|
|
983
|
+
What a rail adds over a strip is a second level. A category is a place and
|
|
984
|
+
takes the fill; a section under it is where the page is scrolled to, which is
|
|
985
|
+
a smaller claim and is drawn as one: brightened text against the dim list
|
|
986
|
+
around it, no fill, no edge. Two fills at two levels would leave the reader
|
|
987
|
+
deciding which of them is the answer.
|
|
988
|
+
|
|
989
|
+
--axi-rail-w is declared nowhere and read with a fallback, i.e. it is the hook
|
|
990
|
+
a consumer overrides to widen the rail for longer labels. */
|
|
991
|
+
.axi-rail {
|
|
992
|
+
display: flex;
|
|
993
|
+
flex-direction: column;
|
|
994
|
+
width: var(--axi-rail-w, 208px);
|
|
995
|
+
flex: none;
|
|
996
|
+
overflow-y: auto;
|
|
997
|
+
padding: var(--axi-rail-pad, 10px);
|
|
998
|
+
background: var(--axi-surface);
|
|
999
|
+
backdrop-filter: var(--axi-surface-filter);
|
|
1000
|
+
border: var(--axi-border-panel) solid var(--axi-ink-line);
|
|
1001
|
+
border-radius: var(--axi-radius);
|
|
1002
|
+
}
|
|
1003
|
+
/* A rail that IS the edge of the page rather than a panel standing in the
|
|
1004
|
+
layout - pinned to the viewport, or a drawer's contents. It keeps the one
|
|
1005
|
+
border that faces the content and drops everything that says "this is an
|
|
1006
|
+
object with space around it": no radius on the flush side, and no block,
|
|
1007
|
+
because a block needs somewhere to fall.
|
|
1008
|
+
|
|
1009
|
+
The block is stated as what a free-standing rail has rather than as
|
|
1010
|
+
something the flush one turns off, so there is exactly one box-shadow here
|
|
1011
|
+
and it names the panel block. `box-shadow: none` would be a second spelling
|
|
1012
|
+
of the raise for a theme to miss. */
|
|
1013
|
+
.axi-rail:not(.axi-rail--flush) { box-shadow: var(--axi-shadow-panel); }
|
|
1014
|
+
.axi-rail--flush {
|
|
1015
|
+
border: 0;
|
|
1016
|
+
border-right: var(--axi-border-panel) solid var(--axi-ink-line);
|
|
1017
|
+
border-radius: 0;
|
|
1018
|
+
}
|
|
1019
|
+
.axi-rail__nav { display: flex; flex-direction: column; gap: 2px; }
|
|
1020
|
+
.axi-rail__item {
|
|
1021
|
+
display: flex;
|
|
1022
|
+
align-items: center;
|
|
1023
|
+
gap: 10px;
|
|
1024
|
+
width: 100%;
|
|
1025
|
+
padding: 8px 10px;
|
|
1026
|
+
font: 800 12.5px/1 var(--axi-sans);
|
|
1027
|
+
color: var(--axi-text-dim);
|
|
1028
|
+
text-align: left;
|
|
1029
|
+
background: transparent;
|
|
1030
|
+
border: var(--axi-border-control) solid transparent;
|
|
1031
|
+
border-radius: var(--axi-radius-sm);
|
|
1032
|
+
cursor: pointer;
|
|
1033
|
+
}
|
|
1034
|
+
.axi-rail__item:hover { color: var(--axi-text); background: var(--axi-surface-raised); }
|
|
1035
|
+
/* The same treatment a pressed pill and a current tab get. Only ever one of
|
|
1036
|
+
these on screen. Any aria-current value, because the right one depends on
|
|
1037
|
+
what the rail navigates - `page` for a view, `location` for a place within
|
|
1038
|
+
one - and the fill means the same thing either way. */
|
|
1039
|
+
.axi-rail__item[aria-current],
|
|
1040
|
+
.axi-rail__item[aria-current]:hover {
|
|
1041
|
+
background: var(--axi-accent);
|
|
1042
|
+
color: var(--axi-accent-ink);
|
|
1043
|
+
border-color: var(--axi-ink-line);
|
|
1044
|
+
box-shadow: var(--axi-shadow-control);
|
|
1045
|
+
}
|
|
1046
|
+
/* An icon beside a label is a label for it, not a second accent - so it takes
|
|
1047
|
+
the faint tone, and inside a filled item it follows the item's ink. */
|
|
1048
|
+
.axi-rail__item .axi-icon { color: var(--axi-text-faint); }
|
|
1049
|
+
.axi-rail__item[aria-current] .axi-icon { color: var(--axi-accent-ink); }
|
|
1050
|
+
/* The second level, indented under the item it belongs to. */
|
|
1051
|
+
.axi-rail__sub { display: flex; flex-direction: column; margin: 3px 0 5px 10px; }
|
|
1052
|
+
.axi-rail__subitem {
|
|
1053
|
+
padding: 5px 8px;
|
|
1054
|
+
font: 700 11.5px/1.3 var(--axi-sans);
|
|
1055
|
+
text-align: left;
|
|
1056
|
+
color: var(--axi-text-faint);
|
|
1057
|
+
background: transparent;
|
|
1058
|
+
border: 0;
|
|
1059
|
+
border-radius: var(--axi-radius-sm);
|
|
1060
|
+
cursor: pointer;
|
|
1061
|
+
}
|
|
1062
|
+
.axi-rail__subitem:hover { color: var(--axi-text-dim); background: var(--axi-surface-raised); }
|
|
1063
|
+
.axi-rail__subitem[aria-current] { color: var(--axi-text); }
|
|
1064
|
+
/* An annotation on an item, not a measurement of it, so rule 5 draws it
|
|
1065
|
+
outlined rather than filled. */
|
|
1066
|
+
.axi-rail__mark {
|
|
1067
|
+
margin-left: auto;
|
|
1068
|
+
padding: 2px 5px;
|
|
1069
|
+
font: var(--axi-t-micro);
|
|
1070
|
+
letter-spacing: .04em;
|
|
1071
|
+
text-transform: uppercase;
|
|
1072
|
+
color: var(--axi-meta);
|
|
1073
|
+
border: var(--axi-border-hairline) solid var(--axi-meta);
|
|
1074
|
+
border-radius: var(--axi-radius-sm);
|
|
1075
|
+
}
|
|
1076
|
+
|
|
938
1077
|
/* ---------- notice ---------- */
|
|
939
1078
|
.axi-notice {
|
|
940
1079
|
display: flex; gap: 14px; padding: 15px 18px;
|
package/dist/themes/glass.css
CHANGED
package/package.json
CHANGED
package/src/primitives.css
CHANGED
|
@@ -29,6 +29,22 @@
|
|
|
29
29
|
padding: var(--axi-panel-pad, 26px);
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
+
/* ---------- well ---------- */
|
|
33
|
+
/* The panel's inverse: a field sunk into the surface around it rather than
|
|
34
|
+
raised off it. No block, because a recess casts nothing, and the rule rather
|
|
35
|
+
than the ink for its edge - see --axi-well-fill in src/tokens.css for why
|
|
36
|
+
both of those follow from the same fact. Reach for this wherever a second
|
|
37
|
+
panel inside a panel was the instinct: a picker list beside a table, a column
|
|
38
|
+
of cards standing on the page, a trough a bar fills. */
|
|
39
|
+
.axi-well {
|
|
40
|
+
background: var(--axi-well-fill);
|
|
41
|
+
border: var(--axi-border-control) solid var(--axi-well-line);
|
|
42
|
+
border-radius: var(--axi-radius);
|
|
43
|
+
/* Tighter than a panel's 26px: a well is a container for objects that carry
|
|
44
|
+
their own padding, not a page margin. */
|
|
45
|
+
padding: var(--axi-well-pad, 10px);
|
|
46
|
+
}
|
|
47
|
+
|
|
32
48
|
/* ---------- button ---------- */
|
|
33
49
|
.axi-btn {
|
|
34
50
|
display: inline-flex; align-items: center; gap: 8px;
|
package/src/shells.css
CHANGED
|
@@ -109,6 +109,107 @@
|
|
|
109
109
|
}
|
|
110
110
|
.axi-tabs .axi-tabs__close:hover { color: var(--axi-text); border-color: transparent; }
|
|
111
111
|
|
|
112
|
+
/* ---------- rail ---------- */
|
|
113
|
+
/* Vertical navigation, for a set too large for a tab strip to hold. Same
|
|
114
|
+
grammar as .axi-tabs deliberately - the item you are on is filled with the
|
|
115
|
+
accent and blocked, the rest are transparent until hovered - because "where
|
|
116
|
+
am I" is one question and should have one answer however the app happens to
|
|
117
|
+
be laying it out.
|
|
118
|
+
|
|
119
|
+
What a rail adds over a strip is a second level. A category is a place and
|
|
120
|
+
takes the fill; a section under it is where the page is scrolled to, which is
|
|
121
|
+
a smaller claim and is drawn as one: brightened text against the dim list
|
|
122
|
+
around it, no fill, no edge. Two fills at two levels would leave the reader
|
|
123
|
+
deciding which of them is the answer.
|
|
124
|
+
|
|
125
|
+
--axi-rail-w is declared nowhere and read with a fallback, i.e. it is the hook
|
|
126
|
+
a consumer overrides to widen the rail for longer labels. */
|
|
127
|
+
.axi-rail {
|
|
128
|
+
display: flex;
|
|
129
|
+
flex-direction: column;
|
|
130
|
+
width: var(--axi-rail-w, 208px);
|
|
131
|
+
flex: none;
|
|
132
|
+
overflow-y: auto;
|
|
133
|
+
padding: var(--axi-rail-pad, 10px);
|
|
134
|
+
background: var(--axi-surface);
|
|
135
|
+
backdrop-filter: var(--axi-surface-filter);
|
|
136
|
+
border: var(--axi-border-panel) solid var(--axi-ink-line);
|
|
137
|
+
border-radius: var(--axi-radius);
|
|
138
|
+
}
|
|
139
|
+
/* A rail that IS the edge of the page rather than a panel standing in the
|
|
140
|
+
layout - pinned to the viewport, or a drawer's contents. It keeps the one
|
|
141
|
+
border that faces the content and drops everything that says "this is an
|
|
142
|
+
object with space around it": no radius on the flush side, and no block,
|
|
143
|
+
because a block needs somewhere to fall.
|
|
144
|
+
|
|
145
|
+
The block is stated as what a free-standing rail has rather than as
|
|
146
|
+
something the flush one turns off, so there is exactly one box-shadow here
|
|
147
|
+
and it names the panel block. `box-shadow: none` would be a second spelling
|
|
148
|
+
of the raise for a theme to miss. */
|
|
149
|
+
.axi-rail:not(.axi-rail--flush) { box-shadow: var(--axi-shadow-panel); }
|
|
150
|
+
.axi-rail--flush {
|
|
151
|
+
border: 0;
|
|
152
|
+
border-right: var(--axi-border-panel) solid var(--axi-ink-line);
|
|
153
|
+
border-radius: 0;
|
|
154
|
+
}
|
|
155
|
+
.axi-rail__nav { display: flex; flex-direction: column; gap: 2px; }
|
|
156
|
+
.axi-rail__item {
|
|
157
|
+
display: flex;
|
|
158
|
+
align-items: center;
|
|
159
|
+
gap: 10px;
|
|
160
|
+
width: 100%;
|
|
161
|
+
padding: 8px 10px;
|
|
162
|
+
font: 800 12.5px/1 var(--axi-sans);
|
|
163
|
+
color: var(--axi-text-dim);
|
|
164
|
+
text-align: left;
|
|
165
|
+
background: transparent;
|
|
166
|
+
border: var(--axi-border-control) solid transparent;
|
|
167
|
+
border-radius: var(--axi-radius-sm);
|
|
168
|
+
cursor: pointer;
|
|
169
|
+
}
|
|
170
|
+
.axi-rail__item:hover { color: var(--axi-text); background: var(--axi-surface-raised); }
|
|
171
|
+
/* The same treatment a pressed pill and a current tab get. Only ever one of
|
|
172
|
+
these on screen. Any aria-current value, because the right one depends on
|
|
173
|
+
what the rail navigates - `page` for a view, `location` for a place within
|
|
174
|
+
one - and the fill means the same thing either way. */
|
|
175
|
+
.axi-rail__item[aria-current],
|
|
176
|
+
.axi-rail__item[aria-current]:hover {
|
|
177
|
+
background: var(--axi-accent);
|
|
178
|
+
color: var(--axi-accent-ink);
|
|
179
|
+
border-color: var(--axi-ink-line);
|
|
180
|
+
box-shadow: var(--axi-shadow-control);
|
|
181
|
+
}
|
|
182
|
+
/* An icon beside a label is a label for it, not a second accent - so it takes
|
|
183
|
+
the faint tone, and inside a filled item it follows the item's ink. */
|
|
184
|
+
.axi-rail__item .axi-icon { color: var(--axi-text-faint); }
|
|
185
|
+
.axi-rail__item[aria-current] .axi-icon { color: var(--axi-accent-ink); }
|
|
186
|
+
/* The second level, indented under the item it belongs to. */
|
|
187
|
+
.axi-rail__sub { display: flex; flex-direction: column; margin: 3px 0 5px 10px; }
|
|
188
|
+
.axi-rail__subitem {
|
|
189
|
+
padding: 5px 8px;
|
|
190
|
+
font: 700 11.5px/1.3 var(--axi-sans);
|
|
191
|
+
text-align: left;
|
|
192
|
+
color: var(--axi-text-faint);
|
|
193
|
+
background: transparent;
|
|
194
|
+
border: 0;
|
|
195
|
+
border-radius: var(--axi-radius-sm);
|
|
196
|
+
cursor: pointer;
|
|
197
|
+
}
|
|
198
|
+
.axi-rail__subitem:hover { color: var(--axi-text-dim); background: var(--axi-surface-raised); }
|
|
199
|
+
.axi-rail__subitem[aria-current] { color: var(--axi-text); }
|
|
200
|
+
/* An annotation on an item, not a measurement of it, so rule 5 draws it
|
|
201
|
+
outlined rather than filled. */
|
|
202
|
+
.axi-rail__mark {
|
|
203
|
+
margin-left: auto;
|
|
204
|
+
padding: 2px 5px;
|
|
205
|
+
font: var(--axi-t-micro);
|
|
206
|
+
letter-spacing: .04em;
|
|
207
|
+
text-transform: uppercase;
|
|
208
|
+
color: var(--axi-meta);
|
|
209
|
+
border: var(--axi-border-hairline) solid var(--axi-meta);
|
|
210
|
+
border-radius: var(--axi-radius-sm);
|
|
211
|
+
}
|
|
212
|
+
|
|
112
213
|
/* ---------- notice ---------- */
|
|
113
214
|
.axi-notice {
|
|
114
215
|
display: flex; gap: 14px; padding: 15px 18px;
|
package/src/tokens.css
CHANGED
|
@@ -39,6 +39,28 @@
|
|
|
39
39
|
--axi-ink-on-fill below, on the other side of the same token. */
|
|
40
40
|
--axi-ground-deep: var(--axi-ink-line);
|
|
41
41
|
--axi-rule: #3a4250; /* internal rules, inside an outlined panel */
|
|
42
|
+
/* --- the well --- */
|
|
43
|
+
/* A field sunk INTO a surface rather than raised off one: a table picker's
|
|
44
|
+
list, a bar's trough, a column of cards standing on the page. The language
|
|
45
|
+
had no name for it, and every consumer that needed one reached for a second
|
|
46
|
+
.axi-panel inside the first - two identical fills parted by a line, which
|
|
47
|
+
reads as one field with a stray rule through it.
|
|
48
|
+
|
|
49
|
+
Two tokens because a well is the exact inverse of a panel on both counts.
|
|
50
|
+
The fill is a SUBTRACTION from whatever is behind it, not a colour of its
|
|
51
|
+
own: spelled as --axi-ground it is right in this theme, where surfaces are
|
|
52
|
+
opaque and the page really is what shows through a hole in one, and wrong
|
|
53
|
+
in a glass theme, where an opaque page colour inside a translucent pane is
|
|
54
|
+
a black patch rather than a recess. A theme restates it as a darkening at
|
|
55
|
+
alpha and the panel's own tint carries through.
|
|
56
|
+
|
|
57
|
+
The line is --axi-rule and not --axi-ink-line, because ink only reads
|
|
58
|
+
against a fill lighter than itself. Every outline in this language is
|
|
59
|
+
near-black on the assumption of a ground the lines can be darker than; a
|
|
60
|
+
well IS at ground level, so an ink edge round one is a black line on a
|
|
61
|
+
black field. Raised takes ink, sunk takes the rule. */
|
|
62
|
+
--axi-well-fill: var(--axi-ground);
|
|
63
|
+
--axi-well-line: var(--axi-rule);
|
|
42
64
|
--axi-text: #f4f6f9;
|
|
43
65
|
--axi-text-dim: #a7b0be;
|
|
44
66
|
--axi-text-faint: #7c8695;
|