@alphacifer/slidev-addon-theme 0.0.7 → 0.0.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/README.md +106 -76
- package/components/{chevron-card → card/chevron-card}/ChevronCard.vue +2 -2
- package/components/{chevron-card → card/chevron-card}/ChevronCardBadge.vue +1 -1
- package/components/{chevron-card → card/chevron-card}/ChevronCardContent.vue +1 -1
- package/components/{chevron-card → card/chevron-card}/ChevronCardHeading.vue +1 -1
- package/components/{horiz-card → card/horiz-card}/HorizCard.vue +2 -2
- package/components/{horiz-card → card/horiz-card}/HorizCardBadge.vue +2 -2
- package/components/{horiz-card → card/horiz-card}/HorizCardContent.vue +2 -2
- package/components/{horiz-card → card/horiz-card}/HorizCardHeading.vue +2 -2
- package/components/{horiz-card → card/horiz-card}/HorizCardIcon.vue +2 -2
- package/components/{vert-card → card/vert-card}/VertCard.vue +2 -2
- package/components/{vert-card → card/vert-card}/VertCardBadge.vue +5 -2
- package/components/{vert-card → card/vert-card}/VertCardContent.vue +2 -2
- package/components/{vert-card → card/vert-card}/VertCardHeading.vue +2 -2
- package/components/{vert-card → card/vert-card}/VertCardIcon.vue +2 -2
- package/components/{vert-card → card/vert-card}/VertCardTitle.vue +2 -2
- package/components/comparisons/arc-comparison/ArcComparison.vue +654 -0
- package/components/comparisons/arc-comparison/ArcComparisonBadge.vue +29 -0
- package/components/comparisons/arc-comparison/ArcComparisonContent.vue +29 -0
- package/components/comparisons/arc-comparison/ArcComparisonContents.vue +17 -0
- package/components/comparisons/arc-comparison/ArcComparisonHeading.vue +29 -0
- package/components/comparisons/arc-comparison/ArcComparisonLeft.vue +268 -0
- package/components/comparisons/arc-comparison/ArcComparisonOrbit.vue +47 -0
- package/components/comparisons/arc-comparison/ArcComparisonRight.vue +271 -0
- package/components/comparisons/arc-comparison/ArcComparisonTitle.vue +29 -0
- package/components/{comparison-table/ComparisonTable.vue → comparisons/table-comparison/TableComparison.vue} +37 -27
- package/components/{comparison-table/ComparisonTableCell.vue → comparisons/table-comparison/TableComparisonCell.vue} +8 -8
- package/components/{comparison-table/ComparisonTableCol.vue → comparisons/table-comparison/TableComparisonCol.vue} +10 -10
- package/components/{comparison-table/ComparisonTableCols.vue → comparisons/table-comparison/TableComparisonCols.vue} +11 -11
- package/components/{comparison-table/ComparisonTableRow.vue → comparisons/table-comparison/TableComparisonRow.vue} +9 -9
- package/components/{comparison-table/ComparisonTableRows.vue → comparisons/table-comparison/TableComparisonRows.vue} +3 -3
- package/components/core/ReflectedTitle.vue +2 -1
- package/components/core/arc-orbit/ArcOrbit.vue +468 -0
- package/components/{arc-compare/ArcCompareBadge.vue → core/arc-orbit/ArcOrbitBadge.vue} +11 -8
- package/components/core/arc-orbit/ArcOrbitCallout.vue +400 -0
- package/components/{arc-compare/ArcCompareContent.vue → core/arc-orbit/ArcOrbitContent.vue} +8 -8
- package/components/{arc-compare/ArcCompareContents.vue → core/arc-orbit/ArcOrbitContents.vue} +3 -3
- package/components/{arc-compare/ArcCompareHeading.vue → core/arc-orbit/ArcOrbitHeading.vue} +11 -8
- package/components/core/arc-orbit/ArcOrbitTitle.vue +50 -0
- package/components/{thanks → core/thanks}/ThanksOutlineSquare.vue +1 -1
- package/components/{thanks → core/thanks}/ThanksSquare.vue +1 -1
- package/components/{quad-hub/QuadHub.vue → facets/tetrad/rect-orbit-tetrad/RectOrbitTetrad.vue} +71 -69
- package/components/{quad-hub/QuadHubCallout.vue → facets/tetrad/rect-orbit-tetrad/RectOrbitTetradCallout.vue} +45 -43
- package/components/{quad-hub/QuadHubCenter.vue → facets/tetrad/rect-orbit-tetrad/RectOrbitTetradCenter.vue} +4 -4
- package/components/{quad-hub/QuadHubContent.vue → facets/tetrad/rect-orbit-tetrad/RectOrbitTetradContent.vue} +6 -6
- package/components/{quad-hub/QuadHubHeading.vue → facets/tetrad/rect-orbit-tetrad/RectOrbitTetradHeading.vue} +6 -6
- package/components/{quad-hub/QuadHubIcon.vue → facets/tetrad/rect-orbit-tetrad/RectOrbitTetradIcon.vue} +6 -6
- package/components/{arrow-triad → facets/triad/arrow-triad}/ArrowTriad.vue +3 -3
- package/components/{arrow-triad → facets/triad/arrow-triad}/ArrowTriadCallout.vue +1 -1
- package/components/{arrow-triad → facets/triad/arrow-triad}/ArrowTriadContent.vue +1 -1
- package/components/{arrow-triad → facets/triad/arrow-triad}/ArrowTriadHeading.vue +1 -1
- package/components/facets/triad/gear-triad/GearTriad.vue +591 -0
- package/components/facets/triad/gear-triad/GearTriadCallout.vue +285 -0
- package/components/facets/triad/gear-triad/GearTriadCenter.vue +41 -0
- package/components/facets/triad/gear-triad/GearTriadContent.vue +58 -0
- package/components/facets/triad/gear-triad/GearTriadContents.vue +111 -0
- package/components/facets/triad/gear-triad/GearTriadDescription.vue +38 -0
- package/components/facets/triad/gear-triad/GearTriadHeading.vue +38 -0
- package/components/facets/triad/gear-triad/GearTriadIcon.vue +157 -0
- package/components/{hex-triad → facets/triad/hex-triad}/HexTriad.vue +2 -2
- package/components/{hex-triad → facets/triad/hex-triad}/HexTriadBadge.vue +1 -1
- package/components/{hex-triad → facets/triad/hex-triad}/HexTriadCallout.vue +1 -1
- package/components/{hex-triad → facets/triad/hex-triad}/HexTriadHeading.vue +1 -1
- package/components/{arc-arrow-process → process/arc-arrow-process}/ArcArrowProcess.vue +2 -2
- package/components/{arc-arrow-process → process/arc-arrow-process}/ArcArrowProcessArrow.vue +1 -1
- package/components/{arc-arrow-process → process/arc-arrow-process}/ArcArrowProcessCallout.vue +1 -1
- package/components/{arc-arrow-process → process/arc-arrow-process}/ArcArrowProcessContent.vue +1 -1
- package/components/{arc-arrow-process → process/arc-arrow-process}/ArcArrowProcessHeading.vue +1 -1
- package/package.json +1 -1
- package/utils/arcComparison/context.ts +40 -0
- package/utils/arcComparison/createArcComparisonGeometry.ts +175 -0
- package/utils/arcComparison/index.ts +3 -0
- package/utils/{arcCompare/resolveArcCompareItems.ts → arcComparison/resolveArcComparisonItems.ts} +24 -45
- package/utils/arcOrbit/context.ts +38 -0
- package/utils/{arcCompare/createArcCompareGeometry.ts → arcOrbit/createArcOrbitGeometry.ts} +77 -108
- package/utils/arcOrbit/index.ts +3 -0
- package/utils/arcOrbit/resolveArcOrbitItems.ts +92 -0
- package/utils/gearTriad/context.ts +51 -0
- package/utils/gearTriad/createGearTriadGeometry.ts +210 -0
- package/utils/gearTriad/index.ts +3 -0
- package/utils/gearTriad/resolveGearTriadItems.ts +159 -0
- package/utils/rectOrbitTetrad/context.ts +31 -0
- package/utils/{quadHub/createQuadHubGeometry.ts → rectOrbitTetrad/createRectOrbitTetradGeometry.ts} +33 -28
- package/utils/rectOrbitTetrad/index.ts +3 -0
- package/utils/{quadHub/resolveQuadHubItems.ts → rectOrbitTetrad/resolveRectOrbitTetradItems.ts} +25 -25
- package/utils/{comparisonTable → tableComparison}/context.ts +6 -6
- package/utils/useDiagramAutoScale.ts +1 -1
- package/components/arc-compare/ArcCompare.vue +0 -443
- package/components/arc-compare/ArcCompareCallout.vue +0 -386
- package/components/arc-compare/ArcCompareLeft.vue +0 -183
- package/components/arc-compare/ArcCompareRight.vue +0 -183
- package/components/arc-compare/ArcCompareTitle.vue +0 -47
- package/utils/arcCompare/context.ts +0 -36
- package/utils/arcCompare/index.ts +0 -3
- package/utils/quadHub/context.ts +0 -26
- package/utils/quadHub/index.ts +0 -3
- /package/components/{shifting-heading → core}/TransitionHeading.vue +0 -0
- /package/components/{thanks → core/thanks}/ThanksContent.vue +0 -0
- /package/components/{arrow-triad → facets/triad/arrow-triad}/ArrowTriadIcon.vue +0 -0
- /package/components/{hex-triad → facets/triad/hex-triad}/HexTriadCenterBadge.vue +0 -0
- /package/components/{hex-triad → facets/triad/hex-triad}/HexTriadContent.vue +0 -0
- /package/components/{hex-triad → facets/triad/hex-triad}/HexTriadLayer.vue +0 -0
- /package/components/{arc-arrow-process → process/arc-arrow-process}/ArcArrowProcessIcon.vue +0 -0
- /package/utils/{comparisonTable → tableComparison}/constants.ts +0 -0
- /package/utils/{comparisonTable → tableComparison}/index.ts +0 -0
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed, Fragment, inject, provide, useSlots, type VNode } from 'vue';
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
GEAR_TRIAD_CALLOUT_KEY,
|
|
6
|
+
GEAR_TRIAD_ROOT_KEY,
|
|
7
|
+
getDefaultGearTriadItem,
|
|
8
|
+
type IGearTriadItem,
|
|
9
|
+
type IResolvedGearTriadItem,
|
|
10
|
+
resolveSingleGearTriadItem,
|
|
11
|
+
type TGearTriadIcon,
|
|
12
|
+
} from '../../../../utils/gearTriad';
|
|
13
|
+
import GearTriadDescription from './GearTriadDescription.vue';
|
|
14
|
+
import GearTriadHeading from './GearTriadHeading.vue';
|
|
15
|
+
|
|
16
|
+
defineOptions({
|
|
17
|
+
name: 'GearTriadCallout',
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
export interface IGearTriadCalloutProps {
|
|
21
|
+
readonly id?: string | number;
|
|
22
|
+
readonly index?: number;
|
|
23
|
+
readonly icon?: TGearTriadIcon;
|
|
24
|
+
readonly color?: string;
|
|
25
|
+
readonly depthColor?: string;
|
|
26
|
+
readonly cardBg?: string;
|
|
27
|
+
readonly textColor?: string;
|
|
28
|
+
readonly titleColor?: string;
|
|
29
|
+
readonly title?: string;
|
|
30
|
+
readonly description?: string;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const props = withDefaults(defineProps<IGearTriadCalloutProps>(), {
|
|
34
|
+
id: undefined,
|
|
35
|
+
index: undefined,
|
|
36
|
+
icon: undefined,
|
|
37
|
+
color: undefined,
|
|
38
|
+
depthColor: undefined,
|
|
39
|
+
cardBg: undefined,
|
|
40
|
+
textColor: undefined,
|
|
41
|
+
titleColor: undefined,
|
|
42
|
+
title: undefined,
|
|
43
|
+
description: undefined,
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
interface INamedComponent {
|
|
47
|
+
readonly name?: string;
|
|
48
|
+
readonly __name?: string;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function hasComponentName(type: unknown, name: string): boolean {
|
|
52
|
+
if (typeof type === 'object' && type !== null) {
|
|
53
|
+
const comp = type as INamedComponent;
|
|
54
|
+
|
|
55
|
+
return comp.name === name || comp.__name === name;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const rootContext = inject(GEAR_TRIAD_ROOT_KEY, undefined);
|
|
62
|
+
|
|
63
|
+
if (!rootContext) {
|
|
64
|
+
console.warn('[GearTriadCallout] Must be used inside <GearTriad>');
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const overrideProps = computed<IGearTriadItem>(() => {
|
|
68
|
+
const raw: IGearTriadItem = {
|
|
69
|
+
id: props.id,
|
|
70
|
+
color: props.color,
|
|
71
|
+
depthColor: props.depthColor,
|
|
72
|
+
icon: props.icon,
|
|
73
|
+
cardBg: props.cardBg,
|
|
74
|
+
textColor: props.textColor,
|
|
75
|
+
titleColor: props.titleColor,
|
|
76
|
+
title: props.title,
|
|
77
|
+
description: props.description,
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
return Object.fromEntries(
|
|
81
|
+
Object.entries(raw).filter(([_, v]) => v !== undefined),
|
|
82
|
+
);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
const registration =
|
|
86
|
+
props.index === undefined
|
|
87
|
+
? rootContext?.registerCallout(overrideProps)
|
|
88
|
+
: undefined;
|
|
89
|
+
|
|
90
|
+
const resolvedIndex = computed(() => {
|
|
91
|
+
if (props.index !== undefined) {
|
|
92
|
+
return props.index;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return registration?.index ?? 0;
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
const activeItem = computed<IResolvedGearTriadItem>(() => {
|
|
99
|
+
const baseItem =
|
|
100
|
+
rootContext?.items.value[resolvedIndex.value] ??
|
|
101
|
+
getDefaultGearTriadItem(resolvedIndex.value);
|
|
102
|
+
|
|
103
|
+
return resolveSingleGearTriadItem(
|
|
104
|
+
{
|
|
105
|
+
...baseItem,
|
|
106
|
+
...overrideProps.value,
|
|
107
|
+
},
|
|
108
|
+
resolvedIndex.value,
|
|
109
|
+
);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
provide(GEAR_TRIAD_CALLOUT_KEY, {
|
|
113
|
+
item: activeItem,
|
|
114
|
+
index: resolvedIndex.value,
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
const slots = useSlots();
|
|
118
|
+
|
|
119
|
+
function flattenVNodes(nodes: VNode[]): VNode[] {
|
|
120
|
+
const result: VNode[] = [];
|
|
121
|
+
|
|
122
|
+
for (const node of nodes) {
|
|
123
|
+
if (node.type === Fragment && Array.isArray(node.children)) {
|
|
124
|
+
result.push(...flattenVNodes(node.children as VNode[]));
|
|
125
|
+
} else {
|
|
126
|
+
result.push(node);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return result;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const defaultNodes = computed(() => {
|
|
134
|
+
if (!slots.default) {
|
|
135
|
+
return [];
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return flattenVNodes(slots.default());
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
const headingNode = computed(() => {
|
|
142
|
+
return defaultNodes.value.find((node) => {
|
|
143
|
+
return hasComponentName(node.type, 'GearTriadHeading');
|
|
144
|
+
});
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
const descriptionNode = computed(() => {
|
|
148
|
+
return defaultNodes.value.find((node) => {
|
|
149
|
+
return hasComponentName(node.type, 'GearTriadDescription');
|
|
150
|
+
});
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
function isValidSlottedNode(node: VNode): boolean {
|
|
154
|
+
if (typeof node.type === 'symbol') {
|
|
155
|
+
return typeof node.children === 'string' && node.children.trim().length > 0;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
return true;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const otherSlottedNodes = computed(() => {
|
|
162
|
+
return defaultNodes.value.filter((node) => {
|
|
163
|
+
return (
|
|
164
|
+
isValidSlottedNode(node) &&
|
|
165
|
+
!hasComponentName(node.type, 'GearTriadHeading') &&
|
|
166
|
+
!hasComponentName(node.type, 'GearTriadDescription')
|
|
167
|
+
);
|
|
168
|
+
});
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
const positionStyle = computed(() => {
|
|
172
|
+
switch (resolvedIndex.value) {
|
|
173
|
+
case 0: {
|
|
174
|
+
// Option 1: Left side, vertically level with Cyan petal
|
|
175
|
+
return 'right: calc(50% + 185px); top: calc(50% - 115px); text-align: right; width: 250px;';
|
|
176
|
+
}
|
|
177
|
+
case 1: {
|
|
178
|
+
// Option 2: Right side, vertically level with Orange petal
|
|
179
|
+
return 'left: calc(50% + 185px); top: calc(50% - 115px); text-align: left; width: 250px;';
|
|
180
|
+
}
|
|
181
|
+
case 2: {
|
|
182
|
+
// Option 3: Bottom centered, below Pink teeth
|
|
183
|
+
return 'left: 50%; transform: translateX(-50%); top: calc(50% + 155px); text-align: center; width: 280px;';
|
|
184
|
+
}
|
|
185
|
+
default: {
|
|
186
|
+
return '';
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
const animation = computed(() => {
|
|
192
|
+
return rootContext?.animation?.value ?? true;
|
|
193
|
+
});
|
|
194
|
+
</script>
|
|
195
|
+
|
|
196
|
+
<template>
|
|
197
|
+
<div
|
|
198
|
+
v-if="resolvedIndex < 3"
|
|
199
|
+
:class="[
|
|
200
|
+
'alpha-gear-triad-callout absolute flex flex-col z-10 select-none box-border pointer-events-auto transition-all duration-500 ease-out',
|
|
201
|
+
`alpha-gear-triad-callout--${resolvedIndex}`,
|
|
202
|
+
{ 'alpha-gear-triad-callout--animated': animation },
|
|
203
|
+
{ 'alpha-gear-triad-callout--shifted': rootContext?.isShifted.value },
|
|
204
|
+
]"
|
|
205
|
+
:style="[
|
|
206
|
+
positionStyle,
|
|
207
|
+
{
|
|
208
|
+
backgroundColor: activeItem.cardBg ?? 'transparent',
|
|
209
|
+
fontFamily:
|
|
210
|
+
'ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, \'Segoe UI\', Roboto, sans-serif',
|
|
211
|
+
},
|
|
212
|
+
]"
|
|
213
|
+
>
|
|
214
|
+
<!-- Title Slot / Heading -->
|
|
215
|
+
<slot name="title">
|
|
216
|
+
<component :is="headingNode" v-if="headingNode" />
|
|
217
|
+
<GearTriadHeading v-else :color="activeItem.titleColor">
|
|
218
|
+
{{ activeItem.title }}
|
|
219
|
+
</GearTriadHeading>
|
|
220
|
+
</slot>
|
|
221
|
+
<!-- Description Slot -->
|
|
222
|
+
<slot name="description">
|
|
223
|
+
<component :is="descriptionNode" v-if="descriptionNode" />
|
|
224
|
+
<GearTriadDescription v-else :color="activeItem.textColor">
|
|
225
|
+
{{ activeItem.description }}
|
|
226
|
+
</GearTriadDescription>
|
|
227
|
+
</slot>
|
|
228
|
+
<!-- Other Slotted Nodes -->
|
|
229
|
+
<component
|
|
230
|
+
:is="node"
|
|
231
|
+
v-for="(node, idx) in otherSlottedNodes"
|
|
232
|
+
:key="idx"
|
|
233
|
+
/>
|
|
234
|
+
</div>
|
|
235
|
+
</template>
|
|
236
|
+
|
|
237
|
+
<style scoped>
|
|
238
|
+
.alpha-gear-triad-callout--animated.alpha-gear-triad-callout--0 {
|
|
239
|
+
animation: gear-triad-callout-fade 450ms cubic-bezier(0.16, 1, 0.3, 1) calc(var(--gear-start-delay, 0ms) + 150ms) both;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
.alpha-gear-triad-callout--animated.alpha-gear-triad-callout--1 {
|
|
243
|
+
animation: gear-triad-callout-fade 450ms cubic-bezier(0.16, 1, 0.3, 1) calc(var(--gear-start-delay, 0ms) + 300ms) both;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
.alpha-gear-triad-callout--animated.alpha-gear-triad-callout--2 {
|
|
247
|
+
animation: gear-triad-callout-fade-center 450ms cubic-bezier(0.16, 1, 0.3, 1) calc(var(--gear-start-delay, 0ms) + 450ms) both;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
.alpha-gear-triad-callout--shifted {
|
|
251
|
+
opacity: 0 !important;
|
|
252
|
+
pointer-events: none !important;
|
|
253
|
+
transform: rotate(-25deg) scale(0.85) !important;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
.alpha-gear-triad-callout--shifted.alpha-gear-triad-callout--1 {
|
|
257
|
+
transform: rotate(25deg) scale(0.85) !important;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
.alpha-gear-triad-callout--shifted.alpha-gear-triad-callout--2 {
|
|
261
|
+
transform: translateX(-50%) rotate(-15deg) scale(0.85) !important;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
@keyframes gear-triad-callout-fade {
|
|
265
|
+
0% {
|
|
266
|
+
opacity: 0;
|
|
267
|
+
transform: translateY(10px) scale(0.97);
|
|
268
|
+
}
|
|
269
|
+
100% {
|
|
270
|
+
opacity: 1;
|
|
271
|
+
transform: translateY(0) scale(1);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
@keyframes gear-triad-callout-fade-center {
|
|
276
|
+
0% {
|
|
277
|
+
opacity: 0;
|
|
278
|
+
transform: translate(-50%, 10px) scale(0.97);
|
|
279
|
+
}
|
|
280
|
+
100% {
|
|
281
|
+
opacity: 1;
|
|
282
|
+
transform: translate(-50%, 0) scale(1);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
</style>
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import GearTriadIcon from './GearTriadIcon.vue';
|
|
3
|
+
|
|
4
|
+
defineOptions({
|
|
5
|
+
name: 'GearTriadCenter',
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
export interface IGearTriadCenterProps {
|
|
9
|
+
readonly radius?: number;
|
|
10
|
+
readonly icon?: string | object | false;
|
|
11
|
+
readonly iconSize?: number;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const props = withDefaults(defineProps<IGearTriadCenterProps>(), {
|
|
15
|
+
radius: 54,
|
|
16
|
+
icon: 'gear',
|
|
17
|
+
iconSize: 42,
|
|
18
|
+
});
|
|
19
|
+
</script>
|
|
20
|
+
|
|
21
|
+
<template>
|
|
22
|
+
<div
|
|
23
|
+
class="alpha-gear-triad-center absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 z-20 rounded-full flex items-center justify-center pointer-events-auto select-none"
|
|
24
|
+
:style="{
|
|
25
|
+
width: `${props.radius * 2}px`,
|
|
26
|
+
height: `${props.radius * 2}px`,
|
|
27
|
+
background: 'linear-gradient(145deg, #ffffff 0%, #f1f5f9 100%)',
|
|
28
|
+
boxShadow: '0 6px 20px -2px rgba(0, 0, 0, 0.22), 0 2px 6px -1px rgba(0, 0, 0, 0.12)',
|
|
29
|
+
}"
|
|
30
|
+
>
|
|
31
|
+
<slot>
|
|
32
|
+
<GearTriadIcon
|
|
33
|
+
v-if="props.icon"
|
|
34
|
+
:icon="props.icon"
|
|
35
|
+
:size="props.iconSize"
|
|
36
|
+
color="#0f172a"
|
|
37
|
+
:stroke-width="1.75"
|
|
38
|
+
/>
|
|
39
|
+
</slot>
|
|
40
|
+
</div>
|
|
41
|
+
</template>
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed, inject } from 'vue';
|
|
3
|
+
|
|
4
|
+
import { GEAR_TRIAD_CONTENTS_KEY } from '../../../../utils/gearTriad';
|
|
5
|
+
|
|
6
|
+
defineOptions({
|
|
7
|
+
name: 'GearTriadContent',
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
export interface IGearTriadContentProps {
|
|
11
|
+
readonly step?: string | number;
|
|
12
|
+
readonly option?: number;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const props = withDefaults(defineProps<IGearTriadContentProps>(), {
|
|
16
|
+
step: undefined,
|
|
17
|
+
option: undefined,
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
const contentsContext = inject(GEAR_TRIAD_CONTENTS_KEY, undefined);
|
|
21
|
+
|
|
22
|
+
const registration = contentsContext
|
|
23
|
+
? contentsContext.registerContent(props.option)
|
|
24
|
+
: undefined;
|
|
25
|
+
|
|
26
|
+
const isVisible = computed(() => {
|
|
27
|
+
if (props.option !== undefined && contentsContext) {
|
|
28
|
+
return props.option === contentsContext.activeOptionIndex.value + 1;
|
|
29
|
+
}
|
|
30
|
+
return true;
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
const resolvedStep = computed(() => {
|
|
34
|
+
if (props.step !== undefined) {
|
|
35
|
+
if (typeof props.step === 'number') {
|
|
36
|
+
return String(props.step).padStart(2, '0');
|
|
37
|
+
}
|
|
38
|
+
return String(props.step);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const idx = (registration?.index ?? 0) + 1;
|
|
42
|
+
return String(idx).padStart(2, '0');
|
|
43
|
+
});
|
|
44
|
+
</script>
|
|
45
|
+
|
|
46
|
+
<template>
|
|
47
|
+
<div
|
|
48
|
+
v-if="isVisible"
|
|
49
|
+
class="alpha-gear-triad-content flex items-start gap-4 select-none"
|
|
50
|
+
>
|
|
51
|
+
<span class="alpha-gear-triad-content__step font-bold text-2xl text-slate-700 w-10 flex-shrink-0 leading-tight font-sans tracking-tight">
|
|
52
|
+
{{ resolvedStep }}
|
|
53
|
+
</span>
|
|
54
|
+
<div class="alpha-gear-triad-content__body flex-1 text-[0.92rem] text-slate-600 font-normal font-sans leading-[1.45]">
|
|
55
|
+
<slot />
|
|
56
|
+
</div>
|
|
57
|
+
</div>
|
|
58
|
+
</template>
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed, inject, onBeforeUpdate, provide, useSlots } from 'vue';
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
GEAR_TRIAD_CONTENTS_KEY,
|
|
6
|
+
GEAR_TRIAD_ROOT_KEY,
|
|
7
|
+
getDefaultGearTriadItem,
|
|
8
|
+
type IResolvedGearTriadItem,
|
|
9
|
+
} from '../../../../utils/gearTriad';
|
|
10
|
+
|
|
11
|
+
defineOptions({
|
|
12
|
+
name: 'GearTriadContents',
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
export interface IGearTriadContentsProps {
|
|
16
|
+
readonly title?: string;
|
|
17
|
+
readonly description?: string;
|
|
18
|
+
readonly option?: number;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const props = withDefaults(defineProps<IGearTriadContentsProps>(), {
|
|
22
|
+
title: undefined,
|
|
23
|
+
description: undefined,
|
|
24
|
+
option: undefined,
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
const slots = useSlots();
|
|
28
|
+
const rootContext = inject(GEAR_TRIAD_ROOT_KEY, undefined);
|
|
29
|
+
rootContext?.registerContents();
|
|
30
|
+
|
|
31
|
+
let contentCounter = 0;
|
|
32
|
+
const optionCounters: Record<number, number> = {};
|
|
33
|
+
onBeforeUpdate(() => {
|
|
34
|
+
contentCounter = 0;
|
|
35
|
+
for (const k in optionCounters) {
|
|
36
|
+
optionCounters[k] = 0;
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
const registerContent = (option?: number) => {
|
|
41
|
+
if (option !== undefined) {
|
|
42
|
+
optionCounters[option] = (optionCounters[option] ?? 0) + 1;
|
|
43
|
+
return { index: optionCounters[option] - 1 };
|
|
44
|
+
}
|
|
45
|
+
const idx = contentCounter++;
|
|
46
|
+
return { index: idx };
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const resolvedOptionIndex = computed(() => {
|
|
50
|
+
if (props.option !== undefined) {
|
|
51
|
+
return Math.max(0, props.option - 1);
|
|
52
|
+
}
|
|
53
|
+
return rootContext?.activeOptionIndex.value ?? 0;
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
const activeItem = computed<IResolvedGearTriadItem>(() => {
|
|
57
|
+
if (rootContext?.items.value) {
|
|
58
|
+
const item = rootContext.items.value[resolvedOptionIndex.value];
|
|
59
|
+
if (item) {
|
|
60
|
+
return item;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return getDefaultGearTriadItem(resolvedOptionIndex.value);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
provide(GEAR_TRIAD_CONTENTS_KEY, {
|
|
67
|
+
activeItem,
|
|
68
|
+
activeOptionIndex: resolvedOptionIndex,
|
|
69
|
+
registerContent,
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
const isVisible = computed(() => {
|
|
73
|
+
if (!rootContext?.isShifted.value) {
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
if (props.option !== undefined) {
|
|
77
|
+
return props.option - 1 === rootContext.activeOptionIndex.value;
|
|
78
|
+
}
|
|
79
|
+
return true;
|
|
80
|
+
});
|
|
81
|
+
</script>
|
|
82
|
+
|
|
83
|
+
<template>
|
|
84
|
+
<div
|
|
85
|
+
class="alpha-gear-triad-contents absolute right-2.5 top-1/2 -translate-y-1/2 w-[490px] flex flex-col select-none box-border pointer-events-auto transition-all duration-500 ease-out"
|
|
86
|
+
:class="[
|
|
87
|
+
isVisible
|
|
88
|
+
? 'opacity-100 translate-x-0 delay-200'
|
|
89
|
+
: 'opacity-0 pointer-events-none translate-x-8',
|
|
90
|
+
]"
|
|
91
|
+
>
|
|
92
|
+
<!-- Header: Option Title -->
|
|
93
|
+
<slot name="title">
|
|
94
|
+
<h3 class="alpha-gear-triad-contents__title text-2xl font-bold font-sans tracking-tight text-slate-900 mb-2">
|
|
95
|
+
{{ props.title ?? activeItem.title }}
|
|
96
|
+
</h3>
|
|
97
|
+
</slot>
|
|
98
|
+
<!-- Header: Option Description -->
|
|
99
|
+
<slot name="description">
|
|
100
|
+
<p class="alpha-gear-triad-contents__desc text-sm font-sans text-slate-500 leading-relaxed mb-6">
|
|
101
|
+
{{ props.description ?? activeItem.description }}
|
|
102
|
+
</p>
|
|
103
|
+
</slot>
|
|
104
|
+
<!-- Body: List of GearTriadContent items -->
|
|
105
|
+
<div class="alpha-gear-triad-contents__items flex flex-col gap-3.5">
|
|
106
|
+
<slot v-if="$slots[String(resolvedOptionIndex + 1)]" :name="String(resolvedOptionIndex + 1)" />
|
|
107
|
+
<slot v-else-if="$slots[`option-${resolvedOptionIndex + 1}`]" :name="`option-${resolvedOptionIndex + 1}`" />
|
|
108
|
+
<slot v-else />
|
|
109
|
+
</div>
|
|
110
|
+
</div>
|
|
111
|
+
</template>
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed, inject } from 'vue';
|
|
3
|
+
|
|
4
|
+
import { GEAR_TRIAD_CALLOUT_KEY } from '../../../../utils/gearTriad';
|
|
5
|
+
|
|
6
|
+
defineOptions({
|
|
7
|
+
name: 'GearTriadDescription',
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
export interface IGearTriadDescriptionProps {
|
|
11
|
+
readonly color?: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const props = withDefaults(defineProps<IGearTriadDescriptionProps>(), {
|
|
15
|
+
color: undefined,
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
const calloutContext = inject(GEAR_TRIAD_CALLOUT_KEY, undefined);
|
|
19
|
+
|
|
20
|
+
const descriptionColor = computed(() => {
|
|
21
|
+
return props.color ?? calloutContext?.item.value.textColor ?? '#64748b';
|
|
22
|
+
});
|
|
23
|
+
</script>
|
|
24
|
+
|
|
25
|
+
<template>
|
|
26
|
+
<div
|
|
27
|
+
class="alpha-gear-triad-description text-[0.92rem] leading-[1.45] font-normal select-none"
|
|
28
|
+
:style="{
|
|
29
|
+
color: descriptionColor,
|
|
30
|
+
fontFamily:
|
|
31
|
+
'ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, \'Segoe UI\', Roboto, sans-serif',
|
|
32
|
+
}"
|
|
33
|
+
>
|
|
34
|
+
<slot>
|
|
35
|
+
{{ calloutContext?.item.value.description }}
|
|
36
|
+
</slot>
|
|
37
|
+
</div>
|
|
38
|
+
</template>
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed, inject } from 'vue';
|
|
3
|
+
|
|
4
|
+
import { GEAR_TRIAD_CALLOUT_KEY } from '../../../../utils/gearTriad';
|
|
5
|
+
|
|
6
|
+
defineOptions({
|
|
7
|
+
name: 'GearTriadHeading',
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
export interface IGearTriadHeadingProps {
|
|
11
|
+
readonly color?: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const props = withDefaults(defineProps<IGearTriadHeadingProps>(), {
|
|
15
|
+
color: undefined,
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
const calloutContext = inject(GEAR_TRIAD_CALLOUT_KEY, undefined);
|
|
19
|
+
|
|
20
|
+
const headingColor = computed(() => {
|
|
21
|
+
return props.color ?? calloutContext?.item.value.titleColor ?? '#0f172a';
|
|
22
|
+
});
|
|
23
|
+
</script>
|
|
24
|
+
|
|
25
|
+
<template>
|
|
26
|
+
<div
|
|
27
|
+
class="alpha-gear-triad-heading font-bold text-[1.15rem] tracking-tight leading-snug mb-1.5 select-none"
|
|
28
|
+
:style="{
|
|
29
|
+
color: headingColor,
|
|
30
|
+
fontFamily:
|
|
31
|
+
'ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, \'Segoe UI\', Roboto, sans-serif',
|
|
32
|
+
}"
|
|
33
|
+
>
|
|
34
|
+
<slot>
|
|
35
|
+
{{ calloutContext?.item.value.title }}
|
|
36
|
+
</slot>
|
|
37
|
+
</div>
|
|
38
|
+
</template>
|