@slidev/client 0.49.28 → 0.50.0-beta.1

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.
Files changed (86) hide show
  1. package/builtin/Arrow.vue +1 -1
  2. package/builtin/CodeBlockWrapper.vue +3 -3
  3. package/builtin/KaTexBlockWrapper.vue +2 -2
  4. package/builtin/Mermaid.vue +1 -1
  5. package/builtin/Monaco.vue +5 -5
  6. package/builtin/RenderWhen.vue +2 -2
  7. package/builtin/ShikiMagicMove.vue +5 -5
  8. package/builtin/SlidevVideo.vue +2 -2
  9. package/builtin/Toc.vue +1 -1
  10. package/builtin/TocList.vue +2 -2
  11. package/builtin/VAfter.ts +1 -1
  12. package/builtin/VClick.ts +1 -1
  13. package/builtin/VClickGap.vue +1 -1
  14. package/builtin/VClicks.ts +1 -1
  15. package/builtin/VDrag.vue +1 -1
  16. package/builtin/VDragArrow.vue +1 -1
  17. package/builtin/VSwitch.ts +4 -4
  18. package/composables/useClicks.ts +1 -1
  19. package/composables/useDragElements.ts +2 -2
  20. package/composables/useDrawings.ts +3 -3
  21. package/composables/useNav.ts +8 -8
  22. package/composables/useSlideInfo.ts +2 -2
  23. package/composables/useSwipeControls.ts +1 -1
  24. package/composables/useViewTransition.ts +1 -1
  25. package/constants.ts +2 -1
  26. package/context.ts +2 -2
  27. package/env.ts +2 -2
  28. package/index.ts +23 -5
  29. package/internals/CodeRunner.vue +4 -4
  30. package/internals/ContextMenu.vue +2 -2
  31. package/internals/Controls.vue +6 -6
  32. package/internals/DevicesList.vue +2 -2
  33. package/internals/DragControl.vue +2 -2
  34. package/internals/Draggable.vue +1 -1
  35. package/internals/DrawingControls.vue +140 -139
  36. package/internals/DrawingLayer.vue +1 -1
  37. package/internals/Goto.vue +3 -3
  38. package/internals/NavControls.vue +8 -8
  39. package/internals/NoteDisplay.vue +1 -1
  40. package/internals/NoteEditable.vue +2 -2
  41. package/internals/PrintContainer.vue +3 -3
  42. package/internals/PrintSlide.vue +1 -1
  43. package/internals/PrintSlideClick.vue +3 -3
  44. package/internals/QuickOverview.vue +9 -7
  45. package/internals/RecordingControls.vue +1 -1
  46. package/internals/RecordingDialog.vue +1 -1
  47. package/internals/SelectList.vue +1 -1
  48. package/internals/Settings.vue +1 -1
  49. package/internals/ShikiEditor.vue +1 -1
  50. package/internals/SideEditor.vue +12 -7
  51. package/internals/SlideContainer.vue +32 -3
  52. package/internals/SlideWrapper.vue +4 -4
  53. package/internals/SlidesShow.vue +6 -6
  54. package/internals/WebCamera.vue +1 -1
  55. package/logic/contextMenu.ts +3 -3
  56. package/logic/recording.ts +4 -4
  57. package/logic/shortcuts.ts +3 -3
  58. package/logic/slides.ts +2 -2
  59. package/logic/snapshot.ts +86 -0
  60. package/modules/context.ts +1 -1
  61. package/modules/mermaid.ts +3 -3
  62. package/modules/v-click.ts +1 -1
  63. package/modules/v-drag.ts +1 -1
  64. package/modules/v-mark.ts +2 -2
  65. package/modules/v-motion.ts +3 -3
  66. package/package.json +25 -24
  67. package/pages/notes.vue +7 -7
  68. package/pages/overview.vue +24 -11
  69. package/pages/play.vue +10 -10
  70. package/pages/presenter/print.vue +2 -2
  71. package/pages/presenter.vue +18 -18
  72. package/pages/print.vue +3 -3
  73. package/setup/code-runners.ts +4 -4
  74. package/setup/context-menu.ts +11 -11
  75. package/setup/main.ts +4 -4
  76. package/setup/mermaid.ts +1 -1
  77. package/setup/monaco.ts +13 -9
  78. package/setup/root.ts +9 -9
  79. package/setup/shortcuts.ts +5 -5
  80. package/state/drawings.ts +1 -0
  81. package/state/index.ts +1 -1
  82. package/state/shared.ts +2 -1
  83. package/state/snapshot.ts +13 -0
  84. package/state/syncState.ts +76 -24
  85. package/styles/index.css +1 -0
  86. package/uno.config.ts +3 -16
