@slidev/client 0.48.1 → 0.48.3
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/builtin/CodeBlockWrapper.vue +2 -6
- package/builtin/KaTexBlockWrapper.vue +2 -6
- package/builtin/RenderWhen.vue +7 -1
- package/builtin/ShikiMagicMove.vue +5 -2
- package/builtin/SlidevVideo.vue +1 -1
- package/builtin/VClickGap.vue +1 -1
- package/composables/useClicks.ts +1 -5
- package/composables/useNav.ts +12 -13
- package/composables/useViewTransition.ts +12 -18
- package/internals/ClicksSlider.vue +5 -5
- package/internals/PrintSlide.vue +5 -3
- package/internals/QuickOverview.vue +0 -1
- package/logic/route.ts +4 -1
- package/logic/transition.ts +1 -1
- package/modules/v-click.ts +1 -1
- package/modules/v-mark.ts +5 -11
- package/package.json +6 -6
- package/pages/overview.vue +31 -27
|
@@ -60,17 +60,13 @@ watchEffect(() => {
|
|
|
60
60
|
})
|
|
61
61
|
|
|
62
62
|
onMounted(() => {
|
|
63
|
-
if (!clicks ||
|
|
63
|
+
if (!clicks || !props.ranges?.length)
|
|
64
64
|
return
|
|
65
65
|
|
|
66
66
|
const { start, end, delta } = clicks.resolve(props.at, props.ranges.length - 1)
|
|
67
67
|
clicks.register(id, { max: end, delta })
|
|
68
68
|
|
|
69
|
-
const index = computed(() =>
|
|
70
|
-
if (clicks.disabled)
|
|
71
|
-
return props.ranges.length - 1
|
|
72
|
-
return Math.max(0, clicks.current - start + 1)
|
|
73
|
-
})
|
|
69
|
+
const index = computed(() => Math.max(0, clicks.current - start + 1))
|
|
74
70
|
|
|
75
71
|
const finallyRange = computed(() => {
|
|
76
72
|
return props.finally === 'last' ? props.ranges.at(-1) : props.finally.toString()
|
|
@@ -55,17 +55,13 @@ onUnmounted(() => {
|
|
|
55
55
|
})
|
|
56
56
|
|
|
57
57
|
onMounted(() => {
|
|
58
|
-
if (!clicks ||
|
|
58
|
+
if (!clicks || !props.ranges?.length)
|
|
59
59
|
return
|
|
60
60
|
|
|
61
61
|
const { start, end, delta } = clicks.resolve(props.at, props.ranges.length - 1)
|
|
62
62
|
clicks.register(id, { max: end, delta })
|
|
63
63
|
|
|
64
|
-
const index = computed(() =>
|
|
65
|
-
if (clicks.disabled)
|
|
66
|
-
return props.ranges.length - 1
|
|
67
|
-
return Math.max(0, clicks.current - start + 1)
|
|
68
|
-
})
|
|
64
|
+
const index = computed(() => Math.max(0, clicks.current - start + 1))
|
|
69
65
|
|
|
70
66
|
const finallyRange = computed(() => {
|
|
71
67
|
return props.finally === 'last' ? props.ranges.at(-1) : props.finally.toString()
|
package/builtin/RenderWhen.vue
CHANGED
|
@@ -3,8 +3,9 @@ import type { RenderContext } from '@slidev/types'
|
|
|
3
3
|
import { computed, ref } from 'vue'
|
|
4
4
|
import { useElementVisibility } from '@vueuse/core'
|
|
5
5
|
import { useSlideContext } from '../context'
|
|
6
|
+
import { useNav } from '../composables/useNav'
|
|
6
7
|
|
|
7
|
-
type Context = 'main' | 'visible' | RenderContext
|
|
8
|
+
type Context = 'main' | 'visible' | 'print' | RenderContext
|
|
8
9
|
|
|
9
10
|
const props = defineProps<{
|
|
10
11
|
context: Context | Context[]
|
|
@@ -17,6 +18,7 @@ const targetVisible = useElementVisibility(target)
|
|
|
17
18
|
const needsDomWrapper = Array.isArray(context) ? context.includes('visible') : context === 'visible'
|
|
18
19
|
|
|
19
20
|
const { $renderContext: currentContext } = useSlideContext()
|
|
21
|
+
const { isPrintMode } = useNav()
|
|
20
22
|
const shouldRender = computed(() => {
|
|
21
23
|
const anyContext = Array.isArray(context) ? context.some(contextMatch) : contextMatch(context)
|
|
22
24
|
const allConditions = Array.isArray(context) ? context.every(conditionsMatch) : conditionsMatch(context)
|
|
@@ -30,6 +32,8 @@ function contextMatch(context: Context) {
|
|
|
30
32
|
return true
|
|
31
33
|
if (context === 'visible')
|
|
32
34
|
return true
|
|
35
|
+
if (context === 'print' && isPrintMode.value)
|
|
36
|
+
return true
|
|
33
37
|
return false
|
|
34
38
|
}
|
|
35
39
|
|
|
@@ -43,6 +47,8 @@ function conditionsMatch(context: Context) {
|
|
|
43
47
|
<template>
|
|
44
48
|
<div v-if="needsDomWrapper" ref="target">
|
|
45
49
|
<slot v-if="shouldRender" />
|
|
50
|
+
<slot v-else name="fallback" />
|
|
46
51
|
</div>
|
|
47
52
|
<slot v-else-if="shouldRender" />
|
|
53
|
+
<slot v-else name="fallback" />
|
|
48
54
|
</template>
|
|
@@ -5,6 +5,7 @@ import { computed, onMounted, onUnmounted, ref, watch } from 'vue'
|
|
|
5
5
|
import lz from 'lz-string'
|
|
6
6
|
import { useSlideContext } from '../context'
|
|
7
7
|
import { makeId, updateCodeHighlightRange } from '../logic/utils'
|
|
8
|
+
import { useNav } from '../composables/useNav'
|
|
8
9
|
|
|
9
10
|
const props = defineProps<{
|
|
10
11
|
at?: string | number
|
|
@@ -14,6 +15,7 @@ const props = defineProps<{
|
|
|
14
15
|
|
|
15
16
|
const steps = JSON.parse(lz.decompressFromBase64(props.stepsLz)) as KeyedTokensInfo[]
|
|
16
17
|
const { $clicksContext: clicks, $scale: scale } = useSlideContext()
|
|
18
|
+
const { isPrintMode } = useNav()
|
|
17
19
|
const id = makeId()
|
|
18
20
|
|
|
19
21
|
const stepIndex = ref(0)
|
|
@@ -23,11 +25,11 @@ const container = ref<HTMLElement>()
|
|
|
23
25
|
const ranges = computed(() => props.stepRanges.map(i => i.length ? i : ['all']))
|
|
24
26
|
|
|
25
27
|
onUnmounted(() => {
|
|
26
|
-
clicks
|
|
28
|
+
clicks?.unregister(id)
|
|
27
29
|
})
|
|
28
30
|
|
|
29
31
|
onMounted(() => {
|
|
30
|
-
if (!clicks
|
|
32
|
+
if (!clicks)
|
|
31
33
|
return
|
|
32
34
|
|
|
33
35
|
if (ranges.value.length !== steps.length)
|
|
@@ -92,6 +94,7 @@ onMounted(() => {
|
|
|
92
94
|
class="slidev-code relative shiki overflow-visible"
|
|
93
95
|
:steps="steps"
|
|
94
96
|
:step="stepIndex"
|
|
97
|
+
:animate="!isPrintMode"
|
|
95
98
|
:options="{
|
|
96
99
|
globalScale: scale,
|
|
97
100
|
// TODO: make this configurable later
|
package/builtin/SlidevVideo.vue
CHANGED
|
@@ -26,7 +26,7 @@ const matchRoute = computed(() => {
|
|
|
26
26
|
})
|
|
27
27
|
|
|
28
28
|
const matchClick = computed(() => {
|
|
29
|
-
if (!video.value || currentContext?.value !== 'slide' || clicks
|
|
29
|
+
if (!video.value || currentContext?.value !== 'slide' || !clicks)
|
|
30
30
|
return false
|
|
31
31
|
return clicks.map.get(video.value)?.isShown?.value ?? true
|
|
32
32
|
})
|
package/builtin/VClickGap.vue
CHANGED
package/composables/useClicks.ts
CHANGED
|
@@ -8,15 +8,11 @@ import { routeForceRefresh } from '../logic/route'
|
|
|
8
8
|
export function createClicksContextBase(
|
|
9
9
|
current: Ref<number>,
|
|
10
10
|
clicksOverrides?: number,
|
|
11
|
-
isDisabled?: () => boolean,
|
|
12
11
|
): ClicksContext {
|
|
13
12
|
const relativeOffsets: ClicksContext['relativeOffsets'] = new Map()
|
|
14
13
|
const map: ClicksContext['map'] = shallowReactive(new Map())
|
|
15
14
|
|
|
16
15
|
return {
|
|
17
|
-
get disabled() {
|
|
18
|
-
return isDisabled ? isDisabled() : false
|
|
19
|
-
},
|
|
20
16
|
get current() {
|
|
21
17
|
return +current.value
|
|
22
18
|
},
|
|
@@ -25,7 +21,7 @@ export function createClicksContextBase(
|
|
|
25
21
|
},
|
|
26
22
|
relativeOffsets,
|
|
27
23
|
map,
|
|
28
|
-
onMounted() {},
|
|
24
|
+
onMounted() { },
|
|
29
25
|
resolve(at, size = 1) {
|
|
30
26
|
const [isRelative, value] = normalizeAtProp(at)
|
|
31
27
|
if (isRelative) {
|
package/composables/useNav.ts
CHANGED
|
@@ -170,15 +170,19 @@ export function useNavBase(
|
|
|
170
170
|
return go(total.value)
|
|
171
171
|
}
|
|
172
172
|
|
|
173
|
-
async function go(page: number | string, clicks
|
|
173
|
+
async function go(page: number | string, clicks: number = 0) {
|
|
174
174
|
skipTransition.value = false
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
175
|
+
const pageChanged = currentSlideNo.value !== page
|
|
176
|
+
const clicksChanged = clicks !== queryClicks.value
|
|
177
|
+
if (pageChanged || clicksChanged) {
|
|
178
|
+
await router?.push({
|
|
179
|
+
path: getSlidePath(page, isPresenter.value),
|
|
180
|
+
query: {
|
|
181
|
+
...router.currentRoute.value.query,
|
|
182
|
+
clicks: clicks === 0 ? undefined : clicks.toString(),
|
|
183
|
+
},
|
|
184
|
+
})
|
|
185
|
+
}
|
|
182
186
|
}
|
|
183
187
|
|
|
184
188
|
return {
|
|
@@ -255,8 +259,6 @@ const useNavState = createSharedComposable((): SlidevContextNavState => {
|
|
|
255
259
|
|
|
256
260
|
const queryClicks = computed({
|
|
257
261
|
get() {
|
|
258
|
-
if (clicksContext.value.disabled)
|
|
259
|
-
return CLICKS_MAX
|
|
260
262
|
let v = +(queryClicksRaw.value || 0)
|
|
261
263
|
if (Number.isNaN(v))
|
|
262
264
|
v = 0
|
|
@@ -277,8 +279,6 @@ const useNavState = createSharedComposable((): SlidevContextNavState => {
|
|
|
277
279
|
const context = createClicksContextBase(
|
|
278
280
|
computed({
|
|
279
281
|
get() {
|
|
280
|
-
if (context.disabled)
|
|
281
|
-
return CLICKS_MAX
|
|
282
282
|
if (currentSlideNo.value === thisNo)
|
|
283
283
|
return +(queryClicksRaw.value || 0) || 0
|
|
284
284
|
else if (currentSlideNo.value > thisNo)
|
|
@@ -292,7 +292,6 @@ const useNavState = createSharedComposable((): SlidevContextNavState => {
|
|
|
292
292
|
},
|
|
293
293
|
}),
|
|
294
294
|
route?.meta?.clicks,
|
|
295
|
-
() => isPrintMode.value && !isPrintWithClicks.value,
|
|
296
295
|
)
|
|
297
296
|
|
|
298
297
|
// On slide mounted, make sure the query is not greater than the total
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { ref } from 'vue'
|
|
2
2
|
import { useRouter } from 'vue-router'
|
|
3
3
|
import { getSlide } from '../logic/slides'
|
|
4
|
+
import { configs } from '../env'
|
|
4
5
|
|
|
5
6
|
export function useViewTransition() {
|
|
6
7
|
const router = useRouter()
|
|
@@ -16,14 +17,9 @@ export function useViewTransition() {
|
|
|
16
17
|
const toMeta = getSlide(to.params.no as string)?.meta
|
|
17
18
|
const fromNo = fromMeta?.slide?.no
|
|
18
19
|
const toNo = toMeta?.slide?.no
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
(fromMeta?.transition === 'view-transition' && fromNo < toNo)
|
|
23
|
-
|| (toMeta?.transition === 'view-transition' && toNo < fromNo)
|
|
24
|
-
)
|
|
25
|
-
)
|
|
26
|
-
) {
|
|
20
|
+
const transitionType = fromNo != null && toNo != null
|
|
21
|
+
&& ((fromNo < toNo ? fromMeta?.transition : toMeta?.transition) ?? configs.transition)
|
|
22
|
+
if (transitionType !== 'view-transition') {
|
|
27
23
|
isViewTransition.value = false
|
|
28
24
|
return
|
|
29
25
|
}
|
|
@@ -43,17 +39,15 @@ export function useViewTransition() {
|
|
|
43
39
|
let changeRoute: () => void
|
|
44
40
|
const ready = new Promise<void>(resolve => (changeRoute = resolve))
|
|
45
41
|
|
|
46
|
-
//
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
42
|
+
// Wait for `TransitionGroup` to become normal `div`
|
|
43
|
+
setTimeout(() => {
|
|
44
|
+
// @ts-expect-error missing types
|
|
45
|
+
document.startViewTransition(() => {
|
|
46
|
+
changeRoute()
|
|
47
|
+
return promise
|
|
48
|
+
})
|
|
49
|
+
}, 50)
|
|
52
50
|
|
|
53
|
-
transition.finished.then(() => {
|
|
54
|
-
viewTransitionAbort = undefined
|
|
55
|
-
viewTransitionFinish = undefined
|
|
56
|
-
})
|
|
57
51
|
return ready
|
|
58
52
|
})
|
|
59
53
|
|
|
@@ -28,21 +28,21 @@ function onMousedown() {
|
|
|
28
28
|
|
|
29
29
|
<template>
|
|
30
30
|
<div
|
|
31
|
-
class="flex gap-
|
|
31
|
+
class="flex gap-1 items-center select-none"
|
|
32
32
|
:title="`Clicks in this slide: ${total}`"
|
|
33
33
|
:class="total ? '' : 'op50'"
|
|
34
34
|
>
|
|
35
|
-
<div class="flex gap-
|
|
35
|
+
<div class="flex gap-0.5 items-center min-w-16 font-mono mr1">
|
|
36
36
|
<carbon:cursor-1 text-sm op50 />
|
|
37
|
+
<div flex-auto />
|
|
37
38
|
<template v-if="current >= 0 && current !== CLICKS_MAX">
|
|
38
|
-
<div flex-auto />
|
|
39
39
|
<span text-primary>{{ current }}</span>
|
|
40
40
|
<span op25>/</span>
|
|
41
41
|
</template>
|
|
42
42
|
<span op50>{{ total }}</span>
|
|
43
43
|
</div>
|
|
44
44
|
<div
|
|
45
|
-
relative flex-auto h5 flex="~"
|
|
45
|
+
relative flex-auto h5 font-mono flex="~"
|
|
46
46
|
@dblclick="current = clicksContext.total"
|
|
47
47
|
>
|
|
48
48
|
<div
|
|
@@ -54,7 +54,7 @@ function onMousedown() {
|
|
|
54
54
|
]"
|
|
55
55
|
:style="{ width: total > 0 ? `${1 / total * 100}%` : '100%' }"
|
|
56
56
|
>
|
|
57
|
-
<div absolute inset-0 :class="i <= current ? 'bg-primary
|
|
57
|
+
<div absolute inset-0 :class="i <= current ? 'bg-primary op15' : ''" />
|
|
58
58
|
<div
|
|
59
59
|
:class="[
|
|
60
60
|
+i === +current ? 'text-primary font-bold op100 border-primary' : 'op30 border-main',
|
package/internals/PrintSlide.vue
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import type { SlideRoute } from '@slidev/types'
|
|
3
|
-
import { useFixedNav } from '../composables/useNav'
|
|
3
|
+
import { useFixedNav, useNav } from '../composables/useNav'
|
|
4
4
|
import { createFixedClicks } from '../composables/useClicks'
|
|
5
|
+
import { CLICKS_MAX } from '../constants'
|
|
5
6
|
import PrintSlideClick from './PrintSlideClick.vue'
|
|
6
7
|
|
|
7
8
|
const { route } = defineProps<{ route: SlideRoute }>()
|
|
8
|
-
const
|
|
9
|
+
const { isPrintWithClicks } = useNav()
|
|
10
|
+
const clicks0 = createFixedClicks(route, isPrintWithClicks.value ? 0 : CLICKS_MAX)
|
|
9
11
|
</script>
|
|
10
12
|
|
|
11
13
|
<template>
|
|
@@ -13,7 +15,7 @@ const clicks0 = createFixedClicks(route, 0)
|
|
|
13
15
|
:clicks-context="clicks0"
|
|
14
16
|
:nav="useFixedNav(route, clicks0)"
|
|
15
17
|
/>
|
|
16
|
-
<template v-if="
|
|
18
|
+
<template v-if="isPrintWithClicks">
|
|
17
19
|
<PrintSlideClick
|
|
18
20
|
v-for="i of clicks0.total"
|
|
19
21
|
:key="i"
|
package/logic/route.ts
CHANGED
|
@@ -22,6 +22,9 @@ export function useRouteQuery<T extends string | string[]>(
|
|
|
22
22
|
},
|
|
23
23
|
set(v) {
|
|
24
24
|
nextTick(() => {
|
|
25
|
+
const oldValue = router.currentRoute.value.query[name]
|
|
26
|
+
if ((oldValue ?? defaultValue?.toString()) === v.toString())
|
|
27
|
+
return
|
|
25
28
|
router[unref(mode) as 'replace' | 'push']({
|
|
26
29
|
query: {
|
|
27
30
|
...router.currentRoute.value.query,
|
|
@@ -30,7 +33,7 @@ export function useRouteQuery<T extends string | string[]>(
|
|
|
30
33
|
})
|
|
31
34
|
})
|
|
32
35
|
},
|
|
33
|
-
})
|
|
36
|
+
})
|
|
34
37
|
}
|
|
35
38
|
|
|
36
39
|
// force update collected elements when the route is fully resolved
|
package/logic/transition.ts
CHANGED
|
@@ -9,7 +9,7 @@ const transitionResolveMap: Record<string, string | undefined> = {
|
|
|
9
9
|
'slide-down': 'slide-down | slide-up',
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
function resolveTransition(transition?: string | TransitionGroupProps, isBackward = false): TransitionGroupProps | undefined {
|
|
13
13
|
if (!transition)
|
|
14
14
|
return undefined
|
|
15
15
|
if (typeof transition === 'string') {
|
package/modules/v-click.ts
CHANGED
|
@@ -132,7 +132,7 @@ function isCurrent(thisClick: number | [number, number], clicks: number) {
|
|
|
132
132
|
export function resolveClick(el: Element, dir: DirectiveBinding<any>, value: VClickValue, clickAfter = false, flagHide = false): ResolvedClicksInfo | null {
|
|
133
133
|
const ctx = dirInject(dir, injectionClicksContext)?.value
|
|
134
134
|
|
|
135
|
-
if (!el || !ctx
|
|
135
|
+
if (!el || !ctx)
|
|
136
136
|
return null
|
|
137
137
|
|
|
138
138
|
if (value === false || value === 'false')
|
package/modules/v-mark.ts
CHANGED
|
@@ -116,7 +116,8 @@ export function createVMarkDirective() {
|
|
|
116
116
|
|
|
117
117
|
const resolvedClick = resolveClick(el, binding, options.value.at)
|
|
118
118
|
if (!resolvedClick) {
|
|
119
|
-
|
|
119
|
+
// No click animation, just show the mark
|
|
120
|
+
annotation.show()
|
|
120
121
|
return
|
|
121
122
|
}
|
|
122
123
|
|
|
@@ -130,19 +131,12 @@ export function createVMarkDirective() {
|
|
|
130
131
|
|
|
131
132
|
const at = options.value.at
|
|
132
133
|
|
|
133
|
-
if (at === true)
|
|
134
|
+
if (at === true)
|
|
134
135
|
shouldShow = true
|
|
135
|
-
|
|
136
|
-
else if (at === false) {
|
|
136
|
+
else if (at === false)
|
|
137
137
|
shouldShow = false
|
|
138
|
-
|
|
139
|
-
else if (resolvedClick) {
|
|
138
|
+
else
|
|
140
139
|
shouldShow = resolvedClick.isActive.value
|
|
141
|
-
}
|
|
142
|
-
else {
|
|
143
|
-
console.error('[Slidev] Invalid value for v-mark:', at)
|
|
144
|
-
return
|
|
145
|
-
}
|
|
146
140
|
|
|
147
141
|
if (shouldShow == null)
|
|
148
142
|
return
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@slidev/client",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.48.
|
|
4
|
+
"version": "0.48.3",
|
|
5
5
|
"description": "Presentation slides for developers",
|
|
6
6
|
"author": "antfu <anthonyfu117@hotmail.com>",
|
|
7
7
|
"license": "MIT",
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"@shikijs/vitepress-twoslash": "^1.1.7",
|
|
37
37
|
"@slidev/rough-notation": "^0.1.0",
|
|
38
38
|
"@typescript/ata": "^0.9.4",
|
|
39
|
-
"@unhead/vue": "^1.8.
|
|
39
|
+
"@unhead/vue": "^1.8.18",
|
|
40
40
|
"@unocss/reset": "^0.58.5",
|
|
41
41
|
"@vueuse/core": "^10.9.0",
|
|
42
42
|
"@vueuse/math": "^10.9.0",
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
"katex": "^0.16.9",
|
|
51
51
|
"lz-string": "^1.5.0",
|
|
52
52
|
"mermaid": "^10.9.0",
|
|
53
|
-
"monaco-editor": "^0.
|
|
53
|
+
"monaco-editor": "^0.47.0",
|
|
54
54
|
"prettier": "^3.2.5",
|
|
55
55
|
"recordrtc": "^5.6.2",
|
|
56
56
|
"shiki": "^1.1.7",
|
|
@@ -60,10 +60,10 @@
|
|
|
60
60
|
"vue": "^3.4.21",
|
|
61
61
|
"vue-demi": "^0.14.7",
|
|
62
62
|
"vue-router": "^4.3.0",
|
|
63
|
-
"@slidev/
|
|
64
|
-
"@slidev/
|
|
63
|
+
"@slidev/types": "0.48.3",
|
|
64
|
+
"@slidev/parser": "0.48.3"
|
|
65
65
|
},
|
|
66
66
|
"devDependencies": {
|
|
67
|
-
"vite": "^5.1.
|
|
67
|
+
"vite": "^5.1.6"
|
|
68
68
|
}
|
|
69
69
|
}
|
package/pages/overview.vue
CHANGED
|
@@ -100,37 +100,42 @@ onMounted(() => {
|
|
|
100
100
|
|
|
101
101
|
<template>
|
|
102
102
|
<div class="h-screen w-screen of-hidden flex">
|
|
103
|
-
<nav class="
|
|
104
|
-
<div class="
|
|
105
|
-
<div
|
|
106
|
-
v-for="(route, idx) of slides"
|
|
107
|
-
:key="route.no"
|
|
108
|
-
class="relative"
|
|
109
|
-
>
|
|
110
|
-
<button
|
|
111
|
-
class="relative transition duration-300 w-8 h-8 rounded hover:bg-active hover:op100"
|
|
112
|
-
:class="activeBlocks.includes(idx) ? 'op100 text-primary bg-gray:5' : 'op20'"
|
|
113
|
-
@click="scrollToSlide(idx)"
|
|
114
|
-
>
|
|
115
|
-
<div>{{ idx + 1 }}</div>
|
|
116
|
-
</button>
|
|
103
|
+
<nav class="grid grid-rows-[auto_max-content] border-r border-main select-none max-h-full h-full">
|
|
104
|
+
<div class="relative">
|
|
105
|
+
<div class="absolute left-0 top-0 bottom-0 w-200 flex flex-col flex-auto items-end group p2 gap-1 max-h-full of-scroll" style="direction:rtl">
|
|
117
106
|
<div
|
|
118
|
-
v-
|
|
119
|
-
|
|
120
|
-
|
|
107
|
+
v-for="(route, idx) of slides"
|
|
108
|
+
:key="route.no"
|
|
109
|
+
class="relative"
|
|
110
|
+
style="direction:ltr"
|
|
121
111
|
>
|
|
122
|
-
|
|
112
|
+
<button
|
|
113
|
+
class="relative transition duration-300 w-8 h-8 rounded hover:bg-active hover:op100"
|
|
114
|
+
:class="activeBlocks.includes(idx) ? 'op100 text-primary bg-gray:5' : 'op20'"
|
|
115
|
+
@click="scrollToSlide(idx)"
|
|
116
|
+
>
|
|
117
|
+
<div>{{ idx + 1 }}</div>
|
|
118
|
+
</button>
|
|
119
|
+
<div
|
|
120
|
+
v-if="route.meta?.slide?.title"
|
|
121
|
+
class="pointer-events-none select-none absolute left-110% backdrop-blur-8 top-50% translate-y--50% ws-nowrap z-10 px2 shadow-xl rounded border border-main transition duration-400 op0 group-hover:op100"
|
|
122
|
+
:class="activeBlocks.includes(idx) ? 'text-primary' : 'text-main important-text-op-50'"
|
|
123
|
+
>
|
|
124
|
+
{{ route.meta?.slide?.title }}
|
|
125
|
+
</div>
|
|
123
126
|
</div>
|
|
124
127
|
</div>
|
|
125
128
|
</div>
|
|
126
|
-
<
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
129
|
+
<div p2 border="t main">
|
|
130
|
+
<IconButton
|
|
131
|
+
v-if="!isColorSchemaConfigured"
|
|
132
|
+
:title="isDark ? 'Switch to light mode theme' : 'Switch to dark mode theme'"
|
|
133
|
+
@click="toggleDark()"
|
|
134
|
+
>
|
|
135
|
+
<carbon-moon v-if="isDark" />
|
|
136
|
+
<carbon-sun v-else />
|
|
137
|
+
</IconButton>
|
|
138
|
+
</div>
|
|
134
139
|
</nav>
|
|
135
140
|
<main
|
|
136
141
|
class="flex-1 h-full of-auto"
|
|
@@ -172,7 +177,6 @@ onMounted(() => {
|
|
|
172
177
|
<SlideContainer
|
|
173
178
|
:key="route.no"
|
|
174
179
|
:width="cardWidth"
|
|
175
|
-
:clicks-disabled="true"
|
|
176
180
|
class="pointer-events-none important:[&_*]:select-none"
|
|
177
181
|
>
|
|
178
182
|
<SlideWrapper
|