Skip to content

Commit 4fdbca8

Browse files
committed
CardCore - Fully tokenise css for consuming apps
1 parent 59ff2ae commit 4fdbca8

4 files changed

Lines changed: 429 additions & 21 deletions

File tree

Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
# CardCore Component
2+
3+
## Overview
4+
5+
`CardCore` is a generic card container that renders dynamic named slots as stacked rows. It
6+
supports four visual variants, an optional blurred backdrop layer, and a full CSS custom property
7+
API for global and per-instance theming.
8+
9+
---
10+
11+
## Props reference
12+
13+
> **Hyphenation rule**: Vue's ESLint config enforces `vue/attribute-hyphenation`. Always write
14+
> camelCase prop names hyphenated in templates: `:style-class-passthrough`.
15+
16+
| Prop (template form) | Type | Default | Notes |
17+
|---|---|---|---|
18+
| `tag` | `"div" \| "section" \| "article" \| "aside" \| "main" \| "nav"` | `"div"` | Root element tag |
19+
| `variant` | `"solid" \| "subtle" \| "soft" \| "outline"` | `"solid"` | Visual style variant |
20+
| `has-dividers` | `boolean` | `false` | Adds a border between each card row |
21+
| `no-outline` | `boolean` | `false` | Removes border and box-shadow |
22+
| `:style-class-passthrough` | `string \| string[]` | `[]` | Extra classes on the root element |
23+
24+
---
25+
26+
## Slots
27+
28+
Named slots are rendered as rows. Any slot name is valid — each becomes a
29+
`.card-row.card-row-{name}` div.
30+
31+
```vue
32+
<CardCore variant="solid">
33+
<template #header>Header content</template>
34+
<template #body>Body content</template>
35+
<template #footer>Footer content</template>
36+
</CardCore>
37+
```
38+
39+
Rendered structure:
40+
41+
```html
42+
<div class="card-core solid">
43+
<div class="card-row card-row-header">...</div>
44+
<div class="card-row card-row-body">...</div>
45+
<div class="card-row card-row-footer">...</div>
46+
</div>
47+
```
48+
49+
---
50+
51+
## Public CSS token API
52+
53+
Set `--card-core-*` tokens at `:root` (global), a page wrapper (scoped), or inline (per-instance).
54+
55+
| Token | Default | Controls |
56+
|---|---|---|
57+
| `--card-core-row-gap` | `1rem` | Gap between card rows |
58+
| `--card-core-inner-padding` | `1rem` | Available for row-level padding (not applied by the component itself) |
59+
| `--card-core-border-radius` | `0.5rem` | Corner rounding |
60+
| `--card-core-border` | `0.2rem solid var(--slate-08)` | Full border shorthand |
61+
| `--card-core-box-shadow` | `0.1rem 0.1rem 0.4rem oklch(from var(--slate-08) l c h / 0.45)` | Box shadow shorthand |
62+
| `--card-core-background-color` | `transparent` | Main background colour |
63+
| `--card-core-background-image` | `none` | Main background image |
64+
| `--card-core-lower-background-color` | `transparent` | Blurred backdrop layer colour |
65+
| `--card-core-lower-background-image` | `none` | Blurred backdrop layer image |
66+
| `--card-core-lower-background-position` | `center` | Backdrop image position |
67+
| `--card-core-lower-background-blur` | `16px` | Backdrop blur amount |
68+
| `--card-core-lower-scale` | `1.1` | Backdrop scale (hides blur-edge artefact) |
69+
70+
> **Variant note**: `solid`, `subtle`, `soft`, and `outline` variants override the internal
71+
> `--_card-background-color` and `--_card-border` tokens directly, bypassing the public tokens
72+
> for those properties. Override variant colours by targeting the variant class (see below).
73+
74+
---
75+
76+
## Global theming — consuming app setup file
77+
78+
Create `assets/styles/setup/07.components/card-core.css` in the consuming app:
79+
80+
```css
81+
/* assets/styles/setup/07.components/card-core.css */
82+
:root {
83+
--card-core-border-radius: 1rem;
84+
--card-core-border: 0.1rem solid var(--brand-border);
85+
--card-core-box-shadow: 0 0.2rem 1.2rem rgb(0 0 0 / 8%);
86+
--card-core-row-gap: 0;
87+
}
88+
89+
/* variant colour overrides */
90+
.card-core {
91+
&.solid {
92+
--_card-background-color: var(--brand-surface);
93+
--_card-border: 0.1rem solid var(--brand-border);
94+
}
95+
96+
&.outline {
97+
--_card-border: 0.15rem solid var(--brand-primary);
98+
}
99+
}
100+
```
101+
102+
---
103+
104+
## Blurred backdrop pattern
105+
106+
`--card-core-lower-*` tokens drive a `::before` pseudo-element behind all card content. Use it
107+
for image-backed cards with a frosted/blurred layer effect.
108+
109+
```css
110+
.card-core {
111+
&.hero-card {
112+
--card-core-lower-background-image: url("/images/hero.jpg");
113+
--card-core-lower-background-blur: 24px;
114+
--card-core-lower-scale: 1.15;
115+
--card-core-lower-background-color: rgb(0 0 0 / 30%);
116+
--card-core-background-color: transparent;
117+
}
118+
}
119+
```
120+
121+
Or inline:
122+
123+
```vue
124+
<CardCore
125+
variant="solid"
126+
style="
127+
--card-core-lower-background-image: url('/images/hero.jpg');
128+
--card-core-lower-background-blur: 20px;
129+
"
130+
>
131+
...
132+
</CardCore>
133+
```
134+
135+
---
136+
137+
## Page-scoped overrides
138+
139+
```css
140+
/* Unscoped <style> block in the consuming page */
141+
.services-page {
142+
.card-core {
143+
--card-core-border-radius: 1.2rem;
144+
--card-core-row-gap: 0;
145+
146+
&.solid {
147+
--_card-background-color: var(--brand-surface-alt);
148+
}
149+
}
150+
}
151+
```
152+
153+
---
154+
155+
## Per-instance override via styleClassPassthrough
156+
157+
```vue
158+
<CardCore :style-class-passthrough="['featured']">
159+
...
160+
</CardCore>
161+
```
162+
163+
```css
164+
.card-core {
165+
&.featured {
166+
--card-core-border: 0.2rem solid var(--brand-primary);
167+
--card-core-box-shadow: 0 0.4rem 2rem rgb(0 0 0 / 15%);
168+
--card-core-border-radius: 1.6rem;
169+
}
170+
}
171+
```
172+
173+
---
174+
175+
## Card row targeting
176+
177+
```css
178+
.card-core {
179+
.card-row-header {
180+
padding: 1.6rem;
181+
background-color: var(--brand-primary);
182+
color: white;
183+
}
184+
185+
.card-row-body {
186+
padding: 1.6rem;
187+
}
188+
189+
.card-row-footer {
190+
padding: 1.2rem 1.6rem;
191+
border-top: 0.1rem solid var(--brand-border);
192+
}
193+
}
194+
```
195+
196+
---
197+
198+
## Notes
199+
200+
- Auto-imported in Nuxt — no manual import needed.
201+
- The `::before` backdrop layer sits at `z-index: 0`; all slot content is lifted to `z-index: 1`
202+
automatically via the `> *` selector.
203+
- `--card-core-inner-padding` is available as a token but the component does not apply it to rows
204+
— the consuming app is expected to set padding on `.card-row-*` selectors directly.
205+
- See `CONSUMER-STYLING.md` in the component source folder for the full override reference.

