srcdev-nuxt-components 9.4.9 → 9.4.11
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/.claude/commands/migrate-component.md +38 -6
- package/.claude/component-ledger/audit.json +1 -1
- package/.claude/component-ledger/build.mjs +26 -0
- package/.claude/component-ledger/output.html +8 -3
- package/.claude/component-ledger/template.html +7 -2
- package/.claude/skills/component-dynamic-slots.md +1 -1
- package/.claude/skills/components/alert-mask-core.md +84 -0
- package/.claude/skills/components/canvas-switcher.md +1 -1
- package/.claude/skills/components/carousel-flip.md +112 -168
- package/.claude/skills/components/container-glow.md +123 -0
- package/.claude/skills/components/dashboard-quad-grid.md +98 -0
- package/.claude/skills/components/dashboard-stats-grid.md +103 -0
- package/.claude/skills/components/display-theme-switch.md +60 -0
- package/.claude/skills/components/glowing-border.md +66 -0
- package/.claude/skills/components/input-number-core.md +214 -0
- package/.claude/skills/components/input-range-core.md +142 -0
- package/.claude/skills/components/input-select-core.md +151 -0
- package/.claude/skills/components/input-text-core.md +16 -0
- package/.claude/skills/components/input-textarea-core.md +154 -0
- package/.claude/skills/components/section-parallax.md +32 -10
- package/.claude/skills/components/select-menu.md +195 -0
- package/.claude/skills/components/toggle-switch-core.md +150 -0
- package/.claude/skills/components/ui-block-decorated.md +56 -0
- package/.claude/skills/components/wipe-away-vertical.md +98 -0
- package/.claude/skills/icon-sets.md +1 -1
- package/.claude/skills/index.md +15 -1
- package/.vscode/css-custom-data.json +38 -0
- package/.vscode/settings.json +3 -0
- package/.vscode/srcdev-component-alert-mask-core.code-snippets +31 -0
- package/.vscode/srcdev-component-carousel-flip.code-snippets +41 -0
- package/.vscode/srcdev-component-container-glow.code-snippets +33 -0
- package/.vscode/srcdev-component-dashboard-quad-grid.code-snippets +36 -0
- package/.vscode/srcdev-component-dashboard-stats-grid.code-snippets +35 -0
- package/.vscode/srcdev-component-display-theme-switch.code-snippets +27 -0
- package/.vscode/srcdev-component-glowing-border.code-snippets +23 -0
- package/.vscode/srcdev-component-input-number.code-snippets +65 -0
- package/.vscode/srcdev-component-input-range.code-snippets +85 -0
- package/.vscode/srcdev-component-input-select.code-snippets +42 -0
- package/.vscode/srcdev-component-input-textarea.code-snippets +40 -0
- package/.vscode/srcdev-component-section-parallax.code-snippets +27 -0
- package/.vscode/srcdev-component-select-menu.code-snippets +65 -0
- package/.vscode/srcdev-component-toggle-switch.code-snippets +49 -0
- package/.vscode/srcdev-component-ui-block-decorated.code-snippets +24 -0
- package/.vscode/srcdev-component-wipe-away-vertical.code-snippets +25 -0
- package/README.md +18 -37
- package/app/components/{alert-mask → 01.atoms/alert-mask}/AlertMaskCore.vue +16 -17
- package/app/components/01.atoms/alert-mask/CONSUMER-STYLING.md +46 -0
- package/app/components/01.atoms/alert-mask/stories/AlertMaskCore.stories.ts +79 -0
- package/app/components/{alert-mask → 01.atoms/alert-mask}/tests/AlertMaskCore.spec.ts +10 -10
- package/app/components/01.atoms/animations/container-glow/CONSUMER-STYLING.md +86 -0
- package/app/components/01.atoms/animations/container-glow/ContainerGlow.vue +299 -0
- package/app/components/01.atoms/animations/container-glow/stories/ContainerGlow.stories.ts +175 -0
- package/app/components/01.atoms/animations/container-glow/tests/ContainerGlow.spec.ts +131 -0
- package/app/components/01.atoms/animations/container-glow/tests/__snapshots__/ContainerGlow.spec.ts.snap +14 -0
- package/app/components/01.atoms/animations/glowing-border/CONSUMER-STYLING.md +61 -0
- package/app/components/01.atoms/animations/glowing-border/GlowingBorder.vue +132 -0
- package/app/components/01.atoms/animations/glowing-border/stories/GlowingBorder.stories.ts +165 -0
- package/app/components/01.atoms/animations/glowing-border/tests/GlowingBorder.spec.ts +94 -0
- package/app/components/01.atoms/animations/glowing-border/tests/__snapshots__/GlowingBorder.spec.ts.snap +3 -0
- package/app/components/01.atoms/animations/marquee-scroller/CONSUMER-STYLING.md +1 -1
- package/app/components/01.atoms/animations/marquee-scroller/MarqueeScroller.vue +1 -1
- package/app/components/01.atoms/animations/marquee-scroller/stories/MarqueeScroller.stories.ts +1 -1
- package/app/components/01.atoms/animations/section-parallax/CONSUMER-STYLING.md +44 -0
- package/app/components/{parallax → 01.atoms/animations/section-parallax}/SectionParallax.vue +11 -10
- package/app/components/01.atoms/animations/section-parallax/stories/SectionParallax.stories.ts +98 -0
- package/app/components/01.atoms/animations/section-parallax/tests/SectionParallax.spec.ts +102 -0
- package/app/components/01.atoms/animations/section-parallax/tests/__snapshots__/SectionParallax.spec.ts.snap +9 -0
- package/app/components/01.atoms/animations/view-timeline/CONSUMER-STYLING.md +70 -0
- package/app/components/01.atoms/animations/view-timeline/WipeAwayVertical.vue +181 -0
- package/app/components/01.atoms/animations/view-timeline/stories/WipeAwayVertical.stories.ts +269 -0
- package/app/components/01.atoms/animations/view-timeline/tests/WipeAwayVertical.spec.ts +127 -0
- package/app/components/01.atoms/canvas-switcher/CONSUMER-STYLING.md +3 -3
- package/app/components/01.atoms/canvas-switcher/CanvasSwitcher.vue +2 -2
- package/app/components/01.atoms/canvas-switcher/stories/CanvasSwitcher.stories.ts +1 -1
- package/app/components/01.atoms/card/CardCore.vue +4 -4
- package/app/components/01.atoms/clipped-panel/CONSUMER-STYLING.md +2 -2
- package/app/components/01.atoms/clipped-panel/ClippedPanel.vue +2 -2
- package/app/components/01.atoms/content-wrappers/layout-grid/dashboard-quad-grid/CONSUMER-STYLING.md +42 -0
- package/app/components/{layout-grids/LayoutGridA.vue → 01.atoms/content-wrappers/layout-grid/dashboard-quad-grid/DashboardQuadGrid.vue} +23 -13
- package/app/components/{layout-grids/stories/LayoutGridA.stories.ts → 01.atoms/content-wrappers/layout-grid/dashboard-quad-grid/stories/DashboardQuadGrid.stories.ts} +151 -23
- package/app/components/{layout-grids/tests/LayoutGridA.spec.ts → 01.atoms/content-wrappers/layout-grid/dashboard-quad-grid/tests/DashboardQuadGrid.spec.ts} +25 -25
- package/app/components/01.atoms/content-wrappers/layout-grid/dashboard-stats-grid/CONSUMER-STYLING.md +41 -0
- package/app/components/01.atoms/content-wrappers/layout-grid/dashboard-stats-grid/DashboardStatsGrid.vue +133 -0
- package/app/components/{layout-grids/stories/LayoutGridB.stories.ts → 01.atoms/content-wrappers/layout-grid/dashboard-stats-grid/stories/DashboardStatsGrid.stories.ts} +24 -24
- package/app/components/{layout-grids/tests/LayoutGridB.spec.ts → 01.atoms/content-wrappers/layout-grid/dashboard-stats-grid/tests/DashboardStatsGrid.spec.ts} +23 -23
- package/app/components/01.atoms/display-tooltip/CONSUMER-STYLING.md +8 -8
- package/app/components/01.atoms/display-tooltip/DisplayTooltip.vue +8 -8
- package/app/components/01.atoms/pop-over/CONSUMER-STYLING.md +6 -6
- package/app/components/01.atoms/pop-over/PopOver.vue +6 -6
- package/app/components/01.atoms/ui-block-decorated/CONSUMER-STYLING.md +39 -0
- package/app/components/01.atoms/ui-block-decorated/UiBlockDecorated.vue +141 -0
- package/app/components/01.atoms/ui-block-decorated/stories/UiBlockDecorated.stories.ts +148 -0
- package/app/components/01.atoms/ui-block-decorated/tests/UiBlockDecorated.spec.ts +80 -0
- package/app/components/01.atoms/ui-block-decorated/tests/__snapshots__/UiBlockDecorated.spec.ts.snap +3 -0
- package/app/components/02.molecules/alert-masked-content/tests/AlertMaskedContent.spec.ts +6 -6
- package/app/components/02.molecules/display-theme-switch/CONSUMER-STYLING.md +34 -0
- package/app/components/02.molecules/display-theme-switch/DisplayThemeSwitch.vue +102 -0
- package/app/components/02.molecules/display-theme-switch/stories/DisplayThemeSwitch.stories.ts +115 -0
- package/app/components/02.molecules/display-theme-switch/tests/DisplayThemeSwitch.spec.ts +86 -0
- package/app/components/02.molecules/navigation/deep-expanding-menu/CONSUMER-STYLING.md +1 -1
- package/app/components/02.molecules/navigation/deep-expanding-menu/DeepExpandingMenu.vue +1 -1
- package/app/components/02.molecules/navigation/deep-expanding-menu-classic/CONSUMER-STYLING.md +1 -1
- package/app/components/02.molecules/navigation/deep-expanding-menu-classic/DeepExpandingMenuClassic.vue +1 -1
- package/app/components/02.molecules/select-menu/CONSUMER-STYLING.md +168 -0
- package/app/components/02.molecules/select-menu/SelectMenu.vue +384 -0
- package/app/components/02.molecules/select-menu/stories/SelectMenu.stories.ts +359 -0
- package/app/components/02.molecules/select-menu/tests/SelectMenu.spec.ts +476 -0
- package/app/components/02.molecules/select-menu/tests/__snapshots__/SelectMenu.spec.ts.snap +42 -0
- package/app/components/03.organisms/image-galleries/carousel-flip/CONSUMER-STYLING.md +46 -0
- package/app/components/{carousels → 03.organisms/image-galleries/carousel-flip}/CarouselFlip.vue +63 -42
- package/app/components/{carousels → 03.organisms/image-galleries/carousel-flip}/stories/CarouselFlip.stories.ts +114 -29
- package/app/components/{carousels → 03.organisms/image-galleries/carousel-flip}/tests/CarouselFlip.spec.ts +80 -0
- package/app/components/05.forms/form-field/FormField.vue +1 -1
- package/app/components/05.forms/form-wrapper/FormWrapper.vue +1 -1
- package/app/components/05.forms/input-button/CONSUMER-STYLING.md +2 -7
- package/app/components/05.forms/input-button/InputButtonCore.vue +1 -5
- package/app/components/05.forms/input-number/CONSUMER-STYLING.md +26 -6
- package/app/components/05.forms/input-number/InputNumberCore.vue +125 -85
- package/app/components/05.forms/input-number/stories/InputNumberCore.stories.ts +92 -0
- package/app/components/05.forms/input-number/tests/InputNumberCore.spec.ts +119 -0
- package/app/components/05.forms/input-number/variants/InputNumberDefault.vue +30 -22
- package/app/components/05.forms/input-number/variants/stories/InputNumberDefault.stories.ts +123 -0
- package/app/components/05.forms/input-number/variants/tests/InputNumberDefault.spec.ts +143 -0
- package/app/components/05.forms/input-range/CONSUMER-STYLING.md +45 -0
- package/app/components/05.forms/input-range/InputRangeCore.vue +79 -143
- package/app/components/05.forms/input-range/stories/InputRangeCore.stories.ts +126 -0
- package/app/components/05.forms/input-range/tests/InputRangeCore.spec.ts +124 -0
- package/app/components/05.forms/input-range/variants/InputRangeDefault.vue +9 -32
- package/app/components/05.forms/input-range/variants/stories/InputRangeDefault.stories.ts +108 -0
- package/app/components/05.forms/input-range/variants/tests/InputRangeDefault.spec.ts +140 -0
- package/app/components/05.forms/input-select/InputSelectCore.vue +23 -30
- package/app/components/05.forms/input-select/stories/InputSelectCore.stories.ts +2 -2
- package/app/components/05.forms/input-select/stories/InputSelectWithLabel.stories.ts +115 -0
- package/app/components/05.forms/input-select/tests/InputSelectCore.spec.ts +129 -0
- package/app/components/05.forms/input-select/variants/InputSelectWithLabel.vue +1 -1
- package/app/components/05.forms/input-select/variants/tests/InputSelectWithLabel.spec.ts +87 -0
- package/app/components/05.forms/input-text/tests/InputTextAsNumberWithLabel.spec.ts +14 -0
- package/app/components/05.forms/input-text/variants/InputTextAsNumberWithLabel.vue +1 -1
- package/app/components/05.forms/input-textarea/CONSUMER-STYLING.md +55 -0
- package/app/components/05.forms/input-textarea/InputTextareaCore.vue +24 -16
- package/app/components/05.forms/input-textarea/stories/InputTextareaWithLabel.stories.ts +1 -1
- package/app/components/05.forms/input-textarea/tests/InputTextareaCore.spec.ts +119 -0
- package/app/components/05.forms/input-textarea/variants/InputTextareaWithLabel.vue +3 -13
- package/app/components/05.forms/input-textarea/variants/tests/InputTextareaWithLabel.spec.ts +93 -0
- package/app/components/05.forms/patterns/stories/MigratedFieldsForm.stories.ts +220 -0
- package/app/components/05.forms/toggle-switch/CONSUMER-STYLING.md +29 -0
- package/app/components/05.forms/toggle-switch/ToggleSwitchCore.vue +120 -119
- package/app/components/05.forms/toggle-switch/stories/ToggleSwitchCore.stories.ts +1 -1
- package/app/components/05.forms/toggle-switch/stories/ToggleSwitchWithLabel.stories.ts +1 -1
- package/app/components/05.forms/toggle-switch/stories/ToggleSwitchWithLabelInline.stories.ts +2 -2
- package/app/components/05.forms/toggle-switch/tests/ToggleSwitchCore.spec.ts +101 -0
- package/app/components/05.forms/toggle-switch/variants/ToggleSwitchWithLabel.vue +3 -5
- package/app/components/05.forms/toggle-switch/variants/ToggleSwitchWithLabelInline.vue +1 -2
- package/app/components/05.forms/toggle-switch/variants/tests/ToggleSwitchWithLabel.spec.ts +77 -0
- package/app/components/05.forms/toggle-switch/variants/tests/ToggleSwitchWithLabelInline.spec.ts +66 -0
- package/app/components/05.forms/triple-toggle-switch/CONSUMER-STYLING.md +20 -6
- package/app/components/05.forms/triple-toggle-switch/TripleToggleSwitchCore.vue +12 -10
- package/app/types/components/container-glow.d.ts +8 -0
- package/app/types/components/index.ts +2 -1
- package/app/types/components/select-menu.d.ts +5 -0
- package/package.json +3 -2
- package/.vscode/srcdev-component-toggle-switch-core.code-snippets +0 -13
- package/app/components/05.forms/input-range-fancy/InputRangeFancyCore.vue +0 -426
- package/app/components/05.forms/input-range-fancy/InputRangeFancyWithLabel.vue +0 -94
- package/app/components/carousels/CarouselBasic.vue +0 -317
- package/app/components/carousels/CarouselInfinite.vue +0 -358
- package/app/components/container-glow/ContainerGlowCore.vue +0 -296
- package/app/components/container-glow/stories/ContainerGlowCore.stories.ts +0 -337
- package/app/components/display-theme-switch/DisplayThemeSwitch.vue +0 -189
- package/app/components/display-theme-switch/stories/DisplayThemeSwitch.stories.ts +0 -154
- package/app/components/glowing-border/GlowingBorder.vue +0 -142
- package/app/components/glowing-border/stories/GlowingBorder.stories.ts +0 -141
- package/app/components/layout-grids/LayoutGridB.vue +0 -134
- package/app/components/test-storybook/TestStorybook.vue +0 -49
- package/app/components/test-storybook/stories/TestStorybook.stories.ts +0 -28
- package/app/components/ui-block-decorated/UiBlockDecorated.vue +0 -167
- package/app/components/view-timeline/WipeAwayVertical.vue +0 -180
- package/app/types/components/carousel-basic.d.ts +0 -19
package/README.md
CHANGED
|
@@ -123,7 +123,7 @@ A formula declared on every potential theme host (`html`, `[data-theme]`, `[data
|
|
|
123
123
|
computes the scale from the two params:
|
|
124
124
|
|
|
125
125
|
```css
|
|
126
|
-
--colour-theme-6: oklch(56% calc(var(--theme-chroma) * 1
|
|
126
|
+
--colour-theme-6: oklch(56% calc(var(--theme-chroma) * 1) var(--theme-hue)); /* peak chroma */
|
|
127
127
|
--colour-theme-0: oklch(98% calc(var(--theme-chroma) * 0.045) var(--theme-hue)); /* near-white */
|
|
128
128
|
--colour-theme-10: oklch(25% calc(var(--theme-chroma) * 0.64) var(--theme-hue)); /* near-black */
|
|
129
129
|
```
|
|
@@ -138,7 +138,7 @@ re-evaluates locally so each themed element gets its own full palette without af
|
|
|
138
138
|
### Built-in named palettes
|
|
139
139
|
|
|
140
140
|
| Name | Hue | Used for |
|
|
141
|
-
|
|
141
|
+
| ------ | --- | ------------------------------------------------- |
|
|
142
142
|
| blue | 255 | Default (page-level) |
|
|
143
143
|
| red | 30 | Error / `data-theme="error"` |
|
|
144
144
|
| green | 157 | Success / `data-theme="success"` |
|
|
@@ -163,7 +163,7 @@ the cascade automatically:
|
|
|
163
163
|
// ramps.config.mjs
|
|
164
164
|
export const ramps = {
|
|
165
165
|
// New palette — adds --gold-00..10 and --palette-gold-* vars
|
|
166
|
-
gold: { hue: 85, chroma: 0.
|
|
166
|
+
gold: { hue: 85, chroma: 0.2 },
|
|
167
167
|
|
|
168
168
|
// Override a built-in — replaces the layer's --blue-00..10 with your values
|
|
169
169
|
// blue: { hue: 240, chroma: 0.18 },
|
|
@@ -218,11 +218,11 @@ In your `app/assets/styles/setup/02.colours/index.css` (create if it doesn't exi
|
|
|
218
218
|
```css
|
|
219
219
|
/* app/assets/styles/setup/03.theming/_default.css */
|
|
220
220
|
:where(html) {
|
|
221
|
-
--theme-hue:
|
|
221
|
+
--theme-hue: var(--palette-gold-hue);
|
|
222
222
|
--theme-chroma: var(--palette-gold-chroma);
|
|
223
223
|
|
|
224
224
|
/* Page-level tokens — readable named steps, not raw oklch */
|
|
225
|
-
--colour-text-accent:
|
|
225
|
+
--colour-text-accent: light-dark(var(--gold-09), var(--gold-04));
|
|
226
226
|
--colour-text-eyebrow: light-dark(var(--gold-09), var(--gold-04));
|
|
227
227
|
}
|
|
228
228
|
```
|
|
@@ -244,7 +244,7 @@ And in `app/assets/styles/main.css`:
|
|
|
244
244
|
### Hue quick reference
|
|
245
245
|
|
|
246
246
|
| Range | Colour |
|
|
247
|
-
|
|
247
|
+
| ------- | -------------- |
|
|
248
248
|
| 0–30 | Red / pink |
|
|
249
249
|
| 30–70 | Orange / amber |
|
|
250
250
|
| 70–100 | Yellow / gold |
|
|
@@ -265,12 +265,12 @@ npm run check:ramps # CI: fail if generated CSS is out of date
|
|
|
265
265
|
|
|
266
266
|
### Further reading
|
|
267
267
|
|
|
268
|
-
| Guide
|
|
269
|
-
|
|
270
|
-
| Full ramp architecture, formula details, hue drift
|
|
271
|
-
| Full palette swap for a consumer app
|
|
268
|
+
| Guide | Location |
|
|
269
|
+
| ------------------------------------------------------- | -------------------------------------------- |
|
|
270
|
+
| Full ramp architecture, formula details, hue drift | `.claude/skills/theming-colour-ramps.md` |
|
|
271
|
+
| Full palette swap for a consumer app | `.claude/skills/theming-override-default.md` |
|
|
272
272
|
| Partial token override (palette shift, buttons, inputs) | `.claude/skills/theming-partial-override.md` |
|
|
273
|
-
| Disable light/dark mode support
|
|
273
|
+
| Disable light/dark mode support | `.claude/skills/colour-scheme-disable.md` |
|
|
274
274
|
|
|
275
275
|
Skills are available in your project after running `npm run setup:claude`.
|
|
276
276
|
|
|
@@ -330,15 +330,19 @@ The `.vscode` directory contains Visual Studio Code configuration files to ensur
|
|
|
330
330
|
- **CSS Development**: `willofindie.vscode-cssvar` - CSS custom property IntelliSense
|
|
331
331
|
- **Testing**: `vitest.explorer` - Vitest test runner integration
|
|
332
332
|
- **Markdown**: `davidanson.vscode-markdownlint` - Markdown linting
|
|
333
|
-
- **Productivity**: `jkjustjoshing.vscode-text-pastry`, `formulahendry.auto-rename-tag`
|
|
333
|
+
- **Productivity**: `jkjustjoshing.vscode-text-pastry`, `formulahendry.auto-rename-tag`, `nixon.env-cmd-file-syntax`
|
|
334
|
+
- **AI-assisted development**: `anthropic.claude-code`
|
|
334
335
|
|
|
335
336
|
### Code Snippets
|
|
336
337
|
|
|
337
|
-
|
|
338
|
+
Every component ships a matching `.vscode/srcdev-component-{name}.code-snippets` file — one per
|
|
339
|
+
component, kept up to date as part of this project's component migration workflow (see
|
|
340
|
+
`CLAUDE.md`). Consumer apps get all of them copied into their own `.vscode/` folder automatically
|
|
341
|
+
via the `postinstall` setup described above; there's nothing to configure manually.
|
|
338
342
|
|
|
339
343
|
## Contact Form — Resend Setup
|
|
340
344
|
|
|
341
|
-
The
|
|
345
|
+
The `ContactSection` component (see it in Storybook under **Molecules/ContactSection**) sends enquiries via [Resend](https://resend.com).
|
|
342
346
|
No extra packages are required — the server route calls the Resend REST API directly.
|
|
343
347
|
|
|
344
348
|
### 1. Create a Resend account
|
|
@@ -490,26 +494,3 @@ Fonts are served instead from local files in `.storybook/public/_fonts/`, declar
|
|
|
490
494
|
| Playfair Display | woff2 | `.storybook/public/_fonts/playfair-display/` |
|
|
491
495
|
|
|
492
496
|
To add a new font, see [.claude/skills/storybook-add-font.md](.claude/skills/storybook-add-font.md).
|
|
493
|
-
|
|
494
|
-
#### Core Components
|
|
495
|
-
|
|
496
|
-
- **`srcdev-nuxt3-component-boilerplate.code-snippets`** - Base component template with prop validation
|
|
497
|
-
- **`srcdev-nuxt3-page-layout.code-snippets`** - Page layout scaffolding
|
|
498
|
-
- **`srcdev-nuxt3-pinia-store-setup.code-snippets`** - Pinia store configuration
|
|
499
|
-
|
|
500
|
-
#### UI Components
|
|
501
|
-
|
|
502
|
-
- **`srcdev-nuxt3-accordian-component.code-snippets`** - Accordion component templates
|
|
503
|
-
- **`srcdev-nuxt3-carousel-basic-component.code-snippets`** - Basic carousel implementation
|
|
504
|
-
- **`srcdev-nuxt3-carousel-flip-component.code-snippets`** - Flip carousel variant
|
|
505
|
-
- **`srcdev-nuxt3-container-glow-component.code-snippets`** - Container with glow effects
|
|
506
|
-
- **`srcdev-nuxt3-dialog-component.code-snippets`** - Modal dialog templates
|
|
507
|
-
- **`srcdev-nuxt3-display-banner-component.code-snippets`** - Display banner component
|
|
508
|
-
- **`srcdev-nuxt3-display-details-component.code-snippets`** - Collapsible details component
|
|
509
|
-
- **`srcdev-nuxt3-display-prompt-component.code-snippets`** - Alert/notification prompts
|
|
510
|
-
- **`srcdev-nuxt3-expanding-panel-component.code-snippets`** - Expandable panel component
|
|
511
|
-
- **`srcdev-nuxt3-layout-row.code-snippets`** - Layout row component
|
|
512
|
-
- **`srcdev-nuxt3-responsive-header-component.code-snippets`** - Responsive navigation header
|
|
513
|
-
- **`srcdev-nuxt3-tabs-component.code-snippets`** - Tab component system
|
|
514
|
-
|
|
515
|
-
Each snippet provides both HTML template usage examples and TypeScript setup code, enabling developers to quickly implement components with proper typing and configuration.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="alert-mask-core" :class="[elementClasses]">
|
|
3
|
-
<svg class="alert-mask-decorator" :style="{ '--
|
|
3
|
+
<svg class="alert-mask-decorator" :style="{ '--_height': svgHeight + 'px' }" xmlns="http://www.w3.org/2000/svg">
|
|
4
4
|
<defs>
|
|
5
5
|
<mask id="borderMask" maskUnits="userSpaceOnUse">
|
|
6
6
|
<path :d="outerPath" fill="white" />
|
|
@@ -15,10 +15,10 @@
|
|
|
15
15
|
<div
|
|
16
16
|
class="alert-mask-content"
|
|
17
17
|
:style="{
|
|
18
|
-
'--
|
|
19
|
-
'--
|
|
20
|
-
'--
|
|
21
|
-
'--
|
|
18
|
+
'--_inset-inline-start': (props.config?.borderLeft ?? 0) + 'px',
|
|
19
|
+
'--_inset-inline-end': (props.config?.borderRight ?? 0) + 'px',
|
|
20
|
+
'--_inset-block-start': (props.config?.borderTop ?? 0) + 'px',
|
|
21
|
+
'--_inset-block-end': (props.config?.borderBottom ?? 0) + 'px',
|
|
22
22
|
}"
|
|
23
23
|
>
|
|
24
24
|
<div ref="alertContentRef" class="alert-mask-content-slot">
|
|
@@ -31,15 +31,14 @@
|
|
|
31
31
|
<script setup lang="ts">
|
|
32
32
|
import type { AlertMaskConfig } from "~/types/components";
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
config
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
},
|
|
34
|
+
interface Props {
|
|
35
|
+
config?: AlertMaskConfig;
|
|
36
|
+
styleClassPassthrough?: string | string[];
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const props = withDefaults(defineProps<Props>(), {
|
|
40
|
+
config: () => ({}),
|
|
41
|
+
styleClassPassthrough: () => [],
|
|
43
42
|
});
|
|
44
43
|
|
|
45
44
|
const { elementClasses } = useStyleClassPassthrough(props.styleClassPassthrough);
|
|
@@ -136,13 +135,13 @@ const innerPath = computed(() => {
|
|
|
136
135
|
.alert-mask-decorator {
|
|
137
136
|
grid-area: mask;
|
|
138
137
|
width: 100%;
|
|
139
|
-
height: var(--
|
|
138
|
+
height: var(--_height);
|
|
140
139
|
}
|
|
141
140
|
|
|
142
141
|
.alert-mask-content {
|
|
143
142
|
grid-area: mask;
|
|
144
|
-
margin-block: var(--
|
|
145
|
-
margin-inline: var(--
|
|
143
|
+
margin-block: var(--_inset-block-start) var(--_inset-block-end);
|
|
144
|
+
margin-inline: var(--_inset-inline-start) var(--_inset-inline-end);
|
|
146
145
|
}
|
|
147
146
|
}
|
|
148
147
|
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# AlertMaskCore — Consumer Styling Guide
|
|
2
|
+
|
|
3
|
+
## No public CSS token API
|
|
4
|
+
|
|
5
|
+
`AlertMaskCore` draws its border/background via an SVG `<mask>` whose path geometry is computed
|
|
6
|
+
from measured content dimensions, so it can't expose colour/radius/thickness as CSS custom
|
|
7
|
+
properties the way most components do — a `var()` can't be interpolated into an SVG path or
|
|
8
|
+
resized reactively the way a `fill` attribute can. Instead, the override surface is the `config`
|
|
9
|
+
prop (`AlertMaskConfig`):
|
|
10
|
+
|
|
11
|
+
```vue
|
|
12
|
+
<AlertMaskCore
|
|
13
|
+
:config="{
|
|
14
|
+
backgroundColour: '#1a1a1a',
|
|
15
|
+
borderColour: 'var(--theme-accent)',
|
|
16
|
+
radiusLeft: 8,
|
|
17
|
+
radiusRight: 4,
|
|
18
|
+
borderLeft: 6,
|
|
19
|
+
borderTop: 1,
|
|
20
|
+
borderRight: 1,
|
|
21
|
+
borderBottom: 1,
|
|
22
|
+
}"
|
|
23
|
+
>
|
|
24
|
+
<p>Alert content</p>
|
|
25
|
+
</AlertMaskCore>
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
All fields are optional and fall back to `backgroundColour: "rgba(0,0,0,0.25)"`,
|
|
29
|
+
`borderColour: "var(--orange-08)"`, `radiusLeft`/`radiusRight: 12`, `borderLeft`/`borderTop`/
|
|
30
|
+
`borderRight`/`borderBottom: 8`.
|
|
31
|
+
|
|
32
|
+
## Class passthrough
|
|
33
|
+
|
|
34
|
+
Use `styleClassPassthrough` to add classes to the root `.alert-mask-core` element for layout
|
|
35
|
+
purposes (positioning, sizing) — it doesn't affect the mask's own colours or geometry, which stay
|
|
36
|
+
governed by `config`.
|
|
37
|
+
|
|
38
|
+
```vue
|
|
39
|
+
<AlertMaskCore style-class-passthrough="my-alert-mask">...</AlertMaskCore>
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Internal (non-overridable) custom properties
|
|
43
|
+
|
|
44
|
+
`--_height`, `--_inset-inline-start`, `--_inset-inline-end`, `--_inset-block-start`, and
|
|
45
|
+
`--_inset-block-end` are set inline from measured content size and `config` border widths. They're
|
|
46
|
+
private implementation plumbing, not a consumer override surface — use `config` instead.
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import AlertMaskCore from "../AlertMaskCore.vue";
|
|
2
|
+
import type { Meta, StoryObj } from "@nuxtjs/storybook";
|
|
3
|
+
|
|
4
|
+
const meta: Meta<typeof AlertMaskCore> = {
|
|
5
|
+
title: "Atoms/AlertMaskCore",
|
|
6
|
+
component: AlertMaskCore,
|
|
7
|
+
argTypes: {
|
|
8
|
+
config: {
|
|
9
|
+
control: "object",
|
|
10
|
+
description:
|
|
11
|
+
"Border/background colour and geometry: backgroundColour, borderColour, radiusLeft, radiusRight, borderLeft, borderTop, borderRight, borderBottom",
|
|
12
|
+
table: { category: "Basic" },
|
|
13
|
+
},
|
|
14
|
+
styleClassPassthrough: {
|
|
15
|
+
table: { disable: true },
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
parameters: {
|
|
19
|
+
docs: {
|
|
20
|
+
description: {
|
|
21
|
+
component:
|
|
22
|
+
"Draws a border/background mask around slotted content via an SVG path, sized to the measured content. Colour and geometry are set via the `config` prop, not CSS tokens — see CONSUMER-STYLING.md.",
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export default meta;
|
|
29
|
+
type Story = StoryObj<typeof AlertMaskCore>;
|
|
30
|
+
|
|
31
|
+
export const Default: Story = {
|
|
32
|
+
args: {
|
|
33
|
+
config: {},
|
|
34
|
+
},
|
|
35
|
+
render: (args) => ({
|
|
36
|
+
components: { AlertMaskCore },
|
|
37
|
+
setup() {
|
|
38
|
+
return { args };
|
|
39
|
+
},
|
|
40
|
+
template: `
|
|
41
|
+
<AlertMaskCore v-bind="args">
|
|
42
|
+
<p style="margin: 0; padding: 1.6rem; color: white;">Default alert mask content</p>
|
|
43
|
+
</AlertMaskCore>
|
|
44
|
+
`,
|
|
45
|
+
}),
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
export const CustomConfig: Story = {
|
|
49
|
+
args: {
|
|
50
|
+
config: {
|
|
51
|
+
backgroundColour: "rgba(0, 0, 0, 0.3)",
|
|
52
|
+
borderColour: "var(--theme-accent)",
|
|
53
|
+
radiusLeft: 8,
|
|
54
|
+
radiusRight: 4,
|
|
55
|
+
borderLeft: 6,
|
|
56
|
+
borderTop: 1,
|
|
57
|
+
borderRight: 1,
|
|
58
|
+
borderBottom: 1,
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
render: (args) => ({
|
|
62
|
+
components: { AlertMaskCore },
|
|
63
|
+
setup() {
|
|
64
|
+
return { args };
|
|
65
|
+
},
|
|
66
|
+
template: `
|
|
67
|
+
<AlertMaskCore v-bind="args">
|
|
68
|
+
<p style="margin: 0; padding: 1.6rem; color: white;">Custom accent-bar config, matching AlertMaskedContent's default shape</p>
|
|
69
|
+
</AlertMaskCore>
|
|
70
|
+
`,
|
|
71
|
+
}),
|
|
72
|
+
parameters: {
|
|
73
|
+
docs: {
|
|
74
|
+
description: {
|
|
75
|
+
story: "The accent-bar shape used by AlertMaskedContent: thick left radius/border, thin elsewhere.",
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
|
2
2
|
import { mountSuspended } from "@nuxt/test-utils/runtime";
|
|
3
3
|
import AlertMaskCore from "../AlertMaskCore.vue";
|
|
4
|
-
import type { AlertMaskConfig } from "
|
|
4
|
+
import type { AlertMaskConfig } from "../../../../types/components/alert-mask-core.d";
|
|
5
5
|
|
|
6
6
|
// Type interface for AlertMaskCore component instance
|
|
7
7
|
interface AlertMaskCoreInstance {
|
|
@@ -193,10 +193,10 @@ describe("AlertMaskCore", () => {
|
|
|
193
193
|
const contentEl = wrapper.find(".alert-mask-content");
|
|
194
194
|
const style = (contentEl.element as HTMLElement).style;
|
|
195
195
|
|
|
196
|
-
expect(style.getPropertyValue("--
|
|
197
|
-
expect(style.getPropertyValue("--
|
|
198
|
-
expect(style.getPropertyValue("--
|
|
199
|
-
expect(style.getPropertyValue("--
|
|
196
|
+
expect(style.getPropertyValue("--_inset-inline-start")).toBe("15px");
|
|
197
|
+
expect(style.getPropertyValue("--_inset-block-start")).toBe("20px");
|
|
198
|
+
expect(style.getPropertyValue("--_inset-inline-end")).toBe("25px");
|
|
199
|
+
expect(style.getPropertyValue("--_inset-block-end")).toBe("30px");
|
|
200
200
|
});
|
|
201
201
|
|
|
202
202
|
it("handles zero border values correctly", async () => {
|
|
@@ -214,10 +214,10 @@ describe("AlertMaskCore", () => {
|
|
|
214
214
|
const contentEl = wrapper.find(".alert-mask-content");
|
|
215
215
|
const style = (contentEl.element as HTMLElement).style;
|
|
216
216
|
|
|
217
|
-
expect(style.getPropertyValue("--
|
|
218
|
-
expect(style.getPropertyValue("--
|
|
219
|
-
expect(style.getPropertyValue("--
|
|
220
|
-
expect(style.getPropertyValue("--
|
|
217
|
+
expect(style.getPropertyValue("--_inset-inline-start")).toBe("0px");
|
|
218
|
+
expect(style.getPropertyValue("--_inset-block-start")).toBe("0px");
|
|
219
|
+
expect(style.getPropertyValue("--_inset-inline-end")).toBe("0px");
|
|
220
|
+
expect(style.getPropertyValue("--_inset-block-end")).toBe("0px");
|
|
221
221
|
});
|
|
222
222
|
|
|
223
223
|
it("sets up ResizeObserver on mount", async () => {
|
|
@@ -271,7 +271,7 @@ describe("AlertMaskCore", () => {
|
|
|
271
271
|
|
|
272
272
|
const svg = wrapper.find(".alert-mask-decorator");
|
|
273
273
|
const style = (svg.element as HTMLElement).style;
|
|
274
|
-
expect(style.getPropertyValue("--
|
|
274
|
+
expect(style.getPropertyValue("--_height")).toBe("150px");
|
|
275
275
|
});
|
|
276
276
|
|
|
277
277
|
it("handles empty configuration object", async () => {
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# ContainerGlow — Consumer Styling Guide
|
|
2
|
+
|
|
3
|
+
## Public CSS custom properties
|
|
4
|
+
|
|
5
|
+
These are static, per-card visual tokens — override them with a `style` attribute or from a
|
|
6
|
+
consuming page's own stylesheet:
|
|
7
|
+
|
|
8
|
+
| Token | Default | Description |
|
|
9
|
+
|---|---|---|
|
|
10
|
+
| `--container-glow-background` | `white` | Card background colour. |
|
|
11
|
+
| `--container-glow-padding` | `2rem` | Card inner padding. |
|
|
12
|
+
| `--container-glow-aspect-ratio` | `330 / 400` | Card aspect ratio. |
|
|
13
|
+
| `--container-glow-border-radius` | `12px` | Card and glow-effect corner radius (shared by the card and every glow layer). |
|
|
14
|
+
| `--container-glow-min-width` | `280px` | Card minimum width. |
|
|
15
|
+
| `--container-glow-max-width` | `280px` | Card maximum width. |
|
|
16
|
+
| `--container-glow-content-gap` | `0.25rem` | Gap between a card's own slotted children. |
|
|
17
|
+
| `--container-glow-highlight-colour` | `hsl(280 10% 50% / 1)` | Tint of the thin proximity-tracking ring drawn under the coloured glow. |
|
|
18
|
+
| `--container-glow-brightness` | `1.5` | Brightness multiplier applied to the coloured glow layer. |
|
|
19
|
+
| `--container-glow-transition-duration` | `1s` | Fade duration when the glow's opacity changes (also disabled under `prefers-reduced-motion: reduce`). |
|
|
20
|
+
| `--container-glow-gradient` | 5-stop conic rainbow gradient | The glow's colour gradient. Override with any valid `background` value (a `conic-gradient(...)`, a flat colour, etc). |
|
|
21
|
+
|
|
22
|
+
```vue
|
|
23
|
+
<ContainerGlow
|
|
24
|
+
style="--container-glow-background: #111; --container-glow-border-radius: 4px; --container-glow-gradient: conic-gradient(from 180deg, #22d3ee, #a855f7, #22d3ee);"
|
|
25
|
+
>
|
|
26
|
+
<template #cta>
|
|
27
|
+
<p>Custom-coloured glow card</p>
|
|
28
|
+
</template>
|
|
29
|
+
</ContainerGlow>
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## The `config` prop (layout and interaction behaviour)
|
|
33
|
+
|
|
34
|
+
Proximity distance, glow spread/blur, wrapper gap, wrapper direction, and the inactive-state
|
|
35
|
+
opacity are **not** CSS tokens — they're computed per-pointer-move in JavaScript and applied as
|
|
36
|
+
private custom properties, so they're driven entirely by the `config` prop instead
|
|
37
|
+
(`ContainerGlowConfig`, importable from `srcdev-nuxt-components`):
|
|
38
|
+
|
|
39
|
+
| Field | Type | Default | Description |
|
|
40
|
+
|---|---|---|---|
|
|
41
|
+
| `proximity` | `number` | `40` | Pointer distance (px) at which a card starts glowing. |
|
|
42
|
+
| `spread` | `number` | `80` | Angular spread of the glow (degrees). |
|
|
43
|
+
| `blur` | `number` | `20` | Blur applied to the glow layer (px). |
|
|
44
|
+
| `gap` | `number` | `32` | Gap between cards in the wrapper (px). |
|
|
45
|
+
| `vertical` | `boolean` | `false` | Stack cards vertically instead of horizontally. |
|
|
46
|
+
| `inactiveOpacity` | `number` | `0` | Glow opacity when the pointer isn't nearby. |
|
|
47
|
+
|
|
48
|
+
All fields are optional — pass only the ones you want to change:
|
|
49
|
+
|
|
50
|
+
```vue
|
|
51
|
+
<ContainerGlow :config="{ blur: 40, vertical: true }">
|
|
52
|
+
<template #one><p>Card one</p></template>
|
|
53
|
+
<template #two><p>Card two</p></template>
|
|
54
|
+
</ContainerGlow>
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Named dynamic slots
|
|
58
|
+
|
|
59
|
+
Each named slot renders as one glow card — the consumer controls the slot names, there's no
|
|
60
|
+
`itemCount`-style prop:
|
|
61
|
+
|
|
62
|
+
```vue
|
|
63
|
+
<ContainerGlow>
|
|
64
|
+
<template #pricing><p>Starter</p></template>
|
|
65
|
+
<template #featured><p>Pro</p></template>
|
|
66
|
+
</ContainerGlow>
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Motion
|
|
70
|
+
|
|
71
|
+
The glow's opacity fade (`--container-glow-transition-duration`) is disabled under
|
|
72
|
+
`prefers-reduced-motion: reduce`, so proximity changes are instant rather than animated.
|
|
73
|
+
|
|
74
|
+
## Class passthrough
|
|
75
|
+
|
|
76
|
+
Use `styleClassPassthrough` to add classes to the root `.container-glow-wrapper` element.
|
|
77
|
+
|
|
78
|
+
```vue
|
|
79
|
+
<ContainerGlow style-class-passthrough="my-container-glow">...</ContainerGlow>
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Internal (non-overridable) custom properties
|
|
83
|
+
|
|
84
|
+
`--_start`, `--_opacity-active`, `--_gap`, `--_blur`, `--_spread`, `--_direction`, and `--_gradient`
|
|
85
|
+
are internal plumbing driven by pointer events and the `config` prop — use `config` (for
|
|
86
|
+
gap/blur/spread/direction/opacity) or the public tokens above (for colour/geometry) instead.
|