@alphacifer/slidev-addon-theme 0.0.6 → 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.
Files changed (105) hide show
  1. package/README.md +117 -51
  2. package/components/{chevron-card → card/chevron-card}/ChevronCard.vue +2 -2
  3. package/components/{chevron-card → card/chevron-card}/ChevronCardBadge.vue +1 -1
  4. package/components/{chevron-card → card/chevron-card}/ChevronCardContent.vue +1 -1
  5. package/components/{chevron-card → card/chevron-card}/ChevronCardHeading.vue +1 -1
  6. package/components/{horiz-card → card/horiz-card}/HorizCard.vue +2 -2
  7. package/components/{horiz-card → card/horiz-card}/HorizCardBadge.vue +2 -2
  8. package/components/{horiz-card → card/horiz-card}/HorizCardContent.vue +2 -2
  9. package/components/{horiz-card → card/horiz-card}/HorizCardHeading.vue +2 -2
  10. package/components/{horiz-card → card/horiz-card}/HorizCardIcon.vue +2 -2
  11. package/components/{vert-card → card/vert-card}/VertCard.vue +2 -2
  12. package/components/{vert-card → card/vert-card}/VertCardBadge.vue +5 -2
  13. package/components/{vert-card → card/vert-card}/VertCardContent.vue +2 -2
  14. package/components/{vert-card → card/vert-card}/VertCardHeading.vue +2 -2
  15. package/components/{vert-card → card/vert-card}/VertCardIcon.vue +2 -2
  16. package/components/{vert-card → card/vert-card}/VertCardTitle.vue +2 -2
  17. package/components/comparisons/arc-comparison/ArcComparison.vue +654 -0
  18. package/components/comparisons/arc-comparison/ArcComparisonBadge.vue +29 -0
  19. package/components/comparisons/arc-comparison/ArcComparisonContent.vue +29 -0
  20. package/components/comparisons/arc-comparison/ArcComparisonContents.vue +17 -0
  21. package/components/comparisons/arc-comparison/ArcComparisonHeading.vue +29 -0
  22. package/components/comparisons/arc-comparison/ArcComparisonLeft.vue +268 -0
  23. package/components/comparisons/arc-comparison/ArcComparisonOrbit.vue +47 -0
  24. package/components/comparisons/arc-comparison/ArcComparisonRight.vue +271 -0
  25. package/components/comparisons/arc-comparison/ArcComparisonTitle.vue +29 -0
  26. package/components/comparisons/table-comparison/TableComparison.vue +254 -0
  27. package/components/comparisons/table-comparison/TableComparisonCell.vue +88 -0
  28. package/components/comparisons/table-comparison/TableComparisonCol.vue +97 -0
  29. package/components/comparisons/table-comparison/TableComparisonCols.vue +74 -0
  30. package/components/comparisons/table-comparison/TableComparisonRow.vue +92 -0
  31. package/components/comparisons/table-comparison/TableComparisonRows.vue +21 -0
  32. package/components/core/ReflectedTitle.vue +2 -1
  33. package/components/core/arc-orbit/ArcOrbit.vue +468 -0
  34. package/components/{arc-compare/ArcCompareBadge.vue → core/arc-orbit/ArcOrbitBadge.vue} +11 -8
  35. package/components/core/arc-orbit/ArcOrbitCallout.vue +400 -0
  36. package/components/{arc-compare/ArcCompareContent.vue → core/arc-orbit/ArcOrbitContent.vue} +8 -8
  37. package/components/{arc-compare/ArcCompareContents.vue → core/arc-orbit/ArcOrbitContents.vue} +3 -3
  38. package/components/{arc-compare/ArcCompareHeading.vue → core/arc-orbit/ArcOrbitHeading.vue} +11 -8
  39. package/components/core/arc-orbit/ArcOrbitTitle.vue +50 -0
  40. package/components/{thanks → core/thanks}/ThanksOutlineSquare.vue +1 -1
  41. package/components/{thanks → core/thanks}/ThanksSquare.vue +1 -1
  42. package/components/{quad-hub/QuadHub.vue → facets/tetrad/rect-orbit-tetrad/RectOrbitTetrad.vue} +71 -69
  43. package/components/{quad-hub/QuadHubCallout.vue → facets/tetrad/rect-orbit-tetrad/RectOrbitTetradCallout.vue} +45 -43
  44. package/components/{quad-hub/QuadHubCenter.vue → facets/tetrad/rect-orbit-tetrad/RectOrbitTetradCenter.vue} +4 -4
  45. package/components/{quad-hub/QuadHubContent.vue → facets/tetrad/rect-orbit-tetrad/RectOrbitTetradContent.vue} +6 -6
  46. package/components/{quad-hub/QuadHubHeading.vue → facets/tetrad/rect-orbit-tetrad/RectOrbitTetradHeading.vue} +6 -6
  47. package/components/{quad-hub/QuadHubIcon.vue → facets/tetrad/rect-orbit-tetrad/RectOrbitTetradIcon.vue} +6 -6
  48. package/components/{arrow-triad → facets/triad/arrow-triad}/ArrowTriad.vue +3 -3
  49. package/components/{arrow-triad → facets/triad/arrow-triad}/ArrowTriadCallout.vue +1 -1
  50. package/components/{arrow-triad → facets/triad/arrow-triad}/ArrowTriadContent.vue +1 -1
  51. package/components/{arrow-triad → facets/triad/arrow-triad}/ArrowTriadHeading.vue +1 -1
  52. package/components/facets/triad/gear-triad/GearTriad.vue +591 -0
  53. package/components/facets/triad/gear-triad/GearTriadCallout.vue +285 -0
  54. package/components/facets/triad/gear-triad/GearTriadCenter.vue +41 -0
  55. package/components/facets/triad/gear-triad/GearTriadContent.vue +58 -0
  56. package/components/facets/triad/gear-triad/GearTriadContents.vue +111 -0
  57. package/components/facets/triad/gear-triad/GearTriadDescription.vue +38 -0
  58. package/components/facets/triad/gear-triad/GearTriadHeading.vue +38 -0
  59. package/components/facets/triad/gear-triad/GearTriadIcon.vue +157 -0
  60. package/components/{hex-triad → facets/triad/hex-triad}/HexTriad.vue +2 -2
  61. package/components/{hex-triad → facets/triad/hex-triad}/HexTriadBadge.vue +1 -1
  62. package/components/{hex-triad → facets/triad/hex-triad}/HexTriadCallout.vue +1 -1
  63. package/components/{hex-triad → facets/triad/hex-triad}/HexTriadHeading.vue +1 -1
  64. package/components/{arc-arrow-process → process/arc-arrow-process}/ArcArrowProcess.vue +2 -2
  65. package/components/{arc-arrow-process → process/arc-arrow-process}/ArcArrowProcessArrow.vue +1 -1
  66. package/components/{arc-arrow-process → process/arc-arrow-process}/ArcArrowProcessCallout.vue +1 -1
  67. package/components/{arc-arrow-process → process/arc-arrow-process}/ArcArrowProcessContent.vue +1 -1
  68. package/components/{arc-arrow-process → process/arc-arrow-process}/ArcArrowProcessHeading.vue +1 -1
  69. package/package.json +1 -1
  70. package/utils/arcComparison/context.ts +40 -0
  71. package/utils/arcComparison/createArcComparisonGeometry.ts +175 -0
  72. package/utils/arcComparison/index.ts +3 -0
  73. package/utils/{arcCompare/resolveArcCompareItems.ts → arcComparison/resolveArcComparisonItems.ts} +24 -45
  74. package/utils/arcOrbit/context.ts +38 -0
  75. package/utils/{arcCompare/createArcCompareGeometry.ts → arcOrbit/createArcOrbitGeometry.ts} +77 -108
  76. package/utils/arcOrbit/index.ts +3 -0
  77. package/utils/arcOrbit/resolveArcOrbitItems.ts +92 -0
  78. package/utils/gearTriad/context.ts +51 -0
  79. package/utils/gearTriad/createGearTriadGeometry.ts +210 -0
  80. package/utils/gearTriad/index.ts +3 -0
  81. package/utils/gearTriad/resolveGearTriadItems.ts +159 -0
  82. package/utils/rectOrbitTetrad/context.ts +31 -0
  83. package/utils/{quadHub/createQuadHubGeometry.ts → rectOrbitTetrad/createRectOrbitTetradGeometry.ts} +33 -28
  84. package/utils/rectOrbitTetrad/index.ts +3 -0
  85. package/utils/{quadHub/resolveQuadHubItems.ts → rectOrbitTetrad/resolveRectOrbitTetradItems.ts} +25 -25
  86. package/utils/tableComparison/constants.ts +72 -0
  87. package/utils/tableComparison/context.ts +24 -0
  88. package/utils/tableComparison/index.ts +2 -0
  89. package/utils/useDiagramAutoScale.ts +1 -1
  90. package/components/arc-compare/ArcCompare.vue +0 -443
  91. package/components/arc-compare/ArcCompareCallout.vue +0 -386
  92. package/components/arc-compare/ArcCompareLeft.vue +0 -183
  93. package/components/arc-compare/ArcCompareRight.vue +0 -183
  94. package/components/arc-compare/ArcCompareTitle.vue +0 -47
  95. package/utils/arcCompare/context.ts +0 -36
  96. package/utils/arcCompare/index.ts +0 -3
  97. package/utils/quadHub/context.ts +0 -26
  98. package/utils/quadHub/index.ts +0 -3
  99. /package/components/{shifting-heading → core}/TransitionHeading.vue +0 -0
  100. /package/components/{thanks → core/thanks}/ThanksContent.vue +0 -0
  101. /package/components/{arrow-triad → facets/triad/arrow-triad}/ArrowTriadIcon.vue +0 -0
  102. /package/components/{hex-triad → facets/triad/hex-triad}/HexTriadCenterBadge.vue +0 -0
  103. /package/components/{hex-triad → facets/triad/hex-triad}/HexTriadContent.vue +0 -0
  104. /package/components/{hex-triad → facets/triad/hex-triad}/HexTriadLayer.vue +0 -0
  105. /package/components/{arc-arrow-process → process/arc-arrow-process}/ArcArrowProcessIcon.vue +0 -0
