@slidev/client 0.48.0-beta.8 → 0.48.0
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/App.vue +7 -0
- package/builtin/Arrow.vue +2 -4
- package/builtin/CodeBlockWrapper.vue +33 -28
- package/builtin/KaTexBlockWrapper.vue +1 -1
- package/builtin/Link.vue +3 -1
- package/builtin/Mermaid.vue +4 -3
- package/builtin/Monaco.vue +166 -93
- package/builtin/ShikiMagicMove.vue +103 -0
- package/builtin/SlidevVideo.vue +1 -1
- package/builtin/Toc.vue +1 -1
- package/builtin/TocList.vue +4 -3
- package/builtin/Tweet.vue +12 -9
- package/builtin/VClick.ts +2 -1
- package/composables/useClicks.ts +19 -32
- package/composables/useDarkMode.ts +9 -0
- package/composables/useDrawings.ts +181 -0
- package/composables/useNav.ts +346 -44
- package/{logic/note.ts → composables/useSlideInfo.ts} +13 -16
- package/composables/useSwipeControls.ts +43 -0
- package/composables/useTocTree.ts +81 -0
- package/composables/useViewTransition.ts +7 -4
- package/constants.ts +4 -3
- package/context.ts +13 -6
- package/env.ts +7 -16
- package/index.html +1 -0
- package/index.ts +12 -0
- package/internals/ClicksSlider.vue +93 -0
- package/internals/CodeRunner.vue +142 -0
- package/internals/Controls.vue +2 -2
- package/internals/DomElement.vue +18 -0
- package/internals/DrawingControls.vue +15 -17
- package/internals/DrawingLayer.vue +6 -5
- package/internals/DrawingPreview.vue +4 -2
- package/internals/Goto.vue +9 -6
- package/internals/IconButton.vue +7 -3
- package/internals/NavControls.vue +31 -12
- package/internals/NoteDisplay.vue +131 -8
- package/internals/NoteEditable.vue +129 -0
- package/internals/NoteStatic.vue +8 -6
- package/internals/PrintContainer.vue +11 -8
- package/internals/PrintSlide.vue +11 -12
- package/internals/PrintSlideClick.vue +14 -19
- package/internals/{SlidesOverview.vue → QuickOverview.vue} +35 -22
- package/internals/RecordingControls.vue +1 -1
- package/internals/RecordingDialog.vue +5 -6
- package/internals/{Editor.vue → SideEditor.vue} +26 -17
- package/internals/SlideContainer.vue +13 -9
- package/internals/SlideLoading.vue +19 -0
- package/internals/SlideWrapper.vue +79 -0
- package/internals/SlidesShow.vue +36 -22
- package/layouts/error.vue +5 -0
- package/layouts/two-cols-header.vue +9 -3
- package/logic/overview.ts +2 -2
- package/logic/route.ts +16 -5
- package/logic/slides.ts +20 -0
- package/logic/transition.ts +50 -0
- package/logic/utils.ts +24 -1
- package/main.ts +3 -15
- package/{setup → modules}/codemirror.ts +1 -3
- package/modules/context.ts +1 -46
- package/modules/mermaid.ts +9 -8
- package/package.json +21 -15
- package/{internals/EntrySelect.vue → pages/entry.vue} +7 -0
- package/{internals/NotesView.vue → pages/notes.vue} +9 -6
- package/pages/overview.vue +231 -0
- package/{internals/Play.vue → pages/play.vue} +22 -15
- package/{internals/PresenterPrint.vue → pages/presenter/print.vue} +15 -8
- package/{internals/Presenter.vue → pages/presenter.vue} +129 -107
- package/{internals/Print.vue → pages/print.vue} +6 -5
- package/routes.ts +26 -57
- package/setup/code-runners.ts +164 -0
- package/setup/main.ts +39 -9
- package/setup/mermaid.ts +5 -6
- package/setup/monaco.ts +114 -51
- package/setup/root.ts +62 -18
- package/setup/shortcuts.ts +15 -12
- package/shim-vue.d.ts +34 -0
- package/shim.d.ts +1 -13
- package/state/index.ts +2 -2
- package/styles/code.css +9 -5
- package/styles/index.css +63 -7
- package/styles/katex.css +1 -1
- package/styles/layouts-base.css +17 -12
- package/styles/shiki-twoslash.css +1 -1
- package/styles/vars.css +1 -0
- package/uno.config.ts +14 -2
- package/utils.ts +15 -2
- package/composables/useContext.ts +0 -17
- package/composables/useTweetScript.ts +0 -17
- package/iframes/monaco/index.css +0 -28
- package/iframes/monaco/index.html +0 -7
- package/iframes/monaco/index.ts +0 -260
- package/internals/NoteEditor.vue +0 -88
- package/internals/SlideWrapper.ts +0 -58
- package/logic/drawings.ts +0 -161
- package/logic/nav.ts +0 -278
- package/setup/prettier.ts +0 -43
- /package/{composables → logic}/hmr.ts +0 -0
|
@@ -1,18 +1,22 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { computed, ref, shallowRef } from 'vue'
|
|
3
3
|
import { isEditorVertical, isScreenVertical, showEditor, slideScale, windowSize } from '../state'
|
|
4
|
-
import {
|
|
5
|
-
import { isDrawing } from '../logic/drawings'
|
|
4
|
+
import { useSwipeControls } from '../composables/useSwipeControls'
|
|
6
5
|
import { registerShortcuts } from '../logic/shortcuts'
|
|
7
|
-
import { configs
|
|
8
|
-
import Controls from '
|
|
9
|
-
import SlideContainer from '
|
|
10
|
-
import NavControls from '
|
|
11
|
-
import SlidesShow from '
|
|
12
|
-
import PrintStyle from '
|
|
6
|
+
import { configs } from '../env'
|
|
7
|
+
import Controls from '../internals/Controls.vue'
|
|
8
|
+
import SlideContainer from '../internals/SlideContainer.vue'
|
|
9
|
+
import NavControls from '../internals/NavControls.vue'
|
|
10
|
+
import SlidesShow from '../internals/SlidesShow.vue'
|
|
11
|
+
import PrintStyle from '../internals/PrintStyle.vue'
|
|
12
|
+
import { useNav } from '../composables/useNav'
|
|
13
|
+
import { useDrawings } from '../composables/useDrawings'
|
|
13
14
|
|
|
14
15
|
registerShortcuts()
|
|
15
16
|
|
|
17
|
+
const { next, prev, isEmbedded, isPrintMode } = useNav()
|
|
18
|
+
const { isDrawing } = useDrawings()
|
|
19
|
+
|
|
16
20
|
const root = ref<HTMLDivElement>()
|
|
17
21
|
function onClick(e: MouseEvent) {
|
|
18
22
|
if (showEditor.value)
|
|
@@ -31,18 +35,21 @@ useSwipeControls(root)
|
|
|
31
35
|
|
|
32
36
|
const persistNav = computed(() => isScreenVertical.value || showEditor.value)
|
|
33
37
|
|
|
34
|
-
const
|
|
38
|
+
const SideEditor = shallowRef<any>()
|
|
35
39
|
if (__DEV__ && __SLIDEV_FEATURE_EDITOR__)
|
|
36
|
-
import('
|
|
40
|
+
import('../internals/SideEditor.vue').then(v => SideEditor.value = v.default)
|
|
37
41
|
|
|
38
42
|
const DrawingControls = shallowRef<any>()
|
|
39
43
|
if (__SLIDEV_FEATURE_DRAWINGS__)
|
|
40
|
-
import('
|
|
44
|
+
import('../internals/DrawingControls.vue').then(v => DrawingControls.value = v.default)
|
|
41
45
|
</script>
|
|
42
46
|
|
|
43
47
|
<template>
|
|
44
48
|
<PrintStyle v-if="isPrintMode" />
|
|
45
|
-
<div
|
|
49
|
+
<div
|
|
50
|
+
id="page-root" ref="root" class="grid"
|
|
51
|
+
:class="isEditorVertical ? 'grid-rows-[1fr_max-content]' : 'grid-cols-[1fr_max-content]'"
|
|
52
|
+
>
|
|
46
53
|
<SlideContainer
|
|
47
54
|
class="w-full h-full"
|
|
48
55
|
:style="{ background: 'var(--slidev-slide-container-background, black)' }"
|
|
@@ -70,9 +77,9 @@ if (__SLIDEV_FEATURE_DRAWINGS__)
|
|
|
70
77
|
</template>
|
|
71
78
|
</SlideContainer>
|
|
72
79
|
|
|
73
|
-
<template v-if="__DEV__ && __SLIDEV_FEATURE_EDITOR__ &&
|
|
74
|
-
<
|
|
80
|
+
<template v-if="__DEV__ && __SLIDEV_FEATURE_EDITOR__ && SideEditor && showEditor">
|
|
81
|
+
<SideEditor :resize="true" />
|
|
75
82
|
</template>
|
|
76
83
|
</div>
|
|
77
84
|
<Controls />
|
|
78
|
-
</template
|
|
85
|
+
</template>../composables/drawings
|
|
@@ -2,9 +2,11 @@
|
|
|
2
2
|
import { computed } from 'vue'
|
|
3
3
|
import { useStyleTag } from '@vueuse/core'
|
|
4
4
|
import { useHead } from '@unhead/vue'
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import NoteDisplay from '
|
|
5
|
+
import { useNav } from '../../composables/useNav'
|
|
6
|
+
import { configs } from '../../env'
|
|
7
|
+
import NoteDisplay from '../../internals/NoteDisplay.vue'
|
|
8
|
+
|
|
9
|
+
const { slides, total } = useNav()
|
|
8
10
|
|
|
9
11
|
useStyleTag(`
|
|
10
12
|
@page {
|
|
@@ -24,15 +26,17 @@ html #page-root {
|
|
|
24
26
|
}
|
|
25
27
|
`)
|
|
26
28
|
|
|
27
|
-
useHead({
|
|
29
|
+
useHead({
|
|
30
|
+
title: `Notes - ${configs.title}`,
|
|
31
|
+
})
|
|
28
32
|
|
|
29
|
-
const slidesWithNote = computed(() =>
|
|
33
|
+
const slidesWithNote = computed(() => slides.value
|
|
30
34
|
.map(route => route.meta?.slide)
|
|
31
35
|
.filter(slide => slide !== undefined && slide.noteHTML !== ''))
|
|
32
36
|
</script>
|
|
33
37
|
|
|
34
38
|
<template>
|
|
35
|
-
<div id="page-root"
|
|
39
|
+
<div id="page-root">
|
|
36
40
|
<div class="m-4">
|
|
37
41
|
<div class="mb-10">
|
|
38
42
|
<h1 class="text-4xl font-bold mt-2">
|
|
@@ -54,9 +58,12 @@ const slidesWithNote = computed(() => rawRoutes
|
|
|
54
58
|
<div class="flex-auto" />
|
|
55
59
|
</div>
|
|
56
60
|
</h2>
|
|
57
|
-
<NoteDisplay
|
|
61
|
+
<NoteDisplay
|
|
62
|
+
:note-html="slide!.noteHTML"
|
|
63
|
+
class="max-w-full"
|
|
64
|
+
/>
|
|
58
65
|
</div>
|
|
59
|
-
<hr v-if="index < slidesWithNote.length - 1" class="border-
|
|
66
|
+
<hr v-if="index < slidesWithNote.length - 1" class="border-main mb-8">
|
|
60
67
|
</div>
|
|
61
68
|
</div>
|
|
62
69
|
</div>
|
|
@@ -2,31 +2,46 @@
|
|
|
2
2
|
import { useHead } from '@unhead/vue'
|
|
3
3
|
import { computed, onMounted, reactive, ref, shallowRef, watch } from 'vue'
|
|
4
4
|
import { useMouse, useWindowFocus } from '@vueuse/core'
|
|
5
|
-
import {
|
|
5
|
+
import { useSwipeControls } from '../composables/useSwipeControls'
|
|
6
6
|
import { decreasePresenterFontSize, increasePresenterFontSize, presenterLayout, presenterNotesFontSize, showEditor, showOverview, showPresenterCursor } from '../state'
|
|
7
|
-
import { configs
|
|
7
|
+
import { configs } from '../env'
|
|
8
8
|
import { sharedState } from '../state/shared'
|
|
9
9
|
import { registerShortcuts } from '../logic/shortcuts'
|
|
10
10
|
import { getSlideClass } from '../utils'
|
|
11
11
|
import { useTimer } from '../logic/utils'
|
|
12
|
-
import {
|
|
13
|
-
import
|
|
14
|
-
import SlideContainer from '
|
|
15
|
-
import NavControls from '
|
|
16
|
-
import
|
|
17
|
-
import
|
|
18
|
-
import NoteStatic from '
|
|
19
|
-
import Goto from '
|
|
20
|
-
import SlidesShow from '
|
|
21
|
-
import
|
|
22
|
-
import
|
|
23
|
-
import
|
|
12
|
+
import { createFixedClicks } from '../composables/useClicks'
|
|
13
|
+
import SlideWrapper from '../internals/SlideWrapper.vue'
|
|
14
|
+
import SlideContainer from '../internals/SlideContainer.vue'
|
|
15
|
+
import NavControls from '../internals/NavControls.vue'
|
|
16
|
+
import QuickOverview from '../internals/QuickOverview.vue'
|
|
17
|
+
import NoteEditable from '../internals/NoteEditable.vue'
|
|
18
|
+
import NoteStatic from '../internals/NoteStatic.vue'
|
|
19
|
+
import Goto from '../internals/Goto.vue'
|
|
20
|
+
import SlidesShow from '../internals/SlidesShow.vue'
|
|
21
|
+
import DrawingControls from '../internals/DrawingControls.vue'
|
|
22
|
+
import IconButton from '../internals/IconButton.vue'
|
|
23
|
+
import ClicksSlider from '../internals/ClicksSlider.vue'
|
|
24
|
+
import { useNav } from '../composables/useNav'
|
|
25
|
+
import { useDrawings } from '../composables/useDrawings'
|
|
24
26
|
|
|
25
27
|
const main = ref<HTMLDivElement>()
|
|
26
28
|
|
|
27
29
|
registerShortcuts()
|
|
28
30
|
useSwipeControls(main)
|
|
29
31
|
|
|
32
|
+
const {
|
|
33
|
+
clicksContext,
|
|
34
|
+
currentSlideNo,
|
|
35
|
+
currentSlideRoute,
|
|
36
|
+
hasNext,
|
|
37
|
+
nextRoute,
|
|
38
|
+
slides,
|
|
39
|
+
queryClicks,
|
|
40
|
+
getPrimaryClicks,
|
|
41
|
+
total,
|
|
42
|
+
} = useNav()
|
|
43
|
+
const { isDrawing } = useDrawings()
|
|
44
|
+
|
|
30
45
|
const slideTitle = configs.titleTemplate.replace('%s', configs.title || 'Slidev')
|
|
31
46
|
useHead({
|
|
32
47
|
title: `Presenter - ${slideTitle}`,
|
|
@@ -36,25 +51,32 @@ const notesEditing = ref(false)
|
|
|
36
51
|
|
|
37
52
|
const { timer, resetTimer } = useTimer()
|
|
38
53
|
|
|
39
|
-
const clicksCtxMap =
|
|
54
|
+
const clicksCtxMap = computed(() => slides.value.map(route => createFixedClicks(route)))
|
|
40
55
|
const nextFrame = computed(() => {
|
|
41
56
|
if (clicksContext.value.current < clicksContext.value.total)
|
|
42
|
-
return [
|
|
57
|
+
return [currentSlideRoute.value!, clicksContext.value.current + 1] as const
|
|
43
58
|
else if (hasNext.value)
|
|
44
59
|
return [nextRoute.value!, 0] as const
|
|
45
60
|
else
|
|
46
61
|
return null
|
|
47
62
|
})
|
|
63
|
+
|
|
48
64
|
const nextFrameClicksCtx = computed(() => {
|
|
49
|
-
return nextFrame.value && clicksCtxMap[
|
|
65
|
+
return nextFrame.value && clicksCtxMap.value[nextFrame.value[0].no - 1]
|
|
50
66
|
})
|
|
51
|
-
watch([currentRoute, queryClicks], () => {
|
|
52
|
-
nextFrameClicksCtx.value && (nextFrameClicksCtx.value[0].value = nextFrame.value![1])
|
|
53
|
-
}, { immediate: true })
|
|
54
67
|
|
|
55
|
-
|
|
68
|
+
watch(
|
|
69
|
+
[currentSlideRoute, queryClicks],
|
|
70
|
+
() => {
|
|
71
|
+
if (nextFrameClicksCtx.value)
|
|
72
|
+
nextFrameClicksCtx.value.current = nextFrame.value![1]
|
|
73
|
+
},
|
|
74
|
+
{ immediate: true },
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
const SideEditor = shallowRef<any>()
|
|
56
78
|
if (__DEV__ && __SLIDEV_FEATURE_EDITOR__)
|
|
57
|
-
import('
|
|
79
|
+
import('../internals/SideEditor.vue').then(v => SideEditor.value = v.default)
|
|
58
80
|
|
|
59
81
|
// sync presenter cursor
|
|
60
82
|
onMounted(() => {
|
|
@@ -86,68 +108,64 @@ onMounted(() => {
|
|
|
86
108
|
<template>
|
|
87
109
|
<div class="bg-main h-full slidev-presenter">
|
|
88
110
|
<div class="grid-container" :class="`layout${presenterLayout}`">
|
|
89
|
-
<div class="grid-section
|
|
90
|
-
<img src="../assets/logo-title-horizontal.png" class="ml-2 my-auto h-10 py-1 lg:h-14 lg:py-2" style="height: 3.5rem;" alt="Slidev logo">
|
|
91
|
-
<div class="flex-auto" />
|
|
92
|
-
<div
|
|
93
|
-
class="timer-btn my-auto relative w-22px h-22px cursor-pointer text-lg"
|
|
94
|
-
opacity="50 hover:100"
|
|
95
|
-
@click="resetTimer"
|
|
96
|
-
>
|
|
97
|
-
<carbon:time class="absolute" />
|
|
98
|
-
<carbon:renew class="absolute opacity-0" />
|
|
99
|
-
</div>
|
|
100
|
-
<div class="text-2xl pl-2 pr-6 my-auto tabular-nums">
|
|
101
|
-
{{ timer }}
|
|
102
|
-
</div>
|
|
103
|
-
</div>
|
|
104
|
-
<div ref="main" class="relative grid-section main flex flex-col p-2 lg:p-4" :style="themeVars">
|
|
111
|
+
<div ref="main" class="relative grid-section main flex flex-col">
|
|
105
112
|
<SlideContainer
|
|
106
113
|
key="main"
|
|
107
|
-
class="h-full w-full"
|
|
114
|
+
class="h-full w-full p-2 lg:p-4 flex-auto"
|
|
108
115
|
>
|
|
109
116
|
<template #default>
|
|
110
117
|
<SlidesShow render-context="presenter" />
|
|
111
118
|
</template>
|
|
112
119
|
</SlideContainer>
|
|
113
|
-
<
|
|
114
|
-
|
|
120
|
+
<ClicksSlider
|
|
121
|
+
:key="currentSlideRoute?.no"
|
|
122
|
+
:clicks-context="getPrimaryClicks(currentSlideRoute)"
|
|
123
|
+
class="w-full pb2 px4 flex-none"
|
|
124
|
+
/>
|
|
125
|
+
<div class="absolute left-0 top-0 bg-main border-b border-r border-main px2 py1 op50 text-sm">
|
|
126
|
+
Current
|
|
115
127
|
</div>
|
|
116
128
|
</div>
|
|
117
|
-
<div class="relative grid-section next flex flex-col p-2 lg:p-4"
|
|
129
|
+
<div class="relative grid-section next flex flex-col p-2 lg:p-4">
|
|
118
130
|
<SlideContainer
|
|
119
131
|
v-if="nextFrame && nextFrameClicksCtx"
|
|
120
132
|
key="next"
|
|
121
133
|
class="h-full w-full"
|
|
122
134
|
>
|
|
123
135
|
<SlideWrapper
|
|
124
|
-
:is="nextFrame[0].component
|
|
125
|
-
:key="nextFrame[0].
|
|
126
|
-
:clicks-context="nextFrameClicksCtx
|
|
136
|
+
:is="nextFrame[0].component!"
|
|
137
|
+
:key="nextFrame[0].no"
|
|
138
|
+
:clicks-context="nextFrameClicksCtx"
|
|
127
139
|
:class="getSlideClass(nextFrame[0])"
|
|
128
140
|
:route="nextFrame[0]"
|
|
129
141
|
render-context="previewNext"
|
|
130
142
|
/>
|
|
131
143
|
</SlideContainer>
|
|
132
|
-
<div class="
|
|
133
|
-
|
|
144
|
+
<div class="absolute left-0 top-0 bg-main border-b border-r border-main px2 py1 op50 text-sm">
|
|
145
|
+
Next
|
|
134
146
|
</div>
|
|
135
147
|
</div>
|
|
136
148
|
<!-- Notes -->
|
|
137
|
-
<div v-if="__DEV__ && __SLIDEV_FEATURE_EDITOR__ &&
|
|
138
|
-
<
|
|
149
|
+
<div v-if="__DEV__ && __SLIDEV_FEATURE_EDITOR__ && SideEditor && showEditor" class="grid-section note of-auto">
|
|
150
|
+
<SideEditor />
|
|
139
151
|
</div>
|
|
140
152
|
<div v-else class="grid-section note grid grid-rows-[1fr_min-content] overflow-hidden">
|
|
141
|
-
<
|
|
153
|
+
<NoteEditable
|
|
142
154
|
v-if="__DEV__"
|
|
155
|
+
:key="`edit-${currentSlideNo}`"
|
|
156
|
+
v-model:editing="notesEditing"
|
|
157
|
+
:no="currentSlideNo"
|
|
143
158
|
class="w-full max-w-full h-full overflow-auto p-2 lg:p-4"
|
|
144
|
-
:
|
|
159
|
+
:clicks-context="clicksContext"
|
|
145
160
|
:style="{ fontSize: `${presenterNotesFontSize}em` }"
|
|
146
161
|
/>
|
|
147
162
|
<NoteStatic
|
|
148
163
|
v-else
|
|
164
|
+
:key="`static-${currentSlideNo}`"
|
|
165
|
+
:no="currentSlideNo"
|
|
149
166
|
class="w-full max-w-full h-full overflow-auto p-2 lg:p-4"
|
|
150
167
|
:style="{ fontSize: `${presenterNotesFontSize}em` }"
|
|
168
|
+
:clicks-context="clicksContext"
|
|
151
169
|
/>
|
|
152
170
|
<div class="border-t border-main py-1 px-2 text-sm">
|
|
153
171
|
<IconButton title="Increase font size" @click="increasePresenterFontSize">
|
|
@@ -165,116 +183,120 @@ onMounted(() => {
|
|
|
165
183
|
</IconButton>
|
|
166
184
|
</div>
|
|
167
185
|
</div>
|
|
168
|
-
<div class="grid-section bottom">
|
|
186
|
+
<div class="grid-section bottom flex">
|
|
169
187
|
<NavControls :persist="true" />
|
|
188
|
+
<div flex-auto />
|
|
189
|
+
<div
|
|
190
|
+
class="timer-btn my-auto relative w-22px h-22px cursor-pointer text-lg"
|
|
191
|
+
opacity="50 hover:100"
|
|
192
|
+
@click="resetTimer"
|
|
193
|
+
>
|
|
194
|
+
<carbon:time class="absolute" />
|
|
195
|
+
<carbon:renew class="absolute opacity-0" />
|
|
196
|
+
</div>
|
|
197
|
+
<div class="text-2xl pl-2 pr-6 my-auto tabular-nums">
|
|
198
|
+
{{ timer }}
|
|
199
|
+
</div>
|
|
170
200
|
</div>
|
|
171
201
|
<DrawingControls v-if="__SLIDEV_FEATURE_DRAWINGS__" />
|
|
172
202
|
</div>
|
|
173
203
|
<div class="progress-bar">
|
|
174
204
|
<div
|
|
175
|
-
class="progress h-
|
|
176
|
-
:style="{ width: `${(
|
|
205
|
+
class="progress h-3px bg-primary transition-all"
|
|
206
|
+
:style="{ width: `${(currentSlideNo - 1) / (total - 1) * 100}%` }"
|
|
177
207
|
/>
|
|
178
208
|
</div>
|
|
179
209
|
</div>
|
|
180
210
|
<Goto />
|
|
181
|
-
<
|
|
211
|
+
<QuickOverview v-model="showOverview" />
|
|
182
212
|
</template>
|
|
183
213
|
|
|
184
|
-
<style
|
|
214
|
+
<style scoped>
|
|
185
215
|
.slidev-presenter {
|
|
186
216
|
--slidev-controls-foreground: current;
|
|
187
217
|
}
|
|
188
218
|
|
|
189
|
-
.timer-btn:hover {
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
@apply opacity-100;
|
|
195
|
-
}
|
|
219
|
+
.timer-btn:hover > :first-child {
|
|
220
|
+
opacity: 0;
|
|
221
|
+
}
|
|
222
|
+
.timer-btn:hover > :last-child {
|
|
223
|
+
opacity: 1;
|
|
196
224
|
}
|
|
197
225
|
|
|
198
226
|
.section-title {
|
|
199
|
-
|
|
227
|
+
--uno: px-4 py-2 text-xl;
|
|
200
228
|
}
|
|
201
229
|
|
|
202
230
|
.grid-container {
|
|
203
|
-
|
|
231
|
+
--uno: bg-gray/20;
|
|
232
|
+
height: 100%;
|
|
233
|
+
width: 100%;
|
|
204
234
|
display: grid;
|
|
205
235
|
gap: 1px 1px;
|
|
206
236
|
}
|
|
207
237
|
|
|
208
238
|
.grid-container.layout1 {
|
|
209
239
|
grid-template-columns: 1fr 1fr;
|
|
210
|
-
grid-template-rows:
|
|
240
|
+
grid-template-rows: 2fr 1fr min-content;
|
|
211
241
|
grid-template-areas:
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
"bottom bottom";
|
|
242
|
+
'main main'
|
|
243
|
+
'note next'
|
|
244
|
+
'bottom bottom';
|
|
216
245
|
}
|
|
217
246
|
|
|
218
247
|
.grid-container.layout2 {
|
|
219
248
|
grid-template-columns: 3fr 2fr;
|
|
220
|
-
grid-template-rows:
|
|
249
|
+
grid-template-rows: 2fr 1fr min-content;
|
|
221
250
|
grid-template-areas:
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
"bottom bottom";
|
|
251
|
+
'note main'
|
|
252
|
+
'note next'
|
|
253
|
+
'bottom bottom';
|
|
226
254
|
}
|
|
227
255
|
|
|
228
256
|
@media (max-aspect-ratio: 3/5) {
|
|
229
257
|
.grid-container.layout1 {
|
|
230
258
|
grid-template-columns: 1fr;
|
|
231
|
-
grid-template-rows:
|
|
259
|
+
grid-template-rows: 1fr 1fr 1fr min-content;
|
|
232
260
|
grid-template-areas:
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
"bottom";
|
|
261
|
+
'main'
|
|
262
|
+
'note'
|
|
263
|
+
'next'
|
|
264
|
+
'bottom';
|
|
238
265
|
}
|
|
239
266
|
}
|
|
240
267
|
|
|
241
268
|
@media (min-aspect-ratio: 1/1) {
|
|
242
269
|
.grid-container.layout1 {
|
|
243
270
|
grid-template-columns: 1fr 1.1fr 0.9fr;
|
|
244
|
-
grid-template-rows:
|
|
271
|
+
grid-template-rows: 1fr 2fr min-content;
|
|
245
272
|
grid-template-areas:
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
"bottom bottom bottom";
|
|
273
|
+
'main main next'
|
|
274
|
+
'main main note'
|
|
275
|
+
'bottom bottom bottom';
|
|
250
276
|
}
|
|
251
277
|
}
|
|
252
278
|
|
|
253
279
|
.progress-bar {
|
|
254
|
-
|
|
280
|
+
--uno: fixed left-0 right-0 top-0;
|
|
255
281
|
}
|
|
256
282
|
|
|
257
283
|
.grid-section {
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
&.top {
|
|
261
|
-
grid-area: top;
|
|
262
|
-
}
|
|
263
|
-
&.main {
|
|
264
|
-
grid-area: main;
|
|
265
|
-
}
|
|
266
|
-
&.next {
|
|
267
|
-
grid-area: next;
|
|
268
|
-
}
|
|
269
|
-
&.note {
|
|
270
|
-
grid-area: note;
|
|
271
|
-
}
|
|
272
|
-
&.bottom {
|
|
273
|
-
grid-area: bottom;
|
|
274
|
-
}
|
|
284
|
+
--uno: bg-main;
|
|
275
285
|
}
|
|
276
286
|
|
|
277
|
-
.
|
|
278
|
-
|
|
287
|
+
.grid-section.top {
|
|
288
|
+
grid-area: top;
|
|
289
|
+
}
|
|
290
|
+
.grid-section.main {
|
|
291
|
+
grid-area: main;
|
|
292
|
+
}
|
|
293
|
+
.grid-section.next {
|
|
294
|
+
grid-area: next;
|
|
295
|
+
}
|
|
296
|
+
.grid-section.note {
|
|
297
|
+
grid-area: note;
|
|
298
|
+
}
|
|
299
|
+
.grid-section.bottom {
|
|
300
|
+
grid-area: bottom;
|
|
279
301
|
}
|
|
280
|
-
</style
|
|
302
|
+
</style>../composables/drawings
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { watchEffect } from 'vue'
|
|
3
3
|
import { windowSize } from '../state'
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
import
|
|
7
|
-
|
|
4
|
+
import PrintContainer from '../internals/PrintContainer.vue'
|
|
5
|
+
import PrintStyle from '../internals/PrintStyle.vue'
|
|
6
|
+
import { useNav } from '../composables/useNav'
|
|
7
|
+
|
|
8
|
+
const { isPrintMode } = useNav()
|
|
8
9
|
|
|
9
10
|
watchEffect(() => {
|
|
10
11
|
if (isPrintMode)
|
|
@@ -16,7 +17,7 @@ watchEffect(() => {
|
|
|
16
17
|
|
|
17
18
|
<template>
|
|
18
19
|
<PrintStyle v-if="isPrintMode" />
|
|
19
|
-
<div id="page-root" class="grid grid-cols-[1fr_max-content]"
|
|
20
|
+
<div id="page-root" class="grid grid-cols-[1fr_max-content]">
|
|
20
21
|
<PrintContainer
|
|
21
22
|
class="w-full h-full"
|
|
22
23
|
:style="{ background: 'var(--slidev-slide-container-background, black)' }"
|
package/routes.ts
CHANGED
|
@@ -1,63 +1,58 @@
|
|
|
1
1
|
import type { RouteLocationNormalized, RouteRecordRaw } from 'vue-router'
|
|
2
|
-
import
|
|
3
|
-
import type { TransitionGroupProps } from 'vue'
|
|
4
|
-
import type { ClicksContext, SlideInfo } from '@slidev/types'
|
|
5
|
-
|
|
6
|
-
// @ts-expect-error missing types
|
|
7
|
-
import _rawRoutes, { redirects } from '/@slidev/routes'
|
|
8
|
-
|
|
9
|
-
// @ts-expect-error missing types
|
|
10
|
-
import _configs from '/@slidev/configs'
|
|
11
|
-
|
|
12
|
-
export const rawRoutes = _rawRoutes as RouteRecordRaw[]
|
|
2
|
+
import configs from '#slidev/configs'
|
|
13
3
|
|
|
14
4
|
export const routes: RouteRecordRaw[] = [
|
|
15
5
|
{
|
|
16
|
-
name: '
|
|
17
|
-
path: '/',
|
|
18
|
-
component: () => import('./
|
|
19
|
-
children: [
|
|
20
|
-
...rawRoutes,
|
|
21
|
-
...redirects,
|
|
22
|
-
],
|
|
6
|
+
name: 'print',
|
|
7
|
+
path: '/print',
|
|
8
|
+
component: () => import('./pages/print.vue'),
|
|
23
9
|
},
|
|
24
|
-
|
|
10
|
+
|
|
11
|
+
// Redirects
|
|
25
12
|
{ path: '', redirect: { path: '/1' } },
|
|
26
|
-
{ path: '/:pathMatch(.*)', redirect: { path: '/1' } },
|
|
27
13
|
]
|
|
28
14
|
|
|
29
15
|
if (__SLIDEV_FEATURE_PRESENTER__) {
|
|
30
16
|
function passwordGuard(to: RouteLocationNormalized) {
|
|
31
|
-
if (!
|
|
17
|
+
if (!configs.remote || configs.remote === to.query.password)
|
|
32
18
|
return true
|
|
33
|
-
if (
|
|
19
|
+
if (configs.remote && to.query.password === undefined) {
|
|
34
20
|
// eslint-disable-next-line no-alert
|
|
35
21
|
const password = prompt('Enter password')
|
|
36
|
-
if (
|
|
22
|
+
if (configs.remote === password)
|
|
37
23
|
return true
|
|
38
24
|
}
|
|
39
25
|
if (to.params.no)
|
|
40
26
|
return { path: `/${to.params.no}` }
|
|
41
27
|
return { path: '' }
|
|
42
28
|
}
|
|
43
|
-
|
|
29
|
+
|
|
30
|
+
routes.push({
|
|
31
|
+
path: '/presenter/print',
|
|
32
|
+
component: () => import('./pages/presenter/print.vue'),
|
|
33
|
+
})
|
|
44
34
|
if (__SLIDEV_HAS_SERVER__) {
|
|
45
35
|
routes.push({
|
|
46
36
|
name: 'entry',
|
|
47
37
|
path: '/entry',
|
|
48
|
-
component: () => import('./
|
|
38
|
+
component: () => import('./pages/entry.vue'),
|
|
39
|
+
})
|
|
40
|
+
routes.push({
|
|
41
|
+
name: 'overview',
|
|
42
|
+
path: '/overview',
|
|
43
|
+
component: () => import('./pages/overview.vue'),
|
|
49
44
|
})
|
|
50
45
|
routes.push({
|
|
51
46
|
name: 'notes',
|
|
52
47
|
path: '/notes',
|
|
53
|
-
component: () => import('./
|
|
48
|
+
component: () => import('./pages/notes.vue'),
|
|
54
49
|
beforeEnter: passwordGuard,
|
|
55
50
|
})
|
|
56
51
|
}
|
|
57
52
|
routes.push({
|
|
58
53
|
name: 'presenter',
|
|
59
54
|
path: '/presenter/:no',
|
|
60
|
-
component: () => import('./
|
|
55
|
+
component: () => import('./pages/presenter.vue'),
|
|
61
56
|
beforeEnter: passwordGuard,
|
|
62
57
|
})
|
|
63
58
|
routes.push({
|
|
@@ -66,34 +61,8 @@ if (__SLIDEV_FEATURE_PRESENTER__) {
|
|
|
66
61
|
})
|
|
67
62
|
}
|
|
68
63
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
routes,
|
|
64
|
+
routes.push({
|
|
65
|
+
name: 'play',
|
|
66
|
+
path: '/:no',
|
|
67
|
+
component: () => import('./pages/play.vue'),
|
|
74
68
|
})
|
|
75
|
-
|
|
76
|
-
declare module 'vue-router' {
|
|
77
|
-
interface RouteMeta {
|
|
78
|
-
// inherited from frontmatter
|
|
79
|
-
layout: string
|
|
80
|
-
name?: string
|
|
81
|
-
class?: string
|
|
82
|
-
clicks?: number
|
|
83
|
-
transition?: string | TransitionGroupProps | undefined
|
|
84
|
-
preload?: boolean
|
|
85
|
-
|
|
86
|
-
// slide info
|
|
87
|
-
slide?: Omit<SlideInfo, 'source'> & {
|
|
88
|
-
noteHTML: string
|
|
89
|
-
filepath: string
|
|
90
|
-
start: number
|
|
91
|
-
id: number
|
|
92
|
-
no: number
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
// private fields
|
|
96
|
-
__clicksContext: null | ClicksContext
|
|
97
|
-
__preloaded?: boolean
|
|
98
|
-
}
|
|
99
|
-
}
|