|
| 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. |
0 commit comments