@alphacifer/slidev-addon-theme 0.0.4 → 0.0.6
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/README.md +127 -2
- package/components/arc-arrow-process/ArcArrowProcess.vue +361 -0
- package/components/arc-arrow-process/ArcArrowProcessArrow.vue +143 -0
- package/components/arc-arrow-process/ArcArrowProcessCallout.vue +361 -0
- package/components/arc-arrow-process/ArcArrowProcessContent.vue +38 -0
- package/components/arc-arrow-process/ArcArrowProcessHeading.vue +43 -0
- package/components/arc-arrow-process/ArcArrowProcessIcon.vue +154 -0
- package/components/arc-compare/ArcCompare.vue +443 -0
- package/components/arc-compare/ArcCompareBadge.vue +63 -0
- package/components/arc-compare/ArcCompareCallout.vue +386 -0
- package/components/arc-compare/ArcCompareContent.vue +52 -0
- package/components/arc-compare/ArcCompareContents.vue +18 -0
- package/components/arc-compare/ArcCompareHeading.vue +52 -0
- package/components/arc-compare/ArcCompareLeft.vue +183 -0
- package/components/arc-compare/ArcCompareRight.vue +183 -0
- package/components/arc-compare/ArcCompareTitle.vue +47 -0
- package/components/arrow-triad/ArrowTriad.vue +368 -0
- package/components/arrow-triad/ArrowTriadCallout.vue +300 -0
- package/components/arrow-triad/ArrowTriadContent.vue +38 -0
- package/components/arrow-triad/ArrowTriadHeading.vue +38 -0
- package/components/arrow-triad/ArrowTriadIcon.vue +96 -0
- package/components/chevron-card/ChevronCard.vue +237 -0
- package/components/chevron-card/ChevronCardBadge.vue +74 -0
- package/components/chevron-card/ChevronCardContent.vue +39 -0
- package/components/chevron-card/ChevronCardHeading.vue +39 -0
- package/components/hex-triad/HexTriad.vue +438 -0
- package/components/hex-triad/HexTriadBadge.vue +110 -0
- package/components/hex-triad/HexTriadCallout.vue +200 -0
- package/components/hex-triad/HexTriadCenterBadge.vue +51 -0
- package/components/hex-triad/HexTriadContent.vue +20 -0
- package/components/hex-triad/HexTriadHeading.vue +28 -0
- package/components/hex-triad/HexTriadLayer.vue +28 -0
- package/components/horiz-card/HorizCard.vue +318 -0
- package/components/horiz-card/HorizCardBadge.vue +75 -0
- package/components/horiz-card/HorizCardContent.vue +46 -0
- package/components/horiz-card/HorizCardHeading.vue +47 -0
- package/components/horiz-card/HorizCardIcon.vue +118 -0
- package/components/quad-hub/QuadHub.vue +642 -0
- package/components/quad-hub/QuadHubCallout.vue +267 -0
- package/components/quad-hub/QuadHubCenter.vue +53 -0
- package/components/quad-hub/QuadHubContent.vue +39 -0
- package/components/quad-hub/QuadHubHeading.vue +44 -0
- package/components/quad-hub/QuadHubIcon.vue +112 -0
- package/components/shifting-heading/TransitionHeading.vue +3 -3
- package/components/vert-card/VertCard.vue +389 -0
- package/components/vert-card/VertCardBadge.vue +72 -0
- package/components/vert-card/VertCardContent.vue +45 -0
- package/components/vert-card/VertCardHeading.vue +68 -0
- package/components/vert-card/VertCardIcon.vue +126 -0
- package/components/vert-card/VertCardTitle.vue +76 -0
- package/layouts/core/arc-toc.vue +76 -113
- package/layouts/core/bg-center.vue +32 -4
- package/layouts/shifting-heading/shifting-intro.vue +35 -7
- package/package.json +3 -2
- package/utils/arcArrowProcess/context.ts +28 -0
- package/utils/arcArrowProcess/createArcArrowProcessGeometry.ts +137 -0
- package/utils/arcArrowProcess/index.ts +3 -0
- package/utils/arcArrowProcess/resolveArcArrowProcessItems.ts +189 -0
- package/utils/arcCompare/context.ts +36 -0
- package/utils/arcCompare/createArcCompareGeometry.ts +254 -0
- package/utils/arcCompare/index.ts +3 -0
- package/utils/arcCompare/resolveArcCompareItems.ts +123 -0
- package/utils/arrowTriad/context.ts +38 -0
- package/utils/arrowTriad/createArrowTriadGeometry.ts +63 -0
- package/utils/arrowTriad/index.ts +3 -0
- package/utils/arrowTriad/resolveArrowTriadItems.ts +121 -0
- package/utils/chevronCard/context.ts +12 -0
- package/utils/chevronCard/createChevronCardGeometry.ts +48 -0
- package/utils/chevronCard/index.ts +2 -0
- package/utils/hexTriad/context.ts +25 -0
- package/utils/hexTriad/createHexTriadGeometry.ts +182 -0
- package/utils/hexTriad/index.ts +3 -0
- package/utils/hexTriad/resolveHexTriadItems.ts +63 -0
- package/utils/horizCard/context.ts +13 -0
- package/utils/horizCard/createHorizCardGeometry.ts +243 -0
- package/utils/horizCard/index.ts +2 -0
- package/utils/quadHub/context.ts +26 -0
- package/utils/quadHub/createQuadHubGeometry.ts +331 -0
- package/utils/quadHub/index.ts +3 -0
- package/utils/quadHub/resolveQuadHubItems.ts +214 -0
- package/utils/useDiagramAutoScale.ts +300 -0
- package/utils/vertCard/context.ts +18 -0
- package/utils/vertCard/createVertCardGeometry.ts +242 -0
- package/utils/vertCard/index.ts +2 -0
|
@@ -0,0 +1,389 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import {
|
|
3
|
+
type ComputedRef,
|
|
4
|
+
computed,
|
|
5
|
+
Fragment,
|
|
6
|
+
provide,
|
|
7
|
+
useSlots,
|
|
8
|
+
type VNode,
|
|
9
|
+
} from 'vue';
|
|
10
|
+
|
|
11
|
+
import { useMergedUnoAttrs } from '../../utils/useMergedUnoAttrs';
|
|
12
|
+
import {
|
|
13
|
+
createVertCardBottomBlobPath,
|
|
14
|
+
createVertCardTopRightBlobPath,
|
|
15
|
+
hexToRgba,
|
|
16
|
+
type TVertCardBadgeVariant,
|
|
17
|
+
VERT_CARD_KEY,
|
|
18
|
+
} from '../../utils/vertCard';
|
|
19
|
+
|
|
20
|
+
defineOptions({
|
|
21
|
+
name: 'VertCard',
|
|
22
|
+
inheritAttrs: false,
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
export interface IVertCardProps {
|
|
26
|
+
readonly color?: string;
|
|
27
|
+
readonly dots?: boolean;
|
|
28
|
+
readonly title?: string;
|
|
29
|
+
readonly cardBg?: string;
|
|
30
|
+
readonly textColor?: string;
|
|
31
|
+
readonly titleColor?: string;
|
|
32
|
+
readonly lightColor?: string;
|
|
33
|
+
readonly stripeColor?: string;
|
|
34
|
+
readonly description?: string;
|
|
35
|
+
readonly hasDivider?: boolean;
|
|
36
|
+
readonly step?: string | number;
|
|
37
|
+
readonly icon?: string | object;
|
|
38
|
+
readonly hasIconCircle?: boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Controls the badge display mode:
|
|
41
|
+
* - 'outside': ribbon badge anchored to the outer left border (default)
|
|
42
|
+
* - 'inside': badge displayed inside the card body (future state)
|
|
43
|
+
* - 'none' | 'hidden': badge is completely hidden
|
|
44
|
+
*/
|
|
45
|
+
readonly variant?: TVertCardBadgeVariant;
|
|
46
|
+
readonly badgeVariant?: TVertCardBadgeVariant;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const props = withDefaults(defineProps<IVertCardProps>(), {
|
|
50
|
+
dots: true,
|
|
51
|
+
step: '01',
|
|
52
|
+
icon: undefined,
|
|
53
|
+
hasDivider: true,
|
|
54
|
+
title: undefined,
|
|
55
|
+
color: '#ea583a',
|
|
56
|
+
cardBg: '#ffffff',
|
|
57
|
+
variant: undefined,
|
|
58
|
+
textColor: undefined,
|
|
59
|
+
lightColor: undefined,
|
|
60
|
+
titleColor: undefined,
|
|
61
|
+
stripeColor: undefined,
|
|
62
|
+
description: undefined,
|
|
63
|
+
badgeVariant: 'outside',
|
|
64
|
+
hasIconCircle: undefined,
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
const slots = useSlots();
|
|
68
|
+
|
|
69
|
+
interface INamedComponent {
|
|
70
|
+
readonly name?: string;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function hasComponentName(type: unknown, name: string): boolean {
|
|
74
|
+
if (typeof type === 'object' && type !== null && 'name' in type) {
|
|
75
|
+
return (type as INamedComponent).name === name;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function flattenVNodes(nodes: VNode[]): VNode[] {
|
|
82
|
+
const result: VNode[] = [];
|
|
83
|
+
|
|
84
|
+
for (const node of nodes) {
|
|
85
|
+
if (node.type === Fragment && Array.isArray(node.children)) {
|
|
86
|
+
result.push(...flattenVNodes(node.children as VNode[]));
|
|
87
|
+
} else {
|
|
88
|
+
result.push(node);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return result;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function isBadgeNode(node: VNode): boolean {
|
|
96
|
+
return hasComponentName(node.type, 'VertCardBadge');
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function isIconNode(node: VNode): boolean {
|
|
100
|
+
return hasComponentName(node.type, 'VertCardIcon');
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function isTitleNode(node: VNode): boolean {
|
|
104
|
+
return (
|
|
105
|
+
hasComponentName(node.type, 'VertCardTitle') ||
|
|
106
|
+
hasComponentName(node.type, 'VertCardHeading')
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function isContentNode(node: VNode): boolean {
|
|
111
|
+
return hasComponentName(node.type, 'VertCardContent');
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const defaultNodes = computed(() => {
|
|
115
|
+
if (!slots.default) {
|
|
116
|
+
return [];
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return flattenVNodes(slots.default());
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
const slottedBadge = computed(() => {
|
|
123
|
+
return defaultNodes.value.find(isBadgeNode);
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
const slottedIcon = computed(() => {
|
|
127
|
+
return defaultNodes.value.find(isIconNode);
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
const slottedTitle = computed(() => {
|
|
131
|
+
return defaultNodes.value.find(isTitleNode);
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
const slottedContent = computed(() => {
|
|
135
|
+
return defaultNodes.value.find(isContentNode);
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
const otherSlottedNodes = computed(() => {
|
|
139
|
+
return defaultNodes.value.filter((node) => {
|
|
140
|
+
return (
|
|
141
|
+
!isBadgeNode(node) &&
|
|
142
|
+
!isIconNode(node) &&
|
|
143
|
+
!isTitleNode(node) &&
|
|
144
|
+
!isContentNode(node)
|
|
145
|
+
);
|
|
146
|
+
});
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
const resolvedColor = computed(() => {
|
|
150
|
+
return props.color;
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
const resolvedLightColor = computed(() => {
|
|
154
|
+
return (
|
|
155
|
+
props.lightColor ??
|
|
156
|
+
hexToRgba({
|
|
157
|
+
alpha: 0.16,
|
|
158
|
+
hex: props.color,
|
|
159
|
+
})
|
|
160
|
+
);
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
const resolvedStripeDarkColor = computed(() => {
|
|
164
|
+
return props.stripeColor ?? props.color;
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
const resolvedStripeLightColor = computed(() => {
|
|
168
|
+
return hexToRgba({
|
|
169
|
+
alpha: 0.55,
|
|
170
|
+
hex: props.color,
|
|
171
|
+
});
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
const resolvedCardBg = computed(() => {
|
|
175
|
+
return props.cardBg;
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
const resolvedTitleColor = computed(() => {
|
|
179
|
+
return props.titleColor ?? props.color;
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
const resolvedTextColor = computed(() => {
|
|
183
|
+
return props.textColor;
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
const resolvedStep = computed(() => {
|
|
187
|
+
return props.step;
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
const resolvedBadgeVariant = computed<TVertCardBadgeVariant>(() => {
|
|
191
|
+
return props.variant ?? props.badgeVariant ?? 'outside';
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
const isBadgeVisible = computed(() => {
|
|
195
|
+
return (
|
|
196
|
+
resolvedBadgeVariant.value !== 'none' &&
|
|
197
|
+
resolvedBadgeVariant.value !== 'hidden'
|
|
198
|
+
);
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
const isBadgeOutside = computed(() => {
|
|
202
|
+
return resolvedBadgeVariant.value === 'outside';
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
provide(VERT_CARD_KEY, {
|
|
206
|
+
step: resolvedStep,
|
|
207
|
+
color: resolvedColor,
|
|
208
|
+
cardBg: resolvedCardBg,
|
|
209
|
+
lightColor: resolvedLightColor,
|
|
210
|
+
titleColor: resolvedTitleColor,
|
|
211
|
+
badgeVariant: resolvedBadgeVariant,
|
|
212
|
+
stripeColor: resolvedStripeDarkColor,
|
|
213
|
+
hasDivider: computed(() => props.hasDivider),
|
|
214
|
+
textColor: resolvedTextColor as ComputedRef<string | undefined>,
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
const BLOB_WIDTH = 128;
|
|
218
|
+
const BLOB_HEIGHT = 112;
|
|
219
|
+
|
|
220
|
+
const bottomBlobPath = computed(() => {
|
|
221
|
+
return createVertCardBottomBlobPath({
|
|
222
|
+
blobHeight: 96,
|
|
223
|
+
blobWidth: 128,
|
|
224
|
+
borderRadius: 21,
|
|
225
|
+
width: BLOB_WIDTH,
|
|
226
|
+
height: BLOB_HEIGHT,
|
|
227
|
+
});
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
const topRightInnerBlobPath = computed(() => {
|
|
231
|
+
return createVertCardTopRightBlobPath({
|
|
232
|
+
blobHeight: 96,
|
|
233
|
+
blobWidth: 128,
|
|
234
|
+
borderRadius: 21,
|
|
235
|
+
width: BLOB_WIDTH,
|
|
236
|
+
height: BLOB_HEIGHT,
|
|
237
|
+
});
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
const topRightOuterBlobPath = computed(() => {
|
|
241
|
+
return createVertCardTopRightBlobPath({
|
|
242
|
+
blobHeight: 76,
|
|
243
|
+
blobWidth: 104,
|
|
244
|
+
borderRadius: 21,
|
|
245
|
+
width: BLOB_WIDTH,
|
|
246
|
+
height: BLOB_HEIGHT,
|
|
247
|
+
});
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
// Determine whether icon circle is active (optional icon)
|
|
251
|
+
const isIconActive = computed(() => {
|
|
252
|
+
if (props.hasIconCircle !== undefined) {
|
|
253
|
+
return props.hasIconCircle;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
return Boolean(props.icon || slots.icon || slottedIcon.value !== undefined);
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
const { className, forwardedAttrs } = useMergedUnoAttrs(
|
|
260
|
+
'alpha-vert-card relative inline-flex flex-col select-none rounded-[24px] border-[2.75px] border-solid font-sans',
|
|
261
|
+
);
|
|
262
|
+
</script>
|
|
263
|
+
|
|
264
|
+
<template>
|
|
265
|
+
<div
|
|
266
|
+
v-bind="forwardedAttrs()"
|
|
267
|
+
:class="className()"
|
|
268
|
+
:style="{
|
|
269
|
+
borderColor: resolvedColor,
|
|
270
|
+
backgroundColor: resolvedCardBg,
|
|
271
|
+
}"
|
|
272
|
+
>
|
|
273
|
+
<!-- Clipped decorative accent layers (responsive and symmetrical in opposite corners) -->
|
|
274
|
+
<div
|
|
275
|
+
class="absolute inset-0 rounded-[21.25px] overflow-hidden pointer-events-none"
|
|
276
|
+
>
|
|
277
|
+
<!-- Bottom-left organic wave blob (kept as requested) -->
|
|
278
|
+
<svg
|
|
279
|
+
class="absolute bottom-0 left-0 w-32 h-28 pointer-events-none overflow-visible"
|
|
280
|
+
viewBox="0 0 128 112"
|
|
281
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
282
|
+
>
|
|
283
|
+
<path
|
|
284
|
+
class="alpha-vert-card__blob"
|
|
285
|
+
:d="bottomBlobPath"
|
|
286
|
+
:fill="resolvedColor"
|
|
287
|
+
/>
|
|
288
|
+
</svg>
|
|
289
|
+
<!-- Top-right corner organic wave blob (symmetrical with bottom-left) -->
|
|
290
|
+
<svg
|
|
291
|
+
class="absolute top-0 right-0 w-32 h-28 pointer-events-none overflow-visible"
|
|
292
|
+
viewBox="0 0 128 112"
|
|
293
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
294
|
+
>
|
|
295
|
+
<!-- Inner diagonal wave band (lighter tone) -->
|
|
296
|
+
<path
|
|
297
|
+
class="alpha-vert-card__blob-top-inner"
|
|
298
|
+
:d="topRightInnerBlobPath"
|
|
299
|
+
:fill="resolvedStripeLightColor"
|
|
300
|
+
/>
|
|
301
|
+
<!-- Outer diagonal wave accent (accent tone) -->
|
|
302
|
+
<path
|
|
303
|
+
class="alpha-vert-card__blob-top-outer"
|
|
304
|
+
:d="topRightOuterBlobPath"
|
|
305
|
+
:fill="resolvedStripeDarkColor"
|
|
306
|
+
/>
|
|
307
|
+
</svg>
|
|
308
|
+
</div>
|
|
309
|
+
<!-- Ribbon Step Badge on left edge (pointing right into the card) -->
|
|
310
|
+
<div
|
|
311
|
+
v-if="isBadgeOutside && isBadgeVisible"
|
|
312
|
+
class="absolute -left-[20px] z-10"
|
|
313
|
+
:class="isIconActive ? 'top-[72px]' : 'top-[60px]'"
|
|
314
|
+
>
|
|
315
|
+
<slot name="badge">
|
|
316
|
+
<component :is="slottedBadge" v-if="slottedBadge" />
|
|
317
|
+
<VertCardBadge v-else :step="resolvedStep" :color="resolvedColor" />
|
|
318
|
+
</slot>
|
|
319
|
+
</div>
|
|
320
|
+
<!-- Card Content Layer -->
|
|
321
|
+
<div
|
|
322
|
+
class="relative z-10 w-full h-full pt-8 pb-5 px-6 flex flex-col justify-between items-center"
|
|
323
|
+
>
|
|
324
|
+
<!-- Optional Icon Circle (rendered when icon/slot is provided) -->
|
|
325
|
+
<template v-if="isIconActive">
|
|
326
|
+
<div class="flex items-center justify-center flex-shrink-0 mb-3">
|
|
327
|
+
<slot name="icon">
|
|
328
|
+
<component :is="slottedIcon" v-if="slottedIcon" />
|
|
329
|
+
<VertCardIcon
|
|
330
|
+
v-else
|
|
331
|
+
:icon="props.icon"
|
|
332
|
+
:color="resolvedColor"
|
|
333
|
+
:light-color="resolvedLightColor"
|
|
334
|
+
:size="108"
|
|
335
|
+
/>
|
|
336
|
+
</slot>
|
|
337
|
+
</div>
|
|
338
|
+
</template>
|
|
339
|
+
<!-- Title, Divider, and Content Description -->
|
|
340
|
+
<div
|
|
341
|
+
class="flex flex-col items-center justify-center flex-1 w-full min-w-0"
|
|
342
|
+
:class="{ 'my-auto py-4': !isIconActive }"
|
|
343
|
+
>
|
|
344
|
+
<slot name="title">
|
|
345
|
+
<component :is="slottedTitle" v-if="slottedTitle" />
|
|
346
|
+
<VertCardTitle
|
|
347
|
+
v-else-if="props.title"
|
|
348
|
+
:color="resolvedTitleColor"
|
|
349
|
+
:has-divider="props.hasDivider"
|
|
350
|
+
>
|
|
351
|
+
{{ props.title }}
|
|
352
|
+
</VertCardTitle>
|
|
353
|
+
</slot>
|
|
354
|
+
<slot name="description">
|
|
355
|
+
<component :is="slottedContent" v-if="slottedContent" />
|
|
356
|
+
<VertCardContent
|
|
357
|
+
v-else-if="props.description"
|
|
358
|
+
:color="resolvedTextColor"
|
|
359
|
+
>
|
|
360
|
+
{{ props.description }}
|
|
361
|
+
</VertCardContent>
|
|
362
|
+
</slot>
|
|
363
|
+
<!-- Any other custom slotted components -->
|
|
364
|
+
<component
|
|
365
|
+
:is="node"
|
|
366
|
+
v-for="(node, index) in otherSlottedNodes"
|
|
367
|
+
:key="index"
|
|
368
|
+
/>
|
|
369
|
+
</div>
|
|
370
|
+
<!-- Bottom Row: Centered Decorative Indicator Dots -->
|
|
371
|
+
<div v-if="props.dots" class="flex justify-center items-center gap-2 pt-1">
|
|
372
|
+
<slot name="dots">
|
|
373
|
+
<span
|
|
374
|
+
class="w-2.5 h-2.5 rounded-full inline-block"
|
|
375
|
+
:style="{ backgroundColor: resolvedColor }"
|
|
376
|
+
/>
|
|
377
|
+
<span
|
|
378
|
+
class="w-2.5 h-2.5 rounded-full inline-block opacity-40"
|
|
379
|
+
:style="{ backgroundColor: resolvedColor }"
|
|
380
|
+
/>
|
|
381
|
+
<span
|
|
382
|
+
class="w-2.5 h-2.5 rounded-full inline-block opacity-40"
|
|
383
|
+
:style="{ backgroundColor: resolvedColor }"
|
|
384
|
+
/>
|
|
385
|
+
</slot>
|
|
386
|
+
</div>
|
|
387
|
+
</div>
|
|
388
|
+
</div>
|
|
389
|
+
</template>
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed, inject } from 'vue';
|
|
3
|
+
|
|
4
|
+
import { useMergedUnoAttrs } from '../../utils/useMergedUnoAttrs';
|
|
5
|
+
import { createVertCardBadgePath, VERT_CARD_KEY } from '../../utils/vertCard';
|
|
6
|
+
|
|
7
|
+
defineOptions({
|
|
8
|
+
inheritAttrs: false,
|
|
9
|
+
name: 'VertCardBadge',
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
export interface IVertCardBadgeProps {
|
|
13
|
+
/**
|
|
14
|
+
* Badge fill color. Overrides context color.
|
|
15
|
+
*/
|
|
16
|
+
readonly color?: string;
|
|
17
|
+
/**
|
|
18
|
+
* Badge text or step number. Overrides context step.
|
|
19
|
+
*/
|
|
20
|
+
readonly step?: string | number;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const props = withDefaults(defineProps<IVertCardBadgeProps>(), {
|
|
24
|
+
step: undefined,
|
|
25
|
+
color: undefined,
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
const context = inject(VERT_CARD_KEY, undefined);
|
|
29
|
+
|
|
30
|
+
const resolvedColor = computed(() => {
|
|
31
|
+
return props.color ?? context?.color.value ?? '#ea583a';
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
const resolvedStep = computed(() => {
|
|
35
|
+
return props.step ?? context?.step.value ?? '01';
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
const badgePath = createVertCardBadgePath({
|
|
39
|
+
width: 62,
|
|
40
|
+
height: 48,
|
|
41
|
+
tipRadius: 6,
|
|
42
|
+
leftRadius: 8,
|
|
43
|
+
sideWidth: 42,
|
|
44
|
+
cornerRadius: 6,
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
const { className, forwardedAttrs } = useMergedUnoAttrs(
|
|
48
|
+
'alpha-vert-card-badge inline-flex items-center justify-center select-none',
|
|
49
|
+
);
|
|
50
|
+
</script>
|
|
51
|
+
|
|
52
|
+
<template>
|
|
53
|
+
<div v-bind="forwardedAttrs()" :class="className()">
|
|
54
|
+
<svg
|
|
55
|
+
class="w-[62px] h-[48px] overflow-visible drop-shadow-sm"
|
|
56
|
+
viewBox="0 0 62 48"
|
|
57
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
58
|
+
>
|
|
59
|
+
<path :d="badgePath" :fill="resolvedColor" />
|
|
60
|
+
<text
|
|
61
|
+
x="23"
|
|
62
|
+
y="24"
|
|
63
|
+
text-anchor="middle"
|
|
64
|
+
dominant-baseline="central"
|
|
65
|
+
fill="#ffffff"
|
|
66
|
+
class="font-sans font-bold text-[20px] tracking-tight"
|
|
67
|
+
>
|
|
68
|
+
<slot>{{ resolvedStep }}</slot>
|
|
69
|
+
</text>
|
|
70
|
+
</svg>
|
|
71
|
+
</div>
|
|
72
|
+
</template>
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed, inject } from 'vue';
|
|
3
|
+
|
|
4
|
+
import { useMergedUnoAttrs } from '../../utils/useMergedUnoAttrs';
|
|
5
|
+
import { VERT_CARD_KEY } from '../../utils/vertCard';
|
|
6
|
+
|
|
7
|
+
defineOptions({
|
|
8
|
+
inheritAttrs: false,
|
|
9
|
+
name: 'VertCardContent',
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
export interface IVertCardContentProps {
|
|
13
|
+
/**
|
|
14
|
+
* Content text color. Overrides context textColor.
|
|
15
|
+
*/
|
|
16
|
+
readonly color?: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const props = withDefaults(defineProps<IVertCardContentProps>(), {
|
|
20
|
+
color: undefined,
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
const context = inject(VERT_CARD_KEY, undefined);
|
|
24
|
+
|
|
25
|
+
const contentColor = computed(() => {
|
|
26
|
+
return props.color ?? context?.textColor.value ?? undefined;
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
const { className, forwardedAttrs } = useMergedUnoAttrs(
|
|
30
|
+
'alpha-vert-card-content mt-3 px-2 font-sans text-base leading-relaxed text-slate-600 dark:text-slate-300 opacity-90 text-center [&_p]:text-base [&_p]:m-0',
|
|
31
|
+
);
|
|
32
|
+
</script>
|
|
33
|
+
|
|
34
|
+
<template>
|
|
35
|
+
<div
|
|
36
|
+
v-bind="forwardedAttrs()"
|
|
37
|
+
:class="className()"
|
|
38
|
+
:style="contentColor ? { color: contentColor } : undefined"
|
|
39
|
+
>
|
|
40
|
+
<slot>
|
|
41
|
+
Lorem ipsum dolor sit amet, nibh est. A magna maecenas, quam magna nec
|
|
42
|
+
quis, lorem nunc. Suspendisse viverra sodales mauris, cras pharetra proin.
|
|
43
|
+
</slot>
|
|
44
|
+
</div>
|
|
45
|
+
</template>
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed, inject } from 'vue';
|
|
3
|
+
|
|
4
|
+
import { useMergedUnoAttrs } from '../../utils/useMergedUnoAttrs';
|
|
5
|
+
import { VERT_CARD_KEY } from '../../utils/vertCard';
|
|
6
|
+
|
|
7
|
+
defineOptions({
|
|
8
|
+
inheritAttrs: false,
|
|
9
|
+
name: 'VertCardHeading',
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
export interface IVertCardHeadingProps {
|
|
13
|
+
/**
|
|
14
|
+
* Title text color. Overrides context titleColor.
|
|
15
|
+
*/
|
|
16
|
+
readonly color?: string;
|
|
17
|
+
/**
|
|
18
|
+
* Whether to render the decorative horizontal line with center dot below the title.
|
|
19
|
+
* @default true
|
|
20
|
+
*/
|
|
21
|
+
readonly hasDivider?: boolean;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const props = withDefaults(defineProps<IVertCardHeadingProps>(), {
|
|
25
|
+
color: undefined,
|
|
26
|
+
hasDivider: true,
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
const context = inject(VERT_CARD_KEY, undefined);
|
|
30
|
+
|
|
31
|
+
const headingColor = computed(() => {
|
|
32
|
+
return (
|
|
33
|
+
props.color ??
|
|
34
|
+
context?.titleColor.value ??
|
|
35
|
+
context?.color.value ??
|
|
36
|
+
'#ea583a'
|
|
37
|
+
);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
const { className, forwardedAttrs } = useMergedUnoAttrs(
|
|
41
|
+
'alpha-vert-card-heading font-sans font-bold text-xl tracking-tight leading-tight text-center',
|
|
42
|
+
);
|
|
43
|
+
</script>
|
|
44
|
+
|
|
45
|
+
<template>
|
|
46
|
+
<div class="flex flex-col items-center w-full">
|
|
47
|
+
<h3
|
|
48
|
+
v-bind="forwardedAttrs()"
|
|
49
|
+
:class="className()"
|
|
50
|
+
:style="{ color: headingColor }"
|
|
51
|
+
>
|
|
52
|
+
<slot>Lorem Ipsum</slot>
|
|
53
|
+
</h3>
|
|
54
|
+
<div
|
|
55
|
+
v-if="props.hasDivider"
|
|
56
|
+
class="mt-2.5 flex items-center justify-center w-32 relative"
|
|
57
|
+
>
|
|
58
|
+
<div
|
|
59
|
+
class="w-full h-[1.5px]"
|
|
60
|
+
:style="{ backgroundColor: headingColor }"
|
|
61
|
+
/>
|
|
62
|
+
<span
|
|
63
|
+
class="absolute w-2 h-2 rounded-full"
|
|
64
|
+
:style="{ backgroundColor: headingColor }"
|
|
65
|
+
/>
|
|
66
|
+
</div>
|
|
67
|
+
</div>
|
|
68
|
+
</template>
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed, inject } from 'vue';
|
|
3
|
+
|
|
4
|
+
import { useMergedUnoAttrs } from '../../utils/useMergedUnoAttrs';
|
|
5
|
+
import { hexToRgba, VERT_CARD_KEY } from '../../utils/vertCard';
|
|
6
|
+
|
|
7
|
+
defineOptions({
|
|
8
|
+
inheritAttrs: false,
|
|
9
|
+
name: 'VertCardIcon',
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
export interface IVertCardIconProps {
|
|
13
|
+
/**
|
|
14
|
+
* Optional icon class (e.g. 'i-carbon-search') or component.
|
|
15
|
+
*/
|
|
16
|
+
readonly icon?: string | object;
|
|
17
|
+
/**
|
|
18
|
+
* Foreground icon color. Overrides context color.
|
|
19
|
+
*/
|
|
20
|
+
readonly color?: string;
|
|
21
|
+
/**
|
|
22
|
+
* Circular background color. Overrides context lightColor.
|
|
23
|
+
*/
|
|
24
|
+
readonly lightColor?: string;
|
|
25
|
+
/**
|
|
26
|
+
* Circle size in pixels or CSS string.
|
|
27
|
+
* @default 108
|
|
28
|
+
*/
|
|
29
|
+
readonly size?: number | string;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const props = withDefaults(defineProps<IVertCardIconProps>(), {
|
|
33
|
+
size: 108,
|
|
34
|
+
icon: undefined,
|
|
35
|
+
color: undefined,
|
|
36
|
+
lightColor: undefined,
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
const context = inject(VERT_CARD_KEY, undefined);
|
|
40
|
+
|
|
41
|
+
const resolvedColor = computed(() => {
|
|
42
|
+
return props.color ?? context?.color.value ?? '#ea583a';
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
const resolvedLightColor = computed(() => {
|
|
46
|
+
if (props.lightColor) {
|
|
47
|
+
return props.lightColor;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (context?.lightColor.value) {
|
|
51
|
+
return context.lightColor.value;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return hexToRgba({
|
|
55
|
+
alpha: 0.16,
|
|
56
|
+
hex: resolvedColor.value,
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
const resolvedSize = computed(() => {
|
|
61
|
+
if (typeof props.size === 'number') {
|
|
62
|
+
return `${props.size}px`;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return props.size;
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
const isStringIcon = computed(() => typeof props.icon === 'string');
|
|
69
|
+
const isComponentIcon = computed(() => {
|
|
70
|
+
return typeof props.icon === 'object' && props.icon !== null;
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
const { className, forwardedAttrs } = useMergedUnoAttrs(
|
|
74
|
+
'alpha-vert-card-icon rounded-full border-2 flex items-center justify-center flex-shrink-0 transition-transform duration-300 select-none',
|
|
75
|
+
);
|
|
76
|
+
</script>
|
|
77
|
+
|
|
78
|
+
<template>
|
|
79
|
+
<div
|
|
80
|
+
v-bind="forwardedAttrs()"
|
|
81
|
+
:class="className()"
|
|
82
|
+
:style="{
|
|
83
|
+
width: resolvedSize,
|
|
84
|
+
height: resolvedSize,
|
|
85
|
+
backgroundColor: resolvedLightColor,
|
|
86
|
+
borderColor: resolvedColor,
|
|
87
|
+
color: resolvedColor,
|
|
88
|
+
}"
|
|
89
|
+
>
|
|
90
|
+
<slot>
|
|
91
|
+
<component
|
|
92
|
+
:is="props.icon"
|
|
93
|
+
v-if="isComponentIcon"
|
|
94
|
+
class="text-4xl"
|
|
95
|
+
:style="{ color: resolvedColor }"
|
|
96
|
+
/>
|
|
97
|
+
<div
|
|
98
|
+
v-else-if="isStringIcon && props.icon !== 'default'"
|
|
99
|
+
:class="props.icon"
|
|
100
|
+
class="text-4xl"
|
|
101
|
+
:style="{ color: resolvedColor }"
|
|
102
|
+
/>
|
|
103
|
+
<!-- Default search icon matching the reference card -->
|
|
104
|
+
<svg
|
|
105
|
+
v-else
|
|
106
|
+
class="w-12 h-12"
|
|
107
|
+
viewBox="0 0 24 24"
|
|
108
|
+
fill="none"
|
|
109
|
+
stroke="currentColor"
|
|
110
|
+
stroke-width="2.5"
|
|
111
|
+
stroke-linecap="round"
|
|
112
|
+
stroke-linejoin="round"
|
|
113
|
+
>
|
|
114
|
+
<circle cx="11" cy="11" r="7" />
|
|
115
|
+
<line
|
|
116
|
+
x1="16.5"
|
|
117
|
+
y1="16.5"
|
|
118
|
+
x2="21"
|
|
119
|
+
y2="21"
|
|
120
|
+
stroke-width="3.2"
|
|
121
|
+
stroke-linecap="round"
|
|
122
|
+
/>
|
|
123
|
+
</svg>
|
|
124
|
+
</slot>
|
|
125
|
+
</div>
|
|
126
|
+
</template>
|