@alphacifer/slidev-addon-theme 0.0.1 → 0.0.2
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/components/core/Date.vue +6 -3
- package/components/core/QnA.vue +12 -6
- package/components/core/Quote.vue +2 -4
- package/components/core/ReflectedTitle.vue +8 -11
- package/components/core/Speaker.vue +4 -2
- package/components/shifting-heading/TransitionHeading.vue +15 -61
- package/components/thanks/ThanksContent.vue +43 -58
- package/components/thanks/ThanksOutlineSquare.vue +1 -1
- package/components/thanks/ThanksSquare.vue +1 -1
- package/layouts/core/bg-center.vue +1 -1
- package/layouts/core/table-of-contents.vue +1 -1
- package/layouts/shifting-heading/shifting-intro.vue +44 -75
- package/layouts/thanks/thanks.vue +1 -1
- package/package.json +1 -1
- package/utils/shiftingHeading/collectShiftingIntroNodes.ts +74 -0
package/components/core/Date.vue
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { formatDate } from '@alphacifer/core-utils/dateUtils';
|
|
3
|
+
import { computed } from 'vue';
|
|
3
4
|
|
|
4
5
|
import { useMergedUnoAttrs } from '../../utils/useMergedUnoAttrs';
|
|
5
6
|
|
|
@@ -14,11 +15,13 @@ const props = defineProps({
|
|
|
14
15
|
},
|
|
15
16
|
});
|
|
16
17
|
|
|
17
|
-
const formattedDate =
|
|
18
|
-
|
|
18
|
+
const formattedDate = computed(() => {
|
|
19
|
+
return formatDate(props.date ?? new Date(), {
|
|
20
|
+
format: 'dd/MM/yyyy',
|
|
21
|
+
});
|
|
19
22
|
});
|
|
20
23
|
|
|
21
|
-
const { className, forwardedAttrs } = useMergedUnoAttrs('
|
|
24
|
+
const { className, forwardedAttrs } = useMergedUnoAttrs('alpha-date');
|
|
22
25
|
</script>
|
|
23
26
|
|
|
24
27
|
<template>
|
package/components/core/QnA.vue
CHANGED
|
@@ -5,15 +5,16 @@ defineOptions({
|
|
|
5
5
|
inheritAttrs: false,
|
|
6
6
|
});
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
startDelay
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
8
|
+
interface IQnAProps {
|
|
9
|
+
readonly startDelay?: number;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
withDefaults(defineProps<IQnAProps>(), {
|
|
13
|
+
startDelay: 11_500,
|
|
13
14
|
});
|
|
14
15
|
|
|
15
16
|
const { className, forwardedAttrs } = useMergedUnoAttrs(
|
|
16
|
-
'
|
|
17
|
+
'alpha-qna flex items-center gap-8 text-8xl font-bold color-[#2b90b6]',
|
|
17
18
|
);
|
|
18
19
|
</script>
|
|
19
20
|
|
|
@@ -21,9 +22,12 @@ const { className, forwardedAttrs } = useMergedUnoAttrs(
|
|
|
21
22
|
<div
|
|
22
23
|
v-bind="forwardedAttrs()"
|
|
23
24
|
:class="className()"
|
|
25
|
+
aria-label="Questions and answers"
|
|
26
|
+
role="img"
|
|
24
27
|
>
|
|
25
28
|
<span
|
|
26
29
|
v-motion
|
|
30
|
+
aria-hidden="true"
|
|
27
31
|
:initial="{
|
|
28
32
|
opacity: 0,
|
|
29
33
|
x: -500,
|
|
@@ -44,6 +48,7 @@ const { className, forwardedAttrs } = useMergedUnoAttrs(
|
|
|
44
48
|
</span>
|
|
45
49
|
<span
|
|
46
50
|
v-motion
|
|
51
|
+
aria-hidden="true"
|
|
47
52
|
:initial="{
|
|
48
53
|
opacity: 1,
|
|
49
54
|
y: -1_000
|
|
@@ -65,6 +70,7 @@ const { className, forwardedAttrs } = useMergedUnoAttrs(
|
|
|
65
70
|
</span>
|
|
66
71
|
<span
|
|
67
72
|
v-motion
|
|
73
|
+
aria-hidden="true"
|
|
68
74
|
:initial="{ opacity: 0, x: 500, rotate: 360 }"
|
|
69
75
|
:enter="{
|
|
70
76
|
opacity: 1,
|
|
@@ -24,11 +24,9 @@ const props = defineProps({
|
|
|
24
24
|
});
|
|
25
25
|
|
|
26
26
|
const { className, forwardedAttrs } = useMergedUnoAttrs(
|
|
27
|
-
'
|
|
27
|
+
'alpha-quote flex flex-col',
|
|
28
28
|
);
|
|
29
|
-
const titleClasses = computed(() =>
|
|
30
|
-
return mergeUno('text-center', props.titleClass);
|
|
31
|
-
});
|
|
29
|
+
const titleClasses = computed(() => mergeUno('text-center', props.titleClass));
|
|
32
30
|
</script>
|
|
33
31
|
|
|
34
32
|
<template>
|
|
@@ -5,21 +5,20 @@ defineOptions({
|
|
|
5
5
|
inheritAttrs: false,
|
|
6
6
|
});
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
title:
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
});
|
|
8
|
+
interface IReflectedTitleProps {
|
|
9
|
+
readonly title: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
defineProps<IReflectedTitleProps>();
|
|
14
13
|
|
|
15
14
|
const { className, forwardedAttrs } = useMergedUnoAttrs(`
|
|
16
|
-
|
|
15
|
+
alpha-reflected-title
|
|
17
16
|
relative
|
|
18
17
|
text-5xl
|
|
19
18
|
font-bold
|
|
20
19
|
tracking-tight
|
|
21
20
|
!text-[#a5f3fc]
|
|
22
|
-
after:content-[
|
|
21
|
+
after:content-[attr(data-title)]
|
|
23
22
|
after:block
|
|
24
23
|
after:mt-2
|
|
25
24
|
after:absolute
|
|
@@ -40,10 +39,8 @@ const { className, forwardedAttrs } = useMergedUnoAttrs(`
|
|
|
40
39
|
<template>
|
|
41
40
|
<h1
|
|
42
41
|
v-bind="forwardedAttrs()"
|
|
43
|
-
:style="{
|
|
44
|
-
'--title': `'${title}'`,
|
|
45
|
-
}"
|
|
46
42
|
:class="className()"
|
|
43
|
+
:data-title="title"
|
|
47
44
|
>
|
|
48
45
|
{{ title }}
|
|
49
46
|
</h1>
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
+
import type { PropType } from 'vue';
|
|
3
|
+
|
|
2
4
|
import { useMergedUnoAttrs } from '../../utils/useMergedUnoAttrs';
|
|
3
5
|
|
|
4
6
|
defineOptions({
|
|
@@ -12,7 +14,7 @@ const props = defineProps({
|
|
|
12
14
|
default: 'Alpha',
|
|
13
15
|
},
|
|
14
16
|
team: {
|
|
15
|
-
type: Array
|
|
17
|
+
type: Array as PropType<string[]>,
|
|
16
18
|
required: false,
|
|
17
19
|
default: () => [],
|
|
18
20
|
},
|
|
@@ -23,7 +25,7 @@ const props = defineProps({
|
|
|
23
25
|
});
|
|
24
26
|
|
|
25
27
|
const { className, forwardedAttrs } = useMergedUnoAttrs(() => [
|
|
26
|
-
'
|
|
28
|
+
'alpha-speaker flex absolute bottom-[15px] right-[30px] flex-col',
|
|
27
29
|
props.team.length ? 'text-left gap-2' : undefined,
|
|
28
30
|
]);
|
|
29
31
|
</script>
|
|
@@ -5,76 +5,30 @@ defineOptions({
|
|
|
5
5
|
inheritAttrs: false,
|
|
6
6
|
});
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
center
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
},
|
|
8
|
+
interface ITransitionHeadingProps {
|
|
9
|
+
readonly center?: boolean;
|
|
10
|
+
readonly idle?: boolean;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const props = withDefaults(defineProps<ITransitionHeadingProps>(), {
|
|
14
|
+
center: false,
|
|
15
|
+
idle: false,
|
|
17
16
|
});
|
|
18
17
|
|
|
19
|
-
const { className, forwardedAttrs } = useMergedUnoAttrs(
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
translate-x-0
|
|
27
|
-
translate-y-0
|
|
28
|
-
origin-left
|
|
29
|
-
`);
|
|
18
|
+
const { className, forwardedAttrs } = useMergedUnoAttrs(() => [
|
|
19
|
+
'alpha-transition-heading transition-all duration-700 ease-in-out absolute whitespace-nowrap',
|
|
20
|
+
{
|
|
21
|
+
'top-[50%] left-[50%] translate-[-50%,-50%]': props.center,
|
|
22
|
+
'top-[2.5rem] left-[3.5rem] translate-[0,0]': props.idle || !props.center,
|
|
23
|
+
},
|
|
24
|
+
]);
|
|
30
25
|
</script>
|
|
31
26
|
|
|
32
27
|
<template>
|
|
33
28
|
<div
|
|
34
29
|
v-bind="forwardedAttrs()"
|
|
35
30
|
:class="className()"
|
|
36
|
-
:data-shifting-heading-state="center && !idle ? 'centered' : 'shifted'"
|
|
37
31
|
>
|
|
38
32
|
<slot />
|
|
39
33
|
</div>
|
|
40
34
|
</template>
|
|
41
|
-
|
|
42
|
-
<style>
|
|
43
|
-
.shifting-heading {
|
|
44
|
-
max-width: calc(
|
|
45
|
-
100% - var(--shifting-heading-inline, 3.5rem) -
|
|
46
|
-
var(--shifting-heading-inline, 3.5rem)
|
|
47
|
-
);
|
|
48
|
-
transition:
|
|
49
|
-
inset-inline-start var(--shifting-heading-duration, 700ms) ease-in-out,
|
|
50
|
-
top var(--shifting-heading-duration, 700ms) ease-in-out,
|
|
51
|
-
transform var(--shifting-heading-duration, 700ms) ease-in-out;
|
|
52
|
-
will-change: inset-inline-start, top, transform;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
.shifting-heading > :is(h1, h2, h3, h4, h5, h6) {
|
|
56
|
-
max-width: 100%;
|
|
57
|
-
margin: 0;
|
|
58
|
-
overflow-wrap: anywhere;
|
|
59
|
-
text-wrap: balance;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
.shifting-heading[data-shifting-heading-state='centered'] {
|
|
63
|
-
inset-inline-start: 50%;
|
|
64
|
-
top: 50%;
|
|
65
|
-
text-align: center;
|
|
66
|
-
transform: translate(-50%, -50%);
|
|
67
|
-
transform-origin: center;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
:where([dir='rtl'])
|
|
71
|
-
.shifting-heading[data-shifting-heading-state='centered'] {
|
|
72
|
-
transform: translate(50%, -50%);
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
@media (prefers-reduced-motion: reduce) {
|
|
76
|
-
.shifting-heading {
|
|
77
|
-
transition-duration: 1ms;
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
</style>
|
|
@@ -1,12 +1,6 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import type { MotionVariants, Variant } from '@vueuse/motion';
|
|
3
3
|
|
|
4
|
-
import { useMergedUnoAttrs } from '../../utils/useMergedUnoAttrs';
|
|
5
|
-
|
|
6
|
-
defineOptions({
|
|
7
|
-
inheritAttrs: false,
|
|
8
|
-
});
|
|
9
|
-
|
|
10
4
|
const { animation } = defineProps({
|
|
11
5
|
animation: {
|
|
12
6
|
type: Boolean,
|
|
@@ -60,18 +54,10 @@ const getMotionProps = ({
|
|
|
60
54
|
initial,
|
|
61
55
|
};
|
|
62
56
|
};
|
|
63
|
-
|
|
64
|
-
const { className, forwardedAttrs } = useMergedUnoAttrs(
|
|
65
|
-
'slidev-addon-thanks-content relative h-full w-full',
|
|
66
|
-
);
|
|
67
57
|
</script>
|
|
68
58
|
|
|
69
59
|
<template>
|
|
70
|
-
<
|
|
71
|
-
v-bind="forwardedAttrs()"
|
|
72
|
-
:class="className()"
|
|
73
|
-
>
|
|
74
|
-
<ThanksSquare
|
|
60
|
+
<ThanksSquare
|
|
75
61
|
v-motion
|
|
76
62
|
v-bind="getMotionProps({
|
|
77
63
|
enter: {
|
|
@@ -85,9 +71,9 @@ const { className, forwardedAttrs } = useMergedUnoAttrs(
|
|
|
85
71
|
y: -100,
|
|
86
72
|
},
|
|
87
73
|
})"
|
|
88
|
-
class="absolute w-[150px] h-[150px] rotate-45 top-[50%] left-[40%] z-10"
|
|
89
|
-
|
|
90
|
-
|
|
74
|
+
class="alpha-thanks-content absolute w-[150px] h-[150px] rotate-45 top-[50%] left-[40%] z-10"
|
|
75
|
+
/>
|
|
76
|
+
<ThanksSquare
|
|
91
77
|
v-motion
|
|
92
78
|
v-bind="getMotionProps({
|
|
93
79
|
initial: {
|
|
@@ -105,9 +91,9 @@ const { className, forwardedAttrs } = useMergedUnoAttrs(
|
|
|
105
91
|
}
|
|
106
92
|
},
|
|
107
93
|
})"
|
|
108
|
-
class="w-[100px] h-[100px] top-[20%] rotate-45 left-[48%] translate-x-[-50%] translate-y-[-50%] opacity-[0.4]"
|
|
109
|
-
|
|
110
|
-
|
|
94
|
+
class="alpha-thanks-content w-[100px] h-[100px] top-[20%] rotate-45 left-[48%] translate-x-[-50%] translate-y-[-50%] opacity-[0.4]"
|
|
95
|
+
/>
|
|
96
|
+
<ThanksSquare
|
|
111
97
|
v-motion
|
|
112
98
|
v-bind="getMotionProps({
|
|
113
99
|
initial: {
|
|
@@ -125,9 +111,9 @@ const { className, forwardedAttrs } = useMergedUnoAttrs(
|
|
|
125
111
|
}
|
|
126
112
|
},
|
|
127
113
|
})"
|
|
128
|
-
class="w-[100px] h-[100px] top-[45%] rotate-45 left-[22%] translate-x-[-50%] translate-y-[-50%] opacity-[0.4]"
|
|
129
|
-
|
|
130
|
-
|
|
114
|
+
class="alpha-thanks-content w-[100px] h-[100px] top-[45%] rotate-45 left-[22%] translate-x-[-50%] translate-y-[-50%] opacity-[0.4]"
|
|
115
|
+
/>
|
|
116
|
+
<ThanksSquare
|
|
131
117
|
v-motion
|
|
132
118
|
v-bind="getMotionProps({
|
|
133
119
|
initial: {
|
|
@@ -145,9 +131,9 @@ const { className, forwardedAttrs } = useMergedUnoAttrs(
|
|
|
145
131
|
}
|
|
146
132
|
},
|
|
147
133
|
})"
|
|
148
|
-
class="w-[100px] h-[100px] bottom-0 rotate-45 left-[48%] translate-x-[-50%] translate-y-[-50%] opacity-[0.4]"
|
|
149
|
-
|
|
150
|
-
|
|
134
|
+
class="alpha-thanks-content w-[100px] h-[100px] bottom-0 rotate-45 left-[48%] translate-x-[-50%] translate-y-[-50%] opacity-[0.4]"
|
|
135
|
+
/>
|
|
136
|
+
<ThanksOutlineSquare
|
|
151
137
|
v-motion
|
|
152
138
|
v-bind="getMotionProps({
|
|
153
139
|
initial: {
|
|
@@ -165,9 +151,9 @@ const { className, forwardedAttrs } = useMergedUnoAttrs(
|
|
|
165
151
|
},
|
|
166
152
|
},
|
|
167
153
|
})"
|
|
168
|
-
class="w-[120px] h-[120px] rotate-45 top-[25%] left-[31%]"
|
|
169
|
-
|
|
170
|
-
|
|
154
|
+
class="alpha-thanks-content w-[120px] h-[120px] rotate-45 top-[25%] left-[31%]"
|
|
155
|
+
/>
|
|
156
|
+
<ThanksOutlineSquare
|
|
171
157
|
v-motion
|
|
172
158
|
v-bind="getMotionProps({
|
|
173
159
|
initial: {
|
|
@@ -185,9 +171,9 @@ const { className, forwardedAttrs } = useMergedUnoAttrs(
|
|
|
185
171
|
},
|
|
186
172
|
},
|
|
187
173
|
})"
|
|
188
|
-
class="w-[70px] h-[70px] rotate-45 top-[52%] left-[30%]"
|
|
189
|
-
|
|
190
|
-
|
|
174
|
+
class="alpha-thanks-content w-[70px] h-[70px] rotate-45 top-[52%] left-[30%]"
|
|
175
|
+
/>
|
|
176
|
+
<ThanksOutlineSquare
|
|
191
177
|
v-motion
|
|
192
178
|
v-bind="getMotionProps({
|
|
193
179
|
initial: {
|
|
@@ -205,31 +191,30 @@ const { className, forwardedAttrs } = useMergedUnoAttrs(
|
|
|
205
191
|
},
|
|
206
192
|
},
|
|
207
193
|
})"
|
|
208
|
-
class="w-[100px] h-[100px] rotate-45 top-[42%] left-[43%]"
|
|
209
|
-
|
|
194
|
+
class="alpha-thanks-content w-[100px] h-[100px] rotate-45 top-[42%] left-[43%]"
|
|
195
|
+
/>
|
|
210
196
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
</div>
|
|
197
|
+
<div
|
|
198
|
+
v-motion
|
|
199
|
+
v-bind="getMotionProps({
|
|
200
|
+
initial: {
|
|
201
|
+
x: -80,
|
|
202
|
+
opacity: 0,
|
|
203
|
+
},
|
|
204
|
+
enter: {
|
|
205
|
+
x: -130,
|
|
206
|
+
y: -46,
|
|
207
|
+
opacity: 1,
|
|
208
|
+
transition: {
|
|
209
|
+
delay: 2_800,
|
|
210
|
+
duration: 1_000,
|
|
211
|
+
}
|
|
212
|
+
},
|
|
213
|
+
})"
|
|
214
|
+
class="alpha-thanks-content color-[#2b90b6] text-3xl absolute top-[50%] left-[69%] translate-x-[-50%] translate-y-[-50%]"
|
|
215
|
+
>
|
|
216
|
+
Thank You
|
|
217
|
+
<br />
|
|
218
|
+
for your attention!
|
|
234
219
|
</div>
|
|
235
220
|
</template>
|
|
@@ -6,7 +6,7 @@ defineOptions({
|
|
|
6
6
|
});
|
|
7
7
|
|
|
8
8
|
const { className, forwardedAttrs } = useMergedUnoAttrs(
|
|
9
|
-
'
|
|
9
|
+
'alpha-thanks-outline-square absolute rounded-2xl border-2 border-color-cyan-500',
|
|
10
10
|
);
|
|
11
11
|
</script>
|
|
12
12
|
|
|
@@ -6,7 +6,7 @@ defineOptions({
|
|
|
6
6
|
});
|
|
7
7
|
|
|
8
8
|
const { className, forwardedAttrs } = useMergedUnoAttrs(
|
|
9
|
-
'
|
|
9
|
+
'alpha-thanks-square absolute bg-gradient-to-br from-cyan-500 to-blue-500 rounded-3xl',
|
|
10
10
|
);
|
|
11
11
|
</script>
|
|
12
12
|
|
|
@@ -19,7 +19,7 @@ const style = computed(() => {
|
|
|
19
19
|
});
|
|
20
20
|
|
|
21
21
|
const { className, forwardedAttrs } = useMergedUnoAttrs(
|
|
22
|
-
'slidev-layout bg-center h-full grid place-content-center',
|
|
22
|
+
'alpha-bg-center slidev-layout bg-center h-full grid place-content-center',
|
|
23
23
|
);
|
|
24
24
|
</script>
|
|
25
25
|
|
|
@@ -1,41 +1,37 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { useSlideContext } from '@slidev/client';
|
|
3
|
-
import {
|
|
3
|
+
import { ref, shallowRef, useSlots, watch, watchEffect } from 'vue';
|
|
4
4
|
|
|
5
|
+
import { collectShiftingIntroNodes } from '../../utils/shiftingHeading/collectShiftingIntroNodes';
|
|
5
6
|
import { useMergedUnoAttrs } from '../../utils/useMergedUnoAttrs';
|
|
6
7
|
|
|
7
8
|
defineOptions({
|
|
8
9
|
inheritAttrs: false,
|
|
9
10
|
});
|
|
10
11
|
|
|
12
|
+
const context = useSlideContext();
|
|
11
13
|
const slots = useSlots();
|
|
12
|
-
const { $clicks } =
|
|
14
|
+
const { $clicks } = context;
|
|
13
15
|
|
|
14
|
-
|
|
15
|
-
return nodes.flatMap((node) => {
|
|
16
|
-
if (node.type === Fragment && Array.isArray(node.children))
|
|
17
|
-
return flattenTopLevel(node.children.filter(isVNode));
|
|
16
|
+
const delayClass = ref('delay-600');
|
|
18
17
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
18
|
+
watch($clicks, (newVal, oldVal) => {
|
|
19
|
+
if (newVal > oldVal) {
|
|
20
|
+
delayClass.value = 'delay-600';
|
|
21
|
+
} else {
|
|
22
|
+
delayClass.value = 'delay-0';
|
|
23
|
+
}
|
|
24
|
+
});
|
|
22
25
|
|
|
23
|
-
const nodes =
|
|
24
|
-
const children = flattenTopLevel(slots.default?.() ?? []);
|
|
25
|
-
const titleIndex = children.findIndex((node) => node.type === 'h1');
|
|
26
|
+
const nodes = shallowRef(collectShiftingIntroNodes([]));
|
|
26
27
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
titleIndex >= 0
|
|
31
|
-
? children.filter((_, index) => index !== titleIndex)
|
|
32
|
-
: children,
|
|
33
|
-
};
|
|
28
|
+
watchEffect(() => {
|
|
29
|
+
const children = slots.default?.() || [];
|
|
30
|
+
nodes.value = collectShiftingIntroNodes(children);
|
|
34
31
|
});
|
|
35
32
|
|
|
36
|
-
const isRevealed = computed(() => !nodes.value.title || $clicks.value > 0);
|
|
37
33
|
const { className, forwardedAttrs } = useMergedUnoAttrs(
|
|
38
|
-
'slidev-layout shifting-intro-layout
|
|
34
|
+
'alpha-shifting-intro slidev-layout shifting-intro-layout',
|
|
39
35
|
);
|
|
40
36
|
</script>
|
|
41
37
|
|
|
@@ -44,68 +40,41 @@ const { className, forwardedAttrs } = useMergedUnoAttrs(
|
|
|
44
40
|
v-bind="forwardedAttrs()"
|
|
45
41
|
:class="className()"
|
|
46
42
|
>
|
|
43
|
+
<component
|
|
44
|
+
:is="nodes.title"
|
|
45
|
+
v-if="nodes.title"
|
|
46
|
+
aria-hidden="true"
|
|
47
|
+
class="op-0"
|
|
48
|
+
/>
|
|
47
49
|
<TransitionHeading
|
|
48
50
|
v-if="nodes.title"
|
|
49
|
-
:
|
|
50
|
-
:
|
|
51
|
+
:idle="$clicks !== 0"
|
|
52
|
+
:center="$clicks === 0"
|
|
51
53
|
>
|
|
52
54
|
<component :is="nodes.title" />
|
|
53
55
|
</TransitionHeading>
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
:size="1"
|
|
56
|
+
<div
|
|
57
|
+
v-click
|
|
58
|
+
class="hidden"
|
|
58
59
|
/>
|
|
59
|
-
|
|
60
60
|
<div
|
|
61
|
-
class="
|
|
62
|
-
:class="
|
|
63
|
-
|
|
64
|
-
|
|
61
|
+
class="transition-all duration-1000"
|
|
62
|
+
:class="[
|
|
63
|
+
$clicks > 0 ? 'opacity-100' : 'opacity-0',
|
|
64
|
+
delayClass,
|
|
65
|
+
]"
|
|
65
66
|
>
|
|
66
|
-
<
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
67
|
+
<template v-for="(content) in nodes.contents" :key="content.key">
|
|
68
|
+
<component
|
|
69
|
+
v-if="nodes.clickRef.has(content.key)"
|
|
70
|
+
:is="content.node"
|
|
71
|
+
v-click="nodes.clickRef.get(content.key)"
|
|
72
|
+
/>
|
|
73
|
+
<component
|
|
74
|
+
v-else
|
|
75
|
+
:is="content.node"
|
|
76
|
+
/>
|
|
77
|
+
</template>
|
|
71
78
|
</div>
|
|
72
79
|
</div>
|
|
73
80
|
</template>
|
|
74
|
-
|
|
75
|
-
<style>
|
|
76
|
-
.shifting-intro-content {
|
|
77
|
-
box-sizing: border-box;
|
|
78
|
-
min-height: 100%;
|
|
79
|
-
padding-top: var(--shifting-heading-content-offset, 4.25rem);
|
|
80
|
-
visibility: hidden;
|
|
81
|
-
opacity: 0;
|
|
82
|
-
transition:
|
|
83
|
-
opacity var(--shifting-content-exit-duration, 250ms) ease-out,
|
|
84
|
-
visibility 0s linear var(--shifting-content-exit-duration, 250ms);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
.shifting-intro-content.is-revealed {
|
|
88
|
-
visibility: visible;
|
|
89
|
-
opacity: 1;
|
|
90
|
-
transition:
|
|
91
|
-
opacity var(--shifting-content-duration, 700ms) ease-out
|
|
92
|
-
var(--shifting-content-delay, 450ms),
|
|
93
|
-
visibility 0s linear;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
@media (prefers-reduced-motion: reduce) {
|
|
97
|
-
.shifting-intro-content,
|
|
98
|
-
.shifting-intro-content.is-revealed {
|
|
99
|
-
transition-duration: 1ms;
|
|
100
|
-
transition-delay: 0ms;
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
@media print {
|
|
105
|
-
.shifting-heading,
|
|
106
|
-
.shifting-intro-content,
|
|
107
|
-
.shifting-intro-content.is-revealed {
|
|
108
|
-
transition: none;
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
</style>
|
package/package.json
CHANGED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import type { Directive, VNode } from 'vue';
|
|
2
|
+
|
|
3
|
+
interface IShiftingIntroContent {
|
|
4
|
+
readonly key: number;
|
|
5
|
+
readonly node: VNode;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export interface IShiftingIntroNodes {
|
|
9
|
+
readonly title: VNode | null;
|
|
10
|
+
readonly clickRef: ReadonlyMap<number, number>;
|
|
11
|
+
readonly contents: readonly IShiftingIntroContent[];
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const CLICK_DIRECTIVE_NAMES = new Set(['click', 'v-click', 'vClick']);
|
|
15
|
+
|
|
16
|
+
const getDirectiveName = (directive: Directive): string | undefined => {
|
|
17
|
+
if (typeof directive === 'function') {
|
|
18
|
+
return directive.name;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
if ('name' in directive && typeof directive.name === 'string') {
|
|
22
|
+
return directive.name;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return undefined;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const hasImplicitClickDirective = (node: VNode): boolean => {
|
|
29
|
+
return Boolean(
|
|
30
|
+
node.dirs?.some(({ dir, value }) => {
|
|
31
|
+
const name = getDirectiveName(dir);
|
|
32
|
+
return (
|
|
33
|
+
name !== undefined &&
|
|
34
|
+
CLICK_DIRECTIVE_NAMES.has(name) &&
|
|
35
|
+
value === undefined
|
|
36
|
+
);
|
|
37
|
+
}),
|
|
38
|
+
);
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Separates the first heading from a shifting-intro slot and remaps implicit
|
|
43
|
+
* v-click directives after the layout's internal reveal click.
|
|
44
|
+
*/
|
|
45
|
+
export const collectShiftingIntroNodes = (
|
|
46
|
+
children: readonly VNode[],
|
|
47
|
+
): IShiftingIntroNodes => {
|
|
48
|
+
let title: VNode | null = null;
|
|
49
|
+
let clickIndex = 1;
|
|
50
|
+
const clickRef = new Map<number, number>();
|
|
51
|
+
const contents: IShiftingIntroContent[] = [];
|
|
52
|
+
|
|
53
|
+
children.forEach((node, key) => {
|
|
54
|
+
if (title === null && node.type === 'h1') {
|
|
55
|
+
title = node;
|
|
56
|
+
} else {
|
|
57
|
+
contents.push({
|
|
58
|
+
key,
|
|
59
|
+
node,
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (hasImplicitClickDirective(node)) {
|
|
64
|
+
clickIndex += 1;
|
|
65
|
+
clickRef.set(key, clickIndex);
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
return {
|
|
70
|
+
title,
|
|
71
|
+
clickRef,
|
|
72
|
+
contents,
|
|
73
|
+
};
|
|
74
|
+
};
|