@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,267 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed, Fragment, inject, provide, useSlots, type VNode } from 'vue';
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
DEFAULT_QUAD_HUB_ITEMS,
|
|
6
|
+
type IResolvedQuadHubItem,
|
|
7
|
+
QUAD_HUB_CALLOUT_KEY,
|
|
8
|
+
QUAD_HUB_ROOT_KEY,
|
|
9
|
+
resolveSingleItem,
|
|
10
|
+
type TQuadHubIcon,
|
|
11
|
+
} from '../../utils/quadHub';
|
|
12
|
+
import QuadHubContent from './QuadHubContent.vue';
|
|
13
|
+
import QuadHubHeading from './QuadHubHeading.vue';
|
|
14
|
+
|
|
15
|
+
defineOptions({
|
|
16
|
+
name: 'QuadHubCallout',
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
export interface IQuadHubCalloutProps {
|
|
20
|
+
readonly id?: string | number;
|
|
21
|
+
readonly icon?: TQuadHubIcon;
|
|
22
|
+
readonly color?: string;
|
|
23
|
+
readonly cardBg?: string;
|
|
24
|
+
readonly arcColor?: string;
|
|
25
|
+
readonly textColor?: string;
|
|
26
|
+
readonly titleColor?: string;
|
|
27
|
+
readonly arcBorderColor?: string;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const props = withDefaults(defineProps<IQuadHubCalloutProps>(), {
|
|
31
|
+
id: undefined,
|
|
32
|
+
icon: undefined,
|
|
33
|
+
color: undefined,
|
|
34
|
+
cardBg: undefined,
|
|
35
|
+
arcColor: undefined,
|
|
36
|
+
textColor: undefined,
|
|
37
|
+
titleColor: undefined,
|
|
38
|
+
arcBorderColor: undefined,
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
interface INamedComponent {
|
|
42
|
+
readonly name?: string;
|
|
43
|
+
readonly __name?: string;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function hasComponentName(type: unknown, name: string): boolean {
|
|
47
|
+
if (typeof type === 'object' && type !== null) {
|
|
48
|
+
const comp = type as INamedComponent;
|
|
49
|
+
return comp.name === name || comp.__name === name;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const rootContext = inject(QUAD_HUB_ROOT_KEY, undefined);
|
|
56
|
+
|
|
57
|
+
if (!rootContext) {
|
|
58
|
+
console.warn('[QuadHubCallout] Must be used inside <QuadHub>');
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const registration = rootContext?.registerCallout(props);
|
|
62
|
+
const index = registration?.index ?? 0;
|
|
63
|
+
|
|
64
|
+
const [firstDefaultItem] = DEFAULT_QUAD_HUB_ITEMS;
|
|
65
|
+
|
|
66
|
+
const fallbackItem = computed<IResolvedQuadHubItem>(() => {
|
|
67
|
+
const current = DEFAULT_QUAD_HUB_ITEMS[index];
|
|
68
|
+
|
|
69
|
+
return resolveSingleItem(current ?? firstDefaultItem, props);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
const item = computed<IResolvedQuadHubItem>(() => {
|
|
73
|
+
return registration?.item.value ?? fallbackItem.value;
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
provide(QUAD_HUB_CALLOUT_KEY, {
|
|
77
|
+
item,
|
|
78
|
+
index,
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
const slots = useSlots();
|
|
82
|
+
|
|
83
|
+
function flattenVNodes(nodes: VNode[]): VNode[] {
|
|
84
|
+
const result: VNode[] = [];
|
|
85
|
+
|
|
86
|
+
for (const node of nodes) {
|
|
87
|
+
if (node.type === Fragment && Array.isArray(node.children)) {
|
|
88
|
+
result.push(...flattenVNodes(node.children as VNode[]));
|
|
89
|
+
} else {
|
|
90
|
+
result.push(node);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return result;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function isHeadingNode(node: VNode): boolean {
|
|
98
|
+
return (
|
|
99
|
+
hasComponentName(node.type, 'QuadHubHeading') ||
|
|
100
|
+
node.type === QuadHubHeading
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function isContentNode(node: VNode): boolean {
|
|
105
|
+
return (
|
|
106
|
+
hasComponentName(node.type, 'QuadHubContent') ||
|
|
107
|
+
node.type === QuadHubContent
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const defaultNodes = computed(() => {
|
|
112
|
+
if (!slots.default) {
|
|
113
|
+
return [];
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return flattenVNodes(slots.default());
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
const headingNode = computed(() => {
|
|
120
|
+
return defaultNodes.value.find(isHeadingNode);
|
|
121
|
+
});
|
|
122
|
+
const contentNode = computed(() => {
|
|
123
|
+
return defaultNodes.value.find(isContentNode);
|
|
124
|
+
});
|
|
125
|
+
const otherNodes = computed(() => {
|
|
126
|
+
return defaultNodes.value.filter((node) => {
|
|
127
|
+
return !isHeadingNode(node) && !isContentNode(node);
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
const isLeftCard = computed(() => {
|
|
132
|
+
return index === 0 || index === 3;
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
// Placement corresponding to:
|
|
136
|
+
// 0: Top-Left (top row, left side) - 1
|
|
137
|
+
// 1: Top-Right (top row, right side) - 2
|
|
138
|
+
// 2: Bottom-Right (bottom row, right side) - 3
|
|
139
|
+
// 3: Bottom-Left (bottom row, left side) - 4
|
|
140
|
+
const positionStyle = computed(() => {
|
|
141
|
+
switch (index) {
|
|
142
|
+
case 0: {
|
|
143
|
+
return 'left: 0; right: calc(50% + 95px); top: 10px; bottom: calc(50% + 14px);';
|
|
144
|
+
}
|
|
145
|
+
case 1: {
|
|
146
|
+
return 'left: calc(50% + 95px); right: 0; top: 10px; bottom: calc(50% + 14px);';
|
|
147
|
+
}
|
|
148
|
+
case 2: {
|
|
149
|
+
return 'left: calc(50% + 95px); right: 0; top: calc(50% + 14px); bottom: 10px;';
|
|
150
|
+
}
|
|
151
|
+
case 3: {
|
|
152
|
+
return 'left: 0; right: calc(50% + 95px); top: calc(50% + 14px); bottom: 10px;';
|
|
153
|
+
}
|
|
154
|
+
default: {
|
|
155
|
+
return '';
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
const animation = computed(() => {
|
|
161
|
+
return rootContext?.animation?.value ?? true;
|
|
162
|
+
});
|
|
163
|
+
</script>
|
|
164
|
+
|
|
165
|
+
<template>
|
|
166
|
+
<div
|
|
167
|
+
v-if="index < 4"
|
|
168
|
+
:class="[
|
|
169
|
+
'alpha-quad-hub-callout absolute rounded-2xl flex flex-col justify-center z-0 transition-all duration-300 pointer-events-auto shadow-sm select-none box-border',
|
|
170
|
+
isLeftCard ? 'pl-5 pr-16 py-4 text-right' : 'pl-16 pr-5 py-4 text-left',
|
|
171
|
+
`alpha-quad-hub-callout--${index}`,
|
|
172
|
+
{ 'alpha-quad-hub-callout--animated': animation },
|
|
173
|
+
]"
|
|
174
|
+
:style="[
|
|
175
|
+
positionStyle,
|
|
176
|
+
{
|
|
177
|
+
backgroundColor: item.cardBg,
|
|
178
|
+
fontFamily:
|
|
179
|
+
'ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, \'Segoe UI\', Roboto, sans-serif',
|
|
180
|
+
},
|
|
181
|
+
]"
|
|
182
|
+
>
|
|
183
|
+
<!-- Left-side callouts (TL & BL): Heading on top (right-aligned), then [description | accentBar] -->
|
|
184
|
+
<template v-if="isLeftCard">
|
|
185
|
+
<div class="w-full flex justify-end mb-1">
|
|
186
|
+
<component :is="headingNode" v-if="headingNode" />
|
|
187
|
+
</div>
|
|
188
|
+
<div class="w-full flex items-stretch justify-end gap-2.5">
|
|
189
|
+
<div class="flex-1 flex flex-col items-end min-w-0">
|
|
190
|
+
<component :is="contentNode" v-if="contentNode" />
|
|
191
|
+
<component :is="node" v-for="(node, i) in otherNodes" :key="i" />
|
|
192
|
+
</div>
|
|
193
|
+
<div
|
|
194
|
+
class="w-[3px] self-stretch min-h-[30px] rounded-full flex-shrink-0 my-0.5"
|
|
195
|
+
:style="{ backgroundColor: item.titleColor }"
|
|
196
|
+
/>
|
|
197
|
+
</div>
|
|
198
|
+
</template>
|
|
199
|
+
<!-- Right-side callouts (TR & BR): Heading on top (left-aligned), then [accentBar | description] -->
|
|
200
|
+
<template v-else>
|
|
201
|
+
<div class="w-full flex justify-start mb-1">
|
|
202
|
+
<component :is="headingNode" v-if="headingNode" />
|
|
203
|
+
</div>
|
|
204
|
+
<div class="w-full flex items-stretch justify-start gap-2.5">
|
|
205
|
+
<div
|
|
206
|
+
class="w-[3px] self-stretch min-h-[30px] rounded-full flex-shrink-0 my-0.5"
|
|
207
|
+
:style="{ backgroundColor: item.titleColor }"
|
|
208
|
+
/>
|
|
209
|
+
<div class="flex-1 flex flex-col items-start min-w-0">
|
|
210
|
+
<component :is="contentNode" v-if="contentNode" />
|
|
211
|
+
<component :is="node" v-for="(node, i) in otherNodes" :key="i" />
|
|
212
|
+
</div>
|
|
213
|
+
</div>
|
|
214
|
+
</template>
|
|
215
|
+
</div>
|
|
216
|
+
</template>
|
|
217
|
+
|
|
218
|
+
<style scoped>
|
|
219
|
+
.alpha-quad-hub-callout :deep(p),
|
|
220
|
+
.alpha-quad-hub-callout :deep(h1),
|
|
221
|
+
.alpha-quad-hub-callout :deep(h2),
|
|
222
|
+
.alpha-quad-hub-callout :deep(h3),
|
|
223
|
+
.alpha-quad-hub-callout :deep(h4),
|
|
224
|
+
.alpha-quad-hub-callout :deep(h5),
|
|
225
|
+
.alpha-quad-hub-callout :deep(h6) {
|
|
226
|
+
margin: 0;
|
|
227
|
+
padding: 0;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
.alpha-quad-hub-callout--animated.alpha-quad-hub-callout--0 {
|
|
231
|
+
animation: quad-callout-left 450ms cubic-bezier(0.16, 1, 0.3, 1) calc(var(--quad-start-delay, 0ms) + 150ms) both;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
.alpha-quad-hub-callout--animated.alpha-quad-hub-callout--1 {
|
|
235
|
+
animation: quad-callout-right 450ms cubic-bezier(0.16, 1, 0.3, 1) calc(var(--quad-start-delay, 0ms) + 300ms) both;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
.alpha-quad-hub-callout--animated.alpha-quad-hub-callout--2 {
|
|
239
|
+
animation: quad-callout-right 450ms cubic-bezier(0.16, 1, 0.3, 1) calc(var(--quad-start-delay, 0ms) + 450ms) both;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
.alpha-quad-hub-callout--animated.alpha-quad-hub-callout--3 {
|
|
243
|
+
animation: quad-callout-left 450ms cubic-bezier(0.16, 1, 0.3, 1) calc(var(--quad-start-delay, 0ms) + 600ms) both;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
@keyframes quad-callout-right {
|
|
247
|
+
0% {
|
|
248
|
+
opacity: 0;
|
|
249
|
+
transform: translateX(-28px);
|
|
250
|
+
}
|
|
251
|
+
100% {
|
|
252
|
+
opacity: 1;
|
|
253
|
+
transform: translateX(0);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
@keyframes quad-callout-left {
|
|
258
|
+
0% {
|
|
259
|
+
opacity: 0;
|
|
260
|
+
transform: translateX(28px);
|
|
261
|
+
}
|
|
262
|
+
100% {
|
|
263
|
+
opacity: 1;
|
|
264
|
+
transform: translateX(0);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
</style>
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
defineOptions({
|
|
3
|
+
name: 'QuadHubCenter',
|
|
4
|
+
});
|
|
5
|
+
|
|
6
|
+
export interface IQuadHubCenterProps {
|
|
7
|
+
readonly title?: string;
|
|
8
|
+
readonly radius?: number;
|
|
9
|
+
readonly subtitle?: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const props = withDefaults(defineProps<IQuadHubCenterProps>(), {
|
|
13
|
+
title: undefined,
|
|
14
|
+
subtitle: undefined,
|
|
15
|
+
radius: 58,
|
|
16
|
+
});
|
|
17
|
+
</script>
|
|
18
|
+
|
|
19
|
+
<template>
|
|
20
|
+
<div
|
|
21
|
+
class="alpha-quad-hub-center absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 z-20 rounded-full bg-white flex flex-col items-center justify-center text-center shadow-lg pointer-events-auto select-none"
|
|
22
|
+
:style="{
|
|
23
|
+
width: `${props.radius * 2}px`,
|
|
24
|
+
height: `${props.radius * 2}px`,
|
|
25
|
+
boxShadow: '0 4px 18px rgba(0, 0, 0, 0.12)',
|
|
26
|
+
fontFamily: 'ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, \'Segoe UI\', Roboto, sans-serif',
|
|
27
|
+
}"
|
|
28
|
+
>
|
|
29
|
+
<slot>
|
|
30
|
+
<slot name="title">
|
|
31
|
+
<span
|
|
32
|
+
v-if="props.title"
|
|
33
|
+
:class="[
|
|
34
|
+
'text-[23px] font-extrabold text-slate-800 tracking-tight leading-none',
|
|
35
|
+
{ 'mb-2': props.subtitle },
|
|
36
|
+
]"
|
|
37
|
+
style="font-family: inherit;"
|
|
38
|
+
>
|
|
39
|
+
{{ props.title }}
|
|
40
|
+
</span>
|
|
41
|
+
</slot>
|
|
42
|
+
<slot name="subtitle">
|
|
43
|
+
<span
|
|
44
|
+
v-if="props.subtitle"
|
|
45
|
+
class="text-[13px] font-medium text-slate-400 tracking-normal leading-none"
|
|
46
|
+
style="font-family: inherit;"
|
|
47
|
+
>
|
|
48
|
+
{{ props.subtitle }}
|
|
49
|
+
</span>
|
|
50
|
+
</slot>
|
|
51
|
+
</slot>
|
|
52
|
+
</div>
|
|
53
|
+
</template>
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed, inject } from 'vue';
|
|
3
|
+
|
|
4
|
+
import { QUAD_HUB_CALLOUT_KEY } from '../../utils/quadHub';
|
|
5
|
+
|
|
6
|
+
defineOptions({
|
|
7
|
+
name: 'QuadHubContent',
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
export interface IQuadHubContentProps {
|
|
11
|
+
readonly color?: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const props = withDefaults(defineProps<IQuadHubContentProps>(), {
|
|
15
|
+
color: undefined,
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
const calloutContext = inject(QUAD_HUB_CALLOUT_KEY, undefined);
|
|
19
|
+
|
|
20
|
+
const contentColor = computed(() => {
|
|
21
|
+
return props.color ?? calloutContext?.item.value.textColor ?? '#555555';
|
|
22
|
+
});
|
|
23
|
+
</script>
|
|
24
|
+
|
|
25
|
+
<template>
|
|
26
|
+
<div
|
|
27
|
+
class="alpha-quad-hub-content text-[1rem] leading-[1.38] font-normal tracking-tight m-0 p-0 select-none"
|
|
28
|
+
:style="{
|
|
29
|
+
color: contentColor,
|
|
30
|
+
margin: 0,
|
|
31
|
+
padding: 0,
|
|
32
|
+
fontSize: '1rem',
|
|
33
|
+
fontFamily:
|
|
34
|
+
'ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, \'Segoe UI\', Roboto, Helvetica, Arial, sans-serif',
|
|
35
|
+
}"
|
|
36
|
+
>
|
|
37
|
+
<slot />
|
|
38
|
+
</div>
|
|
39
|
+
</template>
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed, inject } from 'vue';
|
|
3
|
+
|
|
4
|
+
import { QUAD_HUB_CALLOUT_KEY } from '../../utils/quadHub';
|
|
5
|
+
|
|
6
|
+
defineOptions({
|
|
7
|
+
name: 'QuadHubHeading',
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
export interface IQuadHubHeadingProps {
|
|
11
|
+
readonly color?: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const props = withDefaults(defineProps<IQuadHubHeadingProps>(), {
|
|
15
|
+
color: undefined,
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
const calloutContext = inject(QUAD_HUB_CALLOUT_KEY, undefined);
|
|
19
|
+
|
|
20
|
+
const headingColor = computed(() => {
|
|
21
|
+
return (
|
|
22
|
+
props.color ??
|
|
23
|
+
calloutContext?.item.value.titleColor ??
|
|
24
|
+
calloutContext?.item.value.color ??
|
|
25
|
+
'#f29e4b'
|
|
26
|
+
);
|
|
27
|
+
});
|
|
28
|
+
</script>
|
|
29
|
+
|
|
30
|
+
<template>
|
|
31
|
+
<div
|
|
32
|
+
class="alpha-quad-hub-heading font-bold text-[1.25rem] leading-tight tracking-tight m-0 p-0 select-none"
|
|
33
|
+
:style="{
|
|
34
|
+
color: headingColor,
|
|
35
|
+
margin: 0,
|
|
36
|
+
padding: 0,
|
|
37
|
+
fontSize: '1.25rem',
|
|
38
|
+
fontFamily:
|
|
39
|
+
'ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, \'Segoe UI\', Roboto, Helvetica, Arial, sans-serif',
|
|
40
|
+
}"
|
|
41
|
+
>
|
|
42
|
+
<slot />
|
|
43
|
+
</div>
|
|
44
|
+
</template>
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed } from 'vue';
|
|
3
|
+
|
|
4
|
+
import type { TQuadHubIcon } from '../../utils/quadHub';
|
|
5
|
+
|
|
6
|
+
defineOptions({
|
|
7
|
+
name: 'QuadHubIcon',
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
export interface IQuadHubIconProps {
|
|
11
|
+
readonly size?: number;
|
|
12
|
+
readonly color?: string;
|
|
13
|
+
readonly icon?: TQuadHubIcon;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const props = withDefaults(defineProps<IQuadHubIconProps>(), {
|
|
17
|
+
size: 34,
|
|
18
|
+
icon: undefined,
|
|
19
|
+
color: '#ffffff',
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
const isStringIcon = computed((): boolean => {
|
|
23
|
+
return typeof props.icon === 'string';
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
const isComponentIcon = computed((): boolean => {
|
|
27
|
+
return typeof props.icon === 'object' && props.icon !== null;
|
|
28
|
+
});
|
|
29
|
+
</script>
|
|
30
|
+
|
|
31
|
+
<template>
|
|
32
|
+
<div
|
|
33
|
+
v-if="props.icon !== false"
|
|
34
|
+
class="alpha-quad-hub-icon flex items-center justify-center pointer-events-none select-none"
|
|
35
|
+
:style="{
|
|
36
|
+
color: props.color,
|
|
37
|
+
width: `${props.size}px`,
|
|
38
|
+
height: `${props.size}px`,
|
|
39
|
+
opacity: 0.82,
|
|
40
|
+
}"
|
|
41
|
+
>
|
|
42
|
+
<slot>
|
|
43
|
+
<component
|
|
44
|
+
:is="props.icon"
|
|
45
|
+
v-if="isComponentIcon"
|
|
46
|
+
class="w-full h-full"
|
|
47
|
+
:style="{ color: props.color }"
|
|
48
|
+
/>
|
|
49
|
+
<!-- UnoCSS / Iconify class name (e.g. i-lucide-user) -->
|
|
50
|
+
<span
|
|
51
|
+
v-else-if="isStringIcon && (props.icon as string).includes('-')"
|
|
52
|
+
:class="props.icon"
|
|
53
|
+
class="inline-block"
|
|
54
|
+
:style="{
|
|
55
|
+
color: props.color,
|
|
56
|
+
width: `${props.size}px`,
|
|
57
|
+
height: `${props.size}px`,
|
|
58
|
+
fontSize: `${props.size}px`,
|
|
59
|
+
}"
|
|
60
|
+
/>
|
|
61
|
+
<!-- 01 User Silhouette (matching design) -->
|
|
62
|
+
<svg
|
|
63
|
+
v-else-if="props.icon === 'user'"
|
|
64
|
+
viewBox="0 0 24 24"
|
|
65
|
+
fill="currentColor"
|
|
66
|
+
class="w-full h-full"
|
|
67
|
+
>
|
|
68
|
+
<circle cx="12" cy="7" r="4.2" />
|
|
69
|
+
<path d="M4 19.8c0-4.4 3.6-7.8 8-7.8s8 3.4 8 7.8v0.2H4v-0.2z" />
|
|
70
|
+
</svg>
|
|
71
|
+
<!-- 02 Academic / Mortarboard (matching design) -->
|
|
72
|
+
<svg
|
|
73
|
+
v-else-if="props.icon === 'academic' || props.icon === 'grad'"
|
|
74
|
+
viewBox="0 0 24 24"
|
|
75
|
+
fill="currentColor"
|
|
76
|
+
class="w-full h-full"
|
|
77
|
+
>
|
|
78
|
+
<path d="M12 4L1.5 9.5 12 15l10-5.5L12 4z" />
|
|
79
|
+
<path d="M6 13v4c0 2.2 2.7 4 6 4s6-1.8 6-4v-4l-6 3.2-6-3.2z" />
|
|
80
|
+
<path d="M21.5 10.2v5.3h1v-5.8l-1 0.5z" />
|
|
81
|
+
</svg>
|
|
82
|
+
<!-- 03 Briefcase (matching design) -->
|
|
83
|
+
<svg
|
|
84
|
+
v-else-if="props.icon === 'briefcase' || props.icon === 'portfolio'"
|
|
85
|
+
viewBox="0 0 24 24"
|
|
86
|
+
fill="currentColor"
|
|
87
|
+
class="w-full h-full"
|
|
88
|
+
>
|
|
89
|
+
<path
|
|
90
|
+
d="M9 5h6a1.5 1.5 0 00-1.5-1.5h-3A1.5 1.5 0 009 5zM4 7a2 2 0 00-2 2v2.5c1.2.7 2.8 1.1 4.5 1.3V11.5h11V13c1.7-.2 3.3-.6 4.5-1.3V9a2 2 0 00-2-2H4zm18 7.3c-1.3.8-3.4 1.3-5.5 1.5V17h-9v-1.2c-2.1-.2-4.2-.7-5.5-1.5V18a2 2 0 002 2h16a2 2 0 002-2v-3.7z"
|
|
91
|
+
/>
|
|
92
|
+
</svg>
|
|
93
|
+
<!-- 04 Target / Bullseye with Dart (matching design) -->
|
|
94
|
+
<svg
|
|
95
|
+
v-else-if="props.icon === 'target' || props.icon === 'bullseye'"
|
|
96
|
+
viewBox="0 0 24 24"
|
|
97
|
+
fill="none"
|
|
98
|
+
stroke="currentColor"
|
|
99
|
+
stroke-linecap="round"
|
|
100
|
+
stroke-linejoin="round"
|
|
101
|
+
class="w-full h-full"
|
|
102
|
+
>
|
|
103
|
+
<circle cx="10" cy="14" r="7.5" stroke-width="1.8" />
|
|
104
|
+
<circle cx="10" cy="14" r="4.2" stroke-width="1.8" />
|
|
105
|
+
<circle cx="10" cy="14" r="1.5" fill="currentColor" stroke="none" />
|
|
106
|
+
<path d="M15 9l6-6" stroke-width="2" />
|
|
107
|
+
<path d="M18 3h3v3" stroke-width="2" stroke-linejoin="miter" />
|
|
108
|
+
<path d="M15 6l3 3" stroke-width="1.6" />
|
|
109
|
+
</svg>
|
|
110
|
+
</slot>
|
|
111
|
+
</div>
|
|
112
|
+
</template>
|
|
@@ -6,8 +6,8 @@ defineOptions({
|
|
|
6
6
|
});
|
|
7
7
|
|
|
8
8
|
interface ITransitionHeadingProps {
|
|
9
|
-
readonly center?: boolean;
|
|
10
9
|
readonly idle?: boolean;
|
|
10
|
+
readonly center?: boolean;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
const props = withDefaults(defineProps<ITransitionHeadingProps>(), {
|
|
@@ -16,10 +16,10 @@ const props = withDefaults(defineProps<ITransitionHeadingProps>(), {
|
|
|
16
16
|
});
|
|
17
17
|
|
|
18
18
|
const { className, forwardedAttrs } = useMergedUnoAttrs(() => [
|
|
19
|
-
'alpha-transition-heading transition-all duration-700 ease-in-out absolute whitespace-nowrap',
|
|
19
|
+
'alpha-transition-heading transition-all duration-700 ease-in-out absolute w-fit whitespace-nowrap',
|
|
20
20
|
{
|
|
21
21
|
'top-[50%] left-[50%] translate-[-50%,-50%]': props.center,
|
|
22
|
-
'top-[2.5rem] left-[
|
|
22
|
+
'top-[2.5rem] left-[3rem] translate-[0,0]': props.idle || !props.center,
|
|
23
23
|
},
|
|
24
24
|
]);
|
|
25
25
|
</script>
|