srcdev-nuxt-components 9.1.49 → 9.1.51
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/settings.json +2 -4
- package/.claude/settings.local.json +22 -2
- package/.claude/skills/components/card-core.md +205 -0
- package/.claude/skills/components/display-dialog.md +128 -0
- package/.claude/skills/components/page-hero-highlights.md +1 -1
- package/.claude/skills/components/page-row.md +157 -0
- package/.claude/skills/components/services-card-grid.md +4 -4
- package/.claude/skills/components/services-section-grid.md +4 -4
- package/.claude/skills/components/tab-navigation.md +222 -0
- package/.claude/skills/composable-dialog-controls.md +55 -43
- package/.claude/skills/index.md +5 -2
- package/app/components/01.atoms/card/CONSUMER-STYLING.md +175 -0
- package/app/components/01.atoms/card/CardCore.vue +48 -21
- package/app/components/01.atoms/display-dialog/CONSUMER-STYLING.md +163 -0
- package/app/components/01.atoms/display-dialog/DisplayDialog.vue +277 -0
- package/app/components/01.atoms/display-dialog/stories/DisplayDialog.stories.ts +177 -0
- package/app/components/01.atoms/display-dialog/tests/DisplayDialog.spec.ts +264 -0
- package/app/components/01.atoms/display-dialog/tests/__snapshots__/DisplayDialog.spec.ts.snap +18 -0
- package/app/components/01.atoms/page-row/CONSUMER-STYLING.md +90 -0
- package/app/components/01.atoms/page-row/PageRow.vue +115 -0
- package/app/components/01.atoms/page-row/stories/PageRow.stories.ts +311 -0
- package/app/components/01.atoms/page-row/tests/PageRow.spec.ts +191 -0
- package/app/components/02.molecules/navigation/tab-navigation/CONSUMER-STYLING.md +145 -0
- package/app/components/02.molecules/navigation/tab-navigation/TabNavigation.vue +20 -9
- package/app/components/02.molecules/navigation/tab-navigation/tests/__snapshots__/TabNavigation.spec.ts.snap +12 -6
- package/app/components/{forms/ui → 05.forms/form-field}/FormField.vue +12 -19
- package/app/components/{forms/ui → 05.forms/form-wrapper}/FormWrapper.vue +6 -6
- package/app/components/{forms → 05.forms}/input-button/InputButtonCore.vue +2 -0
- package/app/components/{forms → 05.forms}/input-button/stories/InputButtonCore.stories.ts +1 -1
- package/app/components/{forms → 05.forms}/input-text/InputTextCore.vue +73 -73
- package/app/components/{forms → 05.forms}/input-text/variants/InputTextAsNumberWithLabel.vue +29 -29
- package/app/components/carousels/CarouselBasic.vue +99 -99
- package/app/components/carousels/CarouselInfinite.vue +150 -150
- package/app/components/deep-expanding-menu/DeepExpandingMenu.vue +111 -111
- package/app/components/responsive-header/ResponsiveHeader.vue +250 -282
- package/app/components/test-storybook/TestStorybook.vue +16 -16
- package/app/composables/tests/useDialogControls.spec.ts +34 -64
- package/app/composables/useDialogControls.ts +19 -33
- package/app/composables/useFormControl.ts +0 -2
- package/app/layouts/default.vue +9 -7
- package/app/pages/auto-grid.vue +37 -20
- package/app/pages/banner-video.vue +2 -2
- package/app/pages/forms/examples/buttons/index.vue +189 -215
- package/app/pages/forms/examples/material/text-fields.vue +2 -2
- package/app/pages/grid-stack.vue +10 -10
- package/app/pages/index.vue +20 -20
- package/app/pages/samaritan.vue +4 -4
- package/app/pages/typography/hero-text.vue +6 -6
- package/app/pages/typography/index.vue +4 -4
- package/app/pages/typography/page-body.vue +4 -4
- package/app/pages/typography/page-heading.vue +4 -4
- package/app/pages/typography/page-link.vue +4 -4
- package/app/pages/ui/accordian.vue +4 -4
- package/app/pages/ui/anchor-scroll-tab-navigation.vue +77 -66
- package/app/pages/ui/anchor-scroll.vue +94 -70
- package/app/pages/ui/animated-svg-text.vue +4 -4
- package/app/pages/ui/block-decorators.vue +11 -11
- package/app/pages/ui/card-core.vue +9 -9
- package/app/pages/ui/carousel-basic.vue +4 -4
- package/app/pages/ui/carousel-flip.vue +2 -2
- package/app/pages/ui/carousel-infinite.vue +4 -4
- package/app/pages/ui/clipped-panels.vue +10 -10
- package/app/pages/ui/contact-section.vue +4 -4
- package/app/pages/ui/container-glow.vue +2 -3
- package/app/pages/ui/deep-expanding-menu.vue +138 -0
- package/app/pages/ui/display-avatar.vue +2 -2
- package/app/pages/ui/display-banner.vue +2 -2
- package/app/pages/ui/display-chip.vue +32 -25
- package/app/pages/ui/display-details.vue +6 -10
- package/app/pages/ui/display-dialog.vue +96 -131
- package/app/pages/ui/display-pill.vue +27 -33
- package/app/pages/ui/display-prompt.vue +4 -4
- package/app/pages/ui/display-toast.vue +2 -2
- package/app/pages/ui/expanding-panel.vue +12 -16
- package/app/pages/ui/glowing-border.vue +12 -12
- package/app/pages/ui/layout-grid-a.vue +6 -6
- package/app/pages/ui/layout-grid-b.vue +4 -4
- package/app/pages/ui/magnetic-navigation.vue +6 -6
- package/app/pages/ui/marquee-scroller.vue +2 -2
- package/app/pages/ui/mask-element.vue +2 -2
- package/app/pages/ui/masonry-columns.vue +4 -4
- package/app/pages/ui/masonry-grid-ordered-experiment.vue +4 -4
- package/app/pages/ui/masonry-grid-ordered.vue +4 -4
- package/app/pages/ui/masonry-grid-sorted.vue +4 -4
- package/app/pages/ui/masonry-grid.vue +4 -4
- package/app/pages/ui/navigation/navigation-horizontal.vue +12 -12
- package/app/pages/ui/navigation/tab-navigation.vue +493 -0
- package/app/pages/ui/page-row.vue +127 -0
- package/app/pages/ui/price-list.vue +4 -4
- package/app/pages/ui/profile-section.vue +4 -4
- package/app/pages/ui/qr-code/[componentName].vue +6 -6
- package/app/pages/ui/rotating-carousel.vue +16 -16
- package/app/pages/ui/scroll-reveal-image.vue +20 -20
- package/app/pages/ui/section-parallax.vue +7 -7
- package/app/pages/ui/services/colour-finder.vue +4 -4
- package/app/pages/ui/services/services-cards.vue +4 -4
- package/app/pages/ui/services/services-section/[slug].vue +4 -4
- package/app/pages/ui/services/services-sections-compact.vue +6 -6
- package/app/pages/ui/settings.vue +10 -10
- package/app/pages/ui/simple-grid.vue +2 -2
- package/app/pages/ui/slider-gallery.vue +5 -5
- package/app/pages/ui/tabs-y.vue +2 -3
- package/app/pages/ui/tabs.vue +6 -9
- package/app/pages/ui/tooltips.vue +9 -9
- package/app/pages/ui/wipe-away-vertical.vue +14 -14
- package/package.json +1 -1
- package/.claude/skills/components/layout-row.md +0 -239
- package/app/components/display-dialog/DisplayDialogCore.vue +0 -276
- package/app/components/display-dialog/variants/DisplayDialogConfirm.vue +0 -47
- package/app/components/display-dialog/variants/DisplayDialogScrollableContent.vue +0 -51
- package/app/components/forms/c12/utils.ts +0 -14
- package/app/components/layout-row/LayoutRow.vue +0 -171
- package/app/components/layout-row/stories/LayoutRow.stories.ts +0 -528
- package/app/pages/ui/layout-row.vue +0 -139
- /package/app/components/{forms → 05.forms}/form-errors/InputError.vue +0 -0
- /package/app/components/{forms → 05.forms}/form-errors/tests/InputError.spec.ts +0 -0
- /package/app/components/{forms → 05.forms}/form-fieldset/FormFieldset.vue +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/combo-icons-secondary-chromium-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/combo-icons-secondary-firefox-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/combo-icons-secondary-webkit-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/combo-icons-tertiary-chromium-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/combo-icons-tertiary-firefox-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/combo-icons-tertiary-webkit-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/combo-primary-pending-chromium-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/combo-primary-pending-firefox-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/combo-primary-pending-webkit-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/combo-secondary-pill-chromium-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/combo-secondary-pill-firefox-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/combo-secondary-pill-webkit-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/combo-tertiary-readonly-chromium-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/combo-tertiary-readonly-firefox-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/combo-tertiary-readonly-webkit-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/default-chromium-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/default-firefox-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/default-theme-default-chromium-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/default-theme-default-firefox-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/default-theme-default-webkit-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/default-theme-error-chromium-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/default-theme-error-firefox-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/default-theme-error-webkit-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/default-theme-success-chromium-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/default-theme-success-firefox-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/default-theme-success-webkit-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/default-theme-warning-chromium-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/default-theme-warning-firefox-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/default-theme-warning-webkit-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/default-variant-primary-chromium-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/default-variant-primary-firefox-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/default-variant-primary-webkit-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/default-variant-secondary-chromium-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/default-variant-secondary-firefox-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/default-variant-secondary-webkit-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/default-variant-tertiary-chromium-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/default-variant-tertiary-firefox-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/default-variant-tertiary-webkit-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/default-webkit-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/nuxt-icon-only-component-chromium-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/nuxt-icon-only-component-firefox-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/nuxt-icon-only-component-webkit-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/state-pending-chromium-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/state-pending-firefox-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/state-pending-webkit-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/state-pill-chromium-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/state-pill-firefox-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/state-pill-webkit-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/state-readonly-chromium-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/state-readonly-firefox-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/state-readonly-webkit-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/with-both-nuxt-icon-components-chromium-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/with-both-nuxt-icon-components-firefox-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/with-both-nuxt-icon-components-webkit-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/tests/InputButtonCore.spec.ts +0 -0
- /package/app/components/{forms → 05.forms}/input-button/tests/__snapshots__/InputButtonCore.spec.ts.snap +0 -0
- /package/app/components/{forms → 05.forms}/input-checkbox/MultipleCheckboxes.vue +0 -0
- /package/app/components/{forms → 05.forms}/input-checkbox/SingleCheckbox.vue +0 -0
- /package/app/components/{forms → 05.forms}/input-checkbox/tests/MultipleCheckboxes.spec.ts +0 -0
- /package/app/components/{forms → 05.forms}/input-checkbox/tests/data/tags.json +0 -0
- /package/app/components/{forms → 05.forms}/input-checkbox-radio/InputCheckboxRadioButton.vue +0 -0
- /package/app/components/{forms → 05.forms}/input-checkbox-radio/InputCheckboxRadioCore.vue +0 -0
- /package/app/components/{forms → 05.forms}/input-checkbox-radio/InputCheckboxRadioWithLabel.vue +0 -0
- /package/app/components/{forms → 05.forms}/input-checkbox-radio/tests/InputCheckboxRadioCore.spec.ts +0 -0
- /package/app/components/{forms → 05.forms}/input-copy/InputCopyCore.vue +0 -0
- /package/app/components/{forms → 05.forms}/input-copy/stories/InputCopyCore.stories.ts +0 -0
- /package/app/components/{forms → 05.forms}/input-copy/tests/InputCopyCore.spec.ts +0 -0
- /package/app/components/{forms → 05.forms}/input-copy/tests/__snapshots__/InputCopyCore.spec.ts.snap +0 -0
- /package/app/components/{forms → 05.forms}/input-description/InputDescription.vue +0 -0
- /package/app/components/{forms → 05.forms}/input-description/tests/InputDescription.spec.ts +0 -0
- /package/app/components/{forms → 05.forms}/input-label/InputLabel.vue +0 -0
- /package/app/components/{forms → 05.forms}/input-label/tests/InputLabel.spec.ts +0 -0
- /package/app/components/{forms → 05.forms}/input-number/InputNumberCore.vue +0 -0
- /package/app/components/{forms → 05.forms}/input-number/variants/InputNumberDefault.vue +0 -0
- /package/app/components/{forms → 05.forms}/input-radio/MultipleRadiobuttons.vue +0 -0
- /package/app/components/{forms → 05.forms}/input-radio/tests/MultipleRadioButtons.spec.ts +0 -0
- /package/app/components/{forms → 05.forms}/input-radio/tests/data/tags.json +0 -0
- /package/app/components/{forms → 05.forms}/input-range/InputRangeCore.vue +0 -0
- /package/app/components/{forms → 05.forms}/input-range/variants/InputRangeDefault.vue +0 -0
- /package/app/components/{forms → 05.forms}/input-range-fancy/InputRangeFancyCore.vue +0 -0
- /package/app/components/{forms → 05.forms}/input-range-fancy/InputRangeFancyWithLabel.vue +0 -0
- /package/app/components/{forms → 05.forms}/input-select/InputSelectCore.vue +0 -0
- /package/app/components/{forms → 05.forms}/input-select/variants/InputSelectWithLabel.vue +0 -0
- /package/app/components/{forms → 05.forms}/input-text/stories/InputPasswordWithLabel.stories.ts +0 -0
- /package/app/components/{forms → 05.forms}/input-text/stories/InputTextAsNumberWithLabel.stories.ts +0 -0
- /package/app/components/{forms → 05.forms}/input-text/stories/InputTextCore.stories.ts +0 -0
- /package/app/components/{forms → 05.forms}/input-text/stories/InputTextWithLabel.stories.ts +0 -0
- /package/app/components/{forms → 05.forms}/input-text/variants/InputPasswordWithLabel.vue +0 -0
- /package/app/components/{forms → 05.forms}/input-text/variants/InputTextWithLabel.vue +0 -0
- /package/app/components/{forms → 05.forms}/input-textarea/InputTextareaCore.vue +0 -0
- /package/app/components/{forms → 05.forms}/input-textarea/stories/InputTextareaCore.stories.ts +0 -0
- /package/app/components/{forms → 05.forms}/input-textarea/stories/InputTextareaWithLabel.stories.ts +0 -0
- /package/app/components/{forms → 05.forms}/input-textarea/variants/InputTextareaWithLabel.vue +0 -0
- /package/app/components/{forms → 05.forms}/pending-effect/PendingEffect.vue +0 -0
- /package/app/components/{forms → 05.forms}/toggle-switch/ToggleSwitchCore.vue +0 -0
- /package/app/components/{forms → 05.forms}/toggle-switch/stories/ToggleSwitchCore.stories.ts +0 -0
- /package/app/components/{forms → 05.forms}/toggle-switch/stories/ToggleSwitchWithLabel.stories.ts +0 -0
- /package/app/components/{forms → 05.forms}/toggle-switch/stories/ToggleSwitchWithLabelInline.stories.ts +0 -0
- /package/app/components/{forms → 05.forms}/toggle-switch/variants/ToggleSwitchWithLabel.vue +0 -0
- /package/app/components/{forms → 05.forms}/toggle-switch/variants/ToggleSwitchWithLabelInline.vue +0 -0
- /package/app/components/{forms → 05.forms}/triple-toggle-switch/TripleToggleSwitchCore.vue +0 -0
- /package/app/{components/forms/c12/prop-validators/index.ts → utils/prop-validators.ts} +0 -0
package/.claude/settings.json
CHANGED
|
@@ -27,9 +27,7 @@
|
|
|
27
27
|
"Bash(git ls-tree *)",
|
|
28
28
|
"Bash(node -p \"require\\('./package.json'\\).version\")",
|
|
29
29
|
"Bash(git status *)",
|
|
30
|
-
"Bash(
|
|
31
|
-
|
|
32
|
-
],
|
|
33
|
-
"additionalDirectories": []
|
|
30
|
+
"Bash(xargs ls -1)"
|
|
31
|
+
]
|
|
34
32
|
}
|
|
35
33
|
}
|
|
@@ -1,4 +1,17 @@
|
|
|
1
1
|
{
|
|
2
|
+
"hooks": {
|
|
3
|
+
"PostToolUse": [
|
|
4
|
+
{
|
|
5
|
+
"matcher": "Bash",
|
|
6
|
+
"hooks": [
|
|
7
|
+
{
|
|
8
|
+
"type": "command",
|
|
9
|
+
"command": "grep -q '/Users/' .claude/settings.json 2>/dev/null && { echo 'settings.json contains absolute paths — move them to settings.local.json' >&2; exit 1; } || exit 0"
|
|
10
|
+
}
|
|
11
|
+
]
|
|
12
|
+
}
|
|
13
|
+
]
|
|
14
|
+
},
|
|
2
15
|
"permissions": {
|
|
3
16
|
"allow": [
|
|
4
17
|
"WebSearch",
|
|
@@ -29,7 +42,13 @@
|
|
|
29
42
|
"Bash(SRCDEV_STANDALONE=true npx vitest --run app/composables/tests/useCancellableTimer app/components/02.molecules/samaritan-prompt/tests/SamaritanPromptMixed)",
|
|
30
43
|
"Bash(SRCDEV_STANDALONE=true npx vitest --run app/components/02.molecules/samaritan-prompt/tests/SamaritanPromptMixed)",
|
|
31
44
|
"Bash(SRCDEV_STANDALONE=true npx vitest --run app/composables/tests/useCancellableTimer)",
|
|
32
|
-
"Bash(SRCDEV_STANDALONE=true npm run test:run -- --reporter=verbose)"
|
|
45
|
+
"Bash(SRCDEV_STANDALONE=true npm run test:run -- --reporter=verbose)",
|
|
46
|
+
"Bash(cp /Users/simoncornforth/websites/nuxt-components/.claude/skills/components/data-grid.md /Users/simoncornforth/websites/nuxt-components/.claude/skills/components/auto-grid.md)",
|
|
47
|
+
"Bash(rm /Users/simoncornforth/websites/nuxt-components/.claude/skills/components/data-grid.md)",
|
|
48
|
+
"Bash(git -C /Users/simoncornforth/websites/nuxt-components log --oneline -10)",
|
|
49
|
+
"Bash(git -C /Users/simoncornforth/websites/nuxt-components log 5a80426..HEAD --oneline)",
|
|
50
|
+
"Bash(git -C /Users/simoncornforth/websites/nuxt-components show 71c276e --stat)",
|
|
51
|
+
"Bash(git -C /Users/simoncornforth/websites/nuxt-components show a1e1641 --stat)"
|
|
33
52
|
],
|
|
34
53
|
"additionalDirectories": [
|
|
35
54
|
"/Users/simoncornforth/websites/nuxt-components/app/components/01.atoms/content-wrappers/content-width",
|
|
@@ -40,7 +59,8 @@
|
|
|
40
59
|
"/Users/simoncornforth/websites/nuxt-components/app/assets/styles/extends-layer",
|
|
41
60
|
"/Users/simoncornforth/websites/nuxt-components/app/components/01.atoms",
|
|
42
61
|
"/private/tmp",
|
|
43
|
-
"/Users/simoncornforth/websites/nuxt-components/app/components/01.atoms/banner-video"
|
|
62
|
+
"/Users/simoncornforth/websites/nuxt-components/app/components/01.atoms/banner-video",
|
|
63
|
+
"/Users/simoncornforth/websites/nuxt-components/app/components/01.atoms/page-row"
|
|
44
64
|
]
|
|
45
65
|
}
|
|
46
66
|
}
|
|
@@ -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.
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
# DisplayDialog
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
`DisplayDialog` is a native `<dialog>`-based overlay with header, scrollable content, and footer
|
|
6
|
+
action slots. Five variants cover the common dialog patterns. Pair with `useDialogControls` for
|
|
7
|
+
open/close state management.
|
|
8
|
+
|
|
9
|
+
**Location**: `app/components/01.atoms/display-dialog/DisplayDialog.vue`
|
|
10
|
+
|
|
11
|
+
## Props
|
|
12
|
+
|
|
13
|
+
| Prop | Type | Default | Notes |
|
|
14
|
+
|---|---|---|---|
|
|
15
|
+
| `dataDialogId` | `string` | — | **Required.** Unique identifier rendered as `data-dialog-id` attribute. |
|
|
16
|
+
| `variant` | `'dialog' \| 'modal' \| 'confirm' \| 'alert' \| 'fullscreen'` | `'dialog'` | Controls panel sizing and ARIA role. |
|
|
17
|
+
| `v-model` | `boolean` | — | Controls open/closed state. |
|
|
18
|
+
| `allowContentScroll` | `boolean` | `false` | Enables independent scroll on `.dialog-content`. |
|
|
19
|
+
| `lockViewport` | `boolean` | `true` | Adds/removes `lock` class on `<body>` on mount/close. |
|
|
20
|
+
| `justifyDialog` | `'start' \| 'center' \| 'end'` | `'center'` | Horizontal position of panel within overlay. |
|
|
21
|
+
| `alignDialog` | `'start' \| 'center' \| 'end'` | `'center'` | Vertical position of panel within overlay. |
|
|
22
|
+
| `styleClassPassthrough` | `string \| string[]` | `[]` | Extra classes applied to the root `<dialog>` element. |
|
|
23
|
+
|
|
24
|
+
## Slots
|
|
25
|
+
|
|
26
|
+
| Slot | Renders in |
|
|
27
|
+
|---|---|
|
|
28
|
+
| `#dialogTitle` | `.col-left` in the header (hidden when slot is empty) |
|
|
29
|
+
| `#dialogContent` | `.dialog-content` (hidden when slot is empty) |
|
|
30
|
+
| `#actionButtonLeft` | Left side of `.footer` |
|
|
31
|
+
| `#actionButtonRight` | Right side of `.footer` |
|
|
32
|
+
|
|
33
|
+
`.footer` is omitted entirely when neither action button slot is provided.
|
|
34
|
+
|
|
35
|
+
## Variants
|
|
36
|
+
|
|
37
|
+
| Variant | Panel size | ARIA role | Dismiss on Escape/outside-click |
|
|
38
|
+
|---|---|---|---|
|
|
39
|
+
| `dialog` | `70dvh × min(75%, 72rem)` | `dialog` | Yes |
|
|
40
|
+
| `modal` | Content-sized | `dialog` | Yes |
|
|
41
|
+
| `confirm` | Content-sized | `dialog` | Yes |
|
|
42
|
+
| `alert` | `min(90%, 48rem)` | `alertdialog` | **No** — requires explicit action |
|
|
43
|
+
| `fullscreen` | `100% × 100%` | `dialog` | Yes |
|
|
44
|
+
|
|
45
|
+
## Basic usage
|
|
46
|
+
|
|
47
|
+
```vue
|
|
48
|
+
<script setup lang="ts">
|
|
49
|
+
const { dialogsConfig, openDialog, closeDialog } = useDialogControls({
|
|
50
|
+
logout: {
|
|
51
|
+
onConfirm: () => performLogout(),
|
|
52
|
+
onCancel: () => {},
|
|
53
|
+
},
|
|
54
|
+
})
|
|
55
|
+
</script>
|
|
56
|
+
|
|
57
|
+
<template>
|
|
58
|
+
<button @click="openDialog('logout')">Log out</button>
|
|
59
|
+
|
|
60
|
+
<DisplayDialog
|
|
61
|
+
v-if="dialogsConfig['logout']"
|
|
62
|
+
v-model="dialogsConfig['logout']"
|
|
63
|
+
variant="confirm"
|
|
64
|
+
data-dialog-id="logout"
|
|
65
|
+
>
|
|
66
|
+
<template #dialogTitle>
|
|
67
|
+
<p>Confirm logout?</p>
|
|
68
|
+
</template>
|
|
69
|
+
<template #dialogContent>
|
|
70
|
+
<p>Are you sure you wish to log out?</p>
|
|
71
|
+
</template>
|
|
72
|
+
<template #actionButtonLeft>
|
|
73
|
+
<button @click="closeDialog('logout', 'cancel')">Cancel</button>
|
|
74
|
+
</template>
|
|
75
|
+
<template #actionButtonRight>
|
|
76
|
+
<button @click="closeDialog('logout', 'confirm')">Log out</button>
|
|
77
|
+
</template>
|
|
78
|
+
</DisplayDialog>
|
|
79
|
+
</template>
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Alert variant
|
|
83
|
+
|
|
84
|
+
Use `variant="alert"` for destructive or attention-critical actions. Escape and outside-click
|
|
85
|
+
are both disabled — the user must act via the footer buttons.
|
|
86
|
+
|
|
87
|
+
```vue
|
|
88
|
+
<DisplayDialog
|
|
89
|
+
v-if="dialogsConfig['deleteAccount']"
|
|
90
|
+
v-model="dialogsConfig['deleteAccount']"
|
|
91
|
+
variant="alert"
|
|
92
|
+
data-dialog-id="deleteAccount"
|
|
93
|
+
>
|
|
94
|
+
<template #dialogTitle><p>Delete account?</p></template>
|
|
95
|
+
<template #dialogContent>
|
|
96
|
+
<p>This action is permanent and cannot be undone.</p>
|
|
97
|
+
</template>
|
|
98
|
+
<template #actionButtonLeft>
|
|
99
|
+
<button @click="closeDialog('deleteAccount', 'cancel')">Cancel</button>
|
|
100
|
+
</template>
|
|
101
|
+
<template #actionButtonRight>
|
|
102
|
+
<button @click="closeDialog('deleteAccount', 'confirm')">Delete account</button>
|
|
103
|
+
</template>
|
|
104
|
+
</DisplayDialog>
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## CSS token API
|
|
108
|
+
|
|
109
|
+
See `CONSUMER-STYLING.md` in the component folder for the full token reference. Prefer global
|
|
110
|
+
CSS over per-instance overrides — dialogs are site-wide UI:
|
|
111
|
+
|
|
112
|
+
```css
|
|
113
|
+
/* assets/styles/setup/07.components/display-dialog.css */
|
|
114
|
+
:root {
|
|
115
|
+
--display-dialog-inner-border-radius: 1.2rem;
|
|
116
|
+
--display-dialog-inner-background: var(--brand-surface);
|
|
117
|
+
--display-dialog-inner-border: 0.1rem solid var(--brand-border);
|
|
118
|
+
--display-dialog-transition-duration: 250ms;
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## Notes
|
|
123
|
+
|
|
124
|
+
- Always use `v-if="dialogsConfig['id']"` (not `v-show`) — `DisplayDialog` runs body-lock logic
|
|
125
|
+
in `onMounted`, which must only fire when the dialog actually opens.
|
|
126
|
+
- `dataDialogId` is required; it is used as the `data-dialog-id` DOM attribute and as the key
|
|
127
|
+
for `useDialogControls`.
|
|
128
|
+
- Related: `composable-dialog-controls.md`
|
|
@@ -61,7 +61,7 @@ Each slot accepts any content, but these library components are natural fits:
|
|
|
61
61
|
| `#header` | `HeroText` | Heading with accent text, icon, and configurable size — wires `headingId` for `aria-labelledby` |
|
|
62
62
|
| `#highlights` | `ServicesCard` (×n) | Portrait cards with image, title, description, and CTA slot |
|
|
63
63
|
| `#highlights` | `LayoutGridByCols` wrapping cards | When you want a responsive column grid rather than a single row of cards |
|
|
64
|
-
| `#content` | Any content component | Below the straddle — safe to use `
|
|
64
|
+
| `#content` | Any content component | Below the straddle — safe to use `PageRow`, `ServicesSection`, etc. |
|
|
65
65
|
|
|
66
66
|
Example with `HeroText` in the header slot:
|
|
67
67
|
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
# PageRow Component
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
`PageRow` is a page layout primitive built on CSS Grid named lines. Each `PageRow` is
|
|
6
|
+
simultaneously a CSS grid container (for its children) and a grid item (when nested inside another
|
|
7
|
+
`PageRow`). Compose full-width backgrounds with constrained inner content by nesting PageRows —
|
|
8
|
+
no extra wrapper divs needed.
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Props reference
|
|
13
|
+
|
|
14
|
+
> **Hyphenation rule**: Vue's ESLint config enforces `vue/attribute-hyphenation`. Always write
|
|
15
|
+
> camelCase prop names hyphenated in templates: `:style-class-passthrough`.
|
|
16
|
+
|
|
17
|
+
| Prop (template form) | Type | Default | Notes |
|
|
18
|
+
|---|---|---|---|
|
|
19
|
+
| `tag` | `"div" \| "section" \| "article" \| "header" \| "footer" \| "main" \| "nav"` | `"div"` | Root element tag |
|
|
20
|
+
| `variant` | `"full" \| "popout" \| "content" \| "inset-content"` | `"content"` | Grid column track this element occupies when nested in another PageRow |
|
|
21
|
+
| `align` | `"start" \| "end"` | — | Bleeds one side to the viewport edge while respecting the variant boundary on the other |
|
|
22
|
+
| `id` | `string` | — | `id` attribute on the root element |
|
|
23
|
+
| `:style-class-passthrough` | `string \| string[]` | `[]` | Extra classes on the root element |
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## Track widths
|
|
28
|
+
|
|
29
|
+
| Variant | Max width | Typical use |
|
|
30
|
+
|---|---|---|
|
|
31
|
+
| `full` | 100vw (1fr gutters) | Full-bleed backgrounds, hero sections |
|
|
32
|
+
| `popout` | 1400px | Imagery, callouts that break the text column |
|
|
33
|
+
| `content` | 1064px | Body text, standard page content (default) |
|
|
34
|
+
| `inset-content` | 840px | Focused reading, narrower prose or forms |
|
|
35
|
+
|
|
36
|
+
All widths are overridable via CSS tokens — see [Consumer styling](#consumer-css-token-api).
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## Core composition pattern
|
|
41
|
+
|
|
42
|
+
Nest a `variant="full"` outer PageRow (for backgrounds / borders) with inner PageRows at narrower
|
|
43
|
+
variants. Direct non-PageRow children inherit the outer row's variant as their default grid column.
|
|
44
|
+
|
|
45
|
+
```vue
|
|
46
|
+
<!-- Full-width section background, constrained content -->
|
|
47
|
+
<PageRow tag="section" variant="full" style="background: var(--brand-surface); padding-block: 6rem;">
|
|
48
|
+
<h1>Heading</h1> <!-- spans full track -->
|
|
49
|
+
<p>Body copy</p> <!-- spans full track -->
|
|
50
|
+
|
|
51
|
+
<!-- Break out to a narrower inner width -->
|
|
52
|
+
<PageRow variant="content">
|
|
53
|
+
<p>Constrained to 1064px</p>
|
|
54
|
+
</PageRow>
|
|
55
|
+
</PageRow>
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## Align prop — edge bleed
|
|
61
|
+
|
|
62
|
+
Combine `variant` with `align` to bleed one side to the viewport edge while keeping the opposite
|
|
63
|
+
boundary at the track line. Useful for asymmetric imagery, pull-quotes, or decorative panels.
|
|
64
|
+
|
|
65
|
+
```vue
|
|
66
|
+
<!-- Bleeds left to viewport edge, right boundary at content-end -->
|
|
67
|
+
<PageRow>
|
|
68
|
+
<PageRow variant="content" align="start" style="background: var(--brand-tint);">
|
|
69
|
+
<p>full-start → content-end</p>
|
|
70
|
+
</PageRow>
|
|
71
|
+
</PageRow>
|
|
72
|
+
|
|
73
|
+
<!-- Bleeds right to viewport edge, left boundary at content-start -->
|
|
74
|
+
<PageRow>
|
|
75
|
+
<PageRow variant="content" align="end" style="background: var(--brand-tint);">
|
|
76
|
+
<p>content-start → full-end</p>
|
|
77
|
+
</PageRow>
|
|
78
|
+
</PageRow>
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
`align` has no effect on `variant="full"` (already edge-to-edge).
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## Accessibility — aria-labelledby
|
|
86
|
+
|
|
87
|
+
When `tag` is `section`, `main`, or `article`, `PageRow` automatically generates an
|
|
88
|
+
`aria-labelledby` attribute pointing to the first heading inside. Bind the `headingId` slot prop
|
|
89
|
+
to that heading's `id` to complete the association.
|
|
90
|
+
|
|
91
|
+
```vue
|
|
92
|
+
<PageRow tag="section">
|
|
93
|
+
<template #default="{ headingId }">
|
|
94
|
+
<h2 :id="headingId">Section title</h2>
|
|
95
|
+
<p>Section content</p>
|
|
96
|
+
</template>
|
|
97
|
+
</PageRow>
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Non-landmark tags (`div`, `header`, `footer`, `nav`) do not receive `aria-labelledby`. The
|
|
101
|
+
`headingId` slot prop is still provided but can be ignored.
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## Consumer CSS token API
|
|
106
|
+
|
|
107
|
+
Set `--page-row-*` tokens at `:root` (global), a page wrapper (scoped), or inline (per-instance).
|
|
108
|
+
|
|
109
|
+
| Token | Default | Controls |
|
|
110
|
+
|---|---|---|
|
|
111
|
+
| `--page-row-minimum-content-padding` | `1rem` | Minimum gutter at narrow viewports |
|
|
112
|
+
| `--page-row-popout-max-width` | `1400px` | Max width of the popout track |
|
|
113
|
+
| `--page-row-content-max-width` | `1064px` | Max width of the content track |
|
|
114
|
+
| `--page-row-inset-content-max-width` | `840px` | Max width of the inset-content track |
|
|
115
|
+
|
|
116
|
+
### Global override
|
|
117
|
+
|
|
118
|
+
```css
|
|
119
|
+
/* assets/styles/setup/07.components/page-row.css */
|
|
120
|
+
:root {
|
|
121
|
+
--page-row-minimum-content-padding: 1.6rem;
|
|
122
|
+
--page-row-content-max-width: 960px;
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### Page-scoped override
|
|
127
|
+
|
|
128
|
+
```css
|
|
129
|
+
/* Unscoped <style> in the consuming page */
|
|
130
|
+
.landing-page {
|
|
131
|
+
.page-row {
|
|
132
|
+
--page-row-content-max-width: 800px;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### Per-instance override
|
|
138
|
+
|
|
139
|
+
```vue
|
|
140
|
+
<PageRow variant="content" style="--page-row-content-max-width: 720px;">
|
|
141
|
+
...
|
|
142
|
+
</PageRow>
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
See `CONSUMER-STYLING.md` in the component source folder for the full override reference.
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
## Notes
|
|
150
|
+
|
|
151
|
+
- Auto-imported in Nuxt — no manual import needed.
|
|
152
|
+
- The component applies no padding, margin, or background — these are always set by the consuming
|
|
153
|
+
app on the PageRow element or its children.
|
|
154
|
+
- `container-type: inline-size` is set on every `.page-row`, so `@container` queries on children
|
|
155
|
+
respond to the PageRow's own width, not the viewport.
|
|
156
|
+
- Track widths are derived with `calc()` from the four tokens — adjusting one token shifts all
|
|
157
|
+
related tracks proportionally.
|
|
@@ -48,11 +48,11 @@ Set on `.services-card-grid` (or scoped to a page class):
|
|
|
48
48
|
<div>
|
|
49
49
|
<NuxtLayout name="default">
|
|
50
50
|
<template #layout-content>
|
|
51
|
-
<
|
|
51
|
+
<PageRow tag="div" variant="content" :style-class-passthrough="['mbe-20']">
|
|
52
52
|
<h1 class="page-heading-1">Services</h1>
|
|
53
|
-
</
|
|
53
|
+
</PageRow>
|
|
54
54
|
|
|
55
|
-
<
|
|
55
|
+
<PageRow tag="div" variant="content" :style-class-passthrough="['mbe-20']">
|
|
56
56
|
<ServicesCardGrid
|
|
57
57
|
:services-data="servicesData ?? []"
|
|
58
58
|
:eyebrow-config="{ fontSize: 'large' }"
|
|
@@ -60,7 +60,7 @@ Set on `.services-card-grid` (or scoped to a page class):
|
|
|
60
60
|
href-base="/services/"
|
|
61
61
|
button-text-prefix="More on"
|
|
62
62
|
/>
|
|
63
|
-
</
|
|
63
|
+
</PageRow>
|
|
64
64
|
</template>
|
|
65
65
|
</NuxtLayout>
|
|
66
66
|
</div>
|
|
@@ -71,11 +71,11 @@ The slot is forwarded from the inner `ServicesSection` and receives the current
|
|
|
71
71
|
<div>
|
|
72
72
|
<NuxtLayout name="default">
|
|
73
73
|
<template #layout-content>
|
|
74
|
-
<
|
|
74
|
+
<PageRow tag="div" variant="content" :style-class-passthrough="['mbe-20']">
|
|
75
75
|
<h1 class="page-heading-1">Our Services</h1>
|
|
76
|
-
</
|
|
76
|
+
</PageRow>
|
|
77
77
|
|
|
78
|
-
<
|
|
78
|
+
<PageRow tag="div" variant="content" :style-class-passthrough="['mbe-20']">
|
|
79
79
|
<ServicesSectionGrid
|
|
80
80
|
:services-data="servicesData ?? []"
|
|
81
81
|
:use-alternate-reverse="true"
|
|
@@ -89,7 +89,7 @@ The slot is forwarded from the inner `ServicesSection` and receives the current
|
|
|
89
89
|
/>
|
|
90
90
|
</template>
|
|
91
91
|
</ServicesSectionGrid>
|
|
92
|
-
</
|
|
92
|
+
</PageRow>
|
|
93
93
|
</template>
|
|
94
94
|
</NuxtLayout>
|
|
95
95
|
</div>
|