@keenmate/pure-admin-core 2.9.0-rc04 → 2.9.0-rc05
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 +6 -9
- package/dist/css/main.css +14 -5
- package/package.json +1 -1
- package/snippets/cards.html +99 -44
- package/src/scss/core-components/_cards.scss +38 -6
- package/src/scss/variables/_components.scss +7 -0
package/README.md
CHANGED
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
Lightweight, data-focused CSS/SCSS admin framework with Corporate theme as default.
|
|
4
4
|
|
|
5
|
+
## What's New in 2.9.0-rc05
|
|
6
|
+
|
|
7
|
+
- **Card header — one canonical structure (`.pa-card__title` + new `.pa-card__description`).** The header no longer has two blessed title shapes (bare `<h3>` vs `.pa-card__title`); `.pa-card__title` is now *the* title contract for every card, with the icon optional inside `.pa-card__title-icon` — so a `<Card>` component emits one DOM tree instead of branching on whether an icon was passed. The description is promoted from a bare `<p>` to a real `.pa-card__description` element, making the header fully `title` / `description` / `actions`.
|
|
8
|
+
- **Card footer — reuses `.pa-card__actions`, auto-pinned to the trailing edge.** Footer buttons go in the same actions slot as the header and hug the right automatically, with or without leading meta/text — no more empty spacer `<div>` to right-align them, and no bare buttons scattering to opposite corners.
|
|
9
|
+
- **Header polish: `--pa-card-description-offset-y` token + descender fix.** The (smaller) description now sits on the title's baseline via a per-theme-tunable nudge, and the title's `line-height` was corrected so glyph descenders (g / y / p) are no longer clipped by the header's overflow.
|
|
10
|
+
|
|
5
11
|
## What's New in 2.9.0-rc04
|
|
6
12
|
|
|
7
13
|
- **New: Range Group — a compact multi-range filter (`.pa-range-group` + a reusable `.pa-range` slider).** One toggle summarises several numeric filters inline (`AGE 25–60 / SALARY $40,000–$200,000 / CHILDREN 2+`) and expands into a Floating-UI panel with one slider per dimension — standing in for a row of separate sliders in a filter bar. Per-row dual-thumb range or single-thumb threshold, RTL-correct by construction, with a `--pa-range-*` theming token namespace and a bubbling `change` / `apply` / `reset` event contract keyed by dimension.
|
|
@@ -14,15 +20,6 @@ Lightweight, data-focused CSS/SCSS admin framework with Corporate theme as defau
|
|
|
14
20
|
- **`.pa-splitter` — tap-without-drag on the gutter no longer restores a rail'd pane.** Restore gestures are now: rail-body click, dblclick on the gutter, focus + `Enter`/`Space`, `[data-pa-splitter-toggle]` button, or drag outward past the snap threshold. Users expected drag-to-be-explicit and didn't connect "tap the gutter" with the rail-pane body as a restore surface.
|
|
15
21
|
- **`.pa-splitter` — per-pane orientation class** (`pa-splitter__pane--horizontal` / `--vertical`) stamped at registration. Forward-compat hook for theme authors writing nested-splitter-safe rail CSS without walking the DOM to figure out the enclosing splitter's orientation.
|
|
16
22
|
|
|
17
|
-
## What's New in 2.9.0-rc03
|
|
18
|
-
|
|
19
|
-
- **`.pa-splitter` drag model reworked to "rebalance-on-drag".** Each gutter now resizes only its primary neighbour (edge-closer side, LTR/RTL tiebreaker on ties); the matching delta is absorbed by the immediate adjacent non-rail pane (classic boundary feel), or — when the adjacent pane is rail — tunnels through the rail wall to the contiguous non-rail block beyond. Eliminates the "boundary locks when both sides are rail" deadlock from the prior model — drag-from-rail with a railed neighbour now grows the primary by pulling room from the next section.
|
|
20
|
-
- **Middle panes can now minimize to rail** (previously first / last only). Any pane with `data-pa-splitter-minimize` collapses on toggle / dblclick / drag-snap regardless of position. Snap-into-rail enforces an "at least one expanded pane" invariant — you can't drag the last visible pane to rail and end up with nothing to grab.
|
|
21
|
-
- **Restoring a minimized pane reclaims layout gaps cleanly.** When a prior minimize hit an absorber's `max` cap and left empty space in the layout, restoring the pane now reaches its remembered size by drawing from the gap (not just from other panes' shrink headroom) — fixes the "restored pane stuck at min width" surprise. Conversely, restoring no longer aggressively inflates a sibling pane to fill remaining gap — empty space stays as empty space and gets consumed as more panes restore. No more "sibling pane suddenly jumps" UX.
|
|
22
|
-
- **Rail width in `--pa-splitter-rail-size` now correctly resolves `rem` / non-px units.** Previously `parseFloat("4rem")` returned `4` and snapped rail panes to 4px-wide strips; rebuilt via a hidden probe element so the browser does the unit resolution. The three-step fallback chain (per-instance attribute → CSS var → literal 40) still applies.
|
|
23
|
-
- **Gutter highlighting now isolates the dragged gutter only.** During a drag, the splitter `--dragging` modifier suppresses `:hover` / `:focus-visible` on sibling gutters so they don't light up as the cursor passes over them or as a stale focus ring lingers — only the active gutter carries the highlight.
|
|
24
|
-
- **Splitter padding subtracted from available space.** Flex children sit inside the splitter's content box but `clientWidth` includes padding — without subtracting it the last pane's `flex-basis` overflowed and got clipped by `overflow: hidden`. Visible in the N-pane demo where the rightmost rail's right edge touched the splitter border.
|
|
25
|
-
|
|
26
23
|
## Installation
|
|
27
24
|
|
|
28
25
|
```bash
|
package/dist/css/main.css
CHANGED
|
@@ -5471,7 +5471,8 @@ body:not(.sidebar-hidden) .pa-layout__sidebar--icon-collapse .pa-sidebar__icon {
|
|
|
5471
5471
|
text-overflow: ellipsis;
|
|
5472
5472
|
white-space: nowrap;
|
|
5473
5473
|
}
|
|
5474
|
-
.pa-card__header > p
|
|
5474
|
+
.pa-card__header > p,
|
|
5475
|
+
.pa-card__header > .pa-card__description {
|
|
5475
5476
|
flex: 1;
|
|
5476
5477
|
min-width: 0;
|
|
5477
5478
|
overflow: hidden;
|
|
@@ -5479,6 +5480,8 @@ body:not(.sidebar-hidden) .pa-layout__sidebar--icon-collapse .pa-sidebar__icon {
|
|
|
5479
5480
|
white-space: nowrap;
|
|
5480
5481
|
color: var(--pa-text-color-2);
|
|
5481
5482
|
font-size: 1.4rem;
|
|
5483
|
+
position: relative;
|
|
5484
|
+
top: var(--pa-card-description-offset-y, 1px);
|
|
5482
5485
|
}
|
|
5483
5486
|
.pa-card__header .pa-card__actions,
|
|
5484
5487
|
.pa-card__header .pa-btn-group {
|
|
@@ -5559,12 +5562,14 @@ body:not(.sidebar-hidden) .pa-layout__sidebar--icon-collapse .pa-sidebar__icon {
|
|
|
5559
5562
|
.pa-card__header--wrap {
|
|
5560
5563
|
flex-wrap: wrap;
|
|
5561
5564
|
}
|
|
5562
|
-
.pa-card__header--wrap > h1, .pa-card__header--wrap > h2, .pa-card__header--wrap > h3, .pa-card__header--wrap > h4, .pa-card__header--wrap > h5, .pa-card__header--wrap > h6
|
|
5565
|
+
.pa-card__header--wrap > h1, .pa-card__header--wrap > h2, .pa-card__header--wrap > h3, .pa-card__header--wrap > h4, .pa-card__header--wrap > h5, .pa-card__header--wrap > h6,
|
|
5566
|
+
.pa-card__header--wrap > .pa-card__title .pa-card__title-text {
|
|
5563
5567
|
white-space: normal;
|
|
5564
5568
|
overflow: visible;
|
|
5565
5569
|
text-overflow: clip;
|
|
5566
5570
|
}
|
|
5567
|
-
.pa-card__header--wrap > p
|
|
5571
|
+
.pa-card__header--wrap > p,
|
|
5572
|
+
.pa-card__header--wrap > .pa-card__description {
|
|
5568
5573
|
white-space: normal;
|
|
5569
5574
|
flex-basis: 100%;
|
|
5570
5575
|
order: 1;
|
|
@@ -5575,7 +5580,7 @@ body:not(.sidebar-hidden) .pa-layout__sidebar--icon-collapse .pa-sidebar__icon {
|
|
|
5575
5580
|
align-items: center;
|
|
5576
5581
|
gap: 0.8rem;
|
|
5577
5582
|
min-width: 0;
|
|
5578
|
-
flex: 1;
|
|
5583
|
+
flex: 0 1 auto;
|
|
5579
5584
|
}
|
|
5580
5585
|
.pa-card__title-icon {
|
|
5581
5586
|
flex-shrink: 0;
|
|
@@ -5590,7 +5595,7 @@ body:not(.sidebar-hidden) .pa-layout__sidebar--icon-collapse .pa-sidebar__icon {
|
|
|
5590
5595
|
color: var(--pa-text-color-1);
|
|
5591
5596
|
font-size: 1.6rem;
|
|
5592
5597
|
font-weight: 600;
|
|
5593
|
-
line-height: 1;
|
|
5598
|
+
line-height: 1.4;
|
|
5594
5599
|
}
|
|
5595
5600
|
.pa-card__body {
|
|
5596
5601
|
padding: 1.6rem 1rem;
|
|
@@ -5611,6 +5616,10 @@ body:not(.sidebar-hidden) .pa-layout__sidebar--icon-collapse .pa-sidebar__icon {
|
|
|
5611
5616
|
display: flex;
|
|
5612
5617
|
justify-content: space-between;
|
|
5613
5618
|
align-items: center;
|
|
5619
|
+
gap: 0.8rem;
|
|
5620
|
+
}
|
|
5621
|
+
.pa-card__footer .pa-card__actions {
|
|
5622
|
+
margin-inline-start: auto;
|
|
5614
5623
|
}
|
|
5615
5624
|
.pa-card__actions {
|
|
5616
5625
|
display: flex;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@keenmate/pure-admin-core",
|
|
3
|
-
"version": "2.9.0-
|
|
3
|
+
"version": "2.9.0-rc05",
|
|
4
4
|
"description": "Lightweight, data-focused HTML/CSS admin framework built with PureCSS foundation and comprehensive component system",
|
|
5
5
|
"style": "dist/css/main.css",
|
|
6
6
|
"exports": {
|
package/snippets/cards.html
CHANGED
|
@@ -11,10 +11,16 @@
|
|
|
11
11
|
</div>
|
|
12
12
|
|
|
13
13
|
|
|
14
|
-
<!-- CARD WITH HEADER
|
|
14
|
+
<!-- CARD WITH HEADER
|
|
15
|
+
The title ALWAYS uses .pa-card__title > .pa-card__title-text (the icon
|
|
16
|
+
span is optional). This is the one canonical header title structure —
|
|
17
|
+
a bare <h3> in the header still renders, but is legacy tolerance, not
|
|
18
|
+
the documented shape. -->
|
|
15
19
|
<div class="pa-card">
|
|
16
20
|
<div class="pa-card__header">
|
|
17
|
-
<
|
|
21
|
+
<div class="pa-card__title">
|
|
22
|
+
<h3 class="pa-card__title-text">Card Title</h3>
|
|
23
|
+
</div>
|
|
18
24
|
</div>
|
|
19
25
|
<div class="pa-card__body">
|
|
20
26
|
Card content goes here.
|
|
@@ -28,7 +34,9 @@
|
|
|
28
34
|
Card content goes here.
|
|
29
35
|
</div>
|
|
30
36
|
<div class="pa-card__footer">
|
|
31
|
-
<
|
|
37
|
+
<div class="pa-card__actions">
|
|
38
|
+
<button class="pa-btn pa-btn--primary">Action</button>
|
|
39
|
+
</div>
|
|
32
40
|
</div>
|
|
33
41
|
</div>
|
|
34
42
|
|
|
@@ -36,31 +44,37 @@
|
|
|
36
44
|
<!-- COMPLETE CARD (header + body + footer) -->
|
|
37
45
|
<div class="pa-card">
|
|
38
46
|
<div class="pa-card__header">
|
|
39
|
-
<
|
|
47
|
+
<div class="pa-card__title">
|
|
48
|
+
<h3 class="pa-card__title-text">Complete Card</h3>
|
|
49
|
+
</div>
|
|
40
50
|
</div>
|
|
41
51
|
<div class="pa-card__body">
|
|
42
52
|
<p>This card has all three sections: header, body, and footer.</p>
|
|
43
53
|
</div>
|
|
44
54
|
<div class="pa-card__footer">
|
|
45
|
-
<
|
|
46
|
-
|
|
55
|
+
<div class="pa-card__actions">
|
|
56
|
+
<button class="pa-btn pa-btn--secondary">Cancel</button>
|
|
57
|
+
<button class="pa-btn pa-btn--primary">Save</button>
|
|
58
|
+
</div>
|
|
47
59
|
</div>
|
|
48
60
|
</div>
|
|
49
61
|
|
|
50
62
|
|
|
51
63
|
<!-- ================================
|
|
52
64
|
THREE-PART HEADER LAYOUT
|
|
53
|
-
.pa-card__header is a flex row with
|
|
54
|
-
[
|
|
55
|
-
|
|
65
|
+
.pa-card__header is a flex row with three canonical slots:
|
|
66
|
+
[.pa-card__title (truncates)] — [.pa-card__description (flexes, truncates)] — [.pa-card__actions (fixed)]
|
|
67
|
+
The title-text and description get ellipsis on overflow so narrow cards
|
|
56
68
|
never push content out of the header. Use .pa-card__header--wrap
|
|
57
69
|
if you'd rather have the text wrap to multiple lines instead.
|
|
58
70
|
================================ -->
|
|
59
71
|
|
|
60
72
|
<div class="pa-card">
|
|
61
73
|
<div class="pa-card__header">
|
|
62
|
-
<
|
|
63
|
-
|
|
74
|
+
<div class="pa-card__title">
|
|
75
|
+
<h3 class="pa-card__title-text">Dashboard</h3>
|
|
76
|
+
</div>
|
|
77
|
+
<p class="pa-card__description">Live metrics across every connected service — updated every 30 seconds.</p>
|
|
64
78
|
<div class="pa-card__actions">
|
|
65
79
|
<button class="pa-btn pa-btn--sm pa-btn--secondary">Refresh</button>
|
|
66
80
|
</div>
|
|
@@ -71,8 +85,10 @@
|
|
|
71
85
|
<!-- Wrap instead of truncate -->
|
|
72
86
|
<div class="pa-card">
|
|
73
87
|
<div class="pa-card__header pa-card__header--wrap">
|
|
74
|
-
<
|
|
75
|
-
|
|
88
|
+
<div class="pa-card__title">
|
|
89
|
+
<h3 class="pa-card__title-text">Wrapping Header</h3>
|
|
90
|
+
</div>
|
|
91
|
+
<p class="pa-card__description">This description wraps to multiple lines when the header gets narrow, instead of being clipped with an ellipsis.</p>
|
|
76
92
|
<div class="pa-card__actions">
|
|
77
93
|
<button class="pa-btn pa-btn--sm pa-btn--secondary">Action</button>
|
|
78
94
|
</div>
|
|
@@ -90,7 +106,9 @@
|
|
|
90
106
|
<!-- Default (accent-coloured underline) -->
|
|
91
107
|
<div class="pa-card">
|
|
92
108
|
<div class="pa-card__header pa-card__header--underlined">
|
|
93
|
-
<
|
|
109
|
+
<div class="pa-card__title">
|
|
110
|
+
<h3 class="pa-card__title-text">Section</h3>
|
|
111
|
+
</div>
|
|
94
112
|
</div>
|
|
95
113
|
<div class="pa-card__body">Body content.</div>
|
|
96
114
|
</div>
|
|
@@ -98,14 +116,18 @@
|
|
|
98
116
|
<!-- Semantic colour variants -->
|
|
99
117
|
<div class="pa-card">
|
|
100
118
|
<div class="pa-card__header pa-card__header--underlined pa-card__header--underline-success">
|
|
101
|
-
<
|
|
119
|
+
<div class="pa-card__title">
|
|
120
|
+
<h3 class="pa-card__title-text">Success underline</h3>
|
|
121
|
+
</div>
|
|
102
122
|
</div>
|
|
103
123
|
<div class="pa-card__body">Body.</div>
|
|
104
124
|
</div>
|
|
105
125
|
|
|
106
126
|
<div class="pa-card">
|
|
107
127
|
<div class="pa-card__header pa-card__header--underlined pa-card__header--underline-danger">
|
|
108
|
-
<
|
|
128
|
+
<div class="pa-card__title">
|
|
129
|
+
<h3 class="pa-card__title-text">Danger underline</h3>
|
|
130
|
+
</div>
|
|
109
131
|
</div>
|
|
110
132
|
<div class="pa-card__body">Body.</div>
|
|
111
133
|
</div>
|
|
@@ -113,7 +135,9 @@
|
|
|
113
135
|
<!-- Theme colour slot (1..9) -->
|
|
114
136
|
<div class="pa-card">
|
|
115
137
|
<div class="pa-card__header pa-card__header--underlined pa-card__header--underline-color-3">
|
|
116
|
-
<
|
|
138
|
+
<div class="pa-card__title">
|
|
139
|
+
<h3 class="pa-card__title-text">Theme colour 3 underline</h3>
|
|
140
|
+
</div>
|
|
117
141
|
</div>
|
|
118
142
|
<div class="pa-card__body">Body.</div>
|
|
119
143
|
</div>
|
|
@@ -124,7 +148,7 @@
|
|
|
124
148
|
-->
|
|
125
149
|
|
|
126
150
|
|
|
127
|
-
<!-- CARD WITH TITLE
|
|
151
|
+
<!-- CARD WITH TITLE ICON (the icon span is the only optional part) -->
|
|
128
152
|
<div class="pa-card">
|
|
129
153
|
<div class="pa-card__header">
|
|
130
154
|
<div class="pa-card__title">
|
|
@@ -136,8 +160,9 @@
|
|
|
136
160
|
</div>
|
|
137
161
|
</div>
|
|
138
162
|
<div class="pa-card__body">
|
|
139
|
-
|
|
140
|
-
|
|
163
|
+
The title always uses .pa-card__title > .pa-card__title-text; add the
|
|
164
|
+
.pa-card__title-icon span when you want a leading icon. Same structure
|
|
165
|
+
with or without the icon — never a bare <h3>.
|
|
141
166
|
</div>
|
|
142
167
|
</div>
|
|
143
168
|
|
|
@@ -145,7 +170,9 @@
|
|
|
145
170
|
<!-- CARD WITH METADATA -->
|
|
146
171
|
<div class="pa-card">
|
|
147
172
|
<div class="pa-card__header">
|
|
148
|
-
<
|
|
173
|
+
<div class="pa-card__title">
|
|
174
|
+
<h3 class="pa-card__title-text">Article Title</h3>
|
|
175
|
+
</div>
|
|
149
176
|
<span class="pa-card__meta">Published 2 hours ago</span>
|
|
150
177
|
</div>
|
|
151
178
|
<div class="pa-card__body">Article content.</div>
|
|
@@ -159,7 +186,9 @@
|
|
|
159
186
|
Reach for this by default. -->
|
|
160
187
|
<div class="pa-card">
|
|
161
188
|
<div class="pa-card__header">
|
|
162
|
-
<
|
|
189
|
+
<div class="pa-card__title">
|
|
190
|
+
<h3 class="pa-card__title-text">Card with Actions</h3>
|
|
191
|
+
</div>
|
|
163
192
|
<div class="pa-card__actions">
|
|
164
193
|
<button class="pa-btn pa-btn--sm pa-btn--secondary">Cancel</button>
|
|
165
194
|
<button class="pa-btn pa-btn--sm pa-btn--success">Save</button>
|
|
@@ -176,7 +205,9 @@
|
|
|
176
205
|
the attached-button styling in whether you want it or not. -->
|
|
177
206
|
<div class="pa-card">
|
|
178
207
|
<div class="pa-card__header">
|
|
179
|
-
<
|
|
208
|
+
<div class="pa-card__title">
|
|
209
|
+
<h3 class="pa-card__title-text">Card with Segmented Actions</h3>
|
|
210
|
+
</div>
|
|
180
211
|
<div class="pa-card__actions">
|
|
181
212
|
<div class="pa-btn-group">
|
|
182
213
|
<button class="pa-btn pa-btn--sm pa-btn--secondary">Day</button>
|
|
@@ -192,11 +223,12 @@
|
|
|
192
223
|
<!-- CARD WITH FOOTER ACTIONS -->
|
|
193
224
|
<div class="pa-card">
|
|
194
225
|
<div class="pa-card__header">
|
|
195
|
-
<
|
|
226
|
+
<div class="pa-card__title">
|
|
227
|
+
<h3 class="pa-card__title-text">Form Card</h3>
|
|
228
|
+
</div>
|
|
196
229
|
</div>
|
|
197
230
|
<div class="pa-card__body">Form content here.</div>
|
|
198
231
|
<div class="pa-card__footer">
|
|
199
|
-
<div></div>
|
|
200
232
|
<div class="pa-card__actions">
|
|
201
233
|
<button class="pa-btn pa-btn--secondary">Cancel</button>
|
|
202
234
|
<button class="pa-btn pa-btn--success">Save</button>
|
|
@@ -208,7 +240,9 @@
|
|
|
208
240
|
<!-- CARD WITH NO-PADDING BODY (for flush tables / lists) -->
|
|
209
241
|
<div class="pa-card">
|
|
210
242
|
<div class="pa-card__header">
|
|
211
|
-
<
|
|
243
|
+
<div class="pa-card__title">
|
|
244
|
+
<h3 class="pa-card__title-text">User List</h3>
|
|
245
|
+
</div>
|
|
212
246
|
</div>
|
|
213
247
|
<div class="pa-card__body pa-card__body--no-padding">
|
|
214
248
|
<table class="pa-table">
|
|
@@ -378,7 +412,9 @@
|
|
|
378
412
|
<!-- Inline tabs — pills that live in the header row -->
|
|
379
413
|
<div class="pa-card">
|
|
380
414
|
<div class="pa-card__header">
|
|
381
|
-
<
|
|
415
|
+
<div class="pa-card__title">
|
|
416
|
+
<h3 class="pa-card__title-text">Sales</h3>
|
|
417
|
+
</div>
|
|
382
418
|
<div class="pa-card__tabs pa-card__tabs--inline">
|
|
383
419
|
<button class="pa-card__tab pa-card__tab--active">Day</button>
|
|
384
420
|
<button class="pa-card__tab">Week</button>
|
|
@@ -396,7 +432,9 @@
|
|
|
396
432
|
identical, but the entire area becomes clickable. -->
|
|
397
433
|
<a href="/products/42" class="pa-card">
|
|
398
434
|
<div class="pa-card__header">
|
|
399
|
-
<
|
|
435
|
+
<div class="pa-card__title">
|
|
436
|
+
<h3 class="pa-card__title-text">Widget Pro</h3>
|
|
437
|
+
</div>
|
|
400
438
|
</div>
|
|
401
439
|
<div class="pa-card__body">
|
|
402
440
|
<p>Click anywhere on this card to navigate.</p>
|
|
@@ -498,12 +536,23 @@ CLICKABLE CARD:
|
|
|
498
536
|
looks identical to a regular card.
|
|
499
537
|
|
|
500
538
|
SUB-ELEMENTS:
|
|
501
|
-
- .pa-card__header Flex row
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
539
|
+
- .pa-card__header Flex row of three canonical slots:
|
|
540
|
+
[.pa-card__title] — [.pa-card__description] —
|
|
541
|
+
[.pa-card__actions]. (Bare h1..h6 / <p> children
|
|
542
|
+
still render + auto-truncate as legacy tolerance,
|
|
543
|
+
but the documented shape is the slots above —
|
|
544
|
+
one structure, so a <Card> wrapper emits one tree.)
|
|
545
|
+
- .pa-card__description Muted, flexing, truncating description line —
|
|
546
|
+
the header's middle slot. Bare <p> tolerated.
|
|
505
547
|
- .pa-card__body flex: 1; standard padding.
|
|
506
548
|
- .pa-card__footer Border-top + footer background; flex row.
|
|
549
|
+
Canonical content: optional leading text /
|
|
550
|
+
.pa-card__meta on the left + .pa-card__actions
|
|
551
|
+
on the right. The actions slot auto-pins to the
|
|
552
|
+
trailing edge (no empty spacer <div> needed),
|
|
553
|
+
with or without leading content. Always put
|
|
554
|
+
footer buttons inside .pa-card__actions so they
|
|
555
|
+
don't scatter to opposite corners.
|
|
507
556
|
- .pa-card__actions THE canonical header actions slot. Button/
|
|
508
557
|
control container (gap + align-center);
|
|
509
558
|
flex-shrink: 0 inside header. Use this for any
|
|
@@ -514,11 +563,14 @@ SUB-ELEMENTS:
|
|
|
514
563
|
the actions slot).
|
|
515
564
|
- .pa-card__meta Muted secondary text (dates, byline, etc.).
|
|
516
565
|
|
|
517
|
-
TITLE SUB-COMPONENT:
|
|
518
|
-
- .pa-card__title Flex row wrapping icon + text;
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
566
|
+
TITLE SUB-COMPONENT (the canonical header title — use it for EVERY card):
|
|
567
|
+
- .pa-card__title Flex row wrapping the optional icon + text;
|
|
568
|
+
flex: 0 1 auto (natural width) so a sibling
|
|
569
|
+
.pa-card__description gets the free space and
|
|
570
|
+
.pa-card__actions stays right. Always present,
|
|
571
|
+
with or without an icon — never a bare <h3>.
|
|
572
|
+
- .pa-card__title-icon Fixed-size leading icon (optional).
|
|
573
|
+
- .pa-card__title-text The heading (h1..h6); truncates with ellipsis.
|
|
522
574
|
|
|
523
575
|
BODY MODIFIER:
|
|
524
576
|
- .pa-card__body--no-padding Strips body padding (for tables / lists
|
|
@@ -556,10 +608,9 @@ SECTION WRAPPERS (lighter than a card, for heading-only groupings):
|
|
|
556
608
|
underline, no container behaviour.
|
|
557
609
|
|
|
558
610
|
IMPLICIT BEHAVIOURS:
|
|
559
|
-
- The header
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
--wrap to opt out.
|
|
611
|
+
- The header truncates: .pa-card__title-text and .pa-card__description
|
|
612
|
+
get white-space: nowrap + text-overflow: ellipsis. This is why long
|
|
613
|
+
card titles look "cut off" in narrow columns — use --wrap to opt out.
|
|
563
614
|
- Buttons inside the header get -0.25rem vertical margin so they
|
|
564
615
|
don't grow the header height past $card-header-min-height.
|
|
565
616
|
- Card body :first-child gets margin-top: 0 to avoid double-spacing
|
|
@@ -570,8 +621,10 @@ STRUCTURE PATTERNS:
|
|
|
570
621
|
Card with three-part header:
|
|
571
622
|
<div class="pa-card">
|
|
572
623
|
<div class="pa-card__header">
|
|
573
|
-
<
|
|
574
|
-
|
|
624
|
+
<div class="pa-card__title">
|
|
625
|
+
<h3 class="pa-card__title-text">Title</h3>
|
|
626
|
+
</div>
|
|
627
|
+
<p class="pa-card__description">Description (truncates)</p>
|
|
575
628
|
<div class="pa-card__actions">
|
|
576
629
|
<button class="pa-btn pa-btn--sm">Action</button>
|
|
577
630
|
</div>
|
|
@@ -582,7 +635,9 @@ Card with three-part header:
|
|
|
582
635
|
Card with underlined header (semantic variant):
|
|
583
636
|
<div class="pa-card">
|
|
584
637
|
<div class="pa-card__header pa-card__header--underlined pa-card__header--underline-danger">
|
|
585
|
-
<
|
|
638
|
+
<div class="pa-card__title">
|
|
639
|
+
<h3 class="pa-card__title-text">Critical Settings</h3>
|
|
640
|
+
</div>
|
|
586
641
|
</div>
|
|
587
642
|
<div class="pa-card__body">…</div>
|
|
588
643
|
</div>
|
|
@@ -83,8 +83,11 @@
|
|
|
83
83
|
white-space: nowrap;
|
|
84
84
|
}
|
|
85
85
|
|
|
86
|
-
// Description
|
|
87
|
-
|
|
86
|
+
// Description - flexible middle, truncate with ellipsis.
|
|
87
|
+
// `.pa-card__description` is the canonical element; bare `> p` is kept as
|
|
88
|
+
// legacy tolerance so hand-written markup doesn't break.
|
|
89
|
+
> p,
|
|
90
|
+
> .pa-card__description {
|
|
88
91
|
flex: 1;
|
|
89
92
|
min-width: 0;
|
|
90
93
|
overflow: hidden;
|
|
@@ -92,6 +95,12 @@
|
|
|
92
95
|
white-space: nowrap;
|
|
93
96
|
color: var(--pa-text-color-2);
|
|
94
97
|
font-size: $font-size-sm;
|
|
98
|
+
// Nudge the smaller description onto the title's baseline (see
|
|
99
|
+
// $card-description-offset-y). `position: relative` keeps it in flow —
|
|
100
|
+
// truncation/flex sizing are unaffected — it only shifts the paint.
|
|
101
|
+
// Font-metric dependent, so themes can retune via the CSS variable.
|
|
102
|
+
position: relative;
|
|
103
|
+
top: var(--pa-card-description-offset-y, #{$card-description-offset-y});
|
|
95
104
|
}
|
|
96
105
|
|
|
97
106
|
// Actions container - fixed, doesn't shrink
|
|
@@ -243,13 +252,18 @@
|
|
|
243
252
|
&--wrap {
|
|
244
253
|
flex-wrap: wrap;
|
|
245
254
|
|
|
246
|
-
|
|
255
|
+
// Un-truncate both the bare-heading shorthand AND the canonical
|
|
256
|
+
// `.pa-card__title` > `.pa-card__title-text` so titles wrap (not
|
|
257
|
+
// ellipsis) in wrap mode regardless of which header shape is used.
|
|
258
|
+
> h1, > h2, > h3, > h4, > h5, > h6,
|
|
259
|
+
> .pa-card__title .pa-card__title-text {
|
|
247
260
|
white-space: normal;
|
|
248
261
|
overflow: visible;
|
|
249
262
|
text-overflow: clip;
|
|
250
263
|
}
|
|
251
264
|
|
|
252
|
-
> p
|
|
265
|
+
> p,
|
|
266
|
+
> .pa-card__description {
|
|
253
267
|
white-space: normal;
|
|
254
268
|
flex-basis: 100%;
|
|
255
269
|
order: 1;
|
|
@@ -263,7 +277,11 @@
|
|
|
263
277
|
align-items: center;
|
|
264
278
|
gap: $spacing-sm;
|
|
265
279
|
min-width: 0; // Enable text truncation
|
|
266
|
-
|
|
280
|
+
// Natural width (like a bare heading), shrinkable, no grow — so a sibling
|
|
281
|
+
// `.pa-card__description` gets the free space instead of the title hogging
|
|
282
|
+
// half the row. `justify-content: space-between` on the header still pins
|
|
283
|
+
// `.pa-card__actions` to the right.
|
|
284
|
+
flex: 0 1 auto;
|
|
267
285
|
|
|
268
286
|
&-icon {
|
|
269
287
|
flex-shrink: 0;
|
|
@@ -279,7 +297,9 @@
|
|
|
279
297
|
color: var(--pa-text-color-1);
|
|
280
298
|
font-size: $font-size-base;
|
|
281
299
|
font-weight: $font-weight-semibold;
|
|
282
|
-
line-height
|
|
300
|
+
// Not `1` — line-height 1 clips glyph descenders (g, y, p) under
|
|
301
|
+
// `overflow: hidden`. Matches the room bare headings already leave.
|
|
302
|
+
line-height: 1.4;
|
|
283
303
|
}
|
|
284
304
|
}
|
|
285
305
|
|
|
@@ -306,6 +326,18 @@
|
|
|
306
326
|
display: flex;
|
|
307
327
|
justify-content: space-between;
|
|
308
328
|
align-items: center;
|
|
329
|
+
gap: $spacing-sm;
|
|
330
|
+
|
|
331
|
+
// Canonical footer content model (mirrors the header): optional leading
|
|
332
|
+
// content on the left — text or `.pa-card__meta` — plus `.pa-card__actions`
|
|
333
|
+
// on the right. The auto inline-start margin pins the actions slot to the
|
|
334
|
+
// trailing edge whether or not there's leading content, so an actions-only
|
|
335
|
+
// footer no longer needs an empty spacer `<div>` to fight `space-between`.
|
|
336
|
+
// Buttons live inside `.pa-card__actions` (the same slot as the header) so
|
|
337
|
+
// they never scatter to opposite corners the way bare footer buttons do.
|
|
338
|
+
.pa-card__actions {
|
|
339
|
+
margin-inline-start: auto;
|
|
340
|
+
}
|
|
309
341
|
}
|
|
310
342
|
|
|
311
343
|
&__actions {
|
|
@@ -176,6 +176,13 @@ $card-body-padding-h: 1rem !default; // 10px horizontal
|
|
|
176
176
|
$card-header-padding-v: 0.5rem !default; // 5px vertical
|
|
177
177
|
$card-header-padding-h: 1rem !default; // 10px horizontal - matches body
|
|
178
178
|
$card-header-min-height: 4rem !default; // 40px - fits xs buttons (32px) with padding
|
|
179
|
+
// Vertical nudge that drops the (smaller) header description onto the title's
|
|
180
|
+
// baseline. Under the header's center alignment a 16px title and 14px
|
|
181
|
+
// description don't share a baseline, leaving the description ~1px high. The
|
|
182
|
+
// exact correction is font-metric dependent, so it's exposed as a variable
|
|
183
|
+
// (SCSS default here + `--pa-card-description-offset-y` at runtime) that themes
|
|
184
|
+
// with a different font can retune. Set to 0 to disable the nudge entirely.
|
|
185
|
+
$card-description-offset-y: 1px !default;
|
|
179
186
|
$card-footer-padding-v: 1.2rem !default; // 12px vertical
|
|
180
187
|
$card-footer-padding-h: 1rem !default; // 10px horizontal - matches body
|
|
181
188
|
$card-grid-min-width: 280px !default;
|