@slidev/client 0.48.0-beta.0 → 0.48.0-beta.10
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 +4 -3
- package/builtin/KaTexBlockWrapper.vue +4 -3
- package/builtin/RenderWhen.vue +3 -3
- package/builtin/SlideCurrentNo.vue +2 -3
- package/builtin/SlidesTotal.vue +3 -4
- package/builtin/SlidevVideo.vue +8 -6
- package/builtin/Toc.vue +3 -3
- package/builtin/Tweet.vue +4 -15
- package/builtin/VClickGap.vue +3 -5
- package/builtin/VClicks.ts +9 -9
- package/composables/useClicks.ts +16 -13
- package/composables/useTweetScript.ts +17 -0
- package/constants.ts +56 -8
- package/context.ts +70 -0
- package/internals/DrawingControls.vue +66 -46
- package/internals/DrawingLayer.vue +3 -2
- package/internals/Editor.vue +68 -34
- package/internals/IconButton.vue +15 -0
- package/internals/InfoDialog.vue +1 -1
- package/internals/Modal.vue +1 -1
- package/internals/NavControls.vue +37 -68
- package/internals/NoteDisplay.vue +1 -1
- package/internals/NoteEditor.vue +10 -6
- package/internals/NoteStatic.vue +5 -6
- package/internals/PrintContainer.vue +3 -2
- package/internals/PrintSlideClick.vue +3 -2
- package/internals/RecordingControls.vue +10 -14
- package/internals/RecordingDialog.vue +2 -3
- package/internals/SlideContainer.vue +7 -6
- package/internals/SlideWrapper.ts +28 -12
- package/internals/SlidesOverview.vue +19 -9
- package/logic/drawings.ts +6 -3
- package/logic/nav.ts +6 -6
- package/logic/note.ts +7 -7
- package/main.ts +5 -3
- package/modules/context.ts +4 -3
- package/modules/{directives.ts → v-click.ts} +15 -15
- package/modules/v-mark.ts +159 -0
- package/package.json +21 -13
- package/{internals/EntrySelect.vue → pages/entry.vue} +7 -0
- package/{internals/NotesView.vue → pages/notes.vue} +9 -12
- package/pages/overview.vue +157 -0
- package/{internals/Play.vue → pages/play.vue} +10 -10
- package/{internals/PresenterPrint.vue → pages/presenter/print.vue} +7 -5
- package/{internals/Presenter.vue → pages/presenter.vue} +24 -22
- package/{internals/Print.vue → pages/print.vue} +2 -2
- package/routes.ts +25 -19
- package/setup/codemirror.ts +7 -0
- package/state/index.ts +11 -9
- package/styles/index.css +5 -0
- package/styles/layouts-base.css +6 -4
- package/styles/vars.css +1 -0
- package/uno.config.ts +6 -2
- package/internals/HiddenText.vue +0 -9
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import {
|
|
2
|
+
import { onBeforeUnmount, onMounted, ref, watch } from 'vue'
|
|
3
|
+
import { injectLocal } from '@vueuse/core'
|
|
3
4
|
import { drauu, drawingEnabled, loadCanvas } from '../logic/drawings'
|
|
4
5
|
import { injectionSlideScale } from '../constants'
|
|
5
6
|
|
|
6
|
-
const scale =
|
|
7
|
+
const scale = injectLocal(injectionSlideScale)!
|
|
7
8
|
const svg = ref<SVGSVGElement>()
|
|
8
9
|
|
|
9
10
|
onMounted(() => {
|
package/internals/Editor.vue
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { throttledWatch, useEventListener } from '@vueuse/core'
|
|
3
|
-
import { computed, onMounted, ref, watch } from 'vue'
|
|
4
|
-
import { activeElement, editorWidth, isInputting, showEditor } from '../state'
|
|
3
|
+
import { computed, nextTick, onMounted, ref, watch } from 'vue'
|
|
4
|
+
import { activeElement, editorHeight, editorWidth, isInputting, showEditor, isEditorVertical as vertical } from '../state'
|
|
5
5
|
import { useCodeMirror } from '../setup/codemirror'
|
|
6
6
|
import { currentSlideId, openInEditor } from '../logic/nav'
|
|
7
7
|
import { useDynamicSlideInfo } from '../logic/note'
|
|
8
|
-
import
|
|
8
|
+
import IconButton from './IconButton.vue'
|
|
9
9
|
|
|
10
10
|
const props = defineProps<{
|
|
11
|
-
resize
|
|
11
|
+
resize?: boolean
|
|
12
12
|
}>()
|
|
13
13
|
|
|
14
14
|
const tab = ref<'content' | 'note'>('content')
|
|
@@ -38,7 +38,6 @@ watch(
|
|
|
38
38
|
async function save() {
|
|
39
39
|
dirty.value = false
|
|
40
40
|
await update({
|
|
41
|
-
raw: null!,
|
|
42
41
|
note: note.value || undefined,
|
|
43
42
|
content: content.value,
|
|
44
43
|
// frontmatter: frontmatter.value,
|
|
@@ -56,8 +55,8 @@ useEventListener('keydown', (e) => {
|
|
|
56
55
|
}
|
|
57
56
|
})
|
|
58
57
|
|
|
59
|
-
onMounted(() => {
|
|
60
|
-
useCodeMirror(
|
|
58
|
+
onMounted(async () => {
|
|
59
|
+
const contentEditor = await useCodeMirror(
|
|
61
60
|
contentInput,
|
|
62
61
|
computed({
|
|
63
62
|
get() { return content.value },
|
|
@@ -77,7 +76,7 @@ onMounted(() => {
|
|
|
77
76
|
},
|
|
78
77
|
)
|
|
79
78
|
|
|
80
|
-
useCodeMirror(
|
|
79
|
+
const noteEditor = await useCodeMirror(
|
|
81
80
|
noteInput,
|
|
82
81
|
computed({
|
|
83
82
|
get() { return note.value },
|
|
@@ -94,14 +93,31 @@ onMounted(() => {
|
|
|
94
93
|
fencedCodeBlockDefaultMode: 'javascript',
|
|
95
94
|
},
|
|
96
95
|
)
|
|
96
|
+
|
|
97
|
+
watch([tab, vertical], () => {
|
|
98
|
+
nextTick(() => {
|
|
99
|
+
if (tab.value === 'content')
|
|
100
|
+
contentEditor.refresh()
|
|
101
|
+
else
|
|
102
|
+
noteEditor.refresh()
|
|
103
|
+
})
|
|
104
|
+
})
|
|
105
|
+
|
|
106
|
+
watch(currentSlideId, () => {
|
|
107
|
+
contentEditor.clearHistory()
|
|
108
|
+
noteEditor.clearHistory()
|
|
109
|
+
}, { flush: 'post' })
|
|
97
110
|
})
|
|
98
111
|
|
|
99
112
|
const handlerDown = ref(false)
|
|
100
113
|
function onHandlerDown() {
|
|
101
114
|
handlerDown.value = true
|
|
102
115
|
}
|
|
103
|
-
function
|
|
104
|
-
|
|
116
|
+
function updateSize(v?: number) {
|
|
117
|
+
if (vertical.value)
|
|
118
|
+
editorHeight.value = Math.min(Math.max(300, v ?? editorHeight.value), window.innerHeight - 200)
|
|
119
|
+
else
|
|
120
|
+
editorWidth.value = Math.min(Math.max(318, v ?? editorWidth.value), window.innerWidth - 200)
|
|
105
121
|
}
|
|
106
122
|
function switchTab(newTab: typeof tab.value) {
|
|
107
123
|
tab.value = newTab
|
|
@@ -111,14 +127,17 @@ function switchTab(newTab: typeof tab.value) {
|
|
|
111
127
|
|
|
112
128
|
if (props.resize) {
|
|
113
129
|
useEventListener('pointermove', (e) => {
|
|
114
|
-
if (handlerDown.value)
|
|
115
|
-
|
|
130
|
+
if (handlerDown.value) {
|
|
131
|
+
updateSize(vertical.value
|
|
132
|
+
? window.innerHeight - e.pageY
|
|
133
|
+
: window.innerWidth - e.pageX)
|
|
134
|
+
}
|
|
116
135
|
}, { passive: true })
|
|
117
136
|
useEventListener('pointerup', () => {
|
|
118
137
|
handlerDown.value = false
|
|
119
138
|
})
|
|
120
139
|
useEventListener('resize', () => {
|
|
121
|
-
|
|
140
|
+
updateSize()
|
|
122
141
|
})
|
|
123
142
|
}
|
|
124
143
|
|
|
@@ -134,46 +153,61 @@ throttledWatch(
|
|
|
134
153
|
|
|
135
154
|
<template>
|
|
136
155
|
<div
|
|
137
|
-
v-if="resize"
|
|
138
|
-
class="
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
156
|
+
v-if="resize" class="fixed bg-gray-400 select-none opacity-0 hover:opacity-10 z-100"
|
|
157
|
+
:class="vertical ? 'left-0 right-0 w-full h-10px' : 'top-0 bottom-0 w-10px h-full'" :style="{
|
|
158
|
+
opacity: handlerDown ? '0.3' : undefined,
|
|
159
|
+
bottom: vertical ? `${editorHeight - 5}px` : undefined,
|
|
160
|
+
right: !vertical ? `${editorWidth - 5}px` : undefined,
|
|
161
|
+
cursor: vertical ? 'row-resize' : 'col-resize',
|
|
162
|
+
}" @pointerdown="onHandlerDown"
|
|
142
163
|
/>
|
|
143
164
|
<div
|
|
144
165
|
class="shadow bg-main p-4 grid grid-rows-[max-content_1fr] h-full overflow-hidden"
|
|
145
166
|
:class="resize ? 'border-l border-gray-400 border-opacity-20' : ''"
|
|
146
|
-
:style="resize ? {
|
|
167
|
+
:style="resize ? {
|
|
168
|
+
height: vertical ? `${editorHeight}px` : undefined,
|
|
169
|
+
width: !vertical ? `${editorWidth}px` : undefined,
|
|
170
|
+
} : {}"
|
|
147
171
|
>
|
|
148
172
|
<div class="flex pb-2 text-xl -mt-1">
|
|
149
173
|
<div class="mr-4 rounded flex">
|
|
150
|
-
<
|
|
151
|
-
|
|
174
|
+
<IconButton
|
|
175
|
+
title="Switch to content tab" :class="tab === 'content' ? 'text-primary' : ''"
|
|
176
|
+
@click="switchTab('content')"
|
|
177
|
+
>
|
|
152
178
|
<carbon:account />
|
|
153
|
-
</
|
|
154
|
-
<
|
|
155
|
-
|
|
179
|
+
</IconButton>
|
|
180
|
+
<IconButton
|
|
181
|
+
title="Switch to notes tab" :class="tab === 'note' ? 'text-primary' : ''"
|
|
182
|
+
@click="switchTab('note')"
|
|
183
|
+
>
|
|
156
184
|
<carbon:align-box-bottom-right />
|
|
157
|
-
</
|
|
185
|
+
</IconButton>
|
|
158
186
|
</div>
|
|
159
187
|
<span class="text-2xl pt-1">
|
|
160
188
|
{{ tab === 'content' ? 'Slide' : 'Notes' }}
|
|
161
189
|
</span>
|
|
162
190
|
<div class="flex-auto" />
|
|
163
|
-
<
|
|
164
|
-
<
|
|
191
|
+
<template v-if="resize">
|
|
192
|
+
<IconButton v-if="vertical" title="Dock to right" @click="vertical = false">
|
|
193
|
+
<carbon:open-panel-right />
|
|
194
|
+
</IconButton>
|
|
195
|
+
<IconButton v-else title="Dock to bottom" @click="vertical = true">
|
|
196
|
+
<carbon:open-panel-bottom />
|
|
197
|
+
</IconButton>
|
|
198
|
+
</template>
|
|
199
|
+
<IconButton title="Open in editor" @click="openInEditor()">
|
|
165
200
|
<carbon:launch />
|
|
166
|
-
</
|
|
167
|
-
<
|
|
168
|
-
<HiddenText text="Close" />
|
|
201
|
+
</IconButton>
|
|
202
|
+
<IconButton title="Close" @click="close">
|
|
169
203
|
<carbon:close />
|
|
170
|
-
</
|
|
204
|
+
</IconButton>
|
|
171
205
|
</div>
|
|
172
|
-
<div class="
|
|
173
|
-
<div v-show="tab === 'content'" class="
|
|
206
|
+
<div class="overflow-hidden">
|
|
207
|
+
<div v-show="tab === 'content'" class="w-full h-full">
|
|
174
208
|
<textarea ref="contentInput" placeholder="Create slide content..." />
|
|
175
209
|
</div>
|
|
176
|
-
<div v-show="tab === 'note'" class="
|
|
210
|
+
<div v-show="tab === 'note'" class="w-full h-full">
|
|
177
211
|
<textarea ref="noteInput" placeholder="Write some notes..." />
|
|
178
212
|
</div>
|
|
179
213
|
</div>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
defineProps<{
|
|
3
|
+
title: string
|
|
4
|
+
icon?: string
|
|
5
|
+
}>()
|
|
6
|
+
</script>
|
|
7
|
+
|
|
8
|
+
<template>
|
|
9
|
+
<button class="slidev-icon-btn" :title="title" v-bind="$attrs">
|
|
10
|
+
<span class="sr-only">{{ title }}</span>
|
|
11
|
+
<slot>
|
|
12
|
+
<div :class="icon" />
|
|
13
|
+
</slot>
|
|
14
|
+
</button>
|
|
15
|
+
</template>
|
package/internals/InfoDialog.vue
CHANGED
|
@@ -10,7 +10,7 @@ const props = defineProps({
|
|
|
10
10
|
},
|
|
11
11
|
})
|
|
12
12
|
|
|
13
|
-
const emit = defineEmits
|
|
13
|
+
const emit = defineEmits(['update:modelValue'])
|
|
14
14
|
const value = useVModel(props, 'modelValue', emit)
|
|
15
15
|
const hasInfo = computed(() => typeof configs.info === 'string')
|
|
16
16
|
</script>
|
package/internals/Modal.vue
CHANGED
|
@@ -8,7 +8,7 @@ import { configs } from '../env'
|
|
|
8
8
|
import Settings from './Settings.vue'
|
|
9
9
|
import MenuButton from './MenuButton.vue'
|
|
10
10
|
import VerticalDivider from './VerticalDivider.vue'
|
|
11
|
-
import
|
|
11
|
+
import IconButton from './IconButton.vue'
|
|
12
12
|
|
|
13
13
|
// @ts-expect-error virtual module
|
|
14
14
|
import CustomNavControls from '/@slidev/custom-nav-controls'
|
|
@@ -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__)
|
|
@@ -52,47 +52,27 @@ if (__SLIDEV_FEATURE_DRAWINGS__)
|
|
|
52
52
|
:class="barStyle"
|
|
53
53
|
@mouseleave="onMouseLeave"
|
|
54
54
|
>
|
|
55
|
-
<
|
|
56
|
-
<
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
<template v-else>
|
|
61
|
-
<HiddenText text="Enter fullscreen" />
|
|
62
|
-
<carbon:maximize />
|
|
63
|
-
</template>
|
|
64
|
-
</button>
|
|
65
|
-
|
|
66
|
-
<button class="slidev-icon-btn" :class="{ disabled: !hasPrev }" @click="prev">
|
|
67
|
-
<HiddenText text="Go to previous slide" />
|
|
55
|
+
<IconButton v-if="!isEmbedded" :title="isFullscreen ? 'Close fullscreen' : 'Enter fullscreen'" @click="toggleFullscreen">
|
|
56
|
+
<carbon:minimize v-if="isFullscreen" />
|
|
57
|
+
<carbon:maximize v-else />
|
|
58
|
+
</IconButton>
|
|
59
|
+
<IconButton :class="{ disabled: !hasPrev }" title="Go to previous slide" @click="prev">
|
|
68
60
|
<carbon:arrow-left />
|
|
69
|
-
</
|
|
70
|
-
|
|
71
|
-
<button class="slidev-icon-btn" :class="{ disabled: !hasNext }" title="Next" @click="next">
|
|
72
|
-
<HiddenText text="Go to next slide" />
|
|
61
|
+
</IconButton>
|
|
62
|
+
<IconButton :class="{ disabled: !hasNext }" title="Go to next slide" @click="next">
|
|
73
63
|
<carbon:arrow-right />
|
|
74
|
-
</
|
|
75
|
-
|
|
76
|
-
<button v-if="!isEmbedded" class="slidev-icon-btn" title="Slides overview" @click="toggleOverview()">
|
|
77
|
-
<HiddenText text="Show slide overview" />
|
|
64
|
+
</IconButton>
|
|
65
|
+
<IconButton v-if="!isEmbedded" title="Show slide overview" @click="toggleOverview()">
|
|
78
66
|
<carbon:apps />
|
|
79
|
-
</
|
|
80
|
-
|
|
81
|
-
<button
|
|
67
|
+
</IconButton>
|
|
68
|
+
<IconButton
|
|
82
69
|
v-if="!isColorSchemaConfigured"
|
|
83
|
-
|
|
84
|
-
title="Toggle dark mode"
|
|
70
|
+
:title="isDark ? 'Switch to light mode theme' : 'Switch to dark mode theme'"
|
|
85
71
|
@click="toggleDark()"
|
|
86
72
|
>
|
|
87
|
-
<
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
</template>
|
|
91
|
-
<template v-else>
|
|
92
|
-
<HiddenText text="Switch to dark mode theme" />
|
|
93
|
-
<carbon-sun />
|
|
94
|
-
</template>
|
|
95
|
-
</button>
|
|
73
|
+
<carbon-moon v-if="isDark" />
|
|
74
|
+
<carbon-sun v-else />
|
|
75
|
+
</IconButton>
|
|
96
76
|
|
|
97
77
|
<VerticalDivider />
|
|
98
78
|
|
|
@@ -102,33 +82,25 @@ if (__SLIDEV_FEATURE_DRAWINGS__)
|
|
|
102
82
|
<VerticalDivider />
|
|
103
83
|
</template>
|
|
104
84
|
|
|
105
|
-
<
|
|
85
|
+
<IconButton
|
|
106
86
|
v-if="isPresenter"
|
|
107
|
-
|
|
108
|
-
title="Show presenter cursor"
|
|
87
|
+
:title="showPresenterCursor ? 'Hide presenter cursor' : 'Show presenter cursor'"
|
|
109
88
|
@click="showPresenterCursor = !showPresenterCursor"
|
|
110
89
|
>
|
|
111
|
-
<
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
</template>
|
|
115
|
-
<template v-else>
|
|
116
|
-
<HiddenText text="Show presenter cursor" />
|
|
117
|
-
<ph-cursor-duotone />
|
|
118
|
-
</template>
|
|
119
|
-
</button>
|
|
90
|
+
<ph-cursor-fill v-if="showPresenterCursor" />
|
|
91
|
+
<ph-cursor-duotone v-else />
|
|
92
|
+
</IconButton>
|
|
120
93
|
</template>
|
|
121
94
|
|
|
122
95
|
<template v-if="__SLIDEV_FEATURE_DRAWINGS__ && (!configs.drawings.presenterOnly || isPresenter) && !isEmbedded">
|
|
123
|
-
<
|
|
124
|
-
<HiddenText v-if="drawingEnabled" :text="drawingEnabled ? 'Hide drawing toolbar' : 'Show drawing toolbar'" />
|
|
96
|
+
<IconButton class="relative" :title="drawingEnabled ? 'Hide drawing toolbar' : 'Show drawing toolbar'" @click="drawingEnabled = !drawingEnabled">
|
|
125
97
|
<carbon:pen />
|
|
126
98
|
<div
|
|
127
99
|
v-if="drawingEnabled"
|
|
128
100
|
class="absolute left-1 right-1 bottom-0 h-0.7 rounded-full"
|
|
129
101
|
:style="{ background: brush.color }"
|
|
130
102
|
/>
|
|
131
|
-
</
|
|
103
|
+
</IconButton>
|
|
132
104
|
<VerticalDivider />
|
|
133
105
|
</template>
|
|
134
106
|
|
|
@@ -140,43 +112,40 @@ if (__SLIDEV_FEATURE_DRAWINGS__)
|
|
|
140
112
|
<carbon:user-speaker />
|
|
141
113
|
</RouterLink>
|
|
142
114
|
|
|
143
|
-
<
|
|
115
|
+
<IconButton
|
|
144
116
|
v-if="__DEV__ && __SLIDEV_FEATURE_EDITOR__"
|
|
145
|
-
|
|
117
|
+
:title="showEditor ? 'Hide editor' : 'Show editor'"
|
|
118
|
+
class="<md:hidden"
|
|
146
119
|
@click="showEditor = !showEditor"
|
|
147
120
|
>
|
|
148
|
-
<HiddenText :text="showEditor ? 'Hide editor' : 'Show editor'" />
|
|
149
121
|
<carbon:text-annotation-toggle />
|
|
150
|
-
</
|
|
122
|
+
</IconButton>
|
|
151
123
|
|
|
152
|
-
<
|
|
124
|
+
<IconButton v-if="isPresenter" title="Toggle Presenter Layout" @click="togglePresenterLayout">
|
|
153
125
|
<carbon:template />
|
|
154
126
|
{{ presenterLayout }}
|
|
155
|
-
</
|
|
127
|
+
</IconButton>
|
|
156
128
|
</template>
|
|
157
129
|
<template v-if="!__DEV__">
|
|
158
|
-
<
|
|
159
|
-
<HiddenText text="Download as PDF" />
|
|
130
|
+
<IconButton v-if="configs.download" title="Download as PDF" @click="downloadPDF">
|
|
160
131
|
<carbon:download />
|
|
161
|
-
</
|
|
132
|
+
</IconButton>
|
|
162
133
|
</template>
|
|
163
134
|
|
|
164
|
-
<
|
|
135
|
+
<IconButton
|
|
165
136
|
v-if="!isPresenter && configs.info && !isEmbedded"
|
|
166
|
-
|
|
137
|
+
title="Show info"
|
|
167
138
|
@click="showInfoDialog = !showInfoDialog"
|
|
168
139
|
>
|
|
169
|
-
<HiddenText text="Show info" />
|
|
170
140
|
<carbon:information />
|
|
171
|
-
</
|
|
141
|
+
</IconButton>
|
|
172
142
|
|
|
173
143
|
<template v-if="!isPresenter && !isEmbedded">
|
|
174
144
|
<MenuButton>
|
|
175
145
|
<template #button>
|
|
176
|
-
<
|
|
177
|
-
<HiddenText text="Adjust settings" />
|
|
146
|
+
<IconButton title="Adjust settings">
|
|
178
147
|
<carbon:settings-adjust />
|
|
179
|
-
</
|
|
148
|
+
</IconButton>
|
|
180
149
|
</template>
|
|
181
150
|
<template #menu>
|
|
182
151
|
<Settings />
|
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,10 +35,10 @@ 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
|
-
update({
|
|
41
|
+
update({ note: v }, id)
|
|
40
42
|
}, 500)
|
|
41
43
|
},
|
|
42
44
|
)
|
|
@@ -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>
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { parseRangeString } from '@slidev/parser/core'
|
|
3
|
-
import { computed
|
|
3
|
+
import { computed } from 'vue'
|
|
4
|
+
import { provideLocal } from '@vueuse/core'
|
|
4
5
|
import { configs, slideAspect, slideWidth } from '../env'
|
|
5
6
|
import { injectionSlideScale } from '../constants'
|
|
6
7
|
import { route as currentRoute, rawRoutes } from '../logic/nav'
|
|
@@ -31,7 +32,7 @@ const className = computed(() => ({
|
|
|
31
32
|
'select-none': !configs.selectable,
|
|
32
33
|
}))
|
|
33
34
|
|
|
34
|
-
|
|
35
|
+
provideLocal(injectionSlideScale, scale)
|
|
35
36
|
</script>
|
|
36
37
|
|
|
37
38
|
<template>
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import type { RouteRecordRaw } from 'vue-router'
|
|
3
|
-
import { computed,
|
|
3
|
+
import { computed, reactive, shallowRef } from 'vue'
|
|
4
4
|
import type { ClicksContext } from '@slidev/types'
|
|
5
|
+
import { provideLocal } from '@vueuse/core'
|
|
5
6
|
import { injectionSlidevContext } from '../constants'
|
|
6
7
|
import { configs, slideHeight, slideWidth } from '../env'
|
|
7
8
|
import { getSlideClass } from '../utils'
|
|
@@ -33,7 +34,7 @@ const id = computed(() =>
|
|
|
33
34
|
`${props.route.path.toString().padStart(3, '0')}-${(props.nav.clicks.value + 1).toString().padStart(2, '0')}`,
|
|
34
35
|
)
|
|
35
36
|
|
|
36
|
-
|
|
37
|
+
provideLocal(injectionSlidevContext, reactive({
|
|
37
38
|
nav: props.nav,
|
|
38
39
|
configs,
|
|
39
40
|
themeConfigs: computed(() => configs.themeConfig),
|
|
@@ -5,7 +5,7 @@ import { recorder } from '../logic/recording'
|
|
|
5
5
|
import { currentCamera, showRecordingDialog } from '../state'
|
|
6
6
|
import DevicesList from './DevicesList.vue'
|
|
7
7
|
import MenuButton from './MenuButton.vue'
|
|
8
|
-
import
|
|
8
|
+
import IconButton from './IconButton.vue'
|
|
9
9
|
|
|
10
10
|
const {
|
|
11
11
|
recording,
|
|
@@ -34,33 +34,29 @@ onMounted(() => {
|
|
|
34
34
|
</script>
|
|
35
35
|
|
|
36
36
|
<template>
|
|
37
|
-
<
|
|
37
|
+
<IconButton
|
|
38
38
|
v-if="currentCamera !== 'none'"
|
|
39
|
-
class="
|
|
39
|
+
class="<md:hidden"
|
|
40
40
|
:class="{ 'text-green-500': Boolean(showAvatar && streamCamera) }"
|
|
41
|
-
title="
|
|
41
|
+
title="Toggle camera view"
|
|
42
42
|
@click="toggleAvatar"
|
|
43
43
|
>
|
|
44
|
-
<HiddenText text="Toggle camera view" />
|
|
45
44
|
<carbon:user-avatar />
|
|
46
|
-
</
|
|
45
|
+
</IconButton>
|
|
47
46
|
|
|
48
|
-
<
|
|
49
|
-
class="slidev-icon-btn"
|
|
47
|
+
<IconButton
|
|
50
48
|
:class="{ 'text-red-500': recording }"
|
|
51
|
-
title="
|
|
49
|
+
:title="recording ? 'Stop record video' : 'Record video'"
|
|
52
50
|
@click="toggleRecording"
|
|
53
51
|
>
|
|
54
|
-
<HiddenText :text="recording ? 'Stop record video' : 'Record video'" />
|
|
55
52
|
<carbon:stop-outline v-if="recording" />
|
|
56
53
|
<carbon:video v-else />
|
|
57
|
-
</
|
|
54
|
+
</IconButton>
|
|
58
55
|
<MenuButton :disabled="recording">
|
|
59
56
|
<template #button>
|
|
60
|
-
<
|
|
61
|
-
<HiddenText text="Select recording device" />
|
|
57
|
+
<IconButton title="Select recording device" class="h-full !text-sm !px-0">
|
|
62
58
|
<carbon:chevron-up class="opacity-50" />
|
|
63
|
-
</
|
|
59
|
+
</IconButton>
|
|
64
60
|
</template>
|
|
65
61
|
<template #menu>
|
|
66
62
|
<DevicesList />
|
|
@@ -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
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import { useElementSize, useStyleTag } from '@vueuse/core'
|
|
3
|
-
import { computed,
|
|
2
|
+
import { provideLocal, useElementSize, useStyleTag } from '@vueuse/core'
|
|
3
|
+
import { computed, ref, watchEffect } from 'vue'
|
|
4
4
|
import { configs, slideAspect, slideHeight, slideWidth } from '../env'
|
|
5
5
|
import { injectionSlideScale } from '../constants'
|
|
6
6
|
import { isPrintMode } from '../logic/nav'
|
|
@@ -47,9 +47,10 @@ const scale = computed(() => {
|
|
|
47
47
|
})
|
|
48
48
|
|
|
49
49
|
const style = computed(() => ({
|
|
50
|
-
height: `${slideHeight}px`,
|
|
51
|
-
width: `${slideWidth}px`,
|
|
52
|
-
transform: `translate(-50%, -50%) scale(${scale.value})`,
|
|
50
|
+
'height': `${slideHeight}px`,
|
|
51
|
+
'width': `${slideWidth}px`,
|
|
52
|
+
'transform': `translate(-50%, -50%) scale(${scale.value})`,
|
|
53
|
+
'--slidev-slide-scale': scale.value,
|
|
53
54
|
}))
|
|
54
55
|
|
|
55
56
|
const className = computed(() => ({
|
|
@@ -64,7 +65,7 @@ if (props.isMain) {
|
|
|
64
65
|
`))
|
|
65
66
|
}
|
|
66
67
|
|
|
67
|
-
|
|
68
|
+
provideLocal(injectionSlideScale, scale as any)
|
|
68
69
|
</script>
|
|
69
70
|
|
|
70
71
|
<template>
|