srcdev-nuxt-components 9.4.9 → 9.4.10
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 +20 -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-range-core.md +142 -0
- package/.claude/skills/components/section-parallax.md +32 -10
- 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 +10 -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-range.code-snippets +85 -0
- package/.vscode/srcdev-component-section-parallax.code-snippets +27 -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/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 +1 -1
- package/app/components/01.atoms/canvas-switcher/stories/CanvasSwitcher.stories.ts +1 -1
- 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/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/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 +96 -11
- 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-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/patterns/stories/MigratedFieldsForm.stories.ts +135 -0
- package/app/components/05.forms/triple-toggle-switch/CONSUMER-STYLING.md +16 -2
- package/app/components/05.forms/triple-toggle-switch/TripleToggleSwitchCore.vue +6 -4
- package/app/types/components/container-glow.d.ts +8 -0
- package/app/types/components/index.ts +1 -1
- package/package.json +3 -2
- 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
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# UiBlockDecorated — Consumer Styling Guide
|
|
2
|
+
|
|
3
|
+
## Public token API
|
|
4
|
+
|
|
5
|
+
Each strength level (border 1-6, shadow 1-6, inner shadow 1-4) has its own token, defaulting to a
|
|
6
|
+
built-in elevation/border scale. Only the tokens for the strength levels actually in use need
|
|
7
|
+
overriding.
|
|
8
|
+
|
|
9
|
+
| Token | Default | Controls |
|
|
10
|
+
|---|---|---|
|
|
11
|
+
| `--ui-block-decorated-border-1` .. `-6` | `1px` .. `6px solid var(--theme-border)` | Border at each strength level |
|
|
12
|
+
| `--ui-block-decorated-shadow-1` .. `-6` | `0 1px 2px rgba(0,0,0,0.08)` .. `0 24px 32px rgba(0,0,0,0.18)` | Drop shadow at each strength level |
|
|
13
|
+
| `--ui-block-decorated-inner-shadow-1` .. `-4` | `inset 0 1px 2px rgba(0,0,0,0.08)` .. `inset 0 6px 8px rgba(0,0,0,0.14)` | Inset shadow at each strength level |
|
|
14
|
+
| `--ui-block-decorated-inner-shadow-highlight` | `inset 0 1px 0 rgba(255,255,255,0.15)` | Highlight layered on top of every inner shadow strength |
|
|
15
|
+
|
|
16
|
+
```css
|
|
17
|
+
.my-page {
|
|
18
|
+
--ui-block-decorated-shadow-3: 0 6px 12px rgba(0, 0, 0, 0.2);
|
|
19
|
+
--ui-block-decorated-border-2: 2px dashed hotpink;
|
|
20
|
+
}
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Or scope to a single instance via `styleClassPassthrough`:
|
|
24
|
+
|
|
25
|
+
```vue
|
|
26
|
+
<UiBlockDecorated :shadow-strength="3" style-class-passthrough="promo-block">...</UiBlockDecorated>
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
```css
|
|
30
|
+
.promo-block {
|
|
31
|
+
--ui-block-decorated-shadow-3: 0 6px 12px rgba(0, 0, 0, 0.2);
|
|
32
|
+
}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Strength props apply at most one class each
|
|
36
|
+
|
|
37
|
+
`borderStrength`, `shadowStrength` and `innerShadowStrength` are independent — a value of `0`
|
|
38
|
+
(the default) applies no class for that decoration. All three can be combined on the same
|
|
39
|
+
instance (e.g. a border and a shadow together).
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<component
|
|
3
|
+
:is="tag"
|
|
4
|
+
class="ui-block-decorated"
|
|
5
|
+
:class="[
|
|
6
|
+
{ [`ui-block-decorated-border-${borderStrength}`]: borderStrength > 0 },
|
|
7
|
+
{ [`ui-block-decorated-shadow-${shadowStrength}`]: shadowStrength > 0 },
|
|
8
|
+
{ [`ui-block-decorated-inner-shadow-${innerShadowStrength}`]: innerShadowStrength > 0 },
|
|
9
|
+
elementClasses,
|
|
10
|
+
]"
|
|
11
|
+
>
|
|
12
|
+
<slot name="default"></slot>
|
|
13
|
+
</component>
|
|
14
|
+
</template>
|
|
15
|
+
|
|
16
|
+
<script setup lang="ts">
|
|
17
|
+
interface Props {
|
|
18
|
+
tag?: "div" | "p" | "span" | "section" | "article" | "aside" | "header" | "footer" | "main" | "nav" | "ul" | "ol";
|
|
19
|
+
borderStrength?: 0 | 1 | 2 | 3 | 4 | 5 | 6;
|
|
20
|
+
shadowStrength?: 0 | 1 | 2 | 3 | 4 | 5 | 6;
|
|
21
|
+
innerShadowStrength?: 0 | 1 | 2 | 3 | 4;
|
|
22
|
+
styleClassPassthrough?: string | string[];
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const props = withDefaults(defineProps<Props>(), {
|
|
26
|
+
tag: "div",
|
|
27
|
+
borderStrength: 0,
|
|
28
|
+
shadowStrength: 0,
|
|
29
|
+
innerShadowStrength: 0,
|
|
30
|
+
styleClassPassthrough: () => [],
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
const { elementClasses, resetElementClasses } = useStyleClassPassthrough(props.styleClassPassthrough);
|
|
34
|
+
|
|
35
|
+
watch(
|
|
36
|
+
() => props.styleClassPassthrough,
|
|
37
|
+
() => {
|
|
38
|
+
resetElementClasses(props.styleClassPassthrough);
|
|
39
|
+
}
|
|
40
|
+
);
|
|
41
|
+
</script>
|
|
42
|
+
|
|
43
|
+
<style lang="css">
|
|
44
|
+
@layer components {
|
|
45
|
+
.ui-block-decorated {
|
|
46
|
+
/*
|
|
47
|
+
* Border strength classes
|
|
48
|
+
*/
|
|
49
|
+
&.ui-block-decorated-border-1 {
|
|
50
|
+
border: var(--ui-block-decorated-border-1, 1px solid var(--theme-border));
|
|
51
|
+
}
|
|
52
|
+
&.ui-block-decorated-border-2 {
|
|
53
|
+
border: var(--ui-block-decorated-border-2, 2px solid var(--theme-border));
|
|
54
|
+
}
|
|
55
|
+
&.ui-block-decorated-border-3 {
|
|
56
|
+
border: var(--ui-block-decorated-border-3, 3px solid var(--theme-border));
|
|
57
|
+
}
|
|
58
|
+
&.ui-block-decorated-border-4 {
|
|
59
|
+
border: var(--ui-block-decorated-border-4, 4px solid var(--theme-border));
|
|
60
|
+
}
|
|
61
|
+
&.ui-block-decorated-border-5 {
|
|
62
|
+
border: var(--ui-block-decorated-border-5, 5px solid var(--theme-border));
|
|
63
|
+
}
|
|
64
|
+
&.ui-block-decorated-border-6 {
|
|
65
|
+
border: var(--ui-block-decorated-border-6, 6px solid var(--theme-border));
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/*
|
|
69
|
+
* Shadow strength classes
|
|
70
|
+
*/
|
|
71
|
+
&.ui-block-decorated-shadow-1 {
|
|
72
|
+
box-shadow: var(--ui-block-decorated-shadow-1, 0 1px 2px rgba(0, 0, 0, 0.08));
|
|
73
|
+
}
|
|
74
|
+
&.ui-block-decorated-shadow-2 {
|
|
75
|
+
box-shadow: var(--ui-block-decorated-shadow-2, 0 2px 4px rgba(0, 0, 0, 0.1));
|
|
76
|
+
}
|
|
77
|
+
&.ui-block-decorated-shadow-3 {
|
|
78
|
+
box-shadow: var(--ui-block-decorated-shadow-3, 0 4px 8px rgba(0, 0, 0, 0.12));
|
|
79
|
+
}
|
|
80
|
+
&.ui-block-decorated-shadow-4 {
|
|
81
|
+
box-shadow: var(--ui-block-decorated-shadow-4, 0 8px 16px rgba(0, 0, 0, 0.14));
|
|
82
|
+
}
|
|
83
|
+
&.ui-block-decorated-shadow-5 {
|
|
84
|
+
box-shadow: var(--ui-block-decorated-shadow-5, 0 16px 24px rgba(0, 0, 0, 0.16));
|
|
85
|
+
}
|
|
86
|
+
&.ui-block-decorated-shadow-6 {
|
|
87
|
+
box-shadow: var(--ui-block-decorated-shadow-6, 0 24px 32px rgba(0, 0, 0, 0.18));
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/*
|
|
91
|
+
* Inner shadow strength classes
|
|
92
|
+
* Could use substring match [class*="ui-block-decorated-inner-shadow"] but not as performant
|
|
93
|
+
*/
|
|
94
|
+
|
|
95
|
+
&.ui-block-decorated-inner-shadow-1,
|
|
96
|
+
&.ui-block-decorated-inner-shadow-2,
|
|
97
|
+
&.ui-block-decorated-inner-shadow-3,
|
|
98
|
+
&.ui-block-decorated-inner-shadow-4 {
|
|
99
|
+
position: relative;
|
|
100
|
+
isolation: isolate;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
&.ui-block-decorated-inner-shadow-1::before,
|
|
104
|
+
&.ui-block-decorated-inner-shadow-2::before,
|
|
105
|
+
&.ui-block-decorated-inner-shadow-3::before,
|
|
106
|
+
&.ui-block-decorated-inner-shadow-4::before {
|
|
107
|
+
content: "";
|
|
108
|
+
display: block;
|
|
109
|
+
position: absolute;
|
|
110
|
+
inset: 0;
|
|
111
|
+
pointer-events: none;
|
|
112
|
+
border-radius: inherit;
|
|
113
|
+
z-index: 2;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
&.ui-block-decorated-inner-shadow-1::before {
|
|
117
|
+
box-shadow:
|
|
118
|
+
var(--ui-block-decorated-inner-shadow-1, inset 0 1px 2px rgba(0, 0, 0, 0.08)),
|
|
119
|
+
var(--ui-block-decorated-inner-shadow-highlight, inset 0 1px 0 rgba(255, 255, 255, 0.15));
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
&.ui-block-decorated-inner-shadow-2::before {
|
|
123
|
+
box-shadow:
|
|
124
|
+
var(--ui-block-decorated-inner-shadow-2, inset 0 2px 4px rgba(0, 0, 0, 0.1)),
|
|
125
|
+
var(--ui-block-decorated-inner-shadow-highlight, inset 0 1px 0 rgba(255, 255, 255, 0.15));
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
&.ui-block-decorated-inner-shadow-3::before {
|
|
129
|
+
box-shadow:
|
|
130
|
+
var(--ui-block-decorated-inner-shadow-3, inset 0 4px 6px rgba(0, 0, 0, 0.12)),
|
|
131
|
+
var(--ui-block-decorated-inner-shadow-highlight, inset 0 1px 0 rgba(255, 255, 255, 0.15));
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
&.ui-block-decorated-inner-shadow-4::before {
|
|
135
|
+
box-shadow:
|
|
136
|
+
var(--ui-block-decorated-inner-shadow-4, inset 0 6px 8px rgba(0, 0, 0, 0.14)),
|
|
137
|
+
var(--ui-block-decorated-inner-shadow-highlight, inset 0 1px 0 rgba(255, 255, 255, 0.15));
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
</style>
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import UiBlockDecorated from "../UiBlockDecorated.vue";
|
|
2
|
+
import type { Meta, StoryObj } from "@nuxtjs/storybook";
|
|
3
|
+
|
|
4
|
+
const meta: Meta<typeof UiBlockDecorated> = {
|
|
5
|
+
title: "Atoms/UiBlockDecorated",
|
|
6
|
+
component: UiBlockDecorated,
|
|
7
|
+
argTypes: {
|
|
8
|
+
tag: {
|
|
9
|
+
control: { type: "select" },
|
|
10
|
+
options: ["div", "p", "span", "section", "article", "aside", "header", "footer", "main", "nav", "ul", "ol"],
|
|
11
|
+
description: "Root element tag",
|
|
12
|
+
table: { category: "Basic" },
|
|
13
|
+
},
|
|
14
|
+
borderStrength: {
|
|
15
|
+
control: { type: "select" },
|
|
16
|
+
options: [0, 1, 2, 3, 4, 5, 6],
|
|
17
|
+
description: "Border strength level (0 = none)",
|
|
18
|
+
table: { category: "Basic" },
|
|
19
|
+
},
|
|
20
|
+
shadowStrength: {
|
|
21
|
+
control: { type: "select" },
|
|
22
|
+
options: [0, 1, 2, 3, 4, 5, 6],
|
|
23
|
+
description: "Drop shadow strength level (0 = none)",
|
|
24
|
+
table: { category: "Basic" },
|
|
25
|
+
},
|
|
26
|
+
innerShadowStrength: {
|
|
27
|
+
control: { type: "select" },
|
|
28
|
+
options: [0, 1, 2, 3, 4],
|
|
29
|
+
description: "Inner shadow strength level (0 = none)",
|
|
30
|
+
table: { category: "Basic" },
|
|
31
|
+
},
|
|
32
|
+
styleClassPassthrough: {
|
|
33
|
+
table: { disable: true },
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
parameters: {
|
|
37
|
+
docs: {
|
|
38
|
+
description: {
|
|
39
|
+
component:
|
|
40
|
+
"A plain block wrapper that applies independent border / drop-shadow / inner-shadow strength levels via CSS custom properties (see CONSUMER-STYLING.md).",
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
export default meta;
|
|
47
|
+
type Story = StoryObj<typeof UiBlockDecorated>;
|
|
48
|
+
|
|
49
|
+
const blockStyle = "padding: 2rem; background: var(--theme-surface, #fff);";
|
|
50
|
+
|
|
51
|
+
export const Default: Story = {
|
|
52
|
+
args: {
|
|
53
|
+
tag: "div",
|
|
54
|
+
},
|
|
55
|
+
render: (args) => ({
|
|
56
|
+
components: { UiBlockDecorated },
|
|
57
|
+
setup() {
|
|
58
|
+
return { args, blockStyle };
|
|
59
|
+
},
|
|
60
|
+
template: `<UiBlockDecorated v-bind="args" :style="blockStyle">No decoration</UiBlockDecorated>`,
|
|
61
|
+
}),
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
export const Border: Story = {
|
|
65
|
+
args: {
|
|
66
|
+
tag: "div",
|
|
67
|
+
borderStrength: 3,
|
|
68
|
+
},
|
|
69
|
+
render: (args) => ({
|
|
70
|
+
components: { UiBlockDecorated },
|
|
71
|
+
setup() {
|
|
72
|
+
return { args, blockStyle };
|
|
73
|
+
},
|
|
74
|
+
template: `<UiBlockDecorated v-bind="args" :style="blockStyle">Border strength 3</UiBlockDecorated>`,
|
|
75
|
+
}),
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
export const Shadow: Story = {
|
|
79
|
+
args: {
|
|
80
|
+
tag: "div",
|
|
81
|
+
shadowStrength: 4,
|
|
82
|
+
},
|
|
83
|
+
render: (args) => ({
|
|
84
|
+
components: { UiBlockDecorated },
|
|
85
|
+
setup() {
|
|
86
|
+
return { args, blockStyle };
|
|
87
|
+
},
|
|
88
|
+
template: `<UiBlockDecorated v-bind="args" :style="blockStyle">Shadow strength 4</UiBlockDecorated>`,
|
|
89
|
+
}),
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
export const InnerShadow: Story = {
|
|
93
|
+
args: {
|
|
94
|
+
tag: "div",
|
|
95
|
+
innerShadowStrength: 3,
|
|
96
|
+
},
|
|
97
|
+
render: (args) => ({
|
|
98
|
+
components: { UiBlockDecorated },
|
|
99
|
+
setup() {
|
|
100
|
+
return { args, blockStyle };
|
|
101
|
+
},
|
|
102
|
+
template: `<UiBlockDecorated v-bind="args" :style="blockStyle">Inner shadow strength 3</UiBlockDecorated>`,
|
|
103
|
+
}),
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
export const AllCombined: Story = {
|
|
107
|
+
args: {
|
|
108
|
+
tag: "div",
|
|
109
|
+
borderStrength: 2,
|
|
110
|
+
shadowStrength: 3,
|
|
111
|
+
innerShadowStrength: 2,
|
|
112
|
+
},
|
|
113
|
+
render: (args) => ({
|
|
114
|
+
components: { UiBlockDecorated },
|
|
115
|
+
setup() {
|
|
116
|
+
return { args, blockStyle };
|
|
117
|
+
},
|
|
118
|
+
template: `<UiBlockDecorated v-bind="args" :style="blockStyle">All three combined</UiBlockDecorated>`,
|
|
119
|
+
}),
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
export const CustomTokens: Story = {
|
|
123
|
+
args: {
|
|
124
|
+
tag: "div",
|
|
125
|
+
shadowStrength: 3,
|
|
126
|
+
},
|
|
127
|
+
render: (args) => ({
|
|
128
|
+
components: { UiBlockDecorated },
|
|
129
|
+
setup() {
|
|
130
|
+
return { args, blockStyle };
|
|
131
|
+
},
|
|
132
|
+
template: `
|
|
133
|
+
<UiBlockDecorated
|
|
134
|
+
v-bind="args"
|
|
135
|
+
:style="blockStyle + ' --ui-block-decorated-shadow-3: 0 6px 12px rgba(0, 0, 0, 0.25);'"
|
|
136
|
+
>
|
|
137
|
+
Custom shadow-3 token
|
|
138
|
+
</UiBlockDecorated>
|
|
139
|
+
`,
|
|
140
|
+
}),
|
|
141
|
+
parameters: {
|
|
142
|
+
docs: {
|
|
143
|
+
description: {
|
|
144
|
+
story: "Overriding a strength level's token via an inline `--ui-block-decorated-*` custom property.",
|
|
145
|
+
},
|
|
146
|
+
},
|
|
147
|
+
},
|
|
148
|
+
};
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { mountSuspended } from "@nuxt/test-utils/runtime";
|
|
3
|
+
import UiBlockDecorated from "../UiBlockDecorated.vue";
|
|
4
|
+
|
|
5
|
+
describe("UiBlockDecorated", () => {
|
|
6
|
+
it("mounts without error", async () => {
|
|
7
|
+
const wrapper = await mountSuspended(UiBlockDecorated);
|
|
8
|
+
expect(wrapper.vm).toBeTruthy();
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
it("renders correct HTML structure (default props)", async () => {
|
|
12
|
+
const wrapper = await mountSuspended(UiBlockDecorated);
|
|
13
|
+
expect(wrapper.html()).toMatchSnapshot();
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it("renders a <div> by default", async () => {
|
|
17
|
+
const wrapper = await mountSuspended(UiBlockDecorated);
|
|
18
|
+
expect(wrapper.element.tagName).toBe("DIV");
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it("renders the given tag", async () => {
|
|
22
|
+
const wrapper = await mountSuspended(UiBlockDecorated, { props: { tag: "section" } });
|
|
23
|
+
expect(wrapper.element.tagName).toBe("SECTION");
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it("applies no strength classes by default", async () => {
|
|
27
|
+
const wrapper = await mountSuspended(UiBlockDecorated);
|
|
28
|
+
expect(wrapper.classes()).toEqual(["ui-block-decorated"]);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it("applies the border strength class", async () => {
|
|
32
|
+
const wrapper = await mountSuspended(UiBlockDecorated, { props: { borderStrength: 3 } });
|
|
33
|
+
expect(wrapper.classes()).toContain("ui-block-decorated-border-3");
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it("applies the shadow strength class", async () => {
|
|
37
|
+
const wrapper = await mountSuspended(UiBlockDecorated, { props: { shadowStrength: 5 } });
|
|
38
|
+
expect(wrapper.classes()).toContain("ui-block-decorated-shadow-5");
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it("applies the inner shadow strength class", async () => {
|
|
42
|
+
const wrapper = await mountSuspended(UiBlockDecorated, { props: { innerShadowStrength: 2 } });
|
|
43
|
+
expect(wrapper.classes()).toContain("ui-block-decorated-inner-shadow-2");
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it("combines all three strength classes together", async () => {
|
|
47
|
+
const wrapper = await mountSuspended(UiBlockDecorated, {
|
|
48
|
+
props: { borderStrength: 1, shadowStrength: 2, innerShadowStrength: 3 },
|
|
49
|
+
});
|
|
50
|
+
expect(wrapper.classes()).toContain("ui-block-decorated-border-1");
|
|
51
|
+
expect(wrapper.classes()).toContain("ui-block-decorated-shadow-2");
|
|
52
|
+
expect(wrapper.classes()).toContain("ui-block-decorated-inner-shadow-3");
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it("renders slot content", async () => {
|
|
56
|
+
const wrapper = await mountSuspended(UiBlockDecorated, {
|
|
57
|
+
slots: { default: "<p class='slot-child'>Hello</p>" },
|
|
58
|
+
});
|
|
59
|
+
expect(wrapper.find(".slot-child").exists()).toBe(true);
|
|
60
|
+
expect(wrapper.find(".slot-child").text()).toBe("Hello");
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it("applies styleClassPassthrough classes", async () => {
|
|
64
|
+
const wrapper = await mountSuspended(UiBlockDecorated, {
|
|
65
|
+
props: { styleClassPassthrough: ["custom-class"] },
|
|
66
|
+
});
|
|
67
|
+
expect(wrapper.classes()).toContain("custom-class");
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it("resets classes when styleClassPassthrough prop changes", async () => {
|
|
71
|
+
const wrapper = await mountSuspended(UiBlockDecorated, {
|
|
72
|
+
props: { styleClassPassthrough: ["initial-class"] },
|
|
73
|
+
});
|
|
74
|
+
expect(wrapper.classes()).toContain("initial-class");
|
|
75
|
+
|
|
76
|
+
await wrapper.setProps({ styleClassPassthrough: ["updated-class"] });
|
|
77
|
+
expect(wrapper.classes()).not.toContain("initial-class");
|
|
78
|
+
expect(wrapper.classes()).toContain("updated-class");
|
|
79
|
+
});
|
|
80
|
+
});
|
|
@@ -135,11 +135,11 @@ describe("AlertMaskedContent", () => {
|
|
|
135
135
|
const wrapper = await mountSuspended(AlertMaskedContent, { props: { theme: "info" } });
|
|
136
136
|
const contentEl = wrapper.find(".alert-mask-content");
|
|
137
137
|
const style = (contentEl.element as HTMLElement).style;
|
|
138
|
-
// Default borderLeft: 6 → --
|
|
139
|
-
expect(style.getPropertyValue("--
|
|
140
|
-
expect(style.getPropertyValue("--
|
|
141
|
-
expect(style.getPropertyValue("--
|
|
142
|
-
expect(style.getPropertyValue("--
|
|
138
|
+
// Default borderLeft: 6 → --_inset-inline-start: 6px
|
|
139
|
+
expect(style.getPropertyValue("--_inset-inline-start")).toBe("6px");
|
|
140
|
+
expect(style.getPropertyValue("--_inset-block-start")).toBe("1px");
|
|
141
|
+
expect(style.getPropertyValue("--_inset-inline-end")).toBe("1px");
|
|
142
|
+
expect(style.getPropertyValue("--_inset-block-end")).toBe("1px");
|
|
143
143
|
});
|
|
144
144
|
|
|
145
145
|
it("merges custom maskConfig over defaults", async () => {
|
|
@@ -148,6 +148,6 @@ describe("AlertMaskedContent", () => {
|
|
|
148
148
|
});
|
|
149
149
|
const contentEl = wrapper.find(".alert-mask-content");
|
|
150
150
|
const style = (contentEl.element as HTMLElement).style;
|
|
151
|
-
expect(style.getPropertyValue("--
|
|
151
|
+
expect(style.getPropertyValue("--_inset-inline-start")).toBe("12px");
|
|
152
152
|
});
|
|
153
153
|
});
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# DisplayThemeSwitch — Consumer Styling Guide
|
|
2
|
+
|
|
3
|
+
## No tokens of its own — delegates entirely to TripleToggleSwitchCore
|
|
4
|
+
|
|
5
|
+
`DisplayThemeSwitch` is a thin wrapper around `TripleToggleSwitchCore` (see
|
|
6
|
+
`app/components/05.forms/triple-toggle-switch/CONSUMER-STYLING.md`) and declares no
|
|
7
|
+
`--display-theme-switch-*` tokens of its own. Every colour token documented there
|
|
8
|
+
(`--triple-toggle-switch-surface`, `--triple-toggle-switch-border`, `--triple-toggle-switch-marker-surface`,
|
|
9
|
+
etc.) applies unchanged, since `DisplayThemeSwitch` renders that component directly with no
|
|
10
|
+
intermediate styling layer.
|
|
11
|
+
|
|
12
|
+
## `small` class — compact sizing
|
|
13
|
+
|
|
14
|
+
Pass `"small"` via `styleClassPassthrough` for a more compact gap/padding/icon-size, useful in a
|
|
15
|
+
tight header/nav slot:
|
|
16
|
+
|
|
17
|
+
```vue
|
|
18
|
+
<DisplayThemeSwitch style-class-passthrough="small" />
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
This sets `TripleToggleSwitchCore`'s public `--triple-toggle-switch-gap`/`-padding`/
|
|
22
|
+
`-option-padding`/`-icon-size` tokens to smaller values (`0.2rem`/`0.2rem`/`0.2rem`/`1.6rem` vs the
|
|
23
|
+
default `0.4rem`/`0.4rem`/`0.4rem`/`2rem` — both already more compact than `TripleToggleSwitchCore`'s
|
|
24
|
+
own defaults of `1rem`/`0.6rem`/`0.5rem`/`2rem`). Override any of the four directly for a custom
|
|
25
|
+
size instead of using `small`:
|
|
26
|
+
|
|
27
|
+
```vue
|
|
28
|
+
<DisplayThemeSwitch style="--triple-toggle-switch-icon-size: 2.4rem;" />
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Class passthrough
|
|
32
|
+
|
|
33
|
+
`styleClassPassthrough` also accepts any other class for layout purposes, alongside or instead of
|
|
34
|
+
`small`.
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<ClientOnly>
|
|
3
|
+
<TripleToggleSwitchCore
|
|
4
|
+
v-model="colorModeVal"
|
|
5
|
+
v-model:field-data="sampleFieldData"
|
|
6
|
+
:style-class-passthrough="[`colour-scheme-select`, elementClasses]"
|
|
7
|
+
/>
|
|
8
|
+
</ClientOnly>
|
|
9
|
+
</template>
|
|
10
|
+
|
|
11
|
+
<script setup lang="ts">
|
|
12
|
+
import type { IFormMultipleOptions } from "~/types/forms/types.forms";
|
|
13
|
+
interface Props {
|
|
14
|
+
styleClassPassthrough?: string | string[];
|
|
15
|
+
systemLabel?: string;
|
|
16
|
+
lightLabel?: string;
|
|
17
|
+
darkLabel?: string;
|
|
18
|
+
systemIcon?: string;
|
|
19
|
+
lightIcon?: string;
|
|
20
|
+
darkIcon?: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const props = withDefaults(defineProps<Props>(), {
|
|
24
|
+
styleClassPassthrough: () => [],
|
|
25
|
+
systemLabel: "System",
|
|
26
|
+
lightLabel: "Light",
|
|
27
|
+
darkLabel: "Dark",
|
|
28
|
+
systemIcon: "material-symbols:night-sight-auto-sharp",
|
|
29
|
+
lightIcon: "radix-icons:sun",
|
|
30
|
+
darkIcon: "radix-icons:moon",
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
const { elementClasses } = useStyleClassPassthrough(props.styleClassPassthrough);
|
|
34
|
+
|
|
35
|
+
const sampleFieldData = computed<IFormMultipleOptions>(() => ({
|
|
36
|
+
data: [
|
|
37
|
+
{
|
|
38
|
+
id: "system",
|
|
39
|
+
name: "colorModeVal",
|
|
40
|
+
value: "system",
|
|
41
|
+
label: props.systemLabel,
|
|
42
|
+
icon: props.systemIcon,
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
id: "light",
|
|
46
|
+
name: "colorModeVal",
|
|
47
|
+
value: "light",
|
|
48
|
+
label: props.lightLabel,
|
|
49
|
+
icon: props.lightIcon,
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
id: "dark",
|
|
53
|
+
name: "colorModeVal",
|
|
54
|
+
value: "dark",
|
|
55
|
+
label: props.darkLabel,
|
|
56
|
+
icon: props.darkIcon,
|
|
57
|
+
},
|
|
58
|
+
],
|
|
59
|
+
total: 3,
|
|
60
|
+
skip: 0,
|
|
61
|
+
limit: 3,
|
|
62
|
+
}));
|
|
63
|
+
|
|
64
|
+
const { colourScheme, setColourScheme } = useSettingsStore();
|
|
65
|
+
|
|
66
|
+
const colorModeVal = ref(colourScheme);
|
|
67
|
+
watch(colorModeVal, (val) => {
|
|
68
|
+
setColourScheme(val);
|
|
69
|
+
});
|
|
70
|
+
</script>
|
|
71
|
+
|
|
72
|
+
<style lang="css">
|
|
73
|
+
@layer components {
|
|
74
|
+
.colour-scheme-select {
|
|
75
|
+
/* Everything DisplayThemeSwitch used to redeclare here beyond sizing (wrapper background/border/
|
|
76
|
+
focus ring, marker border, option border/outline/focus/hover, option-icon colours, and the
|
|
77
|
+
system/light/dark marker gradients) was a byte-for-byte duplicate of TripleToggleSwitchCore's
|
|
78
|
+
own defaults for the exact same selectors — a no-op at best, and for the ones that bypassed
|
|
79
|
+
TripleToggleSwitchCore's public --triple-toggle-switch-* tokens with a hardcoded literal
|
|
80
|
+
(background-color, border, focus outline, marker border, option border/hover/focus, icon
|
|
81
|
+
colour) an active bug: a consumer setting e.g. --triple-toggle-switch-surface globally would
|
|
82
|
+
have been silently overridden back to the hardcoded default by this block's higher
|
|
83
|
+
specificity. Removed 2026-09-20 — TripleToggleSwitchCore already owns all of that. Only the
|
|
84
|
+
genuine "small" sizing variant remains, now driving TripleToggleSwitchCore's own public
|
|
85
|
+
sizing tokens instead of reaching into its private --_form-* and --_scheme-icon-font-size
|
|
86
|
+
locals directly (see TripleToggleSwitchCore's CONSUMER-STYLING.md). */
|
|
87
|
+
&.triple-toggle-switch {
|
|
88
|
+
--triple-toggle-switch-gap: 0.4rem;
|
|
89
|
+
--triple-toggle-switch-padding: 0.4rem;
|
|
90
|
+
--triple-toggle-switch-option-padding: 0.4rem;
|
|
91
|
+
--triple-toggle-switch-icon-size: 2rem;
|
|
92
|
+
|
|
93
|
+
&.small {
|
|
94
|
+
--triple-toggle-switch-gap: 0.2rem;
|
|
95
|
+
--triple-toggle-switch-padding: 0.2rem;
|
|
96
|
+
--triple-toggle-switch-option-padding: 0.2rem;
|
|
97
|
+
--triple-toggle-switch-icon-size: 1.6rem;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
</style>
|
package/app/components/02.molecules/display-theme-switch/stories/DisplayThemeSwitch.stories.ts
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import DisplayThemeSwitch from "../DisplayThemeSwitch.vue";
|
|
2
|
+
import type { Meta, StoryObj } from "@nuxtjs/storybook";
|
|
3
|
+
|
|
4
|
+
const meta: Meta<typeof DisplayThemeSwitch> = {
|
|
5
|
+
title: "Molecules/DisplayThemeSwitch",
|
|
6
|
+
component: DisplayThemeSwitch,
|
|
7
|
+
argTypes: {
|
|
8
|
+
styleClassPassthrough: {
|
|
9
|
+
control: "object",
|
|
10
|
+
description: "Extra classes — pass \"small\" for a compact size",
|
|
11
|
+
table: { category: "Styling" },
|
|
12
|
+
},
|
|
13
|
+
systemLabel: {
|
|
14
|
+
control: "text",
|
|
15
|
+
description: "Accessible label for the system option",
|
|
16
|
+
table: { category: "Labels" },
|
|
17
|
+
},
|
|
18
|
+
lightLabel: {
|
|
19
|
+
control: "text",
|
|
20
|
+
description: "Accessible label for the light option",
|
|
21
|
+
table: { category: "Labels" },
|
|
22
|
+
},
|
|
23
|
+
darkLabel: {
|
|
24
|
+
control: "text",
|
|
25
|
+
description: "Accessible label for the dark option",
|
|
26
|
+
table: { category: "Labels" },
|
|
27
|
+
},
|
|
28
|
+
systemIcon: {
|
|
29
|
+
control: "text",
|
|
30
|
+
description: "Icon name for the system option",
|
|
31
|
+
table: { category: "Icons" },
|
|
32
|
+
},
|
|
33
|
+
lightIcon: {
|
|
34
|
+
control: "text",
|
|
35
|
+
description: "Icon name for the light option",
|
|
36
|
+
table: { category: "Icons" },
|
|
37
|
+
},
|
|
38
|
+
darkIcon: {
|
|
39
|
+
control: "text",
|
|
40
|
+
description: "Icon name for the dark option",
|
|
41
|
+
table: { category: "Icons" },
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
parameters: {
|
|
45
|
+
docs: {
|
|
46
|
+
description: {
|
|
47
|
+
component:
|
|
48
|
+
"A system/light/dark theme switch wrapping TripleToggleSwitchCore, wired to useSettingsStore. Colour and sizing are entirely delegated to TripleToggleSwitchCore's public --triple-toggle-switch-* tokens — see CONSUMER-STYLING.md.",
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
export default meta;
|
|
55
|
+
type Story = StoryObj<typeof DisplayThemeSwitch>;
|
|
56
|
+
|
|
57
|
+
export const Default: Story = {
|
|
58
|
+
args: {},
|
|
59
|
+
render: (args) => ({
|
|
60
|
+
components: { DisplayThemeSwitch },
|
|
61
|
+
setup() {
|
|
62
|
+
return { args };
|
|
63
|
+
},
|
|
64
|
+
template: `<DisplayThemeSwitch v-bind="args" />`,
|
|
65
|
+
}),
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
export const Small: Story = {
|
|
69
|
+
args: {
|
|
70
|
+
styleClassPassthrough: "small",
|
|
71
|
+
},
|
|
72
|
+
render: (args) => ({
|
|
73
|
+
components: { DisplayThemeSwitch },
|
|
74
|
+
setup() {
|
|
75
|
+
return { args };
|
|
76
|
+
},
|
|
77
|
+
template: `<DisplayThemeSwitch v-bind="args" />`,
|
|
78
|
+
}),
|
|
79
|
+
parameters: {
|
|
80
|
+
docs: {
|
|
81
|
+
description: {
|
|
82
|
+
story: "Compact sizing for use in a tight header/nav slot.",
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
},
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
export const InNavigation: Story = {
|
|
89
|
+
args: {
|
|
90
|
+
styleClassPassthrough: "small",
|
|
91
|
+
},
|
|
92
|
+
render: (args) => ({
|
|
93
|
+
components: { DisplayThemeSwitch },
|
|
94
|
+
setup() {
|
|
95
|
+
return { args };
|
|
96
|
+
},
|
|
97
|
+
template: `
|
|
98
|
+
<nav style="display: flex; align-items: center; justify-content: space-between; padding: 1.6rem 2.4rem; background: var(--theme-surface); border-radius: 0.8rem; border: 1px solid var(--theme-border);">
|
|
99
|
+
<div style="display: flex; align-items: center; gap: 1.6rem;">
|
|
100
|
+
<span style="font-weight: 600; color: var(--theme-text);">My App</span>
|
|
101
|
+
<a href="#" style="color: var(--theme-text); text-decoration: none;">Home</a>
|
|
102
|
+
<a href="#" style="color: var(--theme-text); text-decoration: none;">About</a>
|
|
103
|
+
</div>
|
|
104
|
+
<DisplayThemeSwitch v-bind="args" />
|
|
105
|
+
</nav>
|
|
106
|
+
`,
|
|
107
|
+
}),
|
|
108
|
+
parameters: {
|
|
109
|
+
docs: {
|
|
110
|
+
description: {
|
|
111
|
+
story: "Example of the theme switch integrated into a navigation bar context.",
|
|
112
|
+
},
|
|
113
|
+
},
|
|
114
|
+
},
|
|
115
|
+
};
|