srcdev-nuxt-components 9.3.7 → 9.3.8
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/hooks/check-component-update.sh +30 -1
- package/.claude/skills/components/breadcrumb.md +49 -0
- package/.claude/skills/components/content-docs.md +1 -1
- package/.claude/skills/components/service-detail.md +156 -0
- package/.claude/skills/components/services-card-grid.md +9 -9
- package/.claude/skills/components/services-card.md +82 -30
- package/.claude/skills/index.md +3 -1
- package/.claude/skills/qa-panel.md +2 -2
- package/.vscode/srcdev-component-breadcrumb.code-snippets +14 -0
- package/.vscode/srcdev-component-service-detail.code-snippets +49 -0
- package/.vscode/srcdev-component-services-card.code-snippets +108 -0
- package/app/components/01.atoms/navigation/breadcrumb/Breadcrumb.vue +94 -0
- package/app/components/01.atoms/navigation/breadcrumb/CONSUMER-STYLING.md +32 -0
- package/app/components/01.atoms/navigation/breadcrumb/stories/Breadcrumb.stories.ts +87 -0
- package/app/components/01.atoms/navigation/breadcrumb/tests/Breadcrumb.spec.ts +87 -0
- package/app/components/01.atoms/navigation/breadcrumb/tests/__snapshots__/Breadcrumb.spec.ts.snap +13 -0
- package/app/components/03.organisms/services/service-detail/CONSUMER-STYLING.md +181 -0
- package/app/components/03.organisms/services/service-detail/ServiceDetail.vue +480 -0
- package/app/components/03.organisms/services/service-detail/stories/ServiceDetail.stories.ts +282 -0
- package/app/components/03.organisms/services/service-detail/tests/ServiceDetail.spec.ts +270 -0
- package/app/components/03.organisms/services/service-detail/tests/__snapshots__/ServiceDetail.spec.ts.snap +99 -0
- package/app/components/03.organisms/services/services-card/CONSUMER-STYLING.md +129 -0
- package/app/components/03.organisms/services/services-card/ServicesCard.vue +153 -39
- package/app/components/03.organisms/services/services-card/stories/ServicesCard.stories.ts +65 -0
- package/app/components/03.organisms/services/services-card/tests/ServicesCard.spec.ts +82 -0
- package/app/components/03.organisms/services/services-card/tests/__snapshots__/ServicesCard.spec.ts.snap +13 -5
- package/app/components/03.organisms/services/services-grids/ServicesCardGrid.vue +3 -7
- package/app/components/03.organisms/services/services-grids/stories/ServicesCardGrid.stories.ts +126 -2
- package/app/components/03.organisms/services/services-grids/stories/ServicesSectionGrid.stories.ts +6 -0
- package/app/components/03.organisms/services/services-grids/tests/__snapshots__/ServicesCardGrid.spec.ts.snap +51 -27
- package/app/types/components/breadcrumb.ts +4 -0
- package/app/types/components/index.ts +1 -0
- package/package.json +2 -2
- package/app/pages/auto-grid.vue +0 -328
- package/app/pages/banner-video.vue +0 -238
- package/app/pages/forms/examples/buttons/index.vue +0 -259
- package/app/pages/forms/examples/material/checkbox-radio-panels.vue +0 -244
- package/app/pages/forms/examples/material/cssbattle.vue +0 -60
- package/app/pages/forms/examples/material/text-fields.vue +0 -910
- package/app/pages/grid-stack.vue +0 -252
- package/app/pages/index.vue +0 -127
- package/app/pages/page-hero-highlights.vue +0 -204
- package/app/pages/samaritan.vue +0 -327
- package/app/pages/typography/hero-text.vue +0 -97
- package/app/pages/typography/index.vue +0 -39
- package/app/pages/typography/page-body.vue +0 -171
- package/app/pages/typography/page-heading.vue +0 -76
- package/app/pages/typography/page-link.vue +0 -103
- package/app/pages/ui/accordian.vue +0 -211
- package/app/pages/ui/anchor-scroll-tab-navigation.vue +0 -191
- package/app/pages/ui/anchor-scroll.vue +0 -367
- package/app/pages/ui/animated-svg-text.vue +0 -85
- package/app/pages/ui/block-decorators.vue +0 -142
- package/app/pages/ui/card-core.vue +0 -82
- package/app/pages/ui/carousel-basic.vue +0 -292
- package/app/pages/ui/carousel-flip.vue +0 -449
- package/app/pages/ui/carousel-infinite.vue +0 -260
- package/app/pages/ui/clipped-panels.vue +0 -101
- package/app/pages/ui/contact-section.vue +0 -323
- package/app/pages/ui/container-glow.vue +0 -106
- package/app/pages/ui/content-width.vue +0 -126
- package/app/pages/ui/deep-expanding-menu.vue +0 -138
- package/app/pages/ui/display-avatar.vue +0 -253
- package/app/pages/ui/display-banner.vue +0 -78
- package/app/pages/ui/display-chip.vue +0 -367
- package/app/pages/ui/display-details.vue +0 -171
- package/app/pages/ui/display-dialog.vue +0 -344
- package/app/pages/ui/display-pill.vue +0 -396
- package/app/pages/ui/display-prompt.vue +0 -284
- package/app/pages/ui/display-toast.vue +0 -311
- package/app/pages/ui/expanding-panel.vue +0 -326
- package/app/pages/ui/glowing-border.vue +0 -111
- package/app/pages/ui/layout-content-docs.vue +0 -72
- package/app/pages/ui/layout-grid-a.vue +0 -96
- package/app/pages/ui/layout-grid-b.vue +0 -132
- package/app/pages/ui/magnetic-navigation.vue +0 -50
- package/app/pages/ui/marquee-scroller.vue +0 -99
- package/app/pages/ui/mask-element.vue +0 -104
- package/app/pages/ui/masonry-columns.vue +0 -55
- package/app/pages/ui/masonry-grid-ordered-experiment.vue +0 -79
- package/app/pages/ui/masonry-grid-ordered.vue +0 -56
- package/app/pages/ui/masonry-grid-sorted.vue +0 -55
- package/app/pages/ui/masonry-grid.vue +0 -55
- package/app/pages/ui/navigation/navigation-horizontal.vue +0 -484
- package/app/pages/ui/navigation/site-navigation/about.vue +0 -36
- package/app/pages/ui/navigation/site-navigation/contact.vue +0 -39
- package/app/pages/ui/navigation/site-navigation/index.vue +0 -38
- package/app/pages/ui/navigation/site-navigation/portfolio.vue +0 -43
- package/app/pages/ui/navigation/site-navigation/services.vue +0 -42
- package/app/pages/ui/navigation/tab-navigation.vue +0 -493
- package/app/pages/ui/page-row.vue +0 -127
- package/app/pages/ui/price-list.vue +0 -65
- package/app/pages/ui/profile-section.vue +0 -142
- package/app/pages/ui/qr-code/[componentName].vue +0 -218
- package/app/pages/ui/rotating-carousel.vue +0 -154
- package/app/pages/ui/scroll-reveal-image.vue +0 -483
- package/app/pages/ui/section-parallax.vue +0 -54
- package/app/pages/ui/services/colour-finder.vue +0 -43
- package/app/pages/ui/services/services-cards.vue +0 -57
- package/app/pages/ui/services/services-section/[slug].vue +0 -61
- package/app/pages/ui/services/services-sections-compact.vue +0 -64
- package/app/pages/ui/settings.vue +0 -54
- package/app/pages/ui/simple-grid.vue +0 -55
- package/app/pages/ui/slider-gallery.vue +0 -261
- package/app/pages/ui/tabs-y.vue +0 -107
- package/app/pages/ui/tabs.vue +0 -189
- package/app/pages/ui/tooltips.vue +0 -104
- package/app/pages/ui/wipe-away-vertical.vue +0 -129
|
@@ -1,311 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<div>
|
|
3
|
-
<NuxtLayout name="default">
|
|
4
|
-
<template #layout-content>
|
|
5
|
-
<PageRow tag="div" variant="content" :style-class-passthrough="['mbe-20', 'p-20']">
|
|
6
|
-
<h2 class="page-heading-2">DisplayToast Masked / DisplayToastProvider</h2>
|
|
7
|
-
|
|
8
|
-
<div v-if="isDev" class="qa-panel">
|
|
9
|
-
<details class="qa-panel__details">
|
|
10
|
-
<summary class="qa-panel__summary">
|
|
11
|
-
<span class="qa-panel__title">QA — DisplayToastProvider</span>
|
|
12
|
-
<code class="qa-panel__status">
|
|
13
|
-
{{ qaTheme }} · {{ qaPosition }}-{{ qaAlignment }} ·
|
|
14
|
-
{{ qaAutoDismiss ? `auto ${qaDuration}ms` : "manual" }} · max:{{ qaMaxVisible }} ·
|
|
15
|
-
{{ qaIsMasked ? "masked" : "solid" }}
|
|
16
|
-
</code>
|
|
17
|
-
</summary>
|
|
18
|
-
<div class="qa-panel__body">
|
|
19
|
-
<div class="qa-panel__group">
|
|
20
|
-
<span class="qa-panel__label">Theme</span>
|
|
21
|
-
<div class="qa-panel__chips">
|
|
22
|
-
<button
|
|
23
|
-
v-for="opt in themes"
|
|
24
|
-
:key="opt"
|
|
25
|
-
class="qa-panel__chip"
|
|
26
|
-
:class="{ 'is-active': qaTheme === opt }"
|
|
27
|
-
@click="qaTheme = opt"
|
|
28
|
-
>
|
|
29
|
-
{{ opt }}
|
|
30
|
-
</button>
|
|
31
|
-
</div>
|
|
32
|
-
</div>
|
|
33
|
-
|
|
34
|
-
<div class="qa-panel__group">
|
|
35
|
-
<span class="qa-panel__label">Position</span>
|
|
36
|
-
<div class="qa-panel__chips">
|
|
37
|
-
<button
|
|
38
|
-
v-for="opt in positions"
|
|
39
|
-
:key="opt"
|
|
40
|
-
class="qa-panel__chip"
|
|
41
|
-
:class="{ 'is-active': qaPosition === opt }"
|
|
42
|
-
@click="qaPosition = opt"
|
|
43
|
-
>
|
|
44
|
-
{{ opt }}
|
|
45
|
-
</button>
|
|
46
|
-
</div>
|
|
47
|
-
</div>
|
|
48
|
-
|
|
49
|
-
<div class="qa-panel__group">
|
|
50
|
-
<span class="qa-panel__label">Alignment</span>
|
|
51
|
-
<div class="qa-panel__chips">
|
|
52
|
-
<button
|
|
53
|
-
v-for="opt in alignments"
|
|
54
|
-
:key="opt"
|
|
55
|
-
class="qa-panel__chip"
|
|
56
|
-
:class="{ 'is-active': qaAlignment === opt }"
|
|
57
|
-
@click="qaAlignment = opt"
|
|
58
|
-
>
|
|
59
|
-
{{ opt }}
|
|
60
|
-
</button>
|
|
61
|
-
</div>
|
|
62
|
-
</div>
|
|
63
|
-
|
|
64
|
-
<div class="qa-panel__group">
|
|
65
|
-
<span class="qa-panel__label">Masked</span>
|
|
66
|
-
<div class="qa-panel__chips">
|
|
67
|
-
<button
|
|
68
|
-
v-for="opt in [true, false]"
|
|
69
|
-
:key="String(opt)"
|
|
70
|
-
class="qa-panel__chip"
|
|
71
|
-
:class="{ 'is-active': qaIsMasked === opt }"
|
|
72
|
-
@click="qaIsMasked = opt"
|
|
73
|
-
>
|
|
74
|
-
{{ opt ? "yes" : "no" }}
|
|
75
|
-
</button>
|
|
76
|
-
</div>
|
|
77
|
-
</div>
|
|
78
|
-
|
|
79
|
-
<div class="qa-panel__group">
|
|
80
|
-
<span class="qa-panel__label">Full Width</span>
|
|
81
|
-
<div class="qa-panel__chips">
|
|
82
|
-
<button
|
|
83
|
-
v-for="opt in [true, false]"
|
|
84
|
-
:key="String(opt)"
|
|
85
|
-
class="qa-panel__chip"
|
|
86
|
-
:class="{ 'is-active': qaFullWidth === opt }"
|
|
87
|
-
@click="qaFullWidth = opt"
|
|
88
|
-
>
|
|
89
|
-
{{ opt ? "yes" : "no" }}
|
|
90
|
-
</button>
|
|
91
|
-
</div>
|
|
92
|
-
</div>
|
|
93
|
-
|
|
94
|
-
<div class="qa-panel__group">
|
|
95
|
-
<span class="qa-panel__label">Auto Dismiss</span>
|
|
96
|
-
<div class="qa-panel__chips">
|
|
97
|
-
<button
|
|
98
|
-
v-for="opt in [true, false]"
|
|
99
|
-
:key="String(opt)"
|
|
100
|
-
class="qa-panel__chip"
|
|
101
|
-
:class="{ 'is-active': qaAutoDismiss === opt }"
|
|
102
|
-
@click="qaAutoDismiss = opt"
|
|
103
|
-
>
|
|
104
|
-
{{ opt ? "yes" : "no" }}
|
|
105
|
-
</button>
|
|
106
|
-
</div>
|
|
107
|
-
</div>
|
|
108
|
-
|
|
109
|
-
<div class="qa-panel__group">
|
|
110
|
-
<span class="qa-panel__label">Duration</span>
|
|
111
|
-
<div class="qa-panel__chips">
|
|
112
|
-
<button
|
|
113
|
-
v-for="opt in durations"
|
|
114
|
-
:key="opt"
|
|
115
|
-
class="qa-panel__chip"
|
|
116
|
-
:class="{ 'is-active': qaDuration === opt }"
|
|
117
|
-
@click="qaDuration = opt"
|
|
118
|
-
>
|
|
119
|
-
{{ opt }}ms
|
|
120
|
-
</button>
|
|
121
|
-
</div>
|
|
122
|
-
</div>
|
|
123
|
-
|
|
124
|
-
<div class="qa-panel__group">
|
|
125
|
-
<span class="qa-panel__label">Max Visible</span>
|
|
126
|
-
<div class="qa-panel__chips">
|
|
127
|
-
<button
|
|
128
|
-
v-for="opt in [1, 2, 3, 4, 5]"
|
|
129
|
-
:key="opt"
|
|
130
|
-
class="qa-panel__chip"
|
|
131
|
-
:class="{ 'is-active': qaMaxVisible === opt }"
|
|
132
|
-
@click="qaMaxVisible = opt"
|
|
133
|
-
>
|
|
134
|
-
{{ opt }}
|
|
135
|
-
</button>
|
|
136
|
-
</div>
|
|
137
|
-
</div>
|
|
138
|
-
</div>
|
|
139
|
-
</details>
|
|
140
|
-
</div>
|
|
141
|
-
|
|
142
|
-
<form class="form-wrapper">
|
|
143
|
-
<div class="demo-buttons">
|
|
144
|
-
<InputButtonCore button-text="Trigger Toast" theme="default" @click.prevent="triggerToast" />
|
|
145
|
-
<InputButtonCore button-text="Queue Multiple" theme="default" @click.prevent="queueMultiple" />
|
|
146
|
-
</div>
|
|
147
|
-
</form>
|
|
148
|
-
</PageRow>
|
|
149
|
-
|
|
150
|
-
<DisplayToastProvider
|
|
151
|
-
:position="qaPosition"
|
|
152
|
-
:alignment="qaAlignment"
|
|
153
|
-
:full-width="qaFullWidth"
|
|
154
|
-
:max-visible="qaMaxVisible"
|
|
155
|
-
/>
|
|
156
|
-
</template>
|
|
157
|
-
</NuxtLayout>
|
|
158
|
-
</div>
|
|
159
|
-
</template>
|
|
160
|
-
|
|
161
|
-
<script setup lang="ts">
|
|
162
|
-
import type { DisplayToastTheme, DisplayToastPosition, DisplayToastAlignment } from "~/types/components";
|
|
163
|
-
|
|
164
|
-
definePageMeta({ layout: false });
|
|
165
|
-
|
|
166
|
-
useHead({
|
|
167
|
-
title: "DisplayToast Masked / DisplayToastProvider",
|
|
168
|
-
meta: [{ name: "description", content: "DisplayToast Masked component demo" }],
|
|
169
|
-
bodyAttrs: { class: "displayToast-page" },
|
|
170
|
-
});
|
|
171
|
-
|
|
172
|
-
const isDev = import.meta.dev;
|
|
173
|
-
const { show } = useToastQueue();
|
|
174
|
-
|
|
175
|
-
const themes = ["info", "success", "warning", "error"] as const;
|
|
176
|
-
const positions = ["top", "bottom"] as const;
|
|
177
|
-
const alignments = ["left", "center", "right"] as const;
|
|
178
|
-
const durations = [2000, 3000, 5000, 8000] as const;
|
|
179
|
-
|
|
180
|
-
const qaTheme = ref<DisplayToastTheme>("info");
|
|
181
|
-
const qaPosition = ref<DisplayToastPosition>("top");
|
|
182
|
-
const qaAlignment = ref<DisplayToastAlignment>("right");
|
|
183
|
-
const qaIsMasked = ref(true);
|
|
184
|
-
const qaFullWidth = ref(false);
|
|
185
|
-
const qaAutoDismiss = ref(true);
|
|
186
|
-
const qaDuration = ref(5000);
|
|
187
|
-
const qaMaxVisible = ref(1);
|
|
188
|
-
|
|
189
|
-
const messages: Record<DisplayToastTheme, { title: string; description: string }> = {
|
|
190
|
-
info: { title: "Information", description: "This is an informational notification." },
|
|
191
|
-
success: { title: "Success!", description: "Your action completed successfully." },
|
|
192
|
-
warning: { title: "Warning", description: "Please review this before continuing." },
|
|
193
|
-
error: { title: "Error", description: "Something went wrong. Please try again." },
|
|
194
|
-
};
|
|
195
|
-
|
|
196
|
-
const triggerToast = () => {
|
|
197
|
-
show({
|
|
198
|
-
appearance: { theme: qaTheme.value, masked: qaIsMasked.value },
|
|
199
|
-
behavior: { autoDismiss: qaAutoDismiss.value, duration: qaDuration.value },
|
|
200
|
-
content: messages[qaTheme.value],
|
|
201
|
-
});
|
|
202
|
-
};
|
|
203
|
-
|
|
204
|
-
const queueMultiple = () => {
|
|
205
|
-
themes.forEach((theme) => {
|
|
206
|
-
show({
|
|
207
|
-
appearance: { theme, masked: qaIsMasked.value },
|
|
208
|
-
behavior: { autoDismiss: qaAutoDismiss.value, duration: qaDuration.value },
|
|
209
|
-
content: messages[theme],
|
|
210
|
-
});
|
|
211
|
-
});
|
|
212
|
-
};
|
|
213
|
-
</script>
|
|
214
|
-
|
|
215
|
-
<style lang="css">
|
|
216
|
-
.demo-buttons {
|
|
217
|
-
display: flex;
|
|
218
|
-
flex-wrap: wrap;
|
|
219
|
-
gap: 1.2rem;
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
.displayToast-page {
|
|
223
|
-
.qa-panel {
|
|
224
|
-
background: oklch(15% 0 0);
|
|
225
|
-
color: white;
|
|
226
|
-
font-size: 1.3rem;
|
|
227
|
-
margin-block: 1.2rem;
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
.qa-panel__details {
|
|
231
|
-
padding: 1rem 2rem;
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
.qa-panel__summary {
|
|
235
|
-
cursor: pointer;
|
|
236
|
-
display: flex;
|
|
237
|
-
align-items: center;
|
|
238
|
-
gap: 1.6rem;
|
|
239
|
-
list-style: none;
|
|
240
|
-
user-select: none;
|
|
241
|
-
|
|
242
|
-
&::-webkit-details-marker {
|
|
243
|
-
display: none;
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
.qa-panel__title {
|
|
248
|
-
font-weight: 600;
|
|
249
|
-
font-size: 1.1rem;
|
|
250
|
-
text-transform: uppercase;
|
|
251
|
-
letter-spacing: 0.08em;
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
.qa-panel__status {
|
|
255
|
-
font-family: monospace;
|
|
256
|
-
font-size: 1.2rem;
|
|
257
|
-
background: oklch(0% 0 0 / 0.3);
|
|
258
|
-
padding: 0.2rem 0.8rem;
|
|
259
|
-
border-radius: 0.4rem;
|
|
260
|
-
user-select: text;
|
|
261
|
-
cursor: text;
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
.qa-panel__body {
|
|
265
|
-
display: flex;
|
|
266
|
-
flex-wrap: wrap;
|
|
267
|
-
gap: 2.4rem;
|
|
268
|
-
padding-block: 1.2rem 0.4rem;
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
.qa-panel__group {
|
|
272
|
-
display: flex;
|
|
273
|
-
flex-direction: column;
|
|
274
|
-
gap: 0.6rem;
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
.qa-panel__label {
|
|
278
|
-
font-size: 1.1rem;
|
|
279
|
-
text-transform: uppercase;
|
|
280
|
-
letter-spacing: 0.08em;
|
|
281
|
-
opacity: 0.55;
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
.qa-panel__chips {
|
|
285
|
-
display: flex;
|
|
286
|
-
flex-wrap: wrap;
|
|
287
|
-
gap: 0.4rem;
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
.qa-panel__chip {
|
|
291
|
-
font-family: monospace;
|
|
292
|
-
font-size: 1.2rem;
|
|
293
|
-
color: white;
|
|
294
|
-
background-color: oklch(0% 0 0 / 0.25);
|
|
295
|
-
border: 1px solid oklch(100% 0 0 / 0.18);
|
|
296
|
-
padding: 0.3rem 1rem;
|
|
297
|
-
border-radius: 0.4rem;
|
|
298
|
-
cursor: pointer;
|
|
299
|
-
transition: background-color 0.15s;
|
|
300
|
-
|
|
301
|
-
&:hover {
|
|
302
|
-
background-color: oklch(0% 0 0 / 0.4);
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
&.is-active {
|
|
306
|
-
background-color: oklch(55% 0.18 240);
|
|
307
|
-
border-color: oklch(55% 0.18 240);
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
</style>
|
|
@@ -1,326 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<div>
|
|
3
|
-
<NuxtLayout name="default">
|
|
4
|
-
<template #layout-content>
|
|
5
|
-
<PageRow tag="div" variant="content" :style-class-passthrough="['expanding-panel-section', 'mb-20']">
|
|
6
|
-
<!-- ── QA Panel ─────────────────────────────────────────────── -->
|
|
7
|
-
<div class="qa-panel">
|
|
8
|
-
<details class="qa-panel__details" open>
|
|
9
|
-
<summary class="qa-panel__summary">
|
|
10
|
-
<span class="qa-panel__title">QA — ExpandingPanel</span>
|
|
11
|
-
<code class="qa-panel__status">
|
|
12
|
-
duration:{{ qaAnimationDuration }}ms · forceOpened:{{ qaForceOpened }} · contentIsOnTop:{{
|
|
13
|
-
qaContentIsOnTop
|
|
14
|
-
}}
|
|
15
|
-
· linked:{{ qaLinked }}
|
|
16
|
-
</code>
|
|
17
|
-
</summary>
|
|
18
|
-
<div class="qa-panel__body">
|
|
19
|
-
<div class="qa-panel__group">
|
|
20
|
-
<span class="qa-panel__label">Animation Duration</span>
|
|
21
|
-
<div class="qa-panel__chips">
|
|
22
|
-
<button
|
|
23
|
-
v-for="d in animationDurations"
|
|
24
|
-
:key="d"
|
|
25
|
-
class="qa-panel__chip"
|
|
26
|
-
:class="{ 'is-active': qaAnimationDuration === d }"
|
|
27
|
-
@click="qaAnimationDuration = d"
|
|
28
|
-
>
|
|
29
|
-
{{ d }}ms
|
|
30
|
-
</button>
|
|
31
|
-
</div>
|
|
32
|
-
</div>
|
|
33
|
-
|
|
34
|
-
<div class="qa-panel__group">
|
|
35
|
-
<span class="qa-panel__label">Force Opened</span>
|
|
36
|
-
<div class="qa-panel__chips">
|
|
37
|
-
<button
|
|
38
|
-
class="qa-panel__chip"
|
|
39
|
-
:class="{ 'is-active': !qaForceOpened }"
|
|
40
|
-
@click="qaForceOpened = false"
|
|
41
|
-
>
|
|
42
|
-
off
|
|
43
|
-
</button>
|
|
44
|
-
<button
|
|
45
|
-
class="qa-panel__chip"
|
|
46
|
-
:class="{ 'is-active': qaForceOpened }"
|
|
47
|
-
@click="qaForceOpened = true"
|
|
48
|
-
>
|
|
49
|
-
on
|
|
50
|
-
</button>
|
|
51
|
-
</div>
|
|
52
|
-
</div>
|
|
53
|
-
|
|
54
|
-
<div class="qa-panel__group">
|
|
55
|
-
<span class="qa-panel__label">Content Is On Top</span>
|
|
56
|
-
<div class="qa-panel__chips">
|
|
57
|
-
<button
|
|
58
|
-
class="qa-panel__chip"
|
|
59
|
-
:class="{ 'is-active': !qaContentIsOnTop }"
|
|
60
|
-
@click="qaContentIsOnTop = false"
|
|
61
|
-
>
|
|
62
|
-
off
|
|
63
|
-
</button>
|
|
64
|
-
<button
|
|
65
|
-
class="qa-panel__chip"
|
|
66
|
-
:class="{ 'is-active': qaContentIsOnTop }"
|
|
67
|
-
@click="qaContentIsOnTop = true"
|
|
68
|
-
>
|
|
69
|
-
on
|
|
70
|
-
</button>
|
|
71
|
-
</div>
|
|
72
|
-
</div>
|
|
73
|
-
|
|
74
|
-
<div class="qa-panel__group">
|
|
75
|
-
<span class="qa-panel__label">Linked (shared name)</span>
|
|
76
|
-
<div class="qa-panel__chips">
|
|
77
|
-
<button class="qa-panel__chip" :class="{ 'is-active': !qaLinked }" @click="qaLinked = false">
|
|
78
|
-
off
|
|
79
|
-
</button>
|
|
80
|
-
<button class="qa-panel__chip" :class="{ 'is-active': qaLinked }" @click="qaLinked = true">
|
|
81
|
-
on
|
|
82
|
-
</button>
|
|
83
|
-
</div>
|
|
84
|
-
</div>
|
|
85
|
-
</div>
|
|
86
|
-
</details>
|
|
87
|
-
</div>
|
|
88
|
-
</PageRow>
|
|
89
|
-
|
|
90
|
-
<PageRow tag="div" variant="content" :style-class-passthrough="['qa-panel__preview']">
|
|
91
|
-
<section class="qa-panel__preview">
|
|
92
|
-
<h2 class="page-heading-3">Interactive preview</h2>
|
|
93
|
-
<div style="position: relative">
|
|
94
|
-
<ExpandingPanel
|
|
95
|
-
v-model="qaOpen1"
|
|
96
|
-
:name="qaPanel1Name"
|
|
97
|
-
:animation-duration="qaAnimationDuration"
|
|
98
|
-
:force-opened="qaForceOpened"
|
|
99
|
-
:content-is-on-top="qaContentIsOnTop"
|
|
100
|
-
:style-class-passthrough="['qa-preview-panel']"
|
|
101
|
-
>
|
|
102
|
-
<template #summary>
|
|
103
|
-
<h3 class="page-heading-3 mb-2">Interactive preview panel 1</h3>
|
|
104
|
-
</template>
|
|
105
|
-
<template #content>
|
|
106
|
-
<!-- Wrapper INSIDE the slot carries visual styling — never .inner itself,
|
|
107
|
-
see .claude/skills/components/expanding-panel.md for why -->
|
|
108
|
-
<div class="qa-preview-panel-body">
|
|
109
|
-
<p class="mt-0">Content driven by the controls above.</p>
|
|
110
|
-
<p class="mb-0">
|
|
111
|
-
Toggle "Content Is On Top" to see it overlay the text below instead of pushing it down.
|
|
112
|
-
</p>
|
|
113
|
-
</div>
|
|
114
|
-
</template>
|
|
115
|
-
</ExpandingPanel>
|
|
116
|
-
|
|
117
|
-
<!-- When "Linked" is on, this shares its name with panel 1 above, grouping them
|
|
118
|
-
into a native accordion (only one open at a time). -->
|
|
119
|
-
<ExpandingPanel
|
|
120
|
-
v-model="qaOpen2"
|
|
121
|
-
:name="qaPanel2Name"
|
|
122
|
-
:animation-duration="qaAnimationDuration"
|
|
123
|
-
:force-opened="qaForceOpened"
|
|
124
|
-
:content-is-on-top="qaContentIsOnTop"
|
|
125
|
-
:style-class-passthrough="['qa-preview-panel']"
|
|
126
|
-
>
|
|
127
|
-
<template #summary>
|
|
128
|
-
<h3 class="page-heading-3 mb-2">Interactive preview panel 2</h3>
|
|
129
|
-
</template>
|
|
130
|
-
<template #content>
|
|
131
|
-
<div class="qa-preview-panel-body">
|
|
132
|
-
<p class="mt-0">When "Linked" is on, opening this panel closes panel 1, and vice versa.</p>
|
|
133
|
-
<p class="mb-0">Also driven by the controls above.</p>
|
|
134
|
-
</div>
|
|
135
|
-
</template>
|
|
136
|
-
</ExpandingPanel>
|
|
137
|
-
|
|
138
|
-
<p class="mbs-16">Page content below the preview panel — stays in place when contentIsOnTop is on.</p>
|
|
139
|
-
</div>
|
|
140
|
-
</section>
|
|
141
|
-
</PageRow>
|
|
142
|
-
</template>
|
|
143
|
-
</NuxtLayout>
|
|
144
|
-
</div>
|
|
145
|
-
</template>
|
|
146
|
-
|
|
147
|
-
<script setup lang="ts">
|
|
148
|
-
definePageMeta({
|
|
149
|
-
layout: false,
|
|
150
|
-
});
|
|
151
|
-
|
|
152
|
-
useHead({
|
|
153
|
-
title: "Browser title tag",
|
|
154
|
-
meta: [
|
|
155
|
-
{
|
|
156
|
-
name: "description",
|
|
157
|
-
content: "Meta description content",
|
|
158
|
-
},
|
|
159
|
-
],
|
|
160
|
-
bodyAttrs: {
|
|
161
|
-
class: "ui-expanding-panel-page",
|
|
162
|
-
},
|
|
163
|
-
});
|
|
164
|
-
|
|
165
|
-
const animationDurations = [0, 300, 800] as const;
|
|
166
|
-
type AnimationDuration = (typeof animationDurations)[number];
|
|
167
|
-
|
|
168
|
-
const qaAnimationDuration = ref<AnimationDuration>(300);
|
|
169
|
-
const qaForceOpened = ref(false);
|
|
170
|
-
const qaContentIsOnTop = ref(false);
|
|
171
|
-
const qaLinked = ref(false);
|
|
172
|
-
const qaOpen1 = ref(false);
|
|
173
|
-
const qaOpen2 = ref(false);
|
|
174
|
-
|
|
175
|
-
const qaPanel1Name = "qa-preview-1";
|
|
176
|
-
const qaPanel2Name = computed(() => (qaLinked.value ? qaPanel1Name : "qa-preview-2"));
|
|
177
|
-
|
|
178
|
-
// forceOpened only forces panels *open*; a panel's own isPanelOpen state is left untouched
|
|
179
|
-
// by the component (see expanding-panel skill notes), so toggling forceOpened off can leave
|
|
180
|
-
// a panel open or closed depending on hidden prior clicks. Reset both panels to a known,
|
|
181
|
-
// visible state on every toggle so the QA control always produces an obvious response.
|
|
182
|
-
watch(qaForceOpened, () => {
|
|
183
|
-
qaOpen1.value = false;
|
|
184
|
-
qaOpen2.value = false;
|
|
185
|
-
});
|
|
186
|
-
</script>
|
|
187
|
-
|
|
188
|
-
<style lang="css">
|
|
189
|
-
.expanding-panel-section {
|
|
190
|
-
.expanding-panel {
|
|
191
|
-
+ .expanding-panel {
|
|
192
|
-
margin-block-start: 1rem;
|
|
193
|
-
}
|
|
194
|
-
&.custom-style-1 {
|
|
195
|
-
.expanding-panel-summary {
|
|
196
|
-
gap: 0;
|
|
197
|
-
flex-direction: row-reverse;
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
&.custom-style-2 {
|
|
202
|
-
.expanding-panel-summary {
|
|
203
|
-
gap: 0;
|
|
204
|
-
flex-direction: row-reverse;
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
&.linked {
|
|
208
|
-
.expanding-panel-summary {
|
|
209
|
-
gap: 0;
|
|
210
|
-
flex-direction: row;
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
.ui-expanding-panel-page {
|
|
217
|
-
.qa-panel {
|
|
218
|
-
background: oklch(15% 0 0);
|
|
219
|
-
color: white;
|
|
220
|
-
font-size: 1.3rem;
|
|
221
|
-
margin-block-end: 2rem;
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
.qa-panel__details {
|
|
225
|
-
padding: 1rem 2rem;
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
.qa-panel__summary {
|
|
229
|
-
cursor: pointer;
|
|
230
|
-
display: flex;
|
|
231
|
-
align-items: center;
|
|
232
|
-
gap: 1.6rem;
|
|
233
|
-
list-style: none;
|
|
234
|
-
user-select: none;
|
|
235
|
-
|
|
236
|
-
&::-webkit-details-marker {
|
|
237
|
-
display: none;
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
.qa-panel__title {
|
|
242
|
-
font-weight: 600;
|
|
243
|
-
font-size: 1.1rem;
|
|
244
|
-
text-transform: uppercase;
|
|
245
|
-
letter-spacing: 0.08em;
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
.qa-panel__status {
|
|
249
|
-
font-family: monospace;
|
|
250
|
-
font-size: 1.2rem;
|
|
251
|
-
background: oklch(0% 0 0 / 0.3);
|
|
252
|
-
padding: 0.2rem 0.8rem;
|
|
253
|
-
border-radius: 0.4rem;
|
|
254
|
-
user-select: text;
|
|
255
|
-
cursor: text;
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
.qa-panel__body {
|
|
259
|
-
display: flex;
|
|
260
|
-
flex-wrap: wrap;
|
|
261
|
-
gap: 2.4rem;
|
|
262
|
-
padding-block: 1.2rem 0.4rem;
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
.qa-panel__group {
|
|
266
|
-
display: flex;
|
|
267
|
-
flex-direction: column;
|
|
268
|
-
gap: 0.6rem;
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
.qa-panel__label {
|
|
272
|
-
font-size: 1.1rem;
|
|
273
|
-
text-transform: uppercase;
|
|
274
|
-
letter-spacing: 0.08em;
|
|
275
|
-
opacity: 0.55;
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
.qa-panel__chips {
|
|
279
|
-
display: flex;
|
|
280
|
-
flex-wrap: wrap;
|
|
281
|
-
gap: 0.4rem;
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
.qa-panel__chip {
|
|
285
|
-
font-family: monospace;
|
|
286
|
-
font-size: 1.2rem;
|
|
287
|
-
color: white;
|
|
288
|
-
background: oklch(0% 0 0 / 0.25);
|
|
289
|
-
border: 1px solid oklch(100% 0 0 / 0.18);
|
|
290
|
-
padding: 0.3rem 1rem;
|
|
291
|
-
border-radius: 0.4rem;
|
|
292
|
-
cursor: pointer;
|
|
293
|
-
transition: background 0.15s;
|
|
294
|
-
|
|
295
|
-
&:hover {
|
|
296
|
-
background: oklch(0% 0 0 / 0.4);
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
&.is-active {
|
|
300
|
-
background: oklch(55% 0.18 240);
|
|
301
|
-
border-color: oklch(55% 0.18 240);
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
.qa-panel__preview {
|
|
306
|
-
padding: 0 2rem 2rem;
|
|
307
|
-
|
|
308
|
-
.expanding-panel.qa-preview-panel {
|
|
309
|
-
--expanding-panel-content-z-index: 20;
|
|
310
|
-
|
|
311
|
-
+ .expanding-panel.qa-preview-panel {
|
|
312
|
-
margin-block-start: 1rem;
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
.qa-preview-panel-body {
|
|
317
|
-
background-color: white;
|
|
318
|
-
color: black;
|
|
319
|
-
border: 1px solid oklch(0% 0 0 / 0.15);
|
|
320
|
-
border-radius: 0.4rem;
|
|
321
|
-
padding: 1rem;
|
|
322
|
-
box-shadow: 0 4px 12px rgb(0 0 0 / 15%);
|
|
323
|
-
}
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
</style>
|