@slidev/client 0.48.0-beta.10 → 0.48.0-beta.11

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.
@@ -10,7 +10,7 @@ Usage:
10
10
  import { computed } from 'vue'
11
11
  import { toArray } from '@antfu/utils'
12
12
  import type { TocItem } from '@slidev/types'
13
- import Titles from '/@slidev/titles.md'
13
+ import Titles from '#slidev/titles.md'
14
14
 
15
15
  const props = withDefaults(defineProps<{
16
16
  level: number
@@ -65,7 +65,8 @@ const styles = computed(() => {
65
65
  .slidev-layout .slidev-toc-item p {
66
66
  margin: 0;
67
67
  }
68
- .slidev-layout .slidev-toc-item div, .slidev-layout .slidev-toc-item div p {
68
+ .slidev-layout .slidev-toc-item div,
69
+ .slidev-layout .slidev-toc-item div p {
69
70
  display: initial;
70
71
  }
71
72
  </style>
@@ -6,7 +6,10 @@ import type { RouteRecordRaw } from 'vue-router'
6
6
  import { currentRoute, isPrintMode, isPrintWithClicks, queryClicks, routeForceRefresh } from '../logic/nav'
7
7
  import { normalizeAtProp } from '../logic/utils'
8
8
 
9
- function useClicksContextBase(getCurrent: () => number, clicksOverrides?: number): ClicksContext {
9
+ /**
10
+ * @internal
11
+ */
12
+ export function useClicksContextBase(getCurrent: () => number, clicksOverrides?: number): ClicksContext {
10
13
  const relativeOffsets: ClicksContext['relativeOffsets'] = new Map()
11
14
  const map: ClicksContext['map'] = shallowReactive(new Map())
12
15
 
package/env.ts CHANGED
@@ -1,15 +1,12 @@
1
- import type { SlidevConfig } from '@slidev/types'
2
- import type { UnwrapNestedRefs } from 'vue'
3
1
  import { computed } from 'vue'
4
2
  import { objectMap } from '@antfu/utils'
3
+ import configs from '#slidev/configs'
5
4
 
6
- // @ts-expect-error missing types
7
- import _configs from '/@slidev/configs'
8
- import type { SlidevContext } from './modules/context'
5
+ export { configs }
9
6
 
10
- export const configs = _configs as SlidevConfig
11
7
  export const slideAspect = configs.aspectRatio ?? (16 / 9)
12
8
  export const slideWidth = configs.canvasWidth ?? 980
9
+
13
10
  // To honor the aspect ratio more as possible, we need to approximate the height to the next integer.
14
11
  // Doing this, we will prevent on print, to create an additional empty white page after each page.
15
12
  export const slideHeight = Math.ceil(slideWidth / slideAspect)
@@ -17,9 +14,3 @@ export const slideHeight = Math.ceil(slideWidth / slideAspect)
17
14
  export const themeVars = computed(() => {
18
15
  return objectMap(configs.themeConfig || {}, (k, v) => [`--slidev-theme-${k}`, v])
19
16
  })
20
-
21
- declare module 'vue' {
22
- interface ComponentCustomProperties {
23
- $slidev: UnwrapNestedRefs<SlidevContext>
24
- }
25
- }
@@ -131,10 +131,8 @@ function setBrushColor(color: typeof brush.color) {
131
131
  </Draggable>
132
132
  </template>
133
133
 
134
- <style lang="postcss">
135
- .v-popper--theme-menu {
136
- .v-popper__arrow-inner {
137
- @apply border-main;
138
- }
134
+ <style>
135
+ .v-popper--theme-menu .v-popper__arrow-inner {
136
+ --uno: border-main;
139
137
  }
140
138
  </style>
@@ -3,7 +3,7 @@ import { computed, ref, watch } from 'vue'
3
3
  import Fuse from 'fuse.js'
4
4
  import { go, rawRoutes } from '../logic/nav'
5
5
  import { activeElement, showGotoDialog } from '../state'
6
- import Titles from '/@slidev/titles.md'
6
+ import Titles from '#slidev/titles.md'
7
7
 
8
8
  const container = ref<HTMLDivElement>()
9
9
  const input = ref<HTMLInputElement>()
@@ -165,10 +165,11 @@ watch(activeElement, () => {
165
165
  </div>
166
166
  </template>
167
167
 
168
- <style scoped lang="postcss">
168
+ <style scoped>
169
169
  .autocomplete-list {
170
- @apply bg-main transform mt-1 overflow-auto;
171
- max-height: calc( 100vh - 100px );
170
+ --uno: bg-main mt-1;
171
+ overflow: auto;
172
+ max-height: calc(100vh - 100px);
172
173
  }
173
174
 
174
175
  .autocomplete {
@@ -10,8 +10,7 @@ import MenuButton from './MenuButton.vue'
10
10
  import VerticalDivider from './VerticalDivider.vue'
11
11
  import IconButton from './IconButton.vue'
12
12
 
13
- // @ts-expect-error virtual module
14
- import CustomNavControls from '/@slidev/custom-nav-controls'
13
+ import CustomNavControls from '#slidev/custom-nav-controls'
15
14
 
16
15
  const props = defineProps({
17
16
  persist: {
@@ -1,6 +1,6 @@
1
1
  <script setup lang="ts">
2
+ import { nextTick, ref, watch, watchEffect } from 'vue'
2
3
  import { ignorableWatch, onClickOutside, useVModel } from '@vueuse/core'
3
- import { ref, watch, watchEffect } from 'vue'
4
4
  import { useDynamicSlideInfo } from '../logic/note'
5
5
  import NoteDisplay from './NoteDisplay.vue'
6
6
 
@@ -20,6 +20,9 @@ const props = defineProps({
20
20
  placeholder: {
21
21
  default: 'No notes for this slide',
22
22
  },
23
+ autoHeight: {
24
+ default: false,
25
+ },
23
26
  })
24
27
 
25
28
  const emit = defineEmits([
@@ -66,6 +69,27 @@ watchEffect(() => {
66
69
  onClickOutside(input, () => {
67
70
  editing.value = false
68
71
  })
72
+
73
+ function calculateHeight() {
74
+ if (!props.autoHeight || !input.value || !editing.value)
75
+ return
76
+ if (input.value.scrollHeight > input.value.clientHeight)
77
+ input.value.style.height = `${input.value.scrollHeight}px`
78
+ }
79
+
80
+ const inputHeight = ref<number | null>()
81
+ watchEffect(() => {
82
+ calculateHeight()
83
+ })
84
+ watch(
85
+ note,
86
+ () => {
87
+ nextTick(() => {
88
+ calculateHeight()
89
+ })
90
+ },
91
+ { flush: 'post' },
92
+ )
69
93
  </script>
70
94
 
71
95
  <template>
@@ -83,7 +107,7 @@ onClickOutside(input, () => {
83
107
  v-model="note"
84
108
  class="prose resize-none overflow-auto outline-none bg-transparent block border-primary border-2"
85
109
  style="line-height: 1.75;"
86
- :style="props.style"
110
+ :style="[props.style, inputHeight != null ? { height: `${inputHeight}px` } : {}]"
87
111
  :class="props.class"
88
112
  :placeholder="placeholder"
89
113
  @keydown.esc=" editing = false"
@@ -9,11 +9,8 @@ import { getSlideClass } from '../utils'
9
9
  import type { SlidevContextNav } from '../modules/context'
10
10
  import SlideWrapper from './SlideWrapper'
11
11
 
12
- // @ts-expect-error virtual module
13
- import GlobalTop from '/@slidev/global-components/top'
14
-
15
- // @ts-expect-error virtual module
16
- import GlobalBottom from '/@slidev/global-components/bottom'
12
+ import GlobalTop from '#slidev/global-components/top'
13
+ import GlobalBottom from '#slidev/global-components/bottom'
17
14
 
18
15
  const props = defineProps<{
19
16
  clicksContext: ClicksContext
@@ -108,18 +108,18 @@ async function start() {
108
108
  }
109
109
  }
110
110
 
111
- input[type="text"] {
111
+ input[type='text'] {
112
112
  @apply border border-main rounded px-2 py-1;
113
113
  }
114
114
 
115
115
  button {
116
116
  @apply bg-orange-400 text-white px-4 py-1 rounded border-b-2 border-orange-600;
117
- @apply hover:(bg-orange-500 border-orange-700)
117
+ @apply hover:(bg-orange-500 border-orange-700);
118
118
  }
119
119
 
120
120
  button.cancel {
121
121
  @apply bg-gray-400 bg-opacity-50 text-white px-4 py-1 rounded border-b-2 border-main;
122
- @apply hover:(bg-opacity-75 border-opacity-75)
122
+ @apply hover:(bg-opacity-75 border-opacity-75);
123
123
  }
124
124
  }
125
125
  </style>
@@ -3,7 +3,7 @@ import { provideLocal, useElementSize, useStyleTag } from '@vueuse/core'
3
3
  import { computed, ref, watchEffect } from 'vue'
4
4
  import { configs, slideAspect, slideHeight, slideWidth } from '../env'
5
5
  import { injectionSlideScale } from '../constants'
6
- import { isPrintMode } from '../logic/nav'
6
+ import { clicksDirection, isPrintMode } from '../logic/nav'
7
7
 
8
8
  const props = defineProps({
9
9
  width: {
@@ -55,6 +55,8 @@ const style = computed(() => ({
55
55
 
56
56
  const className = computed(() => ({
57
57
  'select-none': !configs.selectable,
58
+ 'slidev-nav-go-forward': clicksDirection.value > 0,
59
+ 'slidev-nav-go-backward': clicksDirection.value < 0,
58
60
  }))
59
61
 
60
62
  if (props.isMain) {
@@ -69,8 +71,8 @@ provideLocal(injectionSlideScale, scale as any)
69
71
  </script>
70
72
 
71
73
  <template>
72
- <div id="slide-container" ref="root" :class="className">
73
- <div id="slide-content" :style="style">
74
+ <div id="slide-container" ref="root" class="slidev-slides-container" :class="className">
75
+ <div id="slide-content" class="slidev-slide-content" :style="style">
74
76
  <slot />
75
77
  </div>
76
78
  <slot name="controls" />
@@ -6,14 +6,11 @@ import { useViewTransition } from '../composables/useViewTransition'
6
6
  import { skipTransition } from '../composables/hmr'
7
7
  import { usePrimaryClicks } from '../composables/useClicks'
8
8
  import SlideWrapper from './SlideWrapper'
9
-
10
- // @ts-expect-error virtual module
11
- import GlobalTop from '/@slidev/global-components/top'
12
-
13
- // @ts-expect-error virtual module
14
- import GlobalBottom from '/@slidev/global-components/bottom'
15
9
  import PresenterMouse from './PresenterMouse.vue'
16
10
 
11
+ import GlobalTop from '#slidev/global-components/top'
12
+ import GlobalBottom from '#slidev/global-components/bottom'
13
+
17
14
  defineProps<{
18
15
  renderContext: 'slide' | 'presenter'
19
16
  }>()
@@ -77,10 +74,12 @@ function onAfterLeave() {
77
74
 
78
75
  <style scoped>
79
76
  #slideshow {
80
- @apply h-full;
77
+ height: 100%;
81
78
  }
82
79
 
83
80
  #slideshow > div {
84
- @apply h-full w-full absolute;
81
+ position: absolute;
82
+ height: 100%;
83
+ width: 100%;
85
84
  }
86
85
  </style>
@@ -51,9 +51,15 @@ const props = defineProps({
51
51
  grid-template-rows: repeat(2, 1fr);
52
52
  }
53
53
 
54
- .col-header { grid-area: 1 / 1 / 2 / 3; }
55
- .col-left { grid-area: 2 / 1 / 3 / 2; }
56
- .col-right { grid-area: 2 / 2 / 3 / 3; }
54
+ .col-header {
55
+ grid-area: 1 / 1 / 2 / 3;
56
+ }
57
+ .col-left {
58
+ grid-area: 2 / 1 / 3 / 2;
59
+ }
60
+ .col-right {
61
+ grid-area: 2 / 2 / 3 / 3;
62
+ }
57
63
  .col-bottom {
58
64
  align-self: end;
59
65
  grid-area: 3 / 1 / 3 / 3;
package/logic/nav.ts CHANGED
@@ -22,6 +22,7 @@ nextTick(() => {
22
22
  })
23
23
 
24
24
  export const navDirection = ref(0)
25
+ export const clicksDirection = ref(0)
25
26
 
26
27
  export const route = computed(() => router.currentRoute.value)
27
28
 
@@ -84,6 +85,7 @@ watch(currentRoute, (next, prev) => {
84
85
  })
85
86
 
86
87
  export async function next() {
88
+ clicksDirection.value = 1
87
89
  if (clicksTotal.value <= queryClicks.value)
88
90
  await nextSlide()
89
91
  else
@@ -91,6 +93,7 @@ export async function next() {
91
93
  }
92
94
 
93
95
  export async function prev() {
96
+ clicksDirection.value = -1
94
97
  if (queryClicks.value <= 0)
95
98
  await prevSlide()
96
99
  else
@@ -102,11 +105,13 @@ export function getPath(no: number | string) {
102
105
  }
103
106
 
104
107
  export async function nextSlide() {
108
+ clicksDirection.value = 1
105
109
  if (currentPage.value < rawRoutes.length)
106
110
  await go(currentPage.value + 1)
107
111
  }
108
112
 
109
113
  export async function prevSlide(lastClicks = true) {
114
+ clicksDirection.value = -1
110
115
  const next = Math.max(1, currentPage.value - 1)
111
116
  await go(next)
112
117
  if (lastClicks && clicksTotal.value)
package/main.ts CHANGED
@@ -1,3 +1,5 @@
1
+ /// <reference types="@slidev/types/client" />
2
+
1
3
  import { createApp } from 'vue'
2
4
  import { createHead } from '@unhead/vue'
3
5
  import App from './App.vue'
@@ -7,7 +9,7 @@ import { createVClickDirectives } from './modules/v-click'
7
9
  import { createVMarkDirective } from './modules/v-mark'
8
10
  import { createSlidevContext } from './modules/context'
9
11
 
10
- import '/@slidev/styles'
12
+ import '#slidev/styles'
11
13
 
12
14
  const app = createApp(App)
13
15
  app.use(router)
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.10",
4
+ "version": "0.48.0-beta.11",
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/types": "0.48.0-beta.10",
58
- "@slidev/parser": "0.48.0-beta.10"
57
+ "@slidev/parser": "0.48.0-beta.11",
58
+ "@slidev/types": "0.48.0-beta.11"
59
59
  },
60
60
  "devDependencies": {
61
61
  "vite": "^5.1.4"
@@ -1,9 +1,11 @@
1
1
  <script setup lang="ts">
2
- import { nextTick, onMounted, reactive, ref } from 'vue'
2
+ import { computed, nextTick, onMounted, reactive, ref } from 'vue'
3
3
  import { useHead } from '@unhead/vue'
4
+ import type { RouteRecordRaw } from 'vue-router'
5
+ import type { ClicksContext } from 'packages/types'
4
6
  import { themeVars } from '../env'
5
7
  import { rawRoutes } from '../logic/nav'
6
- import { useFixedClicks } from '../composables/useClicks'
8
+ import { useClicksContextBase } from '../composables/useClicks'
7
9
  import { isColorSchemaConfigured, isDark, toggleDark } from '../logic/dark'
8
10
  import { getSlideClass } from '../utils'
9
11
  import SlideContainer from '../internals/SlideContainer.vue'
@@ -21,6 +23,25 @@ useHead({
21
23
  const blocks: Map<number, HTMLElement> = reactive(new Map())
22
24
  const activeBlocks = ref<number[]>([])
23
25
  const edittingNote = ref<number | null>(null)
26
+ const wordCounts = computed(() => rawRoutes.map(route => wordCount(route.meta?.slide?.note || '')))
27
+ const totalWords = computed(() => wordCounts.value.reduce((a, b) => a + b, 0))
28
+ const totalClicks = computed(() => rawRoutes.map(route => getSlideClicks(route)).reduce((a, b) => a + b, 0))
29
+
30
+ const clicksContextMap = new WeakMap<RouteRecordRaw, ClicksContext>()
31
+ function getClickContext(route: RouteRecordRaw) {
32
+ // We create a local clicks context to calculate the total clicks of the slide
33
+ if (!clicksContextMap.has(route))
34
+ clicksContextMap.set(route, useClicksContextBase(() => 999999, route?.meta?.clicks))
35
+ return clicksContextMap.get(route)!
36
+ }
37
+
38
+ function getSlideClicks(route: RouteRecordRaw) {
39
+ return route.meta?.clicks || getClickContext(route)?.total
40
+ }
41
+
42
+ function wordCount(str: string) {
43
+ return str.match(/[\w\d\’\'-]+/gi)?.length || 0
44
+ }
24
45
 
25
46
  function isElementInViewport(el: HTMLElement) {
26
47
  const rect = el.getBoundingClientRect()
@@ -109,9 +130,17 @@ onMounted(() => {
109
130
  class="relative border-t border-main of-hidden flex gap-4 min-h-50 group"
110
131
  >
111
132
  <div class="select-none w-13 text-right my4">
112
- <div class="text-3xl op20">
133
+ <div class="text-3xl op20 mb2">
113
134
  {{ idx + 1 }}
114
135
  </div>
136
+ <div
137
+ v-if="getSlideClicks(route)"
138
+ class="flex gap-0.5 op50 items-center justify-end"
139
+ :title="`Clicks in this slide: ${getSlideClicks(route)}`"
140
+ >
141
+ <carbon:cursor-1 text-sm />
142
+ {{ getSlideClicks(route) }}
143
+ </div>
115
144
  </div>
116
145
  <div
117
146
  class="border rounded border-main overflow-hidden bg-main my5 select-none h-max"
@@ -127,7 +156,7 @@ onMounted(() => {
127
156
  <SlideWrapper
128
157
  :is="route.component"
129
158
  v-if="route?.component"
130
- :clicks-context="useFixedClicks(route, 99999)[1]"
159
+ :clicks-context="getClickContext(route)"
131
160
  :class="getSlideClass(route)"
132
161
  :route="route"
133
162
  render-context="overview"
@@ -148,10 +177,25 @@ onMounted(() => {
148
177
  <NoteEditor
149
178
  :no="idx"
150
179
  class="max-w-250 w-250 text-lg rounded p3"
180
+ :auto-height="true"
151
181
  :editing="edittingNote === idx"
182
+ @dblclick="edittingNote !== idx ? edittingNote = idx : null"
152
183
  @update:editing="edittingNote = null"
153
184
  />
185
+ <div
186
+ v-if="wordCounts[idx] > 0"
187
+ class="select-none absolute bottom-0 right-0 bg-main rounded-tl p2 op35 text-xs"
188
+ >
189
+ {{ wordCounts[idx] }} words
190
+ </div>
154
191
  </div>
155
192
  </main>
193
+ <div class="absolute top-0 right-0 px3 py1.5 border-b border-l rounded-lb bg-main border-main select-none">
194
+ <div class="text-xs op50">
195
+ {{ rawRoutes.length }} slides ·
196
+ {{ totalClicks + rawRoutes.length - 1 }} clicks ·
197
+ {{ totalWords }} words
198
+ </div>
199
+ </div>
156
200
  </div>
157
201
  </template>
@@ -185,26 +185,26 @@ onMounted(() => {
185
185
  <SlidesOverview v-model="showOverview" />
186
186
  </template>
187
187
 
188
- <style lang="postcss" scoped>
188
+ <style scoped>
189
189
  .slidev-presenter {
190
190
  --slidev-controls-foreground: current;
191
191
  }
192
192
 
193
- .timer-btn:hover {
194
- & > :first-child {
195
- @apply opacity-0;
196
- }
197
- & > :last-child {
198
- @apply opacity-100;
199
- }
193
+ .timer-btn:hover > :first-child {
194
+ opacity: 0;
195
+ }
196
+ .timer-btn:hover > :last-child {
197
+ opacity: 1;
200
198
  }
201
199
 
202
200
  .section-title {
203
- @apply px-4 py-2 text-xl;
201
+ --uno: px-4 py-2 text-xl;
204
202
  }
205
203
 
206
204
  .grid-container {
207
- @apply h-full w-full bg-gray-400 bg-opacity-15;
205
+ --uno: bg-active;
206
+ height: 100%;
207
+ width: 100%;
208
208
  display: grid;
209
209
  gap: 1px 1px;
210
210
  }
@@ -213,20 +213,20 @@ onMounted(() => {
213
213
  grid-template-columns: 1fr 1fr;
214
214
  grid-template-rows: min-content 2fr 1fr min-content;
215
215
  grid-template-areas:
216
- "top top"
217
- "main main"
218
- "note next"
219
- "bottom bottom";
216
+ 'top top'
217
+ 'main main'
218
+ 'note next'
219
+ 'bottom bottom';
220
220
  }
221
221
 
222
222
  .grid-container.layout2 {
223
223
  grid-template-columns: 3fr 2fr;
224
224
  grid-template-rows: min-content 2fr 1fr min-content;
225
225
  grid-template-areas:
226
- "top top"
227
- "note main"
228
- "note next"
229
- "bottom bottom";
226
+ 'top top'
227
+ 'note main'
228
+ 'note next'
229
+ 'bottom bottom';
230
230
  }
231
231
 
232
232
  @media (max-aspect-ratio: 3/5) {
@@ -234,11 +234,11 @@ onMounted(() => {
234
234
  grid-template-columns: 1fr;
235
235
  grid-template-rows: min-content 1fr 1fr 1fr min-content;
236
236
  grid-template-areas:
237
- "top"
238
- "main"
239
- "note"
240
- "next"
241
- "bottom";
237
+ 'top'
238
+ 'main'
239
+ 'note'
240
+ 'next'
241
+ 'bottom';
242
242
  }
243
243
  }
244
244
 
@@ -247,38 +247,40 @@ onMounted(() => {
247
247
  grid-template-columns: 1fr 1.1fr 0.9fr;
248
248
  grid-template-rows: min-content 1fr 2fr min-content;
249
249
  grid-template-areas:
250
- "top top top"
251
- "main main next"
252
- "main main note"
253
- "bottom bottom bottom";
250
+ 'top top top'
251
+ 'main main next'
252
+ 'main main note'
253
+ 'bottom bottom bottom';
254
254
  }
255
255
  }
256
256
 
257
257
  .progress-bar {
258
- @apply fixed left-0 right-0 bottom-0;
258
+ --uno: fixed left-0 right-0 bottom-0;
259
259
  }
260
260
 
261
261
  .grid-section {
262
- @apply bg-main;
263
-
264
- &.top {
265
- grid-area: top;
266
- }
267
- &.main {
268
- grid-area: main;
269
- }
270
- &.next {
271
- grid-area: next;
272
- }
273
- &.note {
274
- grid-area: note;
275
- }
276
- &.bottom {
277
- grid-area: bottom;
278
- }
262
+ --uno: bg-main;
279
263
  }
280
264
 
265
+ .grid-section.top {
266
+ grid-area: top;
267
+ }
268
+ .grid-section.main {
269
+ grid-area: main;
270
+ }
271
+ .grid-section.next {
272
+ grid-area: next;
273
+ }
274
+ .grid-section.note {
275
+ grid-area: note;
276
+ }
277
+ .grid-section.bottom {
278
+ grid-area: bottom;
279
+ }
281
280
  .context {
282
- @apply absolute top-0 left-0 px-1 text-xs bg-gray-400 bg-opacity-50 opacity-75 rounded-br-md;
281
+ position: absolute;
282
+ top: 0;
283
+ left: 0;
284
+ --uno: px-1 text-xs bg-gray-400 bg-opacity-50 opacity-75 rounded-br-md;
283
285
  }
284
286
  </style>
package/routes.ts CHANGED
@@ -1,15 +1,10 @@
1
1
  import type { RouteLocationNormalized, RouteRecordRaw } from 'vue-router'
2
2
  import { createRouter, createWebHashHistory, createWebHistory } from 'vue-router'
3
- import type { TransitionGroupProps } from 'vue'
4
- import type { ClicksContext, SlideInfo } from '@slidev/types'
5
3
 
6
- // @ts-expect-error missing types
7
- import _rawRoutes, { redirects } from '/@slidev/routes'
4
+ import { rawRoutes, redirects } from '#slidev/routes'
5
+ import configs from '#slidev/configs'
8
6
 
9
- // @ts-expect-error missing types
10
- import _configs from '/@slidev/configs'
11
-
12
- export const rawRoutes = _rawRoutes as RouteRecordRaw[]
7
+ export { rawRoutes }
13
8
 
14
9
  export const routes: RouteRecordRaw[] = [
15
10
  {
@@ -34,12 +29,12 @@ export const routes: RouteRecordRaw[] = [
34
29
 
35
30
  if (__SLIDEV_FEATURE_PRESENTER__) {
36
31
  function passwordGuard(to: RouteLocationNormalized) {
37
- if (!_configs.remote || _configs.remote === to.query.password)
32
+ if (!configs.remote || configs.remote === to.query.password)
38
33
  return true
39
- if (_configs.remote && to.query.password === undefined) {
34
+ if (configs.remote && to.query.password === undefined) {
40
35
  // eslint-disable-next-line no-alert
41
36
  const password = prompt('Enter password')
42
- if (_configs.remote === password)
37
+ if (configs.remote === password)
43
38
  return true
44
39
  }
45
40
  if (to.params.no)
@@ -87,28 +82,3 @@ export const router = createRouter({
87
82
  : createWebHistory(import.meta.env.BASE_URL),
88
83
  routes,
89
84
  })
90
-
91
- declare module 'vue-router' {
92
- interface RouteMeta {
93
- // inherited from frontmatter
94
- layout: string
95
- name?: string
96
- class?: string
97
- clicks?: number
98
- transition?: string | TransitionGroupProps | undefined
99
- preload?: boolean
100
-
101
- // slide info
102
- slide?: Omit<SlideInfo, 'source'> & {
103
- noteHTML: string
104
- filepath: string
105
- start: number
106
- id: number
107
- no: number
108
- }
109
-
110
- // private fields
111
- __clicksContext: null | ClicksContext
112
- __preloaded?: boolean
113
- }
114
- }
package/shim-vue.d.ts ADDED
@@ -0,0 +1,35 @@
1
+ declare module 'vue' {
2
+ import type { UnwrapNestedRefs } from 'vue'
3
+ import type { SlidevContext } from './modules/context'
4
+
5
+ interface ComponentCustomProperties {
6
+ $slidev: UnwrapNestedRefs<SlidevContext>
7
+ }
8
+ }
9
+
10
+ declare module 'vue-router' {
11
+ interface RouteMeta {
12
+ // inherited from frontmatter
13
+ layout: string
14
+ name?: string
15
+ class?: string
16
+ clicks?: number
17
+ transition?: string | TransitionGroupProps | undefined
18
+ preload?: boolean
19
+
20
+ // slide info
21
+ slide?: Omit<SlideInfo, 'source'> & {
22
+ noteHTML: string
23
+ filepath: string
24
+ start: number
25
+ id: number
26
+ no: number
27
+ }
28
+
29
+ // private fields
30
+ __clicksContext: null | ClicksContext
31
+ __preloaded?: boolean
32
+ }
33
+ }
34
+
35
+ export {}
package/shim.d.ts CHANGED
@@ -1,9 +1,3 @@
1
- declare interface Window {
2
- // extend the window
3
- }
4
-
5
- declare module '*.vue';
6
-
7
1
  // with unplugin-vue-markdown, markdowns can be treat as Vue components
8
2
  declare module '*.md' {
9
3
  import type { ComponentOptions } from 'vue'
@@ -12,12 +6,6 @@ declare module '*.md' {
12
6
  export default component
13
7
  }
14
8
 
15
- declare module '/@slidev/configs' {
16
- import { SlidevConfig } from '@slidev/types'
17
-
18
- export default SlidevConfig
19
- }
20
-
21
9
  declare module 'mermaid/dist/mermaid.esm.mjs' {
22
10
  import Mermaid from 'mermaid/dist/mermaid.d.ts'
23
11
 
package/styles/code.css CHANGED
@@ -59,7 +59,9 @@ html:not(.dark) .shiki span {
59
59
  .slidev-code-line-numbers .slidev-code code .line::before {
60
60
  content: counter(step);
61
61
  counter-increment: step;
62
- @apply w-4 mr-6 inline-block text-right text-gray-400 dark:text-gray-600;
62
+ display: inline-block;
63
+ text-align: right;
64
+ --uno: w-4 mr-6 text-gray-400 dark:text-gray-600;
63
65
  }
64
66
 
65
67
  /* Inline Code */
@@ -67,7 +69,7 @@ html:not(.dark) .shiki span {
67
69
  font-size: 0.9em;
68
70
  background: var(--slidev-code-background);
69
71
  border-radius: var(--slidev-code-radius);
70
- @apply font-light py-0.5 px-1.5;
72
+ --uno: font-light py-0.5 px-1.5;
71
73
  }
72
74
 
73
75
  .slidev-layout :not(pre) > code:before {
@@ -82,4 +84,6 @@ html:not(.dark) .shiki span {
82
84
  }
83
85
 
84
86
  /* CodeMirror */
85
- .CodeMirror pre.CodeMirror-placeholder { opacity: 0.4; }
87
+ .CodeMirror pre.CodeMirror-placeholder {
88
+ opacity: 0.4;
89
+ }
package/styles/index.css CHANGED
@@ -23,15 +23,16 @@ html {
23
23
  }
24
24
 
25
25
  .slidev-icon-btn.shallow {
26
- @apply opacity-30
26
+ opacity: 0.3;
27
27
  }
28
28
 
29
29
  .slidev-icon-btn.active {
30
- @apply opacity-100
30
+ opacity: 1;
31
31
  }
32
32
 
33
33
  .slidev-icon-btn.disabled {
34
- @apply opacity-25 pointer-events-none;
34
+ opacity: 0.25;
35
+ pointer-events: none;
35
36
  }
36
37
 
37
38
  .slidev-vclick-target {
@@ -39,11 +40,13 @@ html {
39
40
  }
40
41
 
41
42
  .slidev-vclick-hidden {
42
- @apply !opacity-0 !pointer-events-none;
43
+ opacity: 0 !important;
44
+ pointer-events: none !important;
45
+ user-select: none !important;
43
46
  }
44
47
 
45
48
  .slidev-vclick-fade {
46
- @apply opacity-50;
49
+ opacity: 0.5;
47
50
  }
48
51
 
49
52
  .slidev-icon {
@@ -53,7 +56,11 @@ html {
53
56
  }
54
57
 
55
58
  .slidev-page {
56
- @apply absolute top-0 left-0 right-0 w-full relative;
59
+ position: relative;
60
+ top: 0;
61
+ left: 0;
62
+ right: 0;
63
+ width: 100%;
57
64
  }
58
65
 
59
66
  /* Transform the position back for Rough Notation (v-mark) */
package/styles/katex.css CHANGED
@@ -2,4 +2,4 @@
2
2
  }
3
3
  .slidev-katex-wrapper .mord.dishonored {
4
4
  opacity: 0.3;
5
- }
5
+ }
@@ -1,7 +1,8 @@
1
1
  .slidev-layout {
2
2
  @apply px-14 py-10 text-[1.1rem] h-full;
3
3
 
4
- pre, code {
4
+ pre,
5
+ code {
5
6
  @apply select-text;
6
7
  }
7
8
 
@@ -79,11 +80,13 @@
79
80
  @apply border-current border-b border-dashed hover:text-primary hover:border-solid;
80
81
  }
81
82
 
82
- td, th {
83
+ td,
84
+ th {
83
85
  @apply p-2 py-3;
84
86
  }
85
87
 
86
- b, strong {
88
+ b,
89
+ strong {
87
90
  @apply font-600;
88
91
  }
89
92
 
@@ -94,8 +97,8 @@
94
97
  }
95
98
 
96
99
  .slidev-layout,
97
- [dir=ltr],
98
- .slidev-layout [dir=ltr] {
100
+ [dir='ltr'],
101
+ .slidev-layout [dir='ltr'] {
99
102
  h1 {
100
103
  @apply -ml-[0.05em] mr-0;
101
104
  }
@@ -109,10 +112,10 @@
109
112
  }
110
113
  }
111
114
 
112
- [dir=rtl],
113
- .slidev-layout [dir=rtl] {
115
+ [dir='rtl'],
116
+ .slidev-layout [dir='rtl'] {
114
117
  h1 {
115
- @apply -mr-[0.05em] ml-0;
118
+ @apply -mr-[0.05em] ml-0;
116
119
  }
117
120
 
118
121
  h6 {
package/styles/vars.css CHANGED
@@ -7,7 +7,7 @@
7
7
  --slidev-code-line-height: 18px;
8
8
  --slidev-code-radius: 4px;
9
9
  --slidev-code-margin: 4px 0;
10
- --slidev-theme-primary: #3AB9D5;
10
+ --slidev-theme-primary: #3ab9d5;
11
11
 
12
12
  --slidev-transition-duration: 0.5s;
13
13
  --slidev-slide-container-background: black;
package/uno.config.ts CHANGED
@@ -8,6 +8,7 @@ import {
8
8
  transformerDirectives,
9
9
  transformerVariantGroup,
10
10
  } from 'unocss'
11
+ import { variantMatcher } from '@unocss/preset-mini/utils'
11
12
 
12
13
  export default defineConfig({
13
14
  safelist: [
@@ -28,6 +29,13 @@ export default defineConfig({
28
29
  'abs-bl': 'absolute bottom-0 left-0',
29
30
  'abs-br': 'absolute bottom-0 right-0',
30
31
  },
32
+ // Slidev Specific Variants, probably extrat to a preset later
33
+ variants: [
34
+ // `forward:` and `backward:` variant to selectively apply styles based on the direction of the slide
35
+ // For example, `forward:text-red` will only apply to the slides that are navigated forward
36
+ variantMatcher('forward', input => ({ prefix: `.slidev-nav-go-forward ${input.prefix}` })),
37
+ variantMatcher('backward', input => ({ prefix: `.slidev-nav-go-backward ${input.prefix}` })),
38
+ ],
31
39
  presets: [
32
40
  presetUno(),
33
41
  presetAttributify(),