@@ -0,0 +1,17 @@
1
+ <script setup lang="ts">
2
+ import ArcOrbitContents from '../../core/arc-orbit/ArcOrbitContents.vue';
3
+
4
+ defineOptions({
5
+ inheritAttrs: false,
6
+ name: 'ArcComparisonContents',
7
+ });
8
+ </script>
9
+
10
+ <template>
11
+ <ArcOrbitContents
12
+ v-bind="$attrs"
13
+ class="alpha-arc-comparison-contents"
14
+ >
15
+ <slot />
16
+ </ArcOrbitContents>
17
+ </template>
@@ -0,0 +1,29 @@
1
+ <script setup lang="ts">
2
+ import ArcOrbitHeading, {
3
+ type IArcOrbitHeadingProps,
4
+ } from '../../core/arc-orbit/ArcOrbitHeading.vue';
5
+
6
+ defineOptions({
7
+ inheritAttrs: false,
8
+ name: 'ArcComparisonHeading',
9
+ });
10
+
11
+ export interface IArcComparisonHeadingProps extends IArcOrbitHeadingProps {}
12
+
13
+ const props = defineProps<IArcComparisonHeadingProps>();
14
+ </script>
15
+
16
+ <template>
17
+ <ArcOrbitHeading
18
+ v-if="$slots.default"
19
+ v-bind="{ ...props, ...$attrs }"
20
+ class="alpha-arc-comparison-heading"
21
+ >
22
+ <slot />
23
+ </ArcOrbitHeading>
24
+ <ArcOrbitHeading
25
+ v-else
26
+ v-bind="{ ...props, ...$attrs }"
27
+ class="alpha-arc-comparison-heading"
28
+ />
29
+ </template>
@@ -0,0 +1,268 @@
1
+ <script setup lang="ts">
2
+ import {
3
+ type ComputedRef,
4
+ computed,
5
+ Fragment,
6
+ inject,
7
+ provide,
8
+ ref,
9
+ useSlots,
10
+ type VNode,
11
+ } from 'vue';
12
+
13
+ import {
14
+ ARC_COMPARISON_ROOT_KEY,
15
+ ARC_COMPARISON_SIDE_KEY,
16
+ DEFAULT_LEFT_COLOR,
17
+ DEFAULT_LEFT_ITEMS,
18
+ } from '../../../utils/arcComparison';
19
+ import {
20
+ ARC_ORBIT_ROOT_KEY,
21
+ type IArcOrbitGeometry,
22
+ type TArcOrbitPosition,
23
+ } from '../../../utils/arcOrbit';
24
+ import { useMergedUnoAttrs } from '../../../utils/useMergedUnoAttrs';
25
+ import ArcComparisonContents from './ArcComparisonContents.vue';
26
+ import ArcComparisonOrbit from './ArcComparisonOrbit.vue';
27
+ import ArcComparisonTitle from './ArcComparisonTitle.vue';
28
+
29
+ defineOptions({
30
+ inheritAttrs: false,
31
+ name: 'ArcComparisonLeft',
32
+ });
33
+
34
+ export interface IArcComparisonLeftProps {
35
+ readonly color?: string;
36
+ readonly title?: string;
37
+ readonly count?: number;
38
+ }
39
+
40
+ const props = withDefaults(defineProps<IArcComparisonLeftProps>(), {
41
+ color: DEFAULT_LEFT_COLOR,
42
+ title: undefined,
43
+ count: undefined,
44
+ });
45
+
46
+ const rootContext = inject(ARC_COMPARISON_ROOT_KEY, undefined);
47
+
48
+ const slots = useSlots();
49
+
50
+ interface INamedComponent {
51
+ readonly name?: string;
52
+ readonly __name?: string;
53
+ }
54
+
55
+ function hasComponentName(type: unknown, name: string): boolean {
56
+ if (typeof type === 'object' && type !== null) {
57
+ const comp = type as INamedComponent;
58
+
59
+ return comp.name === name || comp.__name === name;
60
+ }
61
+
62
+ if (typeof type === 'function') {
63
+ return (type as { name?: string }).name === name;
64
+ }
65
+
66
+ return false;
67
+ }
68
+
69
+ const registeredCalloutIds = ref<symbol[]>([]);
70
+
71
+ const registerCallout = (id?: symbol): number | ComputedRef<number> => {
72
+ if (id) {
73
+ if (!registeredCalloutIds.value.includes(id)) {
74
+ registeredCalloutIds.value.push(id);
75
+ }
76
+ return computed(() => registeredCalloutIds.value.indexOf(id));
77
+ }
78
+
79
+ const fallbackToken = Symbol();
80
+ registeredCalloutIds.value.push(fallbackToken);
81
+ return registeredCalloutIds.value.indexOf(fallbackToken);
82
+ };
83
+
84
+ const unregisterCallout = (id: symbol): void => {
85
+ registeredCalloutIds.value = registeredCalloutIds.value.filter(
86
+ (item) => item !== id,
87
+ );
88
+ };
89
+
90
+ const sideColor = computed(() => {
91
+ return props.color ?? DEFAULT_LEFT_COLOR;
92
+ });
93
+
94
+ const resolvedCount = computed(() => {
95
+ return props.count ?? rootContext?.pointsCount.value ?? 3;
96
+ });
97
+
98
+ const currentTitle = ref<string>(props.title ?? 'Add Project\nName');
99
+
100
+ provide(ARC_COMPARISON_SIDE_KEY, {
101
+ side: 'left',
102
+ color: sideColor,
103
+ title: computed(() => currentTitle.value),
104
+ setTitle: (val: string) => {
105
+ currentTitle.value = val;
106
+ },
107
+ registerCallout,
108
+ unregisterCallout,
109
+ count: resolvedCount,
110
+ });
111
+
112
+ const leftOrbitGeo = computed<IArcOrbitGeometry>(() => {
113
+ const sideGeo = rootContext?.geo.value.left;
114
+
115
+ return {
116
+ viewBoxWidth: rootContext?.geo.value.viewBoxWidth ?? 500,
117
+ viewBoxHeight: rootContext?.geo.value.viewBoxHeight ?? 480,
118
+ position: 'left',
119
+ hubCenter: sideGeo?.hubCenter ?? { x: 0, y: 240 },
120
+ hubRadius: sideGeo?.hubRadius ?? 135,
121
+ hubPath: sideGeo?.hubPath ?? '',
122
+ arcPath: sideGeo?.arcPath ?? '',
123
+ topDot: sideGeo?.topDot ?? { x: 0, y: 0 },
124
+ bottomDot: sideGeo?.bottomDot ?? { x: 0, y: 0 },
125
+ dotRadius: sideGeo?.dotRadius ?? 3.5,
126
+ nodes: sideGeo?.nodes ?? [],
127
+ callouts: sideGeo?.callouts ?? [],
128
+ pointsCount: resolvedCount.value,
129
+ };
130
+ });
131
+
132
+ provide(ARC_ORBIT_ROOT_KEY, {
133
+ position: computed<TArcOrbitPosition>(() => 'left'),
134
+ color: sideColor,
135
+ pointsCount: resolvedCount,
136
+ geo: leftOrbitGeo,
137
+ animation: computed(() => rootContext?.animation?.value ?? true),
138
+ startDelay: computed(() => rootContext?.startDelay?.value ?? 0),
139
+ title: computed(() => currentTitle.value),
140
+ setTitle: (val: string) => {
141
+ currentTitle.value = val;
142
+ },
143
+ registerCallout,
144
+ unregisterCallout,
145
+ edgeOffset: computed(() => rootContext?.edgeOffset?.value ?? 30),
146
+ items: computed(() => DEFAULT_LEFT_ITEMS),
147
+ });
148
+
149
+ function isSignificantNode(node: VNode): boolean {
150
+ if (typeof node.type === 'symbol') {
151
+ if (typeof node.children === 'string' && !node.children.trim()) {
152
+ return false;
153
+ }
154
+ }
155
+
156
+ if (typeof node.children === 'string' && !node.children.trim()) {
157
+ return false;
158
+ }
159
+
160
+ return true;
161
+ }
162
+
163
+ function flattenVNodes(nodes: VNode[]): VNode[] {
164
+ const result: VNode[] = [];
165
+
166
+ for (const node of nodes) {
167
+ if (node.type === Fragment && Array.isArray(node.children)) {
168
+ result.push(...flattenVNodes(node.children as VNode[]));
169
+ } else if (isSignificantNode(node)) {
170
+ result.push(node);
171
+ }
172
+ }
173
+
174
+ return result;
175
+ }
176
+
177
+ function isTitleNode(node: VNode): boolean {
178
+ return (
179
+ hasComponentName(node.type, 'ArcComparisonTitle') ||
180
+ hasComponentName(node.type, 'ArcOrbitTitle') ||
181
+ node.type === ArcComparisonTitle
182
+ );
183
+ }
184
+
185
+ const defaultNodes = computed(() => {
186
+ if (!slots.default) {
187
+ return [];
188
+ }
189
+
190
+ return flattenVNodes(slots.default());
191
+ });
192
+
193
+ const titleNode = computed(() => {
194
+ return defaultNodes.value.find(isTitleNode);
195
+ });
196
+
197
+ const bodyNodes = computed(() => {
198
+ return defaultNodes.value.filter((node) => !isTitleNode(node));
199
+ });
200
+
201
+ const hubStyle = computed(() => {
202
+ const hubR = rootContext?.geo.value.left.hubRadius ?? 170;
203
+ const centerY = rootContext?.geo.value.centerY ?? 240;
204
+ const isLayout = rootContext?.as?.value === 'layout';
205
+ const isMoved = rootContext?.isMoved?.value ?? false;
206
+ const centerX = rootContext?.geo.value.centerX ?? 500;
207
+ const edgeOffset = rootContext?.edgeOffset?.value ?? 30;
208
+ const inCenter = isLayout && !isMoved;
209
+ const targetLeft = inCenter ? `${centerX - hubR}px` : '0px';
210
+ const targetWidth = inCenter ? `${hubR}px` : `${edgeOffset + hubR}px`;
211
+
212
+ return {
213
+ top: `${centerY - hubR}px`,
214
+ left: targetLeft,
215
+ width: targetWidth,
216
+ height: `${hubR * 2}px`,
217
+ paddingRight: inCenter ? '28px' : undefined,
218
+ paddingLeft: inCenter ? '8px' : undefined,
219
+ transition: 'all 700ms cubic-bezier(0.16, 1, 0.3, 1)',
220
+ };
221
+ });
222
+
223
+ const { className, forwardedAttrs } = useMergedUnoAttrs(
224
+ 'alpha-arc-comparison-left absolute inset-0 w-full h-full pointer-events-none',
225
+ );
226
+ </script>
227
+
228
+ <template>
229
+ <div v-bind="forwardedAttrs()" :class="className()">
230
+ <!-- Left Hub Title Display -->
231
+ <div
232
+ class="alpha-arc-comparison__hub-title alpha-arc-comparison__hub-title--left absolute flex items-center justify-center z-10 pointer-events-auto"
233
+ :style="hubStyle"
234
+ >
235
+ <component :is="titleNode" v-if="titleNode" />
236
+ <ArcComparisonTitle v-else-if="props.title">
237
+ {{ props.title }}
238
+ </ArcComparisonTitle>
239
+ <ArcComparisonTitle v-else />
240
+ </div>
241
+ <!-- Contents & Callouts -->
242
+ <div
243
+ v-if="rootContext?.as?.value !== 'layout' || rootContext?.isMoved?.value"
244
+ class="alpha-arc-comparison__contents-wrapper transition-opacity duration-500 ease-out"
245
+ :class="{
246
+ 'opacity-0': rootContext?.as?.value === 'layout' && !rootContext?.isMoved?.value,
247
+ 'opacity-100': rootContext?.as?.value !== 'layout' || rootContext?.isMoved?.value,
248
+ }"
249
+ :style="{
250
+ transitionDelay:
251
+ rootContext?.as?.value === 'layout' && rootContext?.isMoved?.value
252
+ ? '300ms'
253
+ : '0ms',
254
+ }"
255
+ >
256
+ <template v-if="bodyNodes.length > 0">
257
+ <component :is="node" v-for="(node, i) in bodyNodes" :key="i" />
258
+ </template>
259
+ <ArcComparisonContents v-else>
260
+ <ArcComparisonOrbit
261
+ v-for="idx in resolvedCount"
262
+ :key="idx"
263
+ :index="idx - 1"
264
+ />
265
+ </ArcComparisonContents>
266
+ </div>
267
+ </div>
268
+ </template>
@@ -0,0 +1,47 @@
1
+ <script setup lang="ts">
2
+ import ArcOrbitCallout from '../../core/arc-orbit/ArcOrbitCallout.vue';
3
+
4
+ defineOptions({
5
+ inheritAttrs: false,
6
+ name: 'ArcComparisonOrbit',
7
+ });
8
+
9
+ export interface IArcComparisonOrbitProps {
10
+ readonly side?: 'left' | 'right';
11
+ readonly index?: number;
12
+ readonly id?: string | number;
13
+ readonly title?: string;
14
+ readonly description?: string;
15
+ readonly color?: string;
16
+ readonly textColor?: string;
17
+ readonly textGap?: number;
18
+ }
19
+
20
+ const props = withDefaults(defineProps<IArcComparisonOrbitProps>(), {
21
+ side: undefined,
22
+ index: undefined,
23
+ id: undefined,
24
+ title: undefined,
25
+ description: undefined,
26
+ color: undefined,
27
+ textColor: undefined,
28
+ textGap: undefined,
29
+ });
30
+ </script>
31
+
32
+ <template>
33
+ <ArcOrbitCallout
34
+ v-if="$slots.default"
35
+ v-bind="{ ...props, ...$attrs }"
36
+ :position="props.side"
37
+ class="alpha-arc-comparison-orbit"
38
+ >
39
+ <slot />
40
+ </ArcOrbitCallout>
41
+ <ArcOrbitCallout
42
+ v-else
43
+ v-bind="{ ...props, ...$attrs }"
44
+ :position="props.side"
45
+ class="alpha-arc-comparison-orbit"
46
+ />
47
+ </template>
@@ -0,0 +1,271 @@
1
+ <script setup lang="ts">
2
+ import {
3
+ type ComputedRef,
4
+ computed,
5
+ Fragment,
6
+ inject,
7
+ provide,
8
+ ref,
9
+ useSlots,
10
+ type VNode,
11
+ } from 'vue';
12
+
13
+ import {
14
+ ARC_COMPARISON_ROOT_KEY,
15
+ ARC_COMPARISON_SIDE_KEY,
16
+ DEFAULT_RIGHT_COLOR,
17
+ DEFAULT_RIGHT_ITEMS,
18
+ } from '../../../utils/arcComparison';
19
+ import {
20
+ ARC_ORBIT_ROOT_KEY,
21
+ type IArcOrbitGeometry,
22
+ type TArcOrbitPosition,
23
+ } from '../../../utils/arcOrbit';
24
+ import { useMergedUnoAttrs } from '../../../utils/useMergedUnoAttrs';
25
+ import ArcComparisonContents from './ArcComparisonContents.vue';
26
+ import ArcComparisonOrbit from './ArcComparisonOrbit.vue';
27
+ import ArcComparisonTitle from './ArcComparisonTitle.vue';
28
+
29
+ defineOptions({
30
+ inheritAttrs: false,
31
+ name: 'ArcComparisonRight',
32
+ });
33
+
34
+ export interface IArcComparisonRightProps {
35
+ readonly color?: string;
36
+ readonly title?: string;
37
+ readonly count?: number;
38
+ }
39
+
40
+ const props = withDefaults(defineProps<IArcComparisonRightProps>(), {
41
+ color: DEFAULT_RIGHT_COLOR,
42
+ title: undefined,
43
+ count: undefined,
44
+ });
45
+
46
+ const rootContext = inject(ARC_COMPARISON_ROOT_KEY, undefined);
47
+
48
+ const slots = useSlots();
49
+
50
+ interface INamedComponent {
51
+ readonly name?: string;
52
+ readonly __name?: string;
53
+ }
54
+
55
+ function hasComponentName(type: unknown, name: string): boolean {
56
+ if (typeof type === 'object' && type !== null) {
57
+ const comp = type as INamedComponent;
58
+
59
+ return comp.name === name || comp.__name === name;
60
+ }
61
+
62
+ if (typeof type === 'function') {
63
+ return (type as { name?: string }).name === name;
64
+ }
65
+
66
+ return false;
67
+ }
68
+
69
+ const registeredCalloutIds = ref<symbol[]>([]);
70
+
71
+ const registerCallout = (id?: symbol): number | ComputedRef<number> => {
72
+ if (id) {
73
+ if (!registeredCalloutIds.value.includes(id)) {
74
+ registeredCalloutIds.value.push(id);
75
+ }
76
+ return computed(() => registeredCalloutIds.value.indexOf(id));
77
+ }
78
+
79
+ const fallbackToken = Symbol();
80
+ registeredCalloutIds.value.push(fallbackToken);
81
+ return registeredCalloutIds.value.indexOf(fallbackToken);
82
+ };
83
+
84
+ const unregisterCallout = (id: symbol): void => {
85
+ registeredCalloutIds.value = registeredCalloutIds.value.filter(
86
+ (item) => item !== id,
87
+ );
88
+ };
89
+
90
+ const sideColor = computed(() => {
91
+ return props.color ?? DEFAULT_RIGHT_COLOR;
92
+ });
93
+
94
+ const resolvedCount = computed(() => {
95
+ return props.count ?? rootContext?.pointsCount.value ?? 3;
96
+ });
97
+
98
+ const currentTitle = ref<string>(props.title ?? 'Add Project\nName');
99
+
100
+ provide(ARC_COMPARISON_SIDE_KEY, {
101
+ side: 'right',
102
+ color: sideColor,
103
+ title: computed(() => currentTitle.value),
104
+ setTitle: (val: string) => {
105
+ currentTitle.value = val;
106
+ },
107
+ registerCallout,
108
+ unregisterCallout,
109
+ count: resolvedCount,
110
+ });
111
+
112
+ const rightOrbitGeo = computed<IArcOrbitGeometry>(() => {
113
+ const sideGeo = rootContext?.geo.value.right;
114
+
115
+ return {
116
+ viewBoxWidth: rootContext?.geo.value.viewBoxWidth ?? 500,
117
+ viewBoxHeight: rootContext?.geo.value.viewBoxHeight ?? 480,
118
+ position: 'right',
119
+ hubCenter: sideGeo?.hubCenter ?? { x: 500, y: 240 },
120
+ hubRadius: sideGeo?.hubRadius ?? 135,
121
+ hubPath: sideGeo?.hubPath ?? '',
122
+ arcPath: sideGeo?.arcPath ?? '',
123
+ topDot: sideGeo?.topDot ?? { x: 500, y: 0 },
124
+ bottomDot: sideGeo?.bottomDot ?? { x: 500, y: 0 },
125
+ dotRadius: sideGeo?.dotRadius ?? 3.5,
126
+ nodes: sideGeo?.nodes ?? [],
127
+ callouts: sideGeo?.callouts ?? [],
128
+ pointsCount: resolvedCount.value,
129
+ };
130
+ });
131
+
132
+ provide(ARC_ORBIT_ROOT_KEY, {
133
+ position: computed<TArcOrbitPosition>(() => 'right'),
134
+ color: sideColor,
135
+ pointsCount: resolvedCount,
136
+ geo: rightOrbitGeo,
137
+ animation: computed(() => rootContext?.animation?.value ?? true),
138
+ startDelay: computed(() => rootContext?.startDelay?.value ?? 0),
139
+ title: computed(() => currentTitle.value),
140
+ setTitle: (val: string) => {
141
+ currentTitle.value = val;
142
+ },
143
+ registerCallout,
144
+ unregisterCallout,
145
+ edgeOffset: computed(() => rootContext?.edgeOffset?.value ?? 30),
146
+ items: computed(() => DEFAULT_RIGHT_ITEMS),
147
+ });
148
+
149
+ function isSignificantNode(node: VNode): boolean {
150
+ if (typeof node.type === 'symbol') {
151
+ if (typeof node.children === 'string' && !node.children.trim()) {
152
+ return false;
153
+ }
154
+ }
155
+
156
+ if (typeof node.children === 'string' && !node.children.trim()) {
157
+ return false;
158
+ }
159
+
160
+ return true;
161
+ }
162
+
163
+ function flattenVNodes(nodes: VNode[]): VNode[] {
164
+ const result: VNode[] = [];
165
+
166
+ for (const node of nodes) {
167
+ if (node.type === Fragment && Array.isArray(node.children)) {
168
+ result.push(...flattenVNodes(node.children as VNode[]));
169
+ } else if (isSignificantNode(node)) {
170
+ result.push(node);
171
+ }
172
+ }
173
+
174
+ return result;
175
+ }
176
+
177
+ function isTitleNode(node: VNode): boolean {
178
+ return (
179
+ hasComponentName(node.type, 'ArcComparisonTitle') ||
180
+ hasComponentName(node.type, 'ArcOrbitTitle') ||
181
+ node.type === ArcComparisonTitle
182
+ );
183
+ }
184
+
185
+ const defaultNodes = computed(() => {
186
+ if (!slots.default) {
187
+ return [];
188
+ }
189
+
190
+ return flattenVNodes(slots.default());
191
+ });
192
+
193
+ const titleNode = computed(() => {
194
+ return defaultNodes.value.find(isTitleNode);
195
+ });
196
+
197
+ const bodyNodes = computed(() => {
198
+ return defaultNodes.value.filter((node) => !isTitleNode(node));
199
+ });
200
+
201
+ const hubStyle = computed(() => {
202
+ const hubR = rootContext?.geo.value.right.hubRadius ?? 170;
203
+ const centerY = rootContext?.geo.value.centerY ?? 240;
204
+ const isLayout = rootContext?.as?.value === 'layout';
205
+ const isMoved = rootContext?.isMoved?.value ?? false;
206
+ const centerX = rootContext?.geo.value.centerX ?? 500;
207
+ const viewBoxWidth = rootContext?.geo.value.viewBoxWidth ?? 1000;
208
+ const edgeOffset = rootContext?.edgeOffset?.value ?? 30;
209
+ const inCenter = isLayout && !isMoved;
210
+ const targetLeft = inCenter
211
+ ? `${centerX}px`
212
+ : `${viewBoxWidth - hubR - edgeOffset}px`;
213
+ const targetWidth = inCenter ? `${hubR}px` : `${edgeOffset + hubR}px`;
214
+
215
+ return {
216
+ top: `${centerY - hubR}px`,
217
+ left: targetLeft,
218
+ width: targetWidth,
219
+ height: `${hubR * 2}px`,
220
+ paddingLeft: inCenter ? '28px' : undefined,
221
+ paddingRight: inCenter ? '8px' : undefined,
222
+ transition: 'all 700ms cubic-bezier(0.16, 1, 0.3, 1)',
223
+ };
224
+ });
225
+
226
+ const { className, forwardedAttrs } = useMergedUnoAttrs(
227
+ 'alpha-arc-comparison-right absolute inset-0 w-full h-full pointer-events-none',
228
+ );
229
+ </script>
230
+
231
+ <template>
232
+ <div v-bind="forwardedAttrs()" :class="className()">
233
+ <!-- Right Hub Title Display -->
234
+ <div
235
+ class="alpha-arc-comparison__hub-title alpha-arc-comparison__hub-title--right absolute flex items-center justify-center z-10 pointer-events-auto"
236
+ :style="hubStyle"
237
+ >
238
+ <component :is="titleNode" v-if="titleNode" />
239
+ <ArcComparisonTitle v-else-if="props.title">
240
+ {{ props.title }}
241
+ </ArcComparisonTitle>
242
+ <ArcComparisonTitle v-else />
243
+ </div>
244
+ <!-- Contents & Callouts -->
245
+ <div
246
+ v-if="rootContext?.as?.value !== 'layout' || rootContext?.isMoved?.value"
247
+ class="alpha-arc-comparison__contents-wrapper transition-opacity duration-500 ease-out"
248
+ :class="{
249
+ 'opacity-0': rootContext?.as?.value === 'layout' && !rootContext?.isMoved?.value,
250
+ 'opacity-100': rootContext?.as?.value !== 'layout' || rootContext?.isMoved?.value,
251
+ }"
252
+ :style="{
253
+ transitionDelay:
254
+ rootContext?.as?.value === 'layout' && rootContext?.isMoved?.value
255
+ ? '300ms'
256
+ : '0ms',
257
+ }"
258
+ >
259
+ <template v-if="bodyNodes.length > 0">
260
+ <component :is="node" v-for="(node, i) in bodyNodes" :key="i" />
261
+ </template>
262
+ <ArcComparisonContents v-else>
263
+ <ArcComparisonOrbit
264
+ v-for="idx in resolvedCount"
265
+ :key="idx"
266
+ :index="idx - 1"
267
+ />
268
+ </ArcComparisonContents>
269
+ </div>
270
+ </div>
271
+ </template>
@@ -0,0 +1,29 @@
1
+ <script setup lang="ts">
2
+ import ArcOrbitTitle, {
3
+ type IArcOrbitTitleProps,
4
+ } from '../../core/arc-orbit/ArcOrbitTitle.vue';
5
+
6
+ defineOptions({
7
+ inheritAttrs: false,
8
+ name: 'ArcComparisonTitle',
9
+ });
10
+
11
+ export interface IArcComparisonTitleProps extends IArcOrbitTitleProps {}
12
+
13
+ const props = defineProps<IArcComparisonTitleProps>();
14
+ </script>
15
+
16
+ <template>
17
+ <ArcOrbitTitle
18
+ v-if="$slots.default"
19
+ v-bind="{ ...props, ...$attrs }"
20
+ class="alpha-arc-comparison-title"
21
+ >
22
+ <slot />
23
+ </ArcOrbitTitle>
24
+ <ArcOrbitTitle
25
+ v-else
26
+ v-bind="{ ...props, ...$attrs }"
27
+ class="alpha-arc-comparison-title"
28
+ />
29
+ </template>