@slidev/client 0.48.0-beta.8 → 0.48.0-beta.9
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/internals/DrawingControls.vue +1 -2
- package/internals/Editor.vue +2 -2
- package/internals/IconButton.vue +4 -1
- package/internals/NavControls.vue +1 -1
- package/internals/NoteDisplay.vue +1 -1
- package/internals/NoteEditor.vue +9 -5
- package/internals/NoteStatic.vue +5 -6
- package/internals/RecordingDialog.vue +2 -3
- package/internals/SlidesOverview.vue +16 -6
- package/package.json +3 -3
- package/{internals/EntrySelect.vue → pages/entry.vue} +7 -0
- package/{internals/NotesView.vue → pages/notes.vue} +3 -3
- package/pages/overview.vue +144 -0
- package/{internals/Play.vue → pages/play.vue} +7 -7
- package/{internals/PresenterPrint.vue → pages/presenter/print.vue} +7 -5
- package/{internals/Presenter.vue → pages/presenter.vue} +16 -12
- package/{internals/Print.vue → pages/print.vue} +2 -2
- package/routes.ts +21 -6
- package/styles/layouts-base.css +6 -4
- package/styles/vars.css +1 -0
- package/uno.config.ts +4 -1
|
@@ -40,8 +40,7 @@ function setBrushColor(color: typeof brush.color) {
|
|
|
40
40
|
|
|
41
41
|
<template>
|
|
42
42
|
<Draggable
|
|
43
|
-
class="flex flex-wrap text-xl p-2 gap-1 rounded-md bg-main shadow transition-opacity duration-200 z-20"
|
|
44
|
-
dark="border border-gray-400 border-opacity-10"
|
|
43
|
+
class="flex flex-wrap text-xl p-2 gap-1 rounded-md bg-main shadow transition-opacity duration-200 z-20 border border-main"
|
|
45
44
|
:class="drawingEnabled ? '' : drawingPinned ? 'opacity-40 hover:opacity-90' : 'opacity-0 pointer-events-none'"
|
|
46
45
|
storage-key="slidev-drawing-pos"
|
|
47
46
|
:initial-x="10"
|
package/internals/Editor.vue
CHANGED
|
@@ -172,13 +172,13 @@ throttledWatch(
|
|
|
172
172
|
<div class="flex pb-2 text-xl -mt-1">
|
|
173
173
|
<div class="mr-4 rounded flex">
|
|
174
174
|
<IconButton
|
|
175
|
-
title="Switch to content tab" :class="tab === 'content' ? 'text
|
|
175
|
+
title="Switch to content tab" :class="tab === 'content' ? 'text-primary' : ''"
|
|
176
176
|
@click="switchTab('content')"
|
|
177
177
|
>
|
|
178
178
|
<carbon:account />
|
|
179
179
|
</IconButton>
|
|
180
180
|
<IconButton
|
|
181
|
-
title="Switch to notes tab" :class="tab === 'note' ? 'text
|
|
181
|
+
title="Switch to notes tab" :class="tab === 'note' ? 'text-primary' : ''"
|
|
182
182
|
@click="switchTab('note')"
|
|
183
183
|
>
|
|
184
184
|
<carbon:align-box-bottom-right />
|
package/internals/IconButton.vue
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
defineProps<{
|
|
3
3
|
title: string
|
|
4
|
+
icon?: string
|
|
4
5
|
}>()
|
|
5
6
|
</script>
|
|
6
7
|
|
|
7
8
|
<template>
|
|
8
9
|
<button class="slidev-icon-btn" :title="title" v-bind="$attrs">
|
|
9
10
|
<span class="sr-only">{{ title }}</span>
|
|
10
|
-
<slot
|
|
11
|
+
<slot>
|
|
12
|
+
<div :class="icon" />
|
|
13
|
+
</slot>
|
|
11
14
|
</button>
|
|
12
15
|
</template>
|
|
@@ -34,7 +34,7 @@ function onMouseLeave() {
|
|
|
34
34
|
|
|
35
35
|
const barStyle = computed(() => props.persist
|
|
36
36
|
? 'text-$slidev-controls-foreground bg-transparent'
|
|
37
|
-
: 'rounded-md bg-main shadow dark:border dark:border-
|
|
37
|
+
: 'rounded-md bg-main shadow dark:border dark:border-main')
|
|
38
38
|
|
|
39
39
|
const RecordingControls = shallowRef<any>()
|
|
40
40
|
if (__SLIDEV_FEATURE_RECORD__)
|
package/internals/NoteEditor.vue
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { ignorableWatch, onClickOutside, useVModel } from '@vueuse/core'
|
|
3
3
|
import { ref, watch, watchEffect } from 'vue'
|
|
4
|
-
import { currentSlideId } from '../logic/nav'
|
|
5
4
|
import { useDynamicSlideInfo } from '../logic/note'
|
|
6
5
|
import NoteDisplay from './NoteDisplay.vue'
|
|
7
6
|
|
|
8
7
|
const props = defineProps({
|
|
8
|
+
no: {
|
|
9
|
+
type: Number,
|
|
10
|
+
},
|
|
9
11
|
class: {
|
|
10
12
|
default: '',
|
|
11
13
|
},
|
|
@@ -25,7 +27,7 @@ const emit = defineEmits([
|
|
|
25
27
|
])
|
|
26
28
|
const editing = useVModel(props, 'editing', emit, { passive: true })
|
|
27
29
|
|
|
28
|
-
const { info, update } = useDynamicSlideInfo(
|
|
30
|
+
const { info, update } = useDynamicSlideInfo(props.no)
|
|
29
31
|
|
|
30
32
|
const note = ref('')
|
|
31
33
|
let timer: any
|
|
@@ -33,7 +35,7 @@ let timer: any
|
|
|
33
35
|
const { ignoreUpdates } = ignorableWatch(
|
|
34
36
|
note,
|
|
35
37
|
(v) => {
|
|
36
|
-
const id =
|
|
38
|
+
const id = props.no
|
|
37
39
|
clearTimeout(timer)
|
|
38
40
|
timer = setTimeout(() => {
|
|
39
41
|
update({ note: v }, id)
|
|
@@ -44,6 +46,8 @@ const { ignoreUpdates } = ignorableWatch(
|
|
|
44
46
|
watch(
|
|
45
47
|
info,
|
|
46
48
|
(v) => {
|
|
49
|
+
if (editing.value)
|
|
50
|
+
return
|
|
47
51
|
clearTimeout(timer)
|
|
48
52
|
ignoreUpdates(() => {
|
|
49
53
|
note.value = v?.note || ''
|
|
@@ -68,7 +72,7 @@ onClickOutside(input, () => {
|
|
|
68
72
|
<NoteDisplay
|
|
69
73
|
v-if="!editing"
|
|
70
74
|
class="my--4 border-transparent border-2"
|
|
71
|
-
:class="[props.class, note ? '' : 'opacity-
|
|
75
|
+
:class="[props.class, note ? '' : 'opacity-25 italic select-none']"
|
|
72
76
|
:style="props.style"
|
|
73
77
|
:note="note || placeholder"
|
|
74
78
|
:note-html="info?.noteHTML"
|
|
@@ -77,7 +81,7 @@ onClickOutside(input, () => {
|
|
|
77
81
|
v-else
|
|
78
82
|
ref="input"
|
|
79
83
|
v-model="note"
|
|
80
|
-
class="prose resize-none overflow-auto outline-none bg-transparent block border-
|
|
84
|
+
class="prose resize-none overflow-auto outline-none bg-transparent block border-primary border-2"
|
|
81
85
|
style="line-height: 1.75;"
|
|
82
86
|
:style="props.style"
|
|
83
87
|
:class="props.class"
|
package/internals/NoteStatic.vue
CHANGED
|
@@ -1,20 +1,19 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import {
|
|
3
|
-
import { currentRoute } from '../logic/nav'
|
|
2
|
+
import { useSlideInfo } from '../logic/note'
|
|
4
3
|
import NoteDisplay from './NoteDisplay.vue'
|
|
5
4
|
|
|
6
5
|
const props = defineProps<{
|
|
6
|
+
no?: number
|
|
7
7
|
class?: string
|
|
8
8
|
}>()
|
|
9
9
|
|
|
10
|
-
const
|
|
11
|
-
const noteHtml = computed(() => currentRoute.value?.meta?.slide?.noteHTML)
|
|
10
|
+
const { info } = useSlideInfo(props.no)
|
|
12
11
|
</script>
|
|
13
12
|
|
|
14
13
|
<template>
|
|
15
14
|
<NoteDisplay
|
|
16
15
|
:class="props.class"
|
|
17
|
-
:note="note"
|
|
18
|
-
:note-html="
|
|
16
|
+
:note="info?.note"
|
|
17
|
+
:note-html="info?.noteHTML"
|
|
19
18
|
/>
|
|
20
19
|
</template>
|
|
@@ -109,7 +109,7 @@ async function start() {
|
|
|
109
109
|
}
|
|
110
110
|
|
|
111
111
|
input[type="text"] {
|
|
112
|
-
@apply border border-
|
|
112
|
+
@apply border border-main rounded px-2 py-1;
|
|
113
113
|
}
|
|
114
114
|
|
|
115
115
|
button {
|
|
@@ -118,8 +118,7 @@ async function start() {
|
|
|
118
118
|
}
|
|
119
119
|
|
|
120
120
|
button.cancel {
|
|
121
|
-
@apply bg-gray-400 text-white px-4 py-1 rounded border-b-2 border-
|
|
122
|
-
@apply bg-opacity-50 border-opacity-50;
|
|
121
|
+
@apply bg-gray-400 bg-opacity-50 text-white px-4 py-1 rounded border-b-2 border-main;
|
|
123
122
|
@apply hover:(bg-opacity-75 border-opacity-75)
|
|
124
123
|
}
|
|
125
124
|
}
|
|
@@ -112,7 +112,7 @@ watchEffect(() => {
|
|
|
112
112
|
>
|
|
113
113
|
<div
|
|
114
114
|
v-show="value"
|
|
115
|
-
class="bg-main !bg-opacity-75 p-16 overflow-y-auto backdrop-blur-5px fixed left-0 right-0 top-0 h-[calc(var(--vh,1vh)*100)]"
|
|
115
|
+
class="bg-main !bg-opacity-75 p-16 py-20 overflow-y-auto backdrop-blur-5px fixed left-0 right-0 top-0 h-[calc(var(--vh,1vh)*100)]"
|
|
116
116
|
@click="close()"
|
|
117
117
|
>
|
|
118
118
|
<div
|
|
@@ -125,8 +125,8 @@ watchEffect(() => {
|
|
|
125
125
|
class="relative"
|
|
126
126
|
>
|
|
127
127
|
<div
|
|
128
|
-
class="inline-block border rounded
|
|
129
|
-
:class="(focus(idx + 1) || currentOverviewPage === idx + 1) ? 'border
|
|
128
|
+
class="inline-block border rounded overflow-hidden bg-main hover:border-primary transition"
|
|
129
|
+
:class="(focus(idx + 1) || currentOverviewPage === idx + 1) ? 'border-primary' : 'border-main'"
|
|
130
130
|
:style="themeVars"
|
|
131
131
|
@click="go(+route.path)"
|
|
132
132
|
>
|
|
@@ -163,7 +163,17 @@ watchEffect(() => {
|
|
|
163
163
|
</div>
|
|
164
164
|
</div>
|
|
165
165
|
</Transition>
|
|
166
|
-
<
|
|
167
|
-
<
|
|
168
|
-
|
|
166
|
+
<div class="fixed top-4 right-4 text-gray-400 flex items-center gap-4">
|
|
167
|
+
<RouterLink
|
|
168
|
+
v-if="__DEV__"
|
|
169
|
+
to="/overview"
|
|
170
|
+
tab-index="-1"
|
|
171
|
+
class="border-main border px3 py1 rounded hover:bg-gray/5 hover:text-primary"
|
|
172
|
+
>
|
|
173
|
+
List overview
|
|
174
|
+
</RouterLink>
|
|
175
|
+
<IconButton v-if="value" title="Close" class="text-2xl" @click="close">
|
|
176
|
+
<carbon:close />
|
|
177
|
+
</IconButton>
|
|
178
|
+
</div>
|
|
169
179
|
</template>
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@slidev/client",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.48.0-beta.
|
|
4
|
+
"version": "0.48.0-beta.9",
|
|
5
5
|
"description": "Presentation slides for developers",
|
|
6
6
|
"author": "antfu <anthonyfu117@hotmail.com>",
|
|
7
7
|
"license": "MIT",
|
|
@@ -54,8 +54,8 @@
|
|
|
54
54
|
"unocss": "^0.58.5",
|
|
55
55
|
"vue": "^3.4.19",
|
|
56
56
|
"vue-router": "^4.3.0",
|
|
57
|
-
"@slidev/parser": "0.48.0-beta.
|
|
58
|
-
"@slidev/types": "0.48.0-beta.
|
|
57
|
+
"@slidev/parser": "0.48.0-beta.9",
|
|
58
|
+
"@slidev/types": "0.48.0-beta.9"
|
|
59
59
|
},
|
|
60
60
|
"devDependencies": {
|
|
61
61
|
"vite": "^5.1.4"
|
|
@@ -21,5 +21,12 @@
|
|
|
21
21
|
<carbon:catalog class="text-3em op50" />
|
|
22
22
|
Notes
|
|
23
23
|
</RouterLink>
|
|
24
|
+
<RouterLink
|
|
25
|
+
to="/overview"
|
|
26
|
+
class="flex flex-col gap-2 items-center justify-center h-40 min-w-40 rounded bg-gray:10 p4 hover:bg-gray/20"
|
|
27
|
+
>
|
|
28
|
+
<carbon:list-boxes class="text-3em op50" />
|
|
29
|
+
Overview
|
|
30
|
+
</RouterLink>
|
|
24
31
|
</div>
|
|
25
32
|
</template>
|
|
@@ -7,8 +7,8 @@ import { sharedState } from '../state/shared'
|
|
|
7
7
|
import { fullscreen } from '../state'
|
|
8
8
|
import { total } from '../logic/nav'
|
|
9
9
|
import { rawRoutes } from '../routes'
|
|
10
|
-
import NoteDisplay from '
|
|
11
|
-
import IconButton from '
|
|
10
|
+
import NoteDisplay from '../internals/NoteDisplay.vue'
|
|
11
|
+
import IconButton from '../internals/IconButton.vue'
|
|
12
12
|
|
|
13
13
|
const slideTitle = configs.titleTemplate.replace('%s', configs.title || 'Slidev')
|
|
14
14
|
useHead({
|
|
@@ -53,7 +53,7 @@ function decreaseFontSize() {
|
|
|
53
53
|
:placeholder="`No notes for Slide ${pageNo}.`"
|
|
54
54
|
/>
|
|
55
55
|
</div>
|
|
56
|
-
<div class="flex-none border-t border-
|
|
56
|
+
<div class="flex-none border-t border-main">
|
|
57
57
|
<div class="flex gap-1 items-center px-6 py-3">
|
|
58
58
|
<IconButton :title="isFullscreen ? 'Close fullscreen' : 'Enter fullscreen'" @click="toggleFullscreen">
|
|
59
59
|
<carbon:minimize v-if="isFullscreen" />
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { nextTick, onMounted, reactive, ref } from 'vue'
|
|
3
|
+
import { themeVars } from '../env'
|
|
4
|
+
import { rawRoutes } from '../logic/nav'
|
|
5
|
+
import { useFixedClicks } from '../composables/useClicks'
|
|
6
|
+
import { isColorSchemaConfigured, isDark, toggleDark } from '../logic/dark'
|
|
7
|
+
import { getSlideClass } from '../utils'
|
|
8
|
+
import SlideContainer from '../internals/SlideContainer.vue'
|
|
9
|
+
import SlideWrapper from '../internals/SlideWrapper'
|
|
10
|
+
import DrawingPreview from '../internals/DrawingPreview.vue'
|
|
11
|
+
import IconButton from '../internals/IconButton.vue'
|
|
12
|
+
import NoteEditor from '../internals/NoteEditor.vue'
|
|
13
|
+
|
|
14
|
+
const cardWidth = 450
|
|
15
|
+
|
|
16
|
+
const blocks: Map<number, HTMLElement> = reactive(new Map())
|
|
17
|
+
const activeBlocks = ref<number[]>([])
|
|
18
|
+
const edittingNote = ref<string | null>(null)
|
|
19
|
+
|
|
20
|
+
function isElementInViewport(el: HTMLElement) {
|
|
21
|
+
const rect = el.getBoundingClientRect()
|
|
22
|
+
const delta = 20
|
|
23
|
+
return (
|
|
24
|
+
rect.top >= 0 - delta
|
|
25
|
+
&& rect.left >= 0 - delta
|
|
26
|
+
&& rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) + delta
|
|
27
|
+
&& rect.right <= (window.innerWidth || document.documentElement.clientWidth) + delta
|
|
28
|
+
)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function checkActiveBlocks() {
|
|
32
|
+
const active: number[] = []
|
|
33
|
+
Array.from(blocks.entries())
|
|
34
|
+
.forEach(([idx, el]) => {
|
|
35
|
+
if (isElementInViewport(el))
|
|
36
|
+
active.push(idx)
|
|
37
|
+
})
|
|
38
|
+
activeBlocks.value = active
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function openSlideInNewTab(path: string) {
|
|
42
|
+
const a = document.createElement('a')
|
|
43
|
+
a.target = '_blank'
|
|
44
|
+
a.href = path
|
|
45
|
+
a.click()
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function scrollToSlide(idx: number) {
|
|
49
|
+
const el = blocks.get(idx)
|
|
50
|
+
if (el)
|
|
51
|
+
el.scrollIntoView({ behavior: 'smooth', block: 'start' })
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
onMounted(() => {
|
|
55
|
+
nextTick(() => {
|
|
56
|
+
checkActiveBlocks()
|
|
57
|
+
})
|
|
58
|
+
})
|
|
59
|
+
</script>
|
|
60
|
+
|
|
61
|
+
<template>
|
|
62
|
+
<div class="h-screen w-screen of-hidden flex">
|
|
63
|
+
<nav class="h-full flex flex-col border-r border-main p2 select-none">
|
|
64
|
+
<div class="of-auto flex flex-col flex-auto items-center">
|
|
65
|
+
<button
|
|
66
|
+
v-for="(route, idx) of rawRoutes"
|
|
67
|
+
:key="route.path"
|
|
68
|
+
class="relative transition duration-300 w-8 h-8 rounded hover:bg-gray:10 hover:op100"
|
|
69
|
+
:class="[
|
|
70
|
+
activeBlocks.includes(idx) ? 'op100 text-primary' : 'op20',
|
|
71
|
+
]"
|
|
72
|
+
@click="scrollToSlide(idx)"
|
|
73
|
+
>
|
|
74
|
+
<div>{{ idx + 1 }}</div>
|
|
75
|
+
</button>
|
|
76
|
+
</div>
|
|
77
|
+
<IconButton
|
|
78
|
+
v-if="!isColorSchemaConfigured"
|
|
79
|
+
:title="isDark ? 'Switch to light mode theme' : 'Switch to dark mode theme'"
|
|
80
|
+
@click="toggleDark()"
|
|
81
|
+
>
|
|
82
|
+
<carbon-moon v-if="isDark" />
|
|
83
|
+
<carbon-sun v-else />
|
|
84
|
+
</IconButton>
|
|
85
|
+
</nav>
|
|
86
|
+
<main
|
|
87
|
+
class="flex-1 h-full of-auto"
|
|
88
|
+
:style="`grid-template-columns: repeat(auto-fit,minmax(${cardWidth}px,1fr))`"
|
|
89
|
+
@scroll="checkActiveBlocks"
|
|
90
|
+
>
|
|
91
|
+
<div class="px4 py2 text-orange bg-orange:5 select-none">
|
|
92
|
+
<span font-bold>List Overview</span> is in beta, feedback is welcome!
|
|
93
|
+
</div>
|
|
94
|
+
<div
|
|
95
|
+
v-for="(route, idx) of rawRoutes"
|
|
96
|
+
:key="route.path"
|
|
97
|
+
:ref="el => blocks.set(idx, el)"
|
|
98
|
+
class="relative border-t border-main of-hidden flex gap-4 min-h-50 group"
|
|
99
|
+
>
|
|
100
|
+
<div class="select-none text-3xl op20 w-13 my4 text-right">
|
|
101
|
+
{{ idx + 1 }}
|
|
102
|
+
</div>
|
|
103
|
+
<div
|
|
104
|
+
class="border rounded border-main overflow-hidden bg-main my5 select-none"
|
|
105
|
+
:style="themeVars"
|
|
106
|
+
@dblclick="openSlideInNewTab(route.path)"
|
|
107
|
+
>
|
|
108
|
+
<SlideContainer
|
|
109
|
+
:key="route.path"
|
|
110
|
+
:width="cardWidth"
|
|
111
|
+
:clicks-disabled="true"
|
|
112
|
+
class="pointer-events-none important:[&_*]:select-none"
|
|
113
|
+
>
|
|
114
|
+
<SlideWrapper
|
|
115
|
+
:is="route.component"
|
|
116
|
+
v-if="route?.component"
|
|
117
|
+
:clicks-context="useFixedClicks(route, 99999)[1]"
|
|
118
|
+
:class="getSlideClass(route)"
|
|
119
|
+
:route="route"
|
|
120
|
+
render-context="overview"
|
|
121
|
+
/>
|
|
122
|
+
<DrawingPreview :page="+route.path" />
|
|
123
|
+
</SlideContainer>
|
|
124
|
+
</div>
|
|
125
|
+
<div class="py3 mt-0.5 mr--8 ml--4 op0 transition group-hover:op100">
|
|
126
|
+
<IconButton
|
|
127
|
+
title="Edit Note"
|
|
128
|
+
class="rounded-full w-9 h-9 text-sm"
|
|
129
|
+
:class="edittingNote === idx ? 'important:op0' : ''"
|
|
130
|
+
@click="edittingNote = idx"
|
|
131
|
+
>
|
|
132
|
+
<carbon:pen />
|
|
133
|
+
</IconButton>
|
|
134
|
+
</div>
|
|
135
|
+
<NoteEditor
|
|
136
|
+
:no="idx"
|
|
137
|
+
class="max-w-250 w-250 text-lg rounded p3"
|
|
138
|
+
:editing="edittingNote === idx"
|
|
139
|
+
@update:editing="edittingNote = null"
|
|
140
|
+
/>
|
|
141
|
+
</div>
|
|
142
|
+
</main>
|
|
143
|
+
</div>
|
|
144
|
+
</template>
|
|
@@ -5,11 +5,11 @@ import { isEmbedded, isPrintMode, next, prev, useSwipeControls } from '../logic/
|
|
|
5
5
|
import { isDrawing } from '../logic/drawings'
|
|
6
6
|
import { registerShortcuts } from '../logic/shortcuts'
|
|
7
7
|
import { configs, themeVars } from '../env'
|
|
8
|
-
import Controls from '
|
|
9
|
-
import SlideContainer from '
|
|
10
|
-
import NavControls from '
|
|
11
|
-
import SlidesShow from '
|
|
12
|
-
import PrintStyle from '
|
|
8
|
+
import Controls from '../internals/Controls.vue'
|
|
9
|
+
import SlideContainer from '../internals/SlideContainer.vue'
|
|
10
|
+
import NavControls from '../internals/NavControls.vue'
|
|
11
|
+
import SlidesShow from '../internals/SlidesShow.vue'
|
|
12
|
+
import PrintStyle from '../internals/PrintStyle.vue'
|
|
13
13
|
|
|
14
14
|
registerShortcuts()
|
|
15
15
|
|
|
@@ -33,11 +33,11 @@ const persistNav = computed(() => isScreenVertical.value || showEditor.value)
|
|
|
33
33
|
|
|
34
34
|
const Editor = shallowRef<any>()
|
|
35
35
|
if (__DEV__ && __SLIDEV_FEATURE_EDITOR__)
|
|
36
|
-
import('
|
|
36
|
+
import('../internals/Editor.vue').then(v => Editor.value = v.default)
|
|
37
37
|
|
|
38
38
|
const DrawingControls = shallowRef<any>()
|
|
39
39
|
if (__SLIDEV_FEATURE_DRAWINGS__)
|
|
40
|
-
import('
|
|
40
|
+
import('../internals/DrawingControls.vue').then(v => DrawingControls.value = v.default)
|
|
41
41
|
</script>
|
|
42
42
|
|
|
43
43
|
<template>
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
import { computed } from 'vue'
|
|
3
3
|
import { useStyleTag } from '@vueuse/core'
|
|
4
4
|
import { useHead } from '@unhead/vue'
|
|
5
|
-
import { configs, themeVars } from '
|
|
6
|
-
import { rawRoutes, total } from '
|
|
7
|
-
import NoteDisplay from '
|
|
5
|
+
import { configs, themeVars } from '../../env'
|
|
6
|
+
import { rawRoutes, total } from '../../logic/nav'
|
|
7
|
+
import NoteDisplay from '../../internals/NoteDisplay.vue'
|
|
8
8
|
|
|
9
9
|
useStyleTag(`
|
|
10
10
|
@page {
|
|
@@ -24,7 +24,9 @@ html #page-root {
|
|
|
24
24
|
}
|
|
25
25
|
`)
|
|
26
26
|
|
|
27
|
-
useHead({
|
|
27
|
+
useHead({
|
|
28
|
+
title: `Notes - ${configs.title}`,
|
|
29
|
+
})
|
|
28
30
|
|
|
29
31
|
const slidesWithNote = computed(() => rawRoutes
|
|
30
32
|
.map(route => route.meta?.slide)
|
|
@@ -56,7 +58,7 @@ const slidesWithNote = computed(() => rawRoutes
|
|
|
56
58
|
</h2>
|
|
57
59
|
<NoteDisplay :note-html="slide!.noteHTML" class="max-w-full" />
|
|
58
60
|
</div>
|
|
59
|
-
<hr v-if="index < slidesWithNote.length - 1" class="border-
|
|
61
|
+
<hr v-if="index < slidesWithNote.length - 1" class="border-main mb-8">
|
|
60
62
|
</div>
|
|
61
63
|
</div>
|
|
62
64
|
</div>
|
|
@@ -2,7 +2,7 @@
|
|
|
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 { clicksContext, currentPage, currentRoute, hasNext, nextRoute, queryClicks, rawRoutes, total, useSwipeControls } from '../logic/nav'
|
|
5
|
+
import { clicksContext, currentPage, currentRoute, currentSlideId, hasNext, nextRoute, queryClicks, rawRoutes, total, useSwipeControls } from '../logic/nav'
|
|
6
6
|
import { decreasePresenterFontSize, increasePresenterFontSize, presenterLayout, presenterNotesFontSize, showEditor, showOverview, showPresenterCursor } from '../state'
|
|
7
7
|
import { configs, themeVars } from '../env'
|
|
8
8
|
import { sharedState } from '../state/shared'
|
|
@@ -11,16 +11,16 @@ import { getSlideClass } from '../utils'
|
|
|
11
11
|
import { useTimer } from '../logic/utils'
|
|
12
12
|
import { isDrawing } from '../logic/drawings'
|
|
13
13
|
import { useFixedClicks } from '../composables/useClicks'
|
|
14
|
-
import
|
|
15
|
-
import
|
|
16
|
-
import
|
|
17
|
-
import
|
|
18
|
-
import
|
|
19
|
-
import
|
|
20
|
-
import
|
|
21
|
-
import
|
|
22
|
-
import DrawingControls from '
|
|
23
|
-
import IconButton from '
|
|
14
|
+
import SlideWrapper from '../internals/SlideWrapper'
|
|
15
|
+
import SlideContainer from '../internals/SlideContainer.vue'
|
|
16
|
+
import NavControls from '../internals/NavControls.vue'
|
|
17
|
+
import SlidesOverview from '../internals/SlidesOverview.vue'
|
|
18
|
+
import NoteEditor from '../internals/NoteEditor.vue'
|
|
19
|
+
import NoteStatic from '../internals/NoteStatic.vue'
|
|
20
|
+
import Goto from '../internals/Goto.vue'
|
|
21
|
+
import SlidesShow from '../internals/SlidesShow.vue'
|
|
22
|
+
import DrawingControls from '../internals/DrawingControls.vue'
|
|
23
|
+
import IconButton from '../internals/IconButton.vue'
|
|
24
24
|
|
|
25
25
|
const main = ref<HTMLDivElement>()
|
|
26
26
|
|
|
@@ -54,7 +54,7 @@ watch([currentRoute, queryClicks], () => {
|
|
|
54
54
|
|
|
55
55
|
const Editor = shallowRef<any>()
|
|
56
56
|
if (__DEV__ && __SLIDEV_FEATURE_EDITOR__)
|
|
57
|
-
import('
|
|
57
|
+
import('../internals/Editor.vue').then(v => Editor.value = v.default)
|
|
58
58
|
|
|
59
59
|
// sync presenter cursor
|
|
60
60
|
onMounted(() => {
|
|
@@ -140,12 +140,16 @@ onMounted(() => {
|
|
|
140
140
|
<div v-else class="grid-section note grid grid-rows-[1fr_min-content] overflow-hidden">
|
|
141
141
|
<NoteEditor
|
|
142
142
|
v-if="__DEV__"
|
|
143
|
+
:key="`edit-${currentSlideId}`"
|
|
144
|
+
:no="currentSlideId"
|
|
143
145
|
class="w-full max-w-full h-full overflow-auto p-2 lg:p-4"
|
|
144
146
|
:editing="notesEditing"
|
|
145
147
|
:style="{ fontSize: `${presenterNotesFontSize}em` }"
|
|
146
148
|
/>
|
|
147
149
|
<NoteStatic
|
|
148
150
|
v-else
|
|
151
|
+
:key="`static-${currentSlideId}`"
|
|
152
|
+
:no="currentSlideId"
|
|
149
153
|
class="w-full max-w-full h-full overflow-auto p-2 lg:p-4"
|
|
150
154
|
:style="{ fontSize: `${presenterNotesFontSize}em` }"
|
|
151
155
|
/>
|
|
@@ -3,8 +3,8 @@ import { watchEffect } from 'vue'
|
|
|
3
3
|
import { windowSize } from '../state'
|
|
4
4
|
import { isPrintMode } from '../logic/nav'
|
|
5
5
|
import { themeVars } from '../env'
|
|
6
|
-
import PrintContainer from '
|
|
7
|
-
import PrintStyle from '
|
|
6
|
+
import PrintContainer from '../internals/PrintContainer.vue'
|
|
7
|
+
import PrintStyle from '../internals/PrintStyle.vue'
|
|
8
8
|
|
|
9
9
|
watchEffect(() => {
|
|
10
10
|
if (isPrintMode)
|
package/routes.ts
CHANGED
|
@@ -15,13 +15,19 @@ export const routes: RouteRecordRaw[] = [
|
|
|
15
15
|
{
|
|
16
16
|
name: 'play',
|
|
17
17
|
path: '/',
|
|
18
|
-
component: () => import('./
|
|
18
|
+
component: () => import('./pages/play.vue'),
|
|
19
19
|
children: [
|
|
20
20
|
...rawRoutes,
|
|
21
21
|
...redirects,
|
|
22
22
|
],
|
|
23
23
|
},
|
|
24
|
-
{
|
|
24
|
+
{
|
|
25
|
+
name: 'print',
|
|
26
|
+
path: '/print',
|
|
27
|
+
component: () => import('./pages/print.vue'),
|
|
28
|
+
},
|
|
29
|
+
|
|
30
|
+
// Redirects
|
|
25
31
|
{ path: '', redirect: { path: '/1' } },
|
|
26
32
|
{ path: '/:pathMatch(.*)', redirect: { path: '/1' } },
|
|
27
33
|
]
|
|
@@ -40,24 +46,33 @@ if (__SLIDEV_FEATURE_PRESENTER__) {
|
|
|
40
46
|
return { path: `/${to.params.no}` }
|
|
41
47
|
return { path: '' }
|
|
42
48
|
}
|
|
43
|
-
|
|
49
|
+
|
|
50
|
+
routes.push({
|
|
51
|
+
path: '/presenter/print',
|
|
52
|
+
component: () => import('./pages/presenter/print.vue'),
|
|
53
|
+
})
|
|
44
54
|
if (__SLIDEV_HAS_SERVER__) {
|
|
45
55
|
routes.push({
|
|
46
56
|
name: 'entry',
|
|
47
57
|
path: '/entry',
|
|
48
|
-
component: () => import('./
|
|
58
|
+
component: () => import('./pages/entry.vue'),
|
|
59
|
+
})
|
|
60
|
+
routes.push({
|
|
61
|
+
name: 'overview',
|
|
62
|
+
path: '/overview',
|
|
63
|
+
component: () => import('./pages/overview.vue'),
|
|
49
64
|
})
|
|
50
65
|
routes.push({
|
|
51
66
|
name: 'notes',
|
|
52
67
|
path: '/notes',
|
|
53
|
-
component: () => import('./
|
|
68
|
+
component: () => import('./pages/notes.vue'),
|
|
54
69
|
beforeEnter: passwordGuard,
|
|
55
70
|
})
|
|
56
71
|
}
|
|
57
72
|
routes.push({
|
|
58
73
|
name: 'presenter',
|
|
59
74
|
path: '/presenter/:no',
|
|
60
|
-
component: () => import('./
|
|
75
|
+
component: () => import('./pages/presenter.vue'),
|
|
61
76
|
beforeEnter: passwordGuard,
|
|
62
77
|
})
|
|
63
78
|
routes.push({
|
package/styles/layouts-base.css
CHANGED
|
@@ -54,7 +54,9 @@
|
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
blockquote {
|
|
57
|
-
|
|
57
|
+
background: var(--slidev-code-background);
|
|
58
|
+
color: var(--slidev-code-foreground);
|
|
59
|
+
@apply text-sm px-2 py-1 border-primary border-l rounded;
|
|
58
60
|
}
|
|
59
61
|
|
|
60
62
|
blockquote > * {
|
|
@@ -66,7 +68,7 @@
|
|
|
66
68
|
}
|
|
67
69
|
|
|
68
70
|
tr {
|
|
69
|
-
@apply border-b border-
|
|
71
|
+
@apply border-b border-main;
|
|
70
72
|
}
|
|
71
73
|
|
|
72
74
|
th {
|
|
@@ -74,7 +76,7 @@
|
|
|
74
76
|
}
|
|
75
77
|
|
|
76
78
|
a {
|
|
77
|
-
@apply border-current border-b border-dashed hover:text
|
|
79
|
+
@apply border-current border-b border-dashed hover:text-primary hover:border-solid;
|
|
78
80
|
}
|
|
79
81
|
|
|
80
82
|
td, th {
|
|
@@ -86,7 +88,7 @@
|
|
|
86
88
|
}
|
|
87
89
|
|
|
88
90
|
kbd {
|
|
89
|
-
@apply border border-
|
|
91
|
+
@apply border border-main border-b-2 rounded;
|
|
90
92
|
@apply bg-gray-400 bg-opacity-5 py-0.5 px-1 text-xs font-mono;
|
|
91
93
|
}
|
|
92
94
|
}
|
package/styles/vars.css
CHANGED
package/uno.config.ts
CHANGED
|
@@ -17,7 +17,10 @@ export default defineConfig({
|
|
|
17
17
|
shortcuts: {
|
|
18
18
|
'bg-main': 'bg-white text-[#181818] dark:(bg-[#121212] text-[#ddd])',
|
|
19
19
|
'bg-active': 'bg-gray-400/10',
|
|
20
|
-
'border-main': 'border-gray
|
|
20
|
+
'border-main': 'border-gray/20',
|
|
21
|
+
'text-primary': 'color-$slidev-theme-primary',
|
|
22
|
+
'bg-primary': 'bg-$slidev-theme-primary',
|
|
23
|
+
'border-primary': 'border-$slidev-theme-primary',
|
|
21
24
|
'abs-tl': 'absolute top-0 left-0',
|
|
22
25
|
'abs-tr': 'absolute top-0 right-0',
|
|
23
26
|
'abs-b': 'absolute bottom-0 left-0 right-0',
|