@@ -1,139 +1,140 @@
1
- <script setup lang="ts">
2
- import { Menu } from 'floating-vue'
3
- import { useDrawings } from '../composables/useDrawings'
4
- import VerticalDivider from './VerticalDivider.vue'
5
- import Draggable from './Draggable.vue'
6
- import IconButton from './IconButton.vue'
7
-
8
- const {
9
- brush,
10
- canClear,
11
- canRedo,
12
- canUndo,
13
- clear,
14
- drauu,
15
- drawingEnabled,
16
- drawingMode,
17
- drawingPinned,
18
- brushColors,
19
- } = useDrawings()
20
-
21
- function undo() {
22
- drauu.undo()
23
- }
24
- function redo() {
25
- drauu.redo()
26
- }
27
-
28
- let lastDrawingMode: typeof drawingMode.value = 'stylus'
29
- function setDrawingMode(mode: typeof drawingMode.value) {
30
- drawingMode.value = mode
31
- drawingEnabled.value = true
32
- if (mode !== 'eraseLine')
33
- lastDrawingMode = mode
34
- }
35
- function setBrushColor(color: typeof brush.color) {
36
- brush.color = color
37
- drawingEnabled.value = true
38
- drawingMode.value = lastDrawingMode
39
- }
40
- </script>
41
-
42
- <template>
43
- <Draggable
44
- 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
- :class="drawingEnabled ? '' : drawingPinned ? 'opacity-40 hover:opacity-90' : 'opacity-0 pointer-events-none'"
46
- storage-key="slidev-drawing-pos"
47
- :initial-x="10"
48
- :initial-y="10"
49
- >
50
- <IconButton title="Draw with stylus" :class="{ shallow: drawingMode !== 'stylus' }" @click="setDrawingMode('stylus')">
51
- <carbon:pen />
52
- </IconButton>
53
- <IconButton title="Draw a line" :class="{ shallow: drawingMode !== 'line' }" @click="setDrawingMode('line')">
54
- <svg width="1em" height="1em" class="-mt-0.5" preserveAspectRatio="xMidYMid meet" viewBox="0 0 24 24">
55
- <path d="M21.71 3.29a1 1 0 0 0-1.42 0l-18 18a1 1 0 0 0 0 1.42a1 1 0 0 0 1.42 0l18-18a1 1 0 0 0 0-1.42z" fill="currentColor" />
56
- </svg>
57
- </IconButton>
58
- <IconButton title="Draw an arrow" :class="{ shallow: drawingMode !== 'arrow' }" @click="setDrawingMode('arrow')">
59
- <carbon:arrow-up-right />
60
- </IconButton>
61
- <IconButton title="Draw an ellipse" :class="{ shallow: drawingMode !== 'ellipse' }" @click="setDrawingMode('ellipse')">
62
- <carbon:radio-button />
63
- </IconButton>
64
- <IconButton title="Draw a rectangle" :class="{ shallow: drawingMode !== 'rectangle' }" @click="setDrawingMode('rectangle')">
65
- <carbon:checkbox />
66
- </IconButton>
67
- <IconButton title="Erase" :class="{ shallow: drawingMode !== 'eraseLine' }" @click="setDrawingMode('eraseLine')">
68
- <carbon:erase />
69
- </IconButton>
70
-
71
- <VerticalDivider />
72
-
73
- <Menu>
74
- <IconButton title="Adjust stroke width" :class="{ shallow: drawingMode === 'eraseLine' }">
75
- <svg viewBox="0 0 32 32" width="1.2em" height="1.2em">
76
- <line x1="2" y1="15" x2="22" y2="4" stroke="currentColor" stroke-width="1" stroke-linecap="round" />
77
- <line x1="2" y1="24" x2="28" y2="10" stroke="currentColor" stroke-width="2" stroke-linecap="round" />
78
- <line x1="7" y1="31" x2="29" y2="19" stroke="currentColor" stroke-width="3" stroke-linecap="round" />
79
- </svg>
80
- </IconButton>
81
- <template #popper>
82
- <div class="flex bg-main p-2">
83
- <div class="inline-block w-7 text-center">
84
- {{ brush.size }}
85
- </div>
86
- <div class="pt-.5">
87
- <input v-model="brush.size" type="range" min="1" max="15" @change="drawingMode = lastDrawingMode">
88
- </div>
89
- </div>
90
- </template>
91
- </Menu>
92
- <IconButton
93
- v-for="color of brushColors"
94
- :key="color"
95
- title="Set brush color"
96
- :class="brush.color === color && drawingMode !== 'eraseLine' ? 'active' : 'shallow'"
97
- @click="setBrushColor(color)"
98
- >
99
- <div
100
- class="w-6 h-6 transition-all transform border"
101
- :class="brush.color !== color ? 'rounded-1/2 scale-85 border-white' : 'rounded-md border-gray-300/50'"
102
- :style="drawingEnabled ? { background: color } : { borderColor: color }"
103
- />
104
- </IconButton>
105
-
106
- <VerticalDivider />
107
-
108
- <IconButton title="Undo" :class="{ disabled: !canUndo }" @click="undo()">
109
- <carbon:undo />
110
- </IconButton>
111
- <IconButton title="Redo" :class="{ disabled: !canRedo }" @click="redo()">
112
- <carbon:redo />
113
- </IconButton>
114
- <IconButton title="Delete" :class="{ disabled: !canClear }" @click="clear()">
115
- <carbon:trash-can />
116
- </IconButton>
117
-
118
- <VerticalDivider />
119
- <IconButton :title="drawingPinned ? 'Unpin drawing' : 'Pin drawing'" :class="{ shallow: !drawingPinned }" @click="drawingPinned = !drawingPinned">
120
- <carbon:pin-filled v-show="drawingPinned" class="transform -rotate-45" />
121
- <carbon:pin v-show="!drawingPinned" />
122
- </IconButton>
123
- <IconButton
124
- v-if="drawingEnabled"
125
- :title="drawingPinned ? 'Drawing pinned' : 'Drawing unpinned'"
126
- :class="{ shallow: !drawingEnabled }"
127
- @click="drawingEnabled = !drawingEnabled"
128
- >
129
- <carbon:error v-show="drawingPinned" />
130
- <carbon:close-outline v-show="!drawingPinned" />
131
- </IconButton>
132
- </Draggable>
133
- </template>
134
-
135
- <style>
136
- .v-popper--theme-menu .v-popper__arrow-inner {
137
- --uno: border-main;
138
- }
139
- </style>
1
+ <script setup lang="ts">
2
+ import { Menu } from 'floating-vue'
3
+ import { useDrawings } from '../composables/useDrawings'
4
+ import Draggable from './Draggable.vue'
5
+ import IconButton from './IconButton.vue'
6
+ import VerticalDivider from './VerticalDivider.vue'
7
+
8
+ const {
9
+ brush,
10
+ canClear,
11
+ canRedo,
12
+ canUndo,
13
+ clear,
14
+ drauu,
15
+ drawingEnabled,
16
+ drawingMode,
17
+ drawingPinned,
18
+ brushColors,
19
+ } = useDrawings()
20
+
21
+ function undo() {
22
+ drauu.undo()
23
+ }
24
+ function redo() {
25
+ drauu.redo()
26
+ }
27
+
28
+ let lastDrawingMode: typeof drawingMode.value = 'stylus'
29
+ function setDrawingMode(mode: typeof drawingMode.value) {
30
+ drawingMode.value = mode
31
+ drawingEnabled.value = true
32
+ if (mode !== 'eraseLine')
33
+ lastDrawingMode = mode
34
+ }
35
+ function setBrushColor(color: typeof brush.color) {
36
+ brush.color = color
37
+ drawingEnabled.value = true
38
+ drawingMode.value = lastDrawingMode
39
+ }
40
+ </script>
41
+
42
+ <template>
43
+ <Draggable
44
+ v-if="drawingEnabled || drawingPinned"
45
+ class="flex flex-wrap text-xl p-2 gap-1 rounded-md bg-main shadow transition-opacity duration-200 z-20 border border-main"
46
+ :class="!drawingEnabled && drawingPinned ? 'opacity-40 hover:opacity-90' : ''"
47
+ storage-key="slidev-drawing-pos"
48
+ :initial-x="10"
49
+ :initial-y="10"
50
+ >
51
+ <IconButton title="Draw with stylus" :class="{ shallow: drawingMode !== 'stylus' }" @click="setDrawingMode('stylus')">
52
+ <carbon:pen />
53
+ </IconButton>
54
+ <IconButton title="Draw a line" :class="{ shallow: drawingMode !== 'line' }" @click="setDrawingMode('line')">
55
+ <svg width="1em" height="1em" class="-mt-0.5" preserveAspectRatio="xMidYMid meet" viewBox="0 0 24 24">
56
+ <path d="M21.71 3.29a1 1 0 0 0-1.42 0l-18 18a1 1 0 0 0 0 1.42a1 1 0 0 0 1.42 0l18-18a1 1 0 0 0 0-1.42z" fill="currentColor" />
57
+ </svg>
58
+ </IconButton>
59
+ <IconButton title="Draw an arrow" :class="{ shallow: drawingMode !== 'arrow' }" @click="setDrawingMode('arrow')">
60
+ <carbon:arrow-up-right />
61
+ </IconButton>
62
+ <IconButton title="Draw an ellipse" :class="{ shallow: drawingMode !== 'ellipse' }" @click="setDrawingMode('ellipse')">
63
+ <carbon:radio-button />
64
+ </IconButton>
65
+ <IconButton title="Draw a rectangle" :class="{ shallow: drawingMode !== 'rectangle' }" @click="setDrawingMode('rectangle')">
66
+ <carbon:checkbox />
67
+ </IconButton>
68
+ <IconButton title="Erase" :class="{ shallow: drawingMode !== 'eraseLine' }" @click="setDrawingMode('eraseLine')">
69
+ <carbon:erase />
70
+ </IconButton>
71
+
72
+ <VerticalDivider />
73
+
74
+ <Menu>
75
+ <IconButton title="Adjust stroke width" :class="{ shallow: drawingMode === 'eraseLine' }">
76
+ <svg viewBox="0 0 32 32" width="1.2em" height="1.2em">
77
+ <line x1="2" y1="15" x2="22" y2="4" stroke="currentColor" stroke-width="1" stroke-linecap="round" />
78
+ <line x1="2" y1="24" x2="28" y2="10" stroke="currentColor" stroke-width="2" stroke-linecap="round" />
79
+ <line x1="7" y1="31" x2="29" y2="19" stroke="currentColor" stroke-width="3" stroke-linecap="round" />
80
+ </svg>
81
+ </IconButton>
82
+ <template #popper>
83
+ <div class="flex bg-main p-2">
84
+ <div class="inline-block w-7 text-center">
85
+ {{ brush.size }}
86
+ </div>
87
+ <div class="pt-.5">
88
+ <input v-model="brush.size" type="range" min="1" max="15" @change="drawingMode = lastDrawingMode">
89
+ </div>
90
+ </div>
91
+ </template>
92
+ </Menu>
93
+ <IconButton
94
+ v-for="color of brushColors"
95
+ :key="color"
96
+ title="Set brush color"
97
+ :class="brush.color === color && drawingMode !== 'eraseLine' ? 'active' : 'shallow'"
98
+ @click="setBrushColor(color)"
99
+ >
100
+ <div
101
+ class="w-6 h-6 transition-all transform border"
102
+ :class="brush.color !== color ? 'rounded-1/2 scale-85 border-white' : 'rounded-md border-gray-300/50'"
103
+ :style="drawingEnabled ? { background: color } : { borderColor: color }"
104
+ />
105
+ </IconButton>
106
+
107
+ <VerticalDivider />
108
+
109
+ <IconButton title="Undo" :class="{ disabled: !canUndo }" @click="undo()">
110
+ <carbon:undo />
111
+ </IconButton>
112
+ <IconButton title="Redo" :class="{ disabled: !canRedo }" @click="redo()">
113
+ <carbon:redo />
114
+ </IconButton>
115
+ <IconButton title="Delete" :class="{ disabled: !canClear }" @click="clear()">
116
+ <carbon:trash-can />
117
+ </IconButton>
118
+
119
+ <VerticalDivider />
120
+ <IconButton :title="drawingPinned ? 'Unpin drawing' : 'Pin drawing'" :class="{ shallow: !drawingPinned }" @click="drawingPinned = !drawingPinned">
121
+ <carbon:pin-filled v-show="drawingPinned" class="transform -rotate-45" />
122
+ <carbon:pin v-show="!drawingPinned" />
123
+ </IconButton>
124
+ <IconButton
125
+ v-if="drawingEnabled"
126
+ :title="drawingPinned ? 'Drawing pinned' : 'Drawing unpinned'"
127
+ :class="{ shallow: !drawingEnabled }"
128
+ @click="drawingEnabled = !drawingEnabled"
129
+ >
130
+ <carbon:error v-show="drawingPinned" />
131
+ <carbon:close-outline v-show="!drawingPinned" />
132
+ </IconButton>
133
+ </Draggable>
134
+ </template>
135
+
136
+ <style>
137
+ .v-popper--theme-menu .v-popper__arrow-inner {
138
+ --uno: border-main;
139
+ }
140
+ </style>
@@ -1,7 +1,7 @@
1
1
  <script setup lang="ts">
