@aortl/admin-css 0.15.1 → 0.16.1

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.
@@ -1,5 +1,5 @@
1
1
  @layer components {
2
- /* Outer section — owns striped, copyable, hide-if-empty modifiers. Title
2
+ /* Outer section — owns striped, hide-if-empty modifiers. Title
3
3
  (optional) and the items grid stack vertically. */
4
4
  .property-list {
5
5
  @apply flex flex-col text-sm text-text;
@@ -18,23 +18,18 @@
18
18
 
19
19
  .property-list-label,
20
20
  .property-list-value {
21
- display: flex;
22
- align-items: center;
23
- padding: 0.375rem 0.75rem;
24
- min-height: 2rem;
21
+ @apply flex items-center px-3 py-1.5 min-h-8;
25
22
  }
26
23
 
27
24
  .property-list-label {
28
25
  @apply text-text-muted;
29
26
  }
30
27
 
31
- /* `min-width: 0` lets the value's grid track shrink below its content; pair
32
- it with `overflow-wrap` so long unbreakable values (IDs, hashes, emails,
33
- URLs, file paths) break instead of overflowing the column. */
28
+ /* `min-w-0` lets the value's grid track shrink below its content; pair it
29
+ with `break-words` so long unbreakable values (IDs, hashes, emails, URLs,
30
+ file paths) break instead of overflowing the column. */
34
31
  .property-list-value {
35
- gap: 0.5rem;
36
- min-width: 0;
37
- overflow-wrap: break-word;
32
+ @apply gap-2 min-w-0 break-words;
38
33
  }
39
34
 
40
35
  /* Compact density — tighter rows for sidebar info blocks or very many
@@ -45,8 +40,7 @@
45
40
 
46
41
  .property-list-compact .property-list-label,
47
42
  .property-list-compact .property-list-value {
48
- padding: 0.125rem 0.5rem;
49
- min-height: 1.5rem;
43
+ @apply px-2 py-0.5 min-h-6;
50
44
  }
51
45
 
52
46
  /* Numeric — right-align + tabular-nums on the value. */
@@ -0,0 +1,119 @@
1
+ @layer components {
2
+ /*
3
+ * Long-form rendered HTML — markdown output, CMS bodies, anything you can't
4
+ * annotate with the system's semantic class names. The global reset strips
5
+ * margins, list markers, and link styling from bare elements (so admin chrome
6
+ * stays neutral); `.prose` re-establishes them for its descendants only, using
7
+ * the semantic tokens so it follows dark mode and `--color-*` overrides.
8
+ *
9
+ * Descendant rules use `:where()` to stay at specificity 0 — a consumer's own
10
+ * `.prose a { … }` wins without `!important`.
11
+ */
12
+ .prose {
13
+ @apply text-sm leading-normal text-text;
14
+ /* Long URLs/tokens in flow text break instead of overflowing a narrow
15
+ column. Inherited by p/li/a/td/blockquote; the deliberately-scrolling
16
+ `<pre>` keeps its own `white-space: pre` + `overflow-x: auto`. */
17
+ overflow-wrap: break-word;
18
+ }
19
+
20
+ /* Vertical rhythm — space between flow blocks, none at the container edges. */
21
+ .prose :where(p, ul, ol, blockquote, pre, table, figure) {
22
+ @apply my-3;
23
+ }
24
+ .prose > :first-child {
25
+ margin-top: 0;
26
+ }
27
+ .prose > :last-child {
28
+ margin-bottom: 0;
29
+ }
30
+
31
+ /* Headings — base.css already sizes h1–h3; here we add h4–h6 and the
32
+ sectioning rhythm. The edge reset above zeroes a leading heading's margin. */
33
+ .prose :where(h1, h2, h3, h4, h5, h6) {
34
+ @apply mt-6 mb-2 font-semibold leading-tight;
35
+ }
36
+ .prose :where(h4) {
37
+ @apply text-sm;
38
+ }
39
+ .prose :where(h5, h6) {
40
+ @apply text-xs uppercase tracking-wide text-text-muted;
41
+ }
42
+
43
+ /* Lists — restore the markers the reset removes. */
44
+ .prose :where(ul) {
45
+ @apply list-disc ps-5;
46
+ }
47
+ .prose :where(ol) {
48
+ @apply list-decimal ps-5;
49
+ }
50
+ .prose :where(li) {
51
+ @apply my-1;
52
+ }
53
+ /* Loose lists wrap each item's text in <p> — tighten those back down. */
54
+ .prose :where(li) :where(p) {
55
+ @apply my-1;
56
+ }
57
+ /* Nested lists hug their parent item rather than taking full block spacing. */
58
+ .prose :where(li > ul, li > ol) {
59
+ @apply my-1;
60
+ }
61
+
62
+ /* Links — the .link treatment without needing the class on every anchor. */
63
+ .prose :where(a) {
64
+ @apply rounded-sm text-link underline underline-offset-2
65
+ hover:text-link-hover
66
+ focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-focus;
67
+ }
68
+
69
+ /* Inline code — a tinted chip. */
70
+ .prose :where(code) {
71
+ @apply rounded border border-border bg-code-surface px-1 py-0.5
72
+ font-mono text-code-text;
73
+ font-size: 0.85em;
74
+ }
75
+
76
+ /* Code blocks — the .code-block surface; strip the inline chip off nested
77
+ <code> so a highlighter's own tokens show through. */
78
+ .prose :where(pre) {
79
+ @apply rounded-lg bg-code-surface p-3 font-mono text-sm text-code-text;
80
+ white-space: pre;
81
+ overflow-x: auto;
82
+ }
83
+ .prose :where(pre) code {
84
+ @apply rounded-none border-0 bg-transparent p-0;
85
+ font-size: inherit;
86
+ }
87
+
88
+ /* Blockquote — a quiet inline-start rule. */
89
+ .prose :where(blockquote) {
90
+ @apply border-s-2 border-border-strong ps-3 text-text-muted;
91
+ }
92
+
93
+ /* Thematic break. */
94
+ .prose :where(hr) {
95
+ @apply my-6 border-0 border-t border-border;
96
+ }
97
+
98
+ /* Tables — adopt the .table look for markdown's simple grids. */
99
+ .prose :where(table) {
100
+ @apply w-full border-collapse text-sm;
101
+ }
102
+ .prose :where(th, td) {
103
+ @apply border-b border-border px-3 py-2 text-start align-top;
104
+ }
105
+ .prose :where(thead th) {
106
+ @apply font-semibold text-text-muted;
107
+ }
108
+
109
+ /* Media + emphasis. */
110
+ .prose :where(img) {
111
+ @apply h-auto max-w-full rounded-md;
112
+ }
113
+ .prose :where(figcaption) {
114
+ @apply mt-1 text-xs text-text-muted;
115
+ }
116
+ .prose :where(strong) {
117
+ @apply font-semibold;
118
+ }
119
+ }
@@ -24,6 +24,23 @@
24
24
  @apply inline-flex size-1.5 rounded-full bg-primary-content;
25
25
  }
26
26
 
27
+ /* Native input variant: state is driven by :checked, the dot is ::after.
28
+ Mirrors the Base UI span variant above so a vanilla <input class="radio">
29
+ renders identically (the dot matches .radio-indicator's size + colour). */
30
+ input.radio {
31
+ @apply appearance-none border-border-strong hover:border-text-muted;
32
+ }
33
+
34
+ input.radio:checked {
35
+ @apply bg-primary border-primary hover:bg-primary-hover;
36
+ }
37
+
38
+ input.radio:checked::after {
39
+ content: "";
40
+ @apply size-1.5 rounded-full;
41
+ background-color: var(--color-primary-content);
42
+ }
43
+
27
44
  .radio-group {
28
45
  @apply inline-flex flex-wrap gap-4;
29
46
  }
@@ -36,6 +53,10 @@
36
53
  Covers both the vanilla input.radio and Base UI's span.radio. */
37
54
  label:has(> .radio) {
38
55
  @apply inline-flex items-center gap-2 cursor-pointer;
56
+ /* Let a long label break and shrink beside the `shrink-0` control instead
57
+ of overflowing a narrow form column. */
58
+ overflow-wrap: break-word;
59
+ min-width: 0;
39
60
  }
40
61
 
41
62
  label:has(> .radio:disabled),
@@ -37,12 +37,16 @@
37
37
 
38
38
  /* Native <select> usage: same class, but suppress the native chevron and
39
39
  supply our own via background-image so the look matches the Base UI
40
- trigger. Chevron stroke uses Flexoki base-500, which reads as neutral
41
- in both light and dark mode. */
40
+ trigger. A bare native <select> is a replaced element and can't host a
41
+ tinted `::after` (the React trigger uses a real `.select-icon` SVG), and
42
+ data URIs can't read CSS variables — so the chevron can't ride the
43
+ `--color-text-muted` token directly. The stroke is Flexoki `base-500`
44
+ (#848484), the same mid-gray as the token's dark-mode value, which reads
45
+ as a neutral chevron in both light and dark mode. */
42
46
  select.select {
43
47
  appearance: none;
44
48
  padding-right: 2rem;
45
- background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23878580' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><polyline points='6 9 12 15 18 9'/></svg>");
49
+ background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23848484' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><polyline points='6 9 12 15 18 9'/></svg>");
46
50
  background-repeat: no-repeat;
47
51
  background-position: right 0.5rem center;
48
52
  background-size: 1rem;
@@ -86,6 +90,10 @@
86
90
  .select-item {
87
91
  @apply flex items-center gap-2 px-3 py-1.5 text-sm
88
92
  cursor-pointer select-none outline-none;
93
+ /* Let a long option label (path, ID, email) break and shrink rather than
94
+ grow the popup horizontally. The trailing indicator stays `ml-auto`. */
95
+ overflow-wrap: break-word;
96
+ min-width: 0;
89
97
  }
90
98
 
91
99
  .select-item[data-highlighted] {
@@ -202,7 +202,7 @@
202
202
 
203
203
  /* Mobile drawer surface (rendered inside a Base UI Dialog) */
204
204
  .sidebar-drawer-backdrop {
205
- @apply fixed inset-0 z-40 bg-black/40
205
+ @apply fixed inset-0 z-40 bg-scrim
206
206
  transition-opacity duration-150;
207
207
  }
208
208
 
@@ -53,6 +53,10 @@
53
53
  Switches are wider than checkboxes/radios so the gap is a touch larger. */
54
54
  label:has(> .switch) {
55
55
  @apply inline-flex items-center gap-3 cursor-pointer;
56
+ /* Let a long setting label break and shrink beside the `shrink-0` track
57
+ instead of overflowing a narrow settings panel. */
58
+ overflow-wrap: break-word;
59
+ min-width: 0;
56
60
  }
57
61
 
58
62
  label:has(> .switch:disabled),
@@ -20,6 +20,15 @@
20
20
  @apply font-medium text-text-muted bg-surface-muted border-b-border-strong whitespace-nowrap;
21
21
  }
22
22
 
23
+ /* Body cells only — let a long unbreakable value (ID, hash, email, URL, file
24
+ path) break inside the cell instead of widening the column and forcing the
25
+ whole table into horizontal overflow. Header cells stay `whitespace-nowrap`
26
+ above. */
27
+ .table :where(td),
28
+ .table-cell {
29
+ overflow-wrap: break-word;
30
+ }
31
+
23
32
  /* Drop the divider on the very last row, whether it lives in tbody (no
24
33
  tfoot present) or in tfoot — so the table doesn't double-border against
25
34
  a surrounding container. `.table > :last-child` resolves to the final
@@ -198,7 +198,7 @@
198
198
  @apply pt-3 outline-none;
199
199
  }
200
200
 
201
- /* Vanilla radio-input pattern: only the panel whose data-for matches the
201
+ /* Vanilla radio-input pattern: only the panel whose data-value matches the
202
202
  checked input is shown. Each .tabs root scopes its own selectors. */
203
203
  .tabs .tab-panel {
204
204
  display: none;
@@ -33,9 +33,9 @@
33
33
  }
34
34
 
35
35
  /* Grow with content (Chromium 123+; degrades to a fixed resizable box
36
- elsewhere). `min-h-*` / the `rows` attribute stays the floor; cap growth
37
- with a consumer `max-height`. Manual drag-resize is off — height is
38
- content-driven. */
36
+ elsewhere). The floor is the larger of the base `min-h-*` and the `rows`
37
+ attribute; cap growth with a consumer `max-height`. Manual drag-resize is
38
+ off — height is content-driven. */
39
39
  .textarea-autosize {
40
40
  field-sizing: content;
41
41
  resize: none;
package/src/theme.css CHANGED
@@ -219,6 +219,11 @@
219
219
  --color-code-surface: light-dark(var(--color-base-150), var(--color-base-950));
220
220
  --color-code-text: light-dark(var(--color-base-800), var(--color-base-200));
221
221
 
222
+ /* Modal scrim — the dimming layer behind a `<dialog>` and the mobile
223
+ sidebar drawer. One tint from black so both overlays match and stay
224
+ retintable from a single token. */
225
+ --color-scrim: color-mix(in oklab, var(--color-black) 40%, transparent);
226
+
222
227
  /* Primary — high-contrast neutral (ink). Inverts with the mode: near-black
223
228
  on light surfaces, near-white on dark ones, so a solid `btn-primary` fill
224
229
  always reads against the surface. Unlike the colored accents, `-hover`