@aortl/admin-css 0.16.2 → 0.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/CHANGELOG.md +19 -1
- package/dist/admin.css +351 -7
- package/dist/admin.min.css +1 -1
- package/dist/admin.scoped.css +345 -7
- package/dist/admin.scoped.min.css +67 -5
- package/package.json +1 -1
- package/src/components/alert.css +34 -4
- package/src/components/avatar.css +36 -0
- package/src/components/badge.css +36 -0
- package/src/components/brand-tile.css +36 -0
- package/src/components/card.css +38 -0
- package/src/components/index.css +3 -0
- package/src/components/indicator.css +12 -0
- package/src/components/input-icon.css +46 -0
- package/src/components/separator.css +13 -0
- package/src/components/table.css +10 -0
package/package.json
CHANGED
package/src/components/alert.css
CHANGED
|
@@ -14,13 +14,25 @@
|
|
|
14
14
|
align-items: center;
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
+
/* A trailing action switches to grid even without an icon. */
|
|
18
|
+
.alert:has(> .alert-action) {
|
|
19
|
+
display: grid;
|
|
20
|
+
grid-template-columns: minmax(0, 1fr) auto;
|
|
21
|
+
column-gap: 0.5rem;
|
|
22
|
+
row-gap: 0.25rem;
|
|
23
|
+
align-items: center;
|
|
24
|
+
}
|
|
25
|
+
.alert:has(> :is(i, svg):first-child):has(> .alert-action) {
|
|
26
|
+
grid-template-columns: auto minmax(0, 1fr) auto;
|
|
27
|
+
}
|
|
28
|
+
|
|
17
29
|
.alert > :is(i, svg):first-child {
|
|
18
30
|
font-size: 1rem;
|
|
19
31
|
line-height: 1.25;
|
|
20
32
|
}
|
|
21
33
|
|
|
22
|
-
/*
|
|
23
|
-
.alert:has(> :is(i, svg):first-child):has(> .alert-
|
|
34
|
+
/* Replaces the icon-gated explicit-rows rule — rows whenever anything spans them. */
|
|
35
|
+
.alert:has(> .alert-title):is(:has(> :is(i, svg):first-child), :has(> .alert-action)) {
|
|
24
36
|
grid-template-rows: auto auto;
|
|
25
37
|
align-items: start;
|
|
26
38
|
}
|
|
@@ -29,11 +41,23 @@
|
|
|
29
41
|
grid-row: 1 / -1;
|
|
30
42
|
}
|
|
31
43
|
|
|
32
|
-
/*
|
|
44
|
+
/* The column-2 pin becomes icon-gated so title/description auto-place into
|
|
45
|
+
column 1 in an action-only grid. min-width stays unconditional. */
|
|
33
46
|
.alert > :is(.alert-title, .alert-description) {
|
|
34
|
-
grid-column: 2;
|
|
35
47
|
min-width: 0;
|
|
36
48
|
}
|
|
49
|
+
.alert:has(> :is(i, svg):first-child) > :is(.alert-title, .alert-description) {
|
|
50
|
+
grid-column: 2;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/* `-2` is the last explicit column in both grids; spans both rows, centered. */
|
|
54
|
+
.alert > .alert-action {
|
|
55
|
+
@apply font-medium whitespace-nowrap;
|
|
56
|
+
grid-column: -2;
|
|
57
|
+
grid-row: 1 / -1;
|
|
58
|
+
justify-self: end;
|
|
59
|
+
align-self: center;
|
|
60
|
+
}
|
|
37
61
|
|
|
38
62
|
/* Solid status fills. Title and icon inherit the `-content` color from the
|
|
39
63
|
root, so no per-variant text rule is needed. */
|
|
@@ -60,4 +84,10 @@
|
|
|
60
84
|
.alert-description {
|
|
61
85
|
opacity: 0.85;
|
|
62
86
|
}
|
|
87
|
+
|
|
88
|
+
/* `.link`'s blue is illegible on the solid fills; inherit the variant's content
|
|
89
|
+
color. Underline + weight carry the affordance. */
|
|
90
|
+
.alert .link {
|
|
91
|
+
@apply text-current hover:text-current hover:opacity-85 focus-visible:outline-current;
|
|
92
|
+
}
|
|
63
93
|
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
@layer components {
|
|
2
|
+
.avatar {
|
|
3
|
+
@apply relative inline-flex items-center justify-center
|
|
4
|
+
size-8 rounded-full overflow-hidden
|
|
5
|
+
bg-surface-strong text-text-muted
|
|
6
|
+
text-xs font-medium leading-none tracking-tight
|
|
7
|
+
select-none shrink-0;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/* Layered over the initials so they show until the image loads (no JS). */
|
|
11
|
+
.avatar > img {
|
|
12
|
+
@apply absolute inset-0 size-full object-cover;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.avatar-square {
|
|
16
|
+
@apply rounded-md;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.avatar-sm {
|
|
20
|
+
@apply size-6 text-[0.625rem];
|
|
21
|
+
}
|
|
22
|
+
.avatar-lg {
|
|
23
|
+
@apply size-10 text-sm;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/* Overlapping stack — later siblings paint on top. */
|
|
27
|
+
.avatar-group {
|
|
28
|
+
@apply inline-flex items-center;
|
|
29
|
+
}
|
|
30
|
+
.avatar-group > .avatar {
|
|
31
|
+
@apply ring-2 ring-surface;
|
|
32
|
+
}
|
|
33
|
+
.avatar-group > .avatar + .avatar {
|
|
34
|
+
@apply -ms-2;
|
|
35
|
+
}
|
|
36
|
+
}
|
package/src/components/badge.css
CHANGED
|
@@ -34,6 +34,42 @@
|
|
|
34
34
|
@apply bg-primary text-primary-content;
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
+
/* Soft — composable modifier, pairs with a variant class; bare `.badge` is already the soft neutral. */
|
|
38
|
+
.badge-soft.badge-info {
|
|
39
|
+
@apply bg-info-muted text-info border-info-muted;
|
|
40
|
+
}
|
|
41
|
+
.badge-soft.badge-success {
|
|
42
|
+
@apply bg-success-muted text-success border-success-muted;
|
|
43
|
+
}
|
|
44
|
+
/* Yellow accent text fails contrast on the tinted surface — same constraint as stat-card. */
|
|
45
|
+
.badge-soft.badge-warning {
|
|
46
|
+
@apply bg-warning-muted text-text border-warning-muted;
|
|
47
|
+
}
|
|
48
|
+
.badge-soft.badge-danger {
|
|
49
|
+
@apply bg-danger-muted text-danger border-danger-muted;
|
|
50
|
+
}
|
|
51
|
+
.badge-soft.badge-primary {
|
|
52
|
+
@apply bg-primary-muted text-text border-primary-muted;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/* Remove button — sized to the chip; hover wash from `currentColor` works on solid, soft, and neutral fills. */
|
|
56
|
+
.badge-remove {
|
|
57
|
+
@apply inline-flex items-center justify-center shrink-0
|
|
58
|
+
size-3.5 -mr-1 rounded-full
|
|
59
|
+
text-inherit cursor-pointer
|
|
60
|
+
transition-colors duration-150
|
|
61
|
+
focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-focus;
|
|
62
|
+
}
|
|
63
|
+
.badge-remove:hover {
|
|
64
|
+
background-color: color-mix(in oklab, currentColor 15%, transparent);
|
|
65
|
+
}
|
|
66
|
+
.badge-sm .badge-remove {
|
|
67
|
+
@apply size-3 -mr-0.5;
|
|
68
|
+
}
|
|
69
|
+
.badge-lg .badge-remove {
|
|
70
|
+
@apply size-4.5 -mr-1.5;
|
|
71
|
+
}
|
|
72
|
+
|
|
37
73
|
/* Sizes (md is the default; modifiers override) */
|
|
38
74
|
.badge-sm {
|
|
39
75
|
@apply h-4 px-1.5 text-[0.625rem] gap-0.5;
|
|
@@ -6,4 +6,40 @@
|
|
|
6
6
|
bg-system-accent text-system-accent-content
|
|
7
7
|
shrink-0 select-none;
|
|
8
8
|
}
|
|
9
|
+
|
|
10
|
+
/* Glyph sizing moves into CSS so vanilla drops the inline font-size
|
|
11
|
+
and React renders icons at 1em. */
|
|
12
|
+
.brand-tile > :is(i, svg) {
|
|
13
|
+
font-size: 14px;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.brand-tile-lg {
|
|
17
|
+
@apply size-10 rounded-md text-sm;
|
|
18
|
+
}
|
|
19
|
+
.brand-tile-lg > :is(i, svg) {
|
|
20
|
+
font-size: 20px;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/* Soft tints — *-muted fill, colored glyph. */
|
|
24
|
+
.brand-tile-soft {
|
|
25
|
+
@apply bg-system-accent-muted text-system-accent;
|
|
26
|
+
}
|
|
27
|
+
.brand-tile-info {
|
|
28
|
+
@apply bg-info-muted text-info;
|
|
29
|
+
}
|
|
30
|
+
.brand-tile-success {
|
|
31
|
+
@apply bg-success-muted text-success;
|
|
32
|
+
}
|
|
33
|
+
.brand-tile-danger {
|
|
34
|
+
@apply bg-danger-muted text-danger;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/* Image tile (shop logo) — :has() flips the accent fill to a bordered
|
|
38
|
+
surface; object-contain keeps arbitrary-ratio logos uncropped. */
|
|
39
|
+
.brand-tile:has(> img) {
|
|
40
|
+
@apply bg-surface border border-border p-0.5;
|
|
41
|
+
}
|
|
42
|
+
.brand-tile > img {
|
|
43
|
+
@apply size-full object-contain rounded-[inherit];
|
|
44
|
+
}
|
|
9
45
|
}
|
package/src/components/card.css
CHANGED
|
@@ -96,4 +96,42 @@
|
|
|
96
96
|
|
|
97
97
|
/* No `.card-warning .card-title` rule — the yellow-400 accent fails AA on
|
|
98
98
|
the muted yellow surface. */
|
|
99
|
+
|
|
100
|
+
/* Full-bleed media. Sibling of .card-body; first/last placement picks up the
|
|
101
|
+
card's corner rounding without overflow on the root. */
|
|
102
|
+
.card-media {
|
|
103
|
+
@apply block w-full shrink-0 overflow-hidden;
|
|
104
|
+
}
|
|
105
|
+
.card-media:first-child {
|
|
106
|
+
border-top-left-radius: inherit;
|
|
107
|
+
border-top-right-radius: inherit;
|
|
108
|
+
}
|
|
109
|
+
.card-media:last-child {
|
|
110
|
+
border-bottom-left-radius: inherit;
|
|
111
|
+
border-bottom-right-radius: inherit;
|
|
112
|
+
}
|
|
113
|
+
.card-media > :is(img, video) {
|
|
114
|
+
@apply block w-full h-full object-cover;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/* Scroll region — header/actions pin, body scrolls; consumer sets the height.
|
|
118
|
+
Direct-child header/actions gain padding + a divider since inside
|
|
119
|
+
.card-body they carry none. */
|
|
120
|
+
.card-scroll > .card-header {
|
|
121
|
+
@apply shrink-0 px-5 py-3 border-b border-border;
|
|
122
|
+
}
|
|
123
|
+
.card-scroll > .card-body {
|
|
124
|
+
@apply flex-1 min-h-0 overflow-y-auto;
|
|
125
|
+
}
|
|
126
|
+
.card-scroll > .card-body:last-child {
|
|
127
|
+
/* Keep the scrollbar inside the rounded corners when there's no footer. */
|
|
128
|
+
border-bottom-left-radius: inherit;
|
|
129
|
+
border-bottom-right-radius: inherit;
|
|
130
|
+
}
|
|
131
|
+
.card-scroll > .card-actions {
|
|
132
|
+
@apply shrink-0 px-5 py-3 border-t border-border;
|
|
133
|
+
}
|
|
134
|
+
.card-compact.card-scroll > :is(.card-header, .card-actions) {
|
|
135
|
+
@apply px-3 py-2;
|
|
136
|
+
}
|
|
99
137
|
}
|
package/src/components/index.css
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
@import "./container.css";
|
|
5
5
|
@import "./badge.css";
|
|
6
6
|
@import "./brand-tile.css";
|
|
7
|
+
@import "./avatar.css";
|
|
7
8
|
@import "./kbd.css";
|
|
8
9
|
@import "./indicator.css";
|
|
9
10
|
@import "./spinner.css";
|
|
@@ -11,11 +12,13 @@
|
|
|
11
12
|
@import "./breadcrumbs.css";
|
|
12
13
|
@import "./pagination.css";
|
|
13
14
|
@import "./property-list.css";
|
|
15
|
+
@import "./separator.css";
|
|
14
16
|
@import "./button.css";
|
|
15
17
|
@import "./button-group.css";
|
|
16
18
|
@import "./link.css";
|
|
17
19
|
@import "./input.css";
|
|
18
20
|
@import "./input-group.css";
|
|
21
|
+
@import "./input-icon.css";
|
|
19
22
|
@import "./textarea.css";
|
|
20
23
|
@import "./checkbox.css";
|
|
21
24
|
@import "./radio.css";
|
|
@@ -15,6 +15,18 @@
|
|
|
15
15
|
.indicator:has(> .card) {
|
|
16
16
|
--indicator-offset: 6px;
|
|
17
17
|
}
|
|
18
|
+
.indicator:has(> .avatar) {
|
|
19
|
+
--indicator-offset: 5px;
|
|
20
|
+
}
|
|
21
|
+
.indicator:has(> .avatar-sm) {
|
|
22
|
+
--indicator-offset: 3px;
|
|
23
|
+
}
|
|
24
|
+
.indicator:has(> .avatar-lg) {
|
|
25
|
+
--indicator-offset: 6px;
|
|
26
|
+
}
|
|
27
|
+
.indicator:has(> .avatar-square) {
|
|
28
|
+
--indicator-offset: 2px;
|
|
29
|
+
}
|
|
18
30
|
|
|
19
31
|
.indicator-item {
|
|
20
32
|
@apply absolute z-[1] whitespace-nowrap;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
@layer components {
|
|
2
|
+
/* Overlay wrapper — the .input child keeps its own border, background,
|
|
3
|
+
and focus outline; icons float above it, :has() padding clears them. */
|
|
4
|
+
.input-icon {
|
|
5
|
+
@apply relative inline-flex w-full items-center text-sm text-text-muted;
|
|
6
|
+
--input-icon-inset: calc(var(--spacing) * 3); /* matches .input px-3 */
|
|
7
|
+
--input-icon-pad: calc(var(--spacing) * 9);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
.input-icon:has(> .input-sm) {
|
|
11
|
+
@apply text-xs;
|
|
12
|
+
--input-icon-inset: calc(var(--spacing) * 2.5);
|
|
13
|
+
--input-icon-pad: calc(var(--spacing) * 8);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.input-icon:has(> .input-lg) {
|
|
17
|
+
@apply text-base;
|
|
18
|
+
--input-icon-inset: calc(var(--spacing) * 4);
|
|
19
|
+
--input-icon-pad: calc(var(--spacing) * 10);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/* Clicks pass through the icon to the input beneath it. */
|
|
23
|
+
.input-icon > :where(i, svg) {
|
|
24
|
+
@apply absolute top-1/2 -translate-y-1/2 pointer-events-none;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.input-icon > :where(i, svg):first-child {
|
|
28
|
+
left: var(--input-icon-inset);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.input-icon > .input ~ :where(i, svg) {
|
|
32
|
+
right: var(--input-icon-inset);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.input-icon:has(> :where(i, svg):first-child) > .input {
|
|
36
|
+
padding-left: var(--input-icon-pad);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.input-icon:has(> .input ~ :where(i, svg)) > .input {
|
|
40
|
+
padding-right: var(--input-icon-pad);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.input-icon:has(> .input:disabled) > :where(i, svg) {
|
|
44
|
+
@apply opacity-50;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
@layer components {
|
|
2
|
+
/* Works on <hr> (border reset) and any block element. Margins are zeroed —
|
|
3
|
+
spacing comes from the parent's gap or margin utilities. */
|
|
4
|
+
.separator {
|
|
5
|
+
@apply block h-px w-full m-0 shrink-0 border-0 bg-border;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
.separator-vertical {
|
|
9
|
+
@apply w-px h-auto self-stretch;
|
|
10
|
+
/* Visible outside a stretching flex/grid cross axis. */
|
|
11
|
+
min-height: 1lh;
|
|
12
|
+
}
|
|
13
|
+
}
|
package/src/components/table.css
CHANGED
|
@@ -16,6 +16,16 @@
|
|
|
16
16
|
@apply font-medium text-text-muted bg-surface-muted border-b-border-strong whitespace-nowrap;
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
+
/* Totals/footer — all tfoot rows are emphasized; the first row carries a
|
|
20
|
+
strong divider against the body. 2px so border-collapse picks it over the
|
|
21
|
+
tbody last row's 1px border-b (equal widths resolve to the upper cell). */
|
|
22
|
+
.table :where(tfoot :is(td, th)) {
|
|
23
|
+
@apply font-semibold;
|
|
24
|
+
}
|
|
25
|
+
.table :where(tfoot tr:first-child :is(td, th)) {
|
|
26
|
+
@apply border-t-2 border-t-border-strong;
|
|
27
|
+
}
|
|
28
|
+
|
|
19
29
|
/* Body cells only — break long unbreakable values (IDs, hashes, URLs) instead
|
|
20
30
|
of forcing the table into horizontal overflow. */
|
|
21
31
|
.table :where(td),
|