@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,591 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import {
|
|
3
|
+
type ComputedRef,
|
|
4
|
+
computed,
|
|
5
|
+
inject,
|
|
6
|
+
onBeforeUpdate,
|
|
7
|
+
provide,
|
|
8
|
+
type Ref,
|
|
9
|
+
ref,
|
|
10
|
+
useSlots,
|
|
11
|
+
type VNode,
|
|
12
|
+
watch,
|
|
13
|
+
} from 'vue';
|
|
14
|
+
|
|
15
|
+
import {
|
|
16
|
+
createGearTriadGeometry,
|
|
17
|
+
GEAR_TRIAD_BASE_COLOR,
|
|
18
|
+
GEAR_TRIAD_ROOT_KEY,
|
|
19
|
+
type IGearTriadItem,
|
|
20
|
+
type IResolvedGearTriadItem,
|
|
21
|
+
resolveGearTriadItems,
|
|
22
|
+
resolveSingleGearTriadItem,
|
|
23
|
+
type TGearTriadIcon,
|
|
24
|
+
} from '../../../../utils/gearTriad';
|
|
25
|
+
import { useDiagramAutoScale } from '../../../../utils/useDiagramAutoScale';
|
|
26
|
+
import { useMergedUnoAttrs } from '../../../../utils/useMergedUnoAttrs';
|
|
27
|
+
import GearTriadCallout from './GearTriadCallout.vue';
|
|
28
|
+
import GearTriadCenter from './GearTriadCenter.vue';
|
|
29
|
+
import GearTriadIcon from './GearTriadIcon.vue';
|
|
30
|
+
|
|
31
|
+
defineOptions({
|
|
32
|
+
name: 'GearTriad',
|
|
33
|
+
inheritAttrs: false,
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
export interface IGearTriadProps {
|
|
37
|
+
readonly title?: string;
|
|
38
|
+
readonly subtitle?: string;
|
|
39
|
+
readonly items?: readonly IGearTriadItem[];
|
|
40
|
+
readonly icons?: readonly (TGearTriadIcon | undefined)[];
|
|
41
|
+
readonly animation?: boolean;
|
|
42
|
+
readonly active?: boolean;
|
|
43
|
+
readonly startDelay?: number;
|
|
44
|
+
readonly scale?: number;
|
|
45
|
+
readonly autoScale?: boolean;
|
|
46
|
+
readonly maxScale?: number;
|
|
47
|
+
readonly height?: number | string;
|
|
48
|
+
readonly centerIcon?: string | object | false;
|
|
49
|
+
readonly step?: number;
|
|
50
|
+
readonly clicks?: number;
|
|
51
|
+
readonly moved?: boolean;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const props = withDefaults(defineProps<IGearTriadProps>(), {
|
|
55
|
+
title: undefined,
|
|
56
|
+
subtitle: undefined,
|
|
57
|
+
items: undefined,
|
|
58
|
+
icons: undefined,
|
|
59
|
+
animation: true,
|
|
60
|
+
active: undefined,
|
|
61
|
+
startDelay: undefined,
|
|
62
|
+
scale: undefined,
|
|
63
|
+
autoScale: true,
|
|
64
|
+
maxScale: undefined,
|
|
65
|
+
height: undefined,
|
|
66
|
+
centerIcon: 'gear',
|
|
67
|
+
step: undefined,
|
|
68
|
+
clicks: undefined,
|
|
69
|
+
moved: undefined,
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
const emit = defineEmits<{
|
|
73
|
+
(e: 'click', event: MouseEvent): void;
|
|
74
|
+
(e: 'update:step', step: number): void;
|
|
75
|
+
(e: 'update:moved', moved: boolean): void;
|
|
76
|
+
}>();
|
|
77
|
+
|
|
78
|
+
const slots = useSlots();
|
|
79
|
+
|
|
80
|
+
const slidevClicks = inject<
|
|
81
|
+
| {
|
|
82
|
+
current: Ref<number> | ComputedRef<number> | number;
|
|
83
|
+
total?: Ref<number> | ComputedRef<number> | number;
|
|
84
|
+
}
|
|
85
|
+
| undefined
|
|
86
|
+
>('$$slidev-clicks-context', undefined);
|
|
87
|
+
|
|
88
|
+
const shiftingIntro = inject<
|
|
89
|
+
| {
|
|
90
|
+
active: ComputedRef<boolean>;
|
|
91
|
+
clicks?: Ref<number> | ComputedRef<number>;
|
|
92
|
+
isShifting?: ComputedRef<boolean>;
|
|
93
|
+
}
|
|
94
|
+
| undefined
|
|
95
|
+
>('SLIDEV_LAYOUT_SHIFTING_INTRO', undefined);
|
|
96
|
+
|
|
97
|
+
const internalStep = ref(props.step ?? 0);
|
|
98
|
+
|
|
99
|
+
interface INamedComponent {
|
|
100
|
+
readonly name?: string;
|
|
101
|
+
readonly __name?: string;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const registeredContentsCount = ref(0);
|
|
105
|
+
const registerContents = () => {
|
|
106
|
+
registeredContentsCount.value++;
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
function checkHasContentsVNodes(nodes: readonly VNode[] | undefined): boolean {
|
|
110
|
+
if (!nodes) {
|
|
111
|
+
return false;
|
|
112
|
+
}
|
|
113
|
+
for (const node of nodes) {
|
|
114
|
+
if (!node) {
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
if (typeof node.type === 'object' && node.type !== null) {
|
|
118
|
+
const comp = node.type as INamedComponent;
|
|
119
|
+
if (
|
|
120
|
+
comp.name === 'GearTriadContents' ||
|
|
121
|
+
comp.__name === 'GearTriadContents'
|
|
122
|
+
) {
|
|
123
|
+
return true;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
if (Array.isArray(node.children)) {
|
|
127
|
+
if (checkHasContentsVNodes(node.children as readonly VNode[])) {
|
|
128
|
+
return true;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return false;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const slotHasContents = computed(() => {
|
|
136
|
+
return slots.default ? checkHasContentsVNodes(slots.default()) : false;
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
const supportsClicks = computed(() => {
|
|
140
|
+
return registeredContentsCount.value > 0 || slotHasContents.value;
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
watch(
|
|
144
|
+
() => props.step,
|
|
145
|
+
(val) => {
|
|
146
|
+
if (val !== undefined) {
|
|
147
|
+
internalStep.value = val;
|
|
148
|
+
}
|
|
149
|
+
},
|
|
150
|
+
);
|
|
151
|
+
|
|
152
|
+
watch(
|
|
153
|
+
() => props.moved,
|
|
154
|
+
(val) => {
|
|
155
|
+
if (val !== undefined) {
|
|
156
|
+
internalStep.value = val ? 1 : 0;
|
|
157
|
+
}
|
|
158
|
+
},
|
|
159
|
+
);
|
|
160
|
+
|
|
161
|
+
const resolvedStep = computed(() => {
|
|
162
|
+
if (props.step !== undefined) {
|
|
163
|
+
return props.step;
|
|
164
|
+
}
|
|
165
|
+
if (props.moved !== undefined) {
|
|
166
|
+
return props.moved ? 1 : 0;
|
|
167
|
+
}
|
|
168
|
+
if (props.clicks !== undefined) {
|
|
169
|
+
return props.clicks;
|
|
170
|
+
}
|
|
171
|
+
if (shiftingIntro?.clicks && typeof shiftingIntro.clicks.value === 'number') {
|
|
172
|
+
return shiftingIntro.clicks.value;
|
|
173
|
+
}
|
|
174
|
+
if (slidevClicks) {
|
|
175
|
+
const curr =
|
|
176
|
+
typeof slidevClicks.current === 'object' &&
|
|
177
|
+
'value' in slidevClicks.current
|
|
178
|
+
? slidevClicks.current.value
|
|
179
|
+
: (slidevClicks.current as number);
|
|
180
|
+
if (typeof curr === 'number') {
|
|
181
|
+
return curr;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
return internalStep.value;
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
const isShifted = computed(() => resolvedStep.value > 0);
|
|
188
|
+
|
|
189
|
+
const activeOptionIndex = computed(() => {
|
|
190
|
+
if (resolvedStep.value <= 0) {
|
|
191
|
+
return 0;
|
|
192
|
+
}
|
|
193
|
+
return (resolvedStep.value - 1) % 3;
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
function handleDiagramClick(event: MouseEvent): void {
|
|
197
|
+
emit('click', event);
|
|
198
|
+
if (!supportsClicks.value) {
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
const nextStep = (internalStep.value + 1) % 4;
|
|
202
|
+
internalStep.value = nextStep;
|
|
203
|
+
emit('update:step', nextStep);
|
|
204
|
+
emit('update:moved', nextStep > 0);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
const diagramTranslateX = computed(() => {
|
|
208
|
+
return isShifted.value ? -260 : 0;
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
const gearRotation = computed(() => {
|
|
212
|
+
if (!isShifted.value) {
|
|
213
|
+
return 0;
|
|
214
|
+
}
|
|
215
|
+
if (activeOptionIndex.value === 0) {
|
|
216
|
+
return 150;
|
|
217
|
+
}
|
|
218
|
+
if (activeOptionIndex.value === 1) {
|
|
219
|
+
return 30;
|
|
220
|
+
}
|
|
221
|
+
return -90;
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
const isAnimated = computed(() => {
|
|
225
|
+
if (!props.animation) {
|
|
226
|
+
return false;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
if (props.active !== undefined) {
|
|
230
|
+
return props.active;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
if (shiftingIntro) {
|
|
234
|
+
return shiftingIntro.active.value;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
return true;
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
const resolvedStartDelay = computed(() => {
|
|
241
|
+
if (props.startDelay !== undefined) {
|
|
242
|
+
return props.startDelay;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
if (shiftingIntro) {
|
|
246
|
+
return shiftingIntro.isShifting?.value ? 600 : 0;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
return 0;
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
const calloutOverrides = ref<Record<number, IGearTriadItem>>({});
|
|
253
|
+
|
|
254
|
+
const resolvedItems = computed(() => {
|
|
255
|
+
const base = resolveGearTriadItems(props.items, props.icons);
|
|
256
|
+
|
|
257
|
+
return [
|
|
258
|
+
resolveSingleGearTriadItem(
|
|
259
|
+
{
|
|
260
|
+
...base[0],
|
|
261
|
+
...(calloutOverrides.value[0] ?? {}),
|
|
262
|
+
},
|
|
263
|
+
0,
|
|
264
|
+
),
|
|
265
|
+
resolveSingleGearTriadItem(
|
|
266
|
+
{
|
|
267
|
+
...base[1],
|
|
268
|
+
...(calloutOverrides.value[1] ?? {}),
|
|
269
|
+
},
|
|
270
|
+
1,
|
|
271
|
+
),
|
|
272
|
+
resolveSingleGearTriadItem(
|
|
273
|
+
{
|
|
274
|
+
...base[2],
|
|
275
|
+
...(calloutOverrides.value[2] ?? {}),
|
|
276
|
+
},
|
|
277
|
+
2,
|
|
278
|
+
),
|
|
279
|
+
] as const;
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
let calloutCounter = 0;
|
|
283
|
+
onBeforeUpdate(() => {
|
|
284
|
+
calloutCounter = 0;
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
const registerCallout = (
|
|
288
|
+
override?: ComputedRef<IGearTriadItem> | (() => IGearTriadItem),
|
|
289
|
+
) => {
|
|
290
|
+
const idx = calloutCounter++;
|
|
291
|
+
if (override) {
|
|
292
|
+
watch(
|
|
293
|
+
typeof override === 'function' ? override : () => override.value,
|
|
294
|
+
(val) => {
|
|
295
|
+
if (val) {
|
|
296
|
+
calloutOverrides.value = {
|
|
297
|
+
...calloutOverrides.value,
|
|
298
|
+
[idx]: val,
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
},
|
|
302
|
+
{ immediate: true, deep: true },
|
|
303
|
+
);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
return {
|
|
307
|
+
index: idx,
|
|
308
|
+
item: computed(() => resolvedItems.value[idx] ?? resolvedItems.value[0]),
|
|
309
|
+
};
|
|
310
|
+
};
|
|
311
|
+
|
|
312
|
+
provide(GEAR_TRIAD_ROOT_KEY, {
|
|
313
|
+
registerCallout,
|
|
314
|
+
registerContents,
|
|
315
|
+
hasContents: supportsClicks,
|
|
316
|
+
items: resolvedItems,
|
|
317
|
+
animation: isAnimated,
|
|
318
|
+
isShifted,
|
|
319
|
+
currentStep: resolvedStep,
|
|
320
|
+
activeOptionIndex,
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
const geo = createGearTriadGeometry();
|
|
324
|
+
|
|
325
|
+
const item0 = computed(() => resolvedItems.value[0]);
|
|
326
|
+
const item1 = computed(() => resolvedItems.value[1]);
|
|
327
|
+
const item2 = computed(() => resolvedItems.value[2]);
|
|
328
|
+
|
|
329
|
+
const sectors = computed(() => [
|
|
330
|
+
{
|
|
331
|
+
name: 'pink',
|
|
332
|
+
rotation: 0,
|
|
333
|
+
item: item2.value,
|
|
334
|
+
iconPosition: geo.pinkSector.iconPosition,
|
|
335
|
+
},
|
|
336
|
+
{
|
|
337
|
+
name: 'cyan',
|
|
338
|
+
rotation: 120,
|
|
339
|
+
item: item0.value,
|
|
340
|
+
iconPosition: geo.cyanSector.iconPosition,
|
|
341
|
+
},
|
|
342
|
+
{
|
|
343
|
+
name: 'orange',
|
|
344
|
+
rotation: 240,
|
|
345
|
+
item: item1.value,
|
|
346
|
+
iconPosition: geo.orangeSector.iconPosition,
|
|
347
|
+
},
|
|
348
|
+
]);
|
|
349
|
+
|
|
350
|
+
function getSectorFaceColor(sector: {
|
|
351
|
+
name: string;
|
|
352
|
+
item: IResolvedGearTriadItem;
|
|
353
|
+
}): string {
|
|
354
|
+
if (!isShifted.value) {
|
|
355
|
+
return sector.item.color;
|
|
356
|
+
}
|
|
357
|
+
const focusedSectorName =
|
|
358
|
+
activeOptionIndex.value === 0
|
|
359
|
+
? 'cyan'
|
|
360
|
+
: activeOptionIndex.value === 1
|
|
361
|
+
? 'orange'
|
|
362
|
+
: 'pink';
|
|
363
|
+
if (sector.name === focusedSectorName) {
|
|
364
|
+
return sector.item.color;
|
|
365
|
+
}
|
|
366
|
+
return '#d5d8dc';
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
function getSectorIconColor(sector: { name: string }): string {
|
|
370
|
+
if (!isShifted.value) {
|
|
371
|
+
return '#0f172a';
|
|
372
|
+
}
|
|
373
|
+
const focusedSectorName =
|
|
374
|
+
activeOptionIndex.value === 0
|
|
375
|
+
? 'cyan'
|
|
376
|
+
: activeOptionIndex.value === 1
|
|
377
|
+
? 'orange'
|
|
378
|
+
: 'pink';
|
|
379
|
+
if (sector.name === focusedSectorName) {
|
|
380
|
+
return '#0f172a';
|
|
381
|
+
}
|
|
382
|
+
return '#ffffff';
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
const rootRef = ref<HTMLElement | null>(null);
|
|
386
|
+
|
|
387
|
+
const { resolvedScale, containerHeight } = useDiagramAutoScale({
|
|
388
|
+
rootRef,
|
|
389
|
+
baseWidth: 960,
|
|
390
|
+
baseHeight: 480,
|
|
391
|
+
scale: () => props.scale,
|
|
392
|
+
autoScale: () => props.autoScale,
|
|
393
|
+
maxScale: () => props.maxScale,
|
|
394
|
+
height: () => props.height,
|
|
395
|
+
});
|
|
396
|
+
|
|
397
|
+
const resolvedHeightStyle = computed(() => {
|
|
398
|
+
if (props.height !== undefined) {
|
|
399
|
+
return typeof props.height === 'number'
|
|
400
|
+
? `${props.height}px`
|
|
401
|
+
: props.height;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
if (containerHeight.value > 0) {
|
|
405
|
+
return `${containerHeight.value}px`;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
return '100%';
|
|
409
|
+
});
|
|
410
|
+
|
|
411
|
+
const { className, forwardedAttrs } = useMergedUnoAttrs(
|
|
412
|
+
'alpha-gear-triad w-full flex flex-col items-center justify-center select-none font-sans',
|
|
413
|
+
);
|
|
414
|
+
</script>
|
|
415
|
+
|
|
416
|
+
<template>
|
|
417
|
+
<div
|
|
418
|
+
ref="rootRef"
|
|
419
|
+
v-bind="forwardedAttrs()"
|
|
420
|
+
:class="className()"
|
|
421
|
+
:style="{
|
|
422
|
+
'--gear-start-delay': `${resolvedStartDelay}ms`,
|
|
423
|
+
height: resolvedHeightStyle,
|
|
424
|
+
}"
|
|
425
|
+
>
|
|
426
|
+
<!-- Header (Title / Subtitle) -->
|
|
427
|
+
<header
|
|
428
|
+
v-if="title || $slots.title"
|
|
429
|
+
class="alpha-gear-triad__header mb-2 text-center"
|
|
430
|
+
>
|
|
431
|
+
<slot name="title">
|
|
432
|
+
<h2 class="alpha-gear-triad__title text-2xl font-bold font-sans tracking-tight text-slate-900">
|
|
433
|
+
{{ title }}
|
|
434
|
+
</h2>
|
|
435
|
+
</slot>
|
|
436
|
+
<p
|
|
437
|
+
v-if="subtitle || $slots.subtitle"
|
|
438
|
+
class="alpha-gear-triad__subtitle text-sm font-sans text-slate-500 mt-1"
|
|
439
|
+
>
|
|
440
|
+
<slot name="subtitle">{{ subtitle }}</slot>
|
|
441
|
+
</p>
|
|
442
|
+
</header>
|
|
443
|
+
<!-- Auto-Scaled Stage -->
|
|
444
|
+
<div
|
|
445
|
+
class="alpha-gear-triad__scaler relative flex items-center justify-center origin-center transition-transform duration-200"
|
|
446
|
+
:style="{
|
|
447
|
+
width: '960px',
|
|
448
|
+
height: '480px',
|
|
449
|
+
transform: `scale(${resolvedScale})`,
|
|
450
|
+
}"
|
|
451
|
+
>
|
|
452
|
+
<!-- Central Gear SVG Assembly -->
|
|
453
|
+
<div
|
|
454
|
+
class="alpha-gear-triad__diagram relative flex items-center justify-center w-[540px] h-[480px] transition-transform duration-700 ease-[cubic-bezier(0.16,1,0.3,1)]"
|
|
455
|
+
:class="[
|
|
456
|
+
{ 'alpha-gear-triad__diagram--animated': isAnimated },
|
|
457
|
+
supportsClicks ? 'cursor-pointer' : 'cursor-default',
|
|
458
|
+
]"
|
|
459
|
+
:style="{
|
|
460
|
+
transform: `translateX(${diagramTranslateX}px)`,
|
|
461
|
+
}"
|
|
462
|
+
@click="handleDiagramClick"
|
|
463
|
+
>
|
|
464
|
+
<!-- Rotating Wheel (simultaneously rotates while diagram translates) -->
|
|
465
|
+
<div
|
|
466
|
+
class="alpha-gear-triad__wheel relative w-[540px] h-[480px] transition-transform duration-700 ease-[cubic-bezier(0.16,1,0.3,1)]"
|
|
467
|
+
:style="{
|
|
468
|
+
transformOrigin: `${geo.centerX}px ${geo.centerY}px`,
|
|
469
|
+
transform: `rotate(${gearRotation}deg)`,
|
|
470
|
+
}"
|
|
471
|
+
>
|
|
472
|
+
<svg
|
|
473
|
+
class="alpha-gear-triad__svg w-[540px] h-[480px] overflow-visible"
|
|
474
|
+
:viewBox="`0 0 ${geo.viewBoxWidth} ${geo.viewBoxHeight}`"
|
|
475
|
+
>
|
|
476
|
+
<defs>
|
|
477
|
+
<!-- Elevation Drop Shadow for Gear Assembly -->
|
|
478
|
+
<filter id="alpha-gear-assembly-shadow" x="-20%" y="-20%" width="140%" height="140%">
|
|
479
|
+
<feDropShadow dx="0" dy="10" stdDeviation="14" flood-color="#0f172a" flood-opacity="0.22" />
|
|
480
|
+
<feDropShadow dx="0" dy="3" stdDeviation="5" flood-color="#0f172a" flood-opacity="0.10" />
|
|
481
|
+
</filter>
|
|
482
|
+
</defs>
|
|
483
|
+
<!-- Group containing all gear elements with overall elevation drop shadow -->
|
|
484
|
+
<g
|
|
485
|
+
filter="url(#alpha-gear-assembly-shadow)"
|
|
486
|
+
class="alpha-gear-triad__assembly origin-center"
|
|
487
|
+
>
|
|
488
|
+
<!-- LAYER 1: Inter-Sector Valley Shapes Between the 3 Petals (Reused for all 3 Places) -->
|
|
489
|
+
<path
|
|
490
|
+
v-for="sector in sectors"
|
|
491
|
+
:key="`valley-${sector.name}`"
|
|
492
|
+
:d="geo.petal.valleyPath"
|
|
493
|
+
:transform="`rotate(${sector.rotation}, ${geo.centerX}, ${geo.centerY})`"
|
|
494
|
+
:fill="GEAR_TRIAD_BASE_COLOR"
|
|
495
|
+
class="alpha-gear-triad__valley"
|
|
496
|
+
/>
|
|
497
|
+
<!-- LAYER 2: Single Reusable Petal Surface Face Rotated for the 3 Sectors -->
|
|
498
|
+
<g
|
|
499
|
+
v-for="sector in sectors"
|
|
500
|
+
:key="`petal-${sector.name}`"
|
|
501
|
+
:transform="`rotate(${sector.rotation}, ${geo.centerX}, ${geo.centerY})`"
|
|
502
|
+
>
|
|
503
|
+
<path
|
|
504
|
+
:d="geo.petal.facePath"
|
|
505
|
+
:fill="getSectorFaceColor(sector)"
|
|
506
|
+
:class="`alpha-gear-triad__petal alpha-gear-triad__petal--${sector.name}`"
|
|
507
|
+
class="transition-colors duration-500 ease-out"
|
|
508
|
+
/>
|
|
509
|
+
</g>
|
|
510
|
+
<!-- LAYER 4: Outline Icons Stamped on the 3 Petals -->
|
|
511
|
+
<foreignObject
|
|
512
|
+
v-for="sector in sectors"
|
|
513
|
+
v-show="sector.item.icon"
|
|
514
|
+
:key="`icon-${sector.name}`"
|
|
515
|
+
:x="sector.iconPosition.x - 17"
|
|
516
|
+
:y="sector.iconPosition.y - 17"
|
|
517
|
+
width="34"
|
|
518
|
+
height="34"
|
|
519
|
+
class="overflow-visible pointer-events-none select-none"
|
|
520
|
+
>
|
|
521
|
+
<div
|
|
522
|
+
class="w-full h-full flex items-center justify-center origin-center transition-transform duration-700 ease-[cubic-bezier(0.16,1,0.3,1)]"
|
|
523
|
+
:style="{
|
|
524
|
+
transform: `rotate(${-gearRotation}deg)`,
|
|
525
|
+
}"
|
|
526
|
+
>
|
|
527
|
+
<GearTriadIcon
|
|
528
|
+
:icon="sector.item.icon"
|
|
529
|
+
:size="34"
|
|
530
|
+
:color="getSectorIconColor(sector)"
|
|
531
|
+
:stroke-width="2"
|
|
532
|
+
/>
|
|
533
|
+
</div>
|
|
534
|
+
</foreignObject>
|
|
535
|
+
</g>
|
|
536
|
+
</svg>
|
|
537
|
+
</div>
|
|
538
|
+
<!-- LAYER 5: Center Floating Circular Hub -->
|
|
539
|
+
<slot name="center">
|
|
540
|
+
<GearTriadCenter
|
|
541
|
+
:radius="geo.hubRadius"
|
|
542
|
+
:icon="props.centerIcon"
|
|
543
|
+
:icon-size="44"
|
|
544
|
+
:class="{ 'alpha-gear-center--animated': isAnimated }"
|
|
545
|
+
:style="{
|
|
546
|
+
top: `${geo.centerY}px`,
|
|
547
|
+
left: `${geo.centerX}px`,
|
|
548
|
+
}"
|
|
549
|
+
/>
|
|
550
|
+
</slot>
|
|
551
|
+
</div>
|
|
552
|
+
<!-- LAYER 6: Surrounding Callouts & Detail Contents -->
|
|
553
|
+
<slot v-if="$slots.default" />
|
|
554
|
+
<template v-else>
|
|
555
|
+
<GearTriadCallout />
|
|
556
|
+
<GearTriadCallout />
|
|
557
|
+
<GearTriadCallout />
|
|
558
|
+
</template>
|
|
559
|
+
</div>
|
|
560
|
+
</div>
|
|
561
|
+
</template>
|
|
562
|
+
|
|
563
|
+
<style scoped>
|
|
564
|
+
.alpha-gear-triad__diagram--animated {
|
|
565
|
+
animation: gear-triad-fade-in 700ms cubic-bezier(0.16, 1, 0.3, 1) calc(var(--gear-start-delay, 0ms)) backwards;
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
.alpha-gear-center--animated {
|
|
569
|
+
animation: gear-center-pop-in 600ms cubic-bezier(0.34, 1.56, 0.64, 1) calc(var(--gear-start-delay, 0ms) + 100ms) backwards;
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
@keyframes gear-triad-fade-in {
|
|
573
|
+
0% {
|
|
574
|
+
opacity: 0;
|
|
575
|
+
}
|
|
576
|
+
100% {
|
|
577
|
+
opacity: 1;
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
@keyframes gear-center-pop-in {
|
|
582
|
+
0% {
|
|
583
|
+
opacity: 0;
|
|
584
|
+
transform: translate(-50%, -50%) scale(0.6);
|
|
585
|
+
}
|
|
586
|
+
100% {
|
|
587
|
+
opacity: 1;
|
|
588
|
+
transform: translate(-50%, -50%) scale(1);
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
</style>
|