2
2
  import { onBeforeUnmount, onMounted, ref, watch } from 'vue'
3
- import { useSlideContext } from '../context'
4
3
  import { useDrawings } from '../composables/useDrawings'
4
+ import { useSlideContext } from '../context'
5
5
 
6
6
  const { drauu, drawingEnabled, loadCanvas } = useDrawings()
7
7
 
@@ -1,9 +1,9 @@
1
1
  <script setup lang="ts">
2
- import { computed, ref, watch } from 'vue'
2
+ import TitleRenderer from '#slidev/title-renderer'
3
3
  import Fuse from 'fuse.js'
4
- import { activeElement, showGotoDialog } from '../state'
4
+ import { computed, ref, watch } from 'vue'
5
5
  import { useNav } from '../composables/useNav'
6
- import TitleRenderer from '#slidev/title-renderer'
6
+ import { activeElement, showGotoDialog } from '../state'
7
7
 
8
8
  const container = ref<HTMLDivElement>()
9
9
  const input = ref<HTMLInputElement>()
@@ -1,17 +1,17 @@
1
1
  <script setup lang="ts">
2
+ import CustomNavControls from '#slidev/custom-nav-controls'
2
3
  import { computed, ref, shallowRef } from 'vue'
4
+ import { useDrawings } from '../composables/useDrawings'
5
+ import { useNav } from '../composables/useNav'
6
+ import { configs } from '../env'
3
7
  import { isColorSchemaConfigured, isDark, toggleDark } from '../logic/dark'
4
- import { downloadPDF } from '../utils'
5
8
  import { activeElement, breakpoints, fullscreen, presenterLayout, showEditor, showInfoDialog, showPresenterCursor, toggleOverview, togglePresenterLayout } from '../state'
6
- import { configs } from '../env'
7
- import { useNav } from '../composables/useNav'
8
- import { useDrawings } from '../composables/useDrawings'
9
- import Settings from './Settings.vue'
10
- import MenuButton from './MenuButton.vue'
11
- import VerticalDivider from './VerticalDivider.vue'
9
+ import { downloadPDF } from '../utils'
12
10
  import IconButton from './IconButton.vue'
11
+ import MenuButton from './MenuButton.vue'
12
+ import Settings from './Settings.vue'
13
13
 
14
- import CustomNavControls from '#slidev/custom-nav-controls'
14
+ import VerticalDivider from './VerticalDivider.vue'
15
15
 
16
16
  const props = defineProps({
17
17
  persist: {
@@ -1,6 +1,6 @@
1
1
  <script setup lang="ts">
2
- import { computed, nextTick, onMounted, ref, watch, watchEffect } from 'vue'
3
2
  import type { ClicksContext } from '@slidev/types'
3
+ import { computed, nextTick, onMounted, ref, watch, watchEffect } from 'vue'
4
4
  import { CLICKS_MAX } from '../constants'
5
5
 
6
6
  const props = withDefaults(
@@ -1,8 +1,8 @@
1
1
  <script setup lang="ts">
2
+ import type { ClicksContext } from '@slidev/types'
2
3
  import type { PropType } from 'vue'
3
- import { nextTick, ref, toRef, watch, watchEffect } from 'vue'
4
4
  import { ignorableWatch, onClickOutside, useVModel } from '@vueuse/core'
5
- import type { ClicksContext } from '@slidev/types'
5
+ import { nextTick, ref, toRef, watch, watchEffect } from 'vue'
6
6
  import { useDynamicSlideInfo } from '../composables/useSlideInfo'
7
7
  import NoteDisplay from './NoteDisplay.vue'
8
8
 
@@ -1,10 +1,10 @@
1
1
  <script setup lang="ts">
2
2
  import { parseRangeString } from '@slidev/parser/core'
3
- import { computed } from 'vue'
4
3
  import { provideLocal } from '@vueuse/core'
5
- import { configs, slideAspect, slideWidth } from '../env'
6
- import { injectionSlideScale } from '../constants'
4
+ import { computed } from 'vue'
7
5
  import { useNav } from '../composables/useNav'
6
+ import { injectionSlideScale } from '../constants'
7
+ import { configs, slideAspect, slideWidth } from '../env'
8
8
  import PrintSlide from './PrintSlide.vue'
9
9
 
10
10
  const props = defineProps<{
@@ -1,7 +1,7 @@
1
1
  <script setup lang="ts">
2
2
  import type { SlideRoute } from '@slidev/types'
3
- import { useFixedNav, useNav } from '../composables/useNav'
4
3
  import { createFixedClicks } from '../composables/useClicks'
4
+ import { useFixedNav, useNav } from '../composables/useNav'
5
5
  import { CLICKS_MAX } from '../constants'
6
6
  import PrintSlideClick from './PrintSlideClick.vue'
7
7
 
@@ -1,12 +1,12 @@
1
1
  <script setup lang="ts">
2
- import { computed, reactive, shallowRef } from 'vue'
2
+ import type { SlidevContextNav } from '../composables/useNav'
3
+ import { GlobalBottom, GlobalTop } from '#slidev/global-layers'
3
4
  import { provideLocal } from '@vueuse/core'
5
+ import { computed, reactive, shallowRef } from 'vue'
4
6
  import { injectionSlidevContext } from '../constants'
5
7
  import { configs, slideHeight, slideWidth } from '../env'
6
8
  import { getSlideClass } from '../utils'
7
- import type { SlidevContextNav } from '../composables/useNav'
8
9
  import SlideWrapper from './SlideWrapper.vue'
9
- import { GlobalBottom, GlobalTop } from '#slidev/global-layers'
10
10
 
11
11
  const { nav } = defineProps<{
12
12
  nav: SlidevContextNav
@@ -1,16 +1,16 @@
1
1
  <script setup lang="ts">
2
2
  import { useEventListener } from '@vueuse/core'
3
3
  import { computed, ref, watchEffect } from 'vue'
4
- import { breakpoints, showOverview, windowSize } from '../state'
5
- import { currentOverviewPage, overviewRowCount } from '../logic/overview'
6
4
  import { createFixedClicks } from '../composables/useClicks'
7
- import { CLICKS_MAX } from '../constants'
8
5
  import { useNav } from '../composables/useNav'
9
- import { pathPrefix } from '../env'
10
- import SlideContainer from './SlideContainer.vue'
11
- import SlideWrapper from './SlideWrapper.vue'
6
+ import { CLICKS_MAX } from '../constants'
7
+ import { configs, pathPrefix } from '../env'
8
+ import { currentOverviewPage, overviewRowCount } from '../logic/overview'
9
+ import { breakpoints, showOverview, windowSize } from '../state'
12
10
  import DrawingPreview from './DrawingPreview.vue'
13
11
  import IconButton from './IconButton.vue'
12
+ import SlideContainer from './SlideContainer.vue'
13
+ import SlideWrapper from './SlideWrapper.vue'
14
14
 
15
15
  const { currentSlideNo, go: goSlide, slides } = useNav()
16
16
 
@@ -109,7 +109,7 @@ watchEffect(() => {
109
109
  >
110
110
  <div
111
111
  v-if="showOverview"
112
- class="fixed left-0 right-0 top-0 h-[calc(var(--vh,1vh)*100)] z-20 bg-main !bg-opacity-75 p-16 py-20 overflow-y-auto backdrop-blur-5px"
112
+ class="fixed left-0 right-0 top-0 h-[calc(var(--vh,1vh)*100)] z-20 bg-main !bg-opacity-75 p-16 py-20 overflow-y-auto backdrop-blur-5px select-none"
113
113
  @click="close"
114
114
  >
115
115
  <div
@@ -128,6 +128,8 @@ watchEffect(() => {
128
128
  >
129
129
  <SlideContainer
130
130
  :key="route.no"
131
+ :no="route.no"
132
+ :use-snapshot="configs.overviewSnapshots"
131
133
  :width="cardWidth"
132
134
  class="pointer-events-none"
133
135
  >
@@ -4,8 +4,8 @@ import { onMounted, watch } from 'vue'
4
4
  import { recorder } from '../logic/recording'
5
5
  import { currentCamera, showRecordingDialog } from '../state'
6
6
  import DevicesList from './DevicesList.vue'
7
- import MenuButton from './MenuButton.vue'
8
7
  import IconButton from './IconButton.vue'
8
+ import MenuButton from './MenuButton.vue'
9
9
 
10
10
  const {
11
11
  recording,
@@ -2,8 +2,8 @@
2
2
  import { useVModel } from '@vueuse/core'
3
3
  import { nextTick } from 'vue'
4
4
  import { getFilename, mimeType, recordCamera, recorder, recordingName } from '../logic/recording'
5
- import Modal from './Modal.vue'
6
5
  import DevicesList from './DevicesList.vue'
6
+ import Modal from './Modal.vue'
7
7
 
8
8
  const props = defineProps({
9
9
  modelValue: {
@@ -1,7 +1,7 @@
1
1
  <script setup lang="ts">
2
- import { useVModel } from '@vueuse/core'
3
2
  import type { PropType } from 'vue'
4
3
  import type { SelectionItem } from './types'
4
+ import { useVModel } from '@vueuse/core'
5
5
 
6
6
  const props = defineProps({
7
7
  modelValue: {
@@ -1,8 +1,8 @@
1
1
  <script setup lang="ts">
2
+ import type { SelectionItem } from './types'
2
3
  import { useWakeLock } from '@vueuse/core'
3
4
  import { slideScale, wakeLockEnabled } from '../state'
4
5
  import SelectList from './SelectList.vue'
5
- import type { SelectionItem } from './types'
6
6
 
7
7
  const scaleItems: SelectionItem<number>[] = [
8
8
  {
@@ -1,6 +1,6 @@
1
1
  <script setup lang="ts">
2
- import { ref, shallowRef } from 'vue'
3
2
  import { getHighlighter } from '#slidev/shiki'
3
+ import { ref, shallowRef } from 'vue'
4
4
 
5
5
  const props = defineProps<{
6
6
  placeholder?: string
@@ -1,9 +1,9 @@
1
1
  <script setup lang="ts">
2
2
  import { throttledWatch, useEventListener } from '@vueuse/core'
3
3
  import { computed, ref, watch } from 'vue'
4
- import { activeElement, editorHeight, editorWidth, isInputting, showEditor, isEditorVertical as vertical } from '../state'
5
4
  import { useNav } from '../composables/useNav'
6
5
  import { useDynamicSlideInfo } from '../composables/useSlideInfo'
6
+ import { activeElement, editorHeight, editorWidth, isInputting, showEditor, isEditorVertical as vertical } from '../state'
7
7
  import IconButton from './IconButton.vue'
8
8
  import ShikiEditor from './ShikiEditor.vue'
9
9
 
@@ -17,18 +17,16 @@ const tab = ref<'content' | 'note'>('content')
17
17
  const content = ref('')
18
18
  const note = ref('')
19
19
  const dirty = ref(false)
20
- const frontmatter = ref<any>({})
21
20
 
22
21
  const { info, update } = useDynamicSlideInfo(currentSlideNo)
23
22
 
24
23
  watch(
25
24
  info,
26
25
  (v) => {
27
- frontmatter.value = v?.frontmatter || {}
28
-
29
26
  if (!isInputting.value) {
30
27
  note.value = (v?.note || '').trim()
31
- content.value = (v?.content || '').trim()
28
+ const frontmatterPart = v?.frontmatterRaw?.trim() ? `---\n${v.frontmatterRaw.trim()}\n---\n\n` : ''
29
+ content.value = frontmatterPart + (v?.content || '').trim()
32
30
  dirty.value = false
33
31
  }
34
32
  },
@@ -37,10 +35,17 @@ watch(
37
35
 
38
36
  async function save() {
39
37
  dirty.value = false
38
+
39
+ let frontmatterRaw: string | undefined
40
+ const contentOnly = content.value.trim().replace(/^---\n([\s\S]*?)\n---\n/, (_, f) => {
41
+ frontmatterRaw = f
42
+ return ''
43
+ })
44
+
40
45
  await update({
41
46
  note: note.value || undefined,
42
- content: content.value,
43
- // frontmatter: frontmatter.value,
47
+ content: contentOnly,
48
+ frontmatterRaw,
44
49
  })
45
50
  }
46
51
 
@@ -1,9 +1,10 @@
1
1
  <script setup lang="ts">
2
2
  import { provideLocal, useElementSize, useStyleTag } from '@vueuse/core'
3
- import { computed, ref } from 'vue'
3
+ import { computed, onMounted, ref } from 'vue'
4
+ import { useNav } from '../composables/useNav'
4
5
  import { injectionSlideElement, injectionSlideScale } from '../constants'
5
6
  import { slideAspect, slideHeight, slideWidth } from '../env'
6
- import { useNav } from '../composables/useNav'
7
+ import { snapshotManager } from '../logic/snapshot'
7
8
  import { slideScale } from '../state'
8
9
 
9
10
  const props = defineProps({
@@ -17,6 +18,14 @@ const props = defineProps({
17
18
  type: Boolean,
18
19
  default: false,
19
20
  },
21
+ no: {
22
+ type: Number,
23
+ required: false,
24
+ },
25
+ useSnapshot: {
26
+ type: Boolean,
27
+ default: false,
28
+ },
20
29
  })
21
30
 
22
31
  const { isPrintMode } = useNav()
@@ -54,15 +63,35 @@ if (props.isMain)
54
63
 
55
64
  provideLocal(injectionSlideScale, scale)
56
65
  provideLocal(injectionSlideElement, slideElement)
66
+
67
+ const snapshot = computed(() => {
68
+ if (!props.useSnapshot || props.no == null)
69
+ return undefined
70
+ return snapshotManager.getSnapshot(props.no)
71
+ })
72
+
73
+ onMounted(() => {
74
+ if (container.value && props.useSnapshot && props.no != null) {
75
+ snapshotManager.captureSnapshot(props.no, container.value)
76
+ }
77
+ })
57
78
  </script>
58
79
 
59
80
  <template>
60
- <div :id="isMain ? 'slide-container' : undefined" ref="container" class="slidev-slide-container" :style="containerStyle">
81
+ <div v-if="!snapshot" :id="isMain ? 'slide-container' : undefined" ref="container" class="slidev-slide-container" :style="containerStyle">
61
82
  <div :id="isMain ? 'slide-content' : undefined" ref="slideElement" class="slidev-slide-content" :style="contentStyle">
62
83
  <slot />
63
84
  </div>
64
85
  <slot name="controls" />
65
86
  </div>
87
+ <!-- Image preview -->
88
+ <template v-else>
89
+ <img
90
+ :src="snapshot"
91
+ class="w-full object-cover"
92
+ :style="containerStyle"
93
+ >
94
+ </template>
66
95
  </template>
67
96
 
68
97
  <style scoped lang="postcss">
@@ -1,12 +1,12 @@
1
1
  <script setup lang="ts">
2
- import { computed, ref, toRef } from 'vue'
2
+ import type { ClicksContext, RenderContext, SlideRoute } from '@slidev/types'
3
3
  import type { CSSProperties, PropType } from 'vue'
4
+ import { SlideBottom, SlideTop } from '#slidev/global-layers'
4
5
  import { provideLocal } from '@vueuse/core'
5
- import type { ClicksContext, RenderContext, SlideRoute } from '@slidev/types'
6
+ import { computed, ref, toRef } from 'vue'
6
7
  import { injectionClicksContext, injectionCurrentPage, injectionFrontmatter, injectionRenderContext, injectionRoute, injectionSlideZoom } from '../constants'
7
- import { getSlideClass } from '../utils'
8
8
  import { configs } from '../env'
9
- import { SlideBottom, SlideTop } from '#slidev/global-layers'
9
+ import { getSlideClass } from '../utils'
10
10
 
11
11
  const props = defineProps({
12
12
  clicksContext: {