.claude/skills/index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ Each skill is a single markdown file named `<area>-<task>.md`.
8080
├── decode-qr-code.md — DecodeQrCode: file picker + drag-and-drop image decoder, shared results list, CSS override points
8181
├── auto-grid.md — AutoGrid: auto-fit responsive grid, $slots iteration, --auto-grid-min-col-size/gap tokens, semantic tag + aria
8282
├── display-avatar.md — DisplayAvatar: circular avatar with image/initials fallback, size variants, chip badge, icon slot, styleClassPassthrough
83+
├── card-core.md — CardCore: generic card container, dynamic named slots as rows, 4 variants, blurred backdrop layer, full CSS token API
8384
├── display-chip.md — DisplayChip: status indicator chip overlay, CSS trig positioning, circle/square shapes, status colours, icon/label content
8485
├── display-pill.md — DisplayPill: pill/badge label with icon slot, 6 variants, 3 sizes, reversible order, full CSS token API for border/outline/colour
8586
├── carousel-flip.md — CarouselFlip: FLIP-animated carousel, carouselDataIds slot API, buttonLayout variants (sides/controls-flanking/controls-grouped-right/overlay), CSS tokens
Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
# CardCore — Consumer Styling Guide
2+
3+
## Public token API
4+
5+
All `--card-core-*` tokens are the stable override surface. Set them at any scope (global, page,
6+
or instance) without touching the component itself.
7+
8+
| Token | Default | Controls |
9+
|---|---|---|
10+
| `--card-core-row-gap` | `1rem` | Gap between card rows |
11+
| `--card-core-inner-padding` | `1rem` | Internal padding (applied per row by the consumer) |
12+
| `--card-core-border-radius` | `0.5rem` | Corner rounding |
13+
| `--card-core-border` | `0.2rem solid var(--slate-08)` | Full border shorthand |
14+
| `--card-core-box-shadow` | `0.1rem 0.1rem 0.4rem oklch(from var(--slate-08) l c h / 0.45)` | Box shadow shorthand |
15+
| `--card-core-background-color` | `transparent` | Main background colour |
16+
| `--card-core-background-image` | `none` | Main background image |
17+
| `--card-core-lower-background-color` | `transparent` | Blurred backdrop layer colour |
18+
| `--card-core-lower-background-image` | `none` | Blurred backdrop layer image |
19+
| `--card-core-lower-background-position` | `center` | Backdrop image position |
20+
| `--card-core-lower-background-blur` | `16px` | Backdrop blur amount |
21+
| `--card-core-lower-scale` | `1.1` | Backdrop scale (zoom to hide blur edges) |
22+
23+
> **Variant note**: The `solid`, `subtle`, `soft`, and `outline` variants directly override the
24+
> internal `--_card-background-color` and `--_card-border` tokens, bypassing the public tokens
25+
> for those properties. To override a variant's colours, target the variant class directly (see
26+
> [Per-variant overrides](#per-variant-overrides) below).
27+
28+
---
29+
30+
## Global theming — app-level CSS file
31+
32+
Create `assets/styles/setup/07.components/card-core.css` in the consuming app and set tokens on
33+
`:root`. These values apply to every `CardCore` instance across the site.
34+
35+
```css
36+
/* assets/styles/setup/07.components/card-core.css */
37+
:root {
38+
--card-core-border-radius: 1rem;
39+
--card-core-border: 0.1rem solid var(--brand-border);
40+
--card-core-box-shadow: 0 0.2rem 1.2rem rgb(0 0 0 / 8%);
41+
--card-core-row-gap: 0;
42+
}
43+
```
44+
45+
---
46+
47+
## Per-variant overrides
48+
49+
Variants override internal tokens directly, so target the variant class to change their colours:
50+
51+
```css
52+
/* assets/styles/setup/07.components/card-core.css */
53+
:root {
54+
/* shared geometry */
55+
--card-core-border-radius: 0.8rem;
56+
}
57+
58+
/* variant colour overrides — set on the variant class, not :root */
59+
.card-core {
60+
&.solid {
61+
--_card-background-color: var(--brand-surface);
62+
--_card-border: 0.1rem solid var(--brand-border);
63+
}
64+
65+
&.subtle {
66+
--_card-background-color: color-mix(in oklab, var(--brand-surface) 50%, transparent);
67+
--_card-border: 0.1rem solid var(--brand-border);
68+
}
69+
70+
&.outline {
71+
--_card-border: 0.15rem solid var(--brand-primary);
72+
}
73+
}
74+
```
75+
76+
---
77+
78+
## Blurred backdrop pattern
79+
80+
Set `--card-core-lower-background-image` and `--card-core-lower-background-color` to create a
81+
blurred translucent layer behind the card content. The `::before` pseudo-element handles the blur
82+
and the scale hides the blur-edge artefact.
83+
84+
```css
85+
.card-core {
86+
&.hero-card {
87+
--card-core-lower-background-image: url("/images/hero.jpg");
88+
--card-core-lower-background-blur: 24px;
89+
--card-core-lower-scale: 1.15;
90+
--card-core-lower-background-color: rgb(0 0 0 / 30%); /* tint over image */
91+
--card-core-background-color: transparent;
92+
}
93+
}
94+
```
95+
96+
Or inline for a single instance:
97+
98+
```vue
99+
<CardCore
100+
variant="solid"
101+
style="
102+
--card-core-lower-background-image: url('/images/hero.jpg');
103+
--card-core-lower-background-blur: 20px;
104+
"
105+
>
106+
...
107+
</CardCore>
108+
```
109+
110+
---
111+
112+
## Page-scoped overrides
113+
114+
When a card appears in a specific page context, scope overrides under the page wrapper. No
115+
`:deep()` is required (component styles are unscoped).
116+
117+
```css
118+
/* In the consuming page's unscoped <style> block */
119+
.services-page {
120+
.card-core {
121+
--card-core-border-radius: 1.2rem;
122+
--card-core-row-gap: 0;
123+
124+
&.solid {
125+
--_card-background-color: var(--brand-surface-alt);
126+
}
127+
}
128+
}
129+
```
130+
131+
---
132+
133+
## Per-instance overrides via styleClassPassthrough
134+
135+
```vue
136+
<CardCore :style-class-passthrough="['featured']">
137+
...
138+
</CardCore>
139+
```
140+
141+
```css
142+
.card-core {
143+
&.featured {
144+
--card-core-border: 0.2rem solid var(--brand-primary);
145+
--card-core-box-shadow: 0 0.4rem 2rem rgb(0 0 0 / 15%);
146+
--card-core-border-radius: 1.6rem;
147+
}
148+
}
149+
```
150+
151+
---
152+
153+
## Card row targeting
154+
155+
Slot content is wrapped in `.card-row.card-row-{name}`. Target rows for padding, borders, or
156+
backgrounds without modifying the component:
157+
158+
```css
159+
.card-core {
160+
.card-row-header {
161+
padding: 1.6rem;
162+
background-color: var(--brand-primary);
163+
color: white;
164+
}
165+
166+
.card-row-body {
167+
padding: 1.6rem;
168+
}
169+
170+
.card-row-footer {
171+
padding: 1.2rem 1.6rem;
172+
border-top: 0.1rem solid var(--brand-border);
173+
}
174+
}
175+
```

0 commit comments

Comments
 (0)