Skip to content

Commit

Permalink
chore: update
Browse files Browse the repository at this point in the history
  • Loading branch information
KermanX committed Jun 28, 2024
1 parent e700071 commit 6ea7189
Show file tree
Hide file tree
Showing 13 changed files with 96 additions and 104 deletions.
31 changes: 14 additions & 17 deletions packages/client/composables/useClicks.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { clamp, sum } from '@antfu/utils'
import type { ClicksContext, NormalizedRangeClickValue, NormalizedSingleClickValue, RawAtValue, RawSingleAtValue, SlideRoute } from '@slidev/types'
import type { Ref } from 'vue'
import { computed, ref, shallowReactive } from 'vue'
import { routeForceRefresh } from '../logic/route'
import { computed, onMounted, onUnmounted, ref, shallowReactive } from 'vue'

export function normalizeSingleAtValue(at: RawSingleAtValue): NormalizedSingleClickValue {
if (at === false || at === 'false')
Expand Down Expand Up @@ -54,17 +53,19 @@ export function createClicksContextBase(
get isMounted() {
return isMounted.value
},
onMounted: () => {
isMounted.value = true
// Convert maxMap to reactive
maxMap = shallowReactive(maxMap)
// Make sure the query is not greater than the total
context.current = current.value
},
onUnmounted: () => {
isMounted.value = false
relativeSizeMap = new Map()
maxMap = new Map()
setup() {
onMounted(() => {
isMounted.value = true
// Convert maxMap to reactive
maxMap = shallowReactive(maxMap)
// Make sure the query is not greater than the total
context.current = current.value
})
onUnmounted(() => {
isMounted.value = false
relativeSizeMap = new Map()
maxMap = new Map()
})
},
calculateSince(rawAt, size = 1) {
const at = normalizeSingleAtValue(rawAt)
Expand Down Expand Up @@ -144,13 +145,9 @@ export function createClicksContextBase(
maxMap.delete(el)
},
get currentOffset() {
// eslint-disable-next-line no-unused-expressions
routeForceRefresh.value
return sum(...relativeSizeMap.values())
},
get total() {
// eslint-disable-next-line no-unused-expressions
routeForceRefresh.value
return clicksTotalOverrides
?? (isMounted.value
? Math.max(0, ...maxMap.values())
Expand Down
1 change: 0 additions & 1 deletion packages/client/internals/PrintSlideClick.vue
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ provideLocal(injectionSlidevContext, reactive({
<GlobalBottom />

<SlideWrapper
:is="route.component!"
:clicks-context="nav.clicksContext.value"
:class="getSlideClass(route)"
:route="route"
Expand Down
17 changes: 14 additions & 3 deletions packages/client/internals/ShikiEditor.vue
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,28 @@ watchEffect((onCleanup) => {
const highlight = await getHighlighter()
if (canceled)
return
const h = await highlight(c, 'markdown')
const h = await highlight(c, 'markdown', { mergeWhitespaces: 'never' })
let trailingEmptyLines = 0
for (const line of c.split('\n').reverse()) {
if (line.trim() === '')
trailingEmptyLines++
else
break
}
if (canceled)
return
html.value = h
html.value = `${h}${'<br>'.repeat(trailingEmptyLines)}`
}
updateHtml()
})
function setFocus() {
textareaEl.value?.focus()
}
</script>

<template>
<div class="absolute left-3 right-0 inset-y-2 font-mono overflow-x-hidden overflow-y-auto">
<div class="absolute left-3 right-0 inset-y-2 font-mono overflow-x-hidden overflow-y-auto cursor-text" @click="setFocus">
<div class="relative w-full h-max">
<div class="relative w-full h-max" v-html="html" />
<textarea
Expand Down
5 changes: 2 additions & 3 deletions packages/client/internals/SideEditor.vue
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,9 @@ useEventListener('keydown', (e) => {
const contentRef = computed({
get() { return content.value },
set(v) {
if (content.value.trim() !== v.trim()) {
content.value = v
if (content.value.trim() !== v.trim())
dirty.value = true
}
content.value = v
},
})
Expand Down
16 changes: 6 additions & 10 deletions packages/client/internals/SlideContainer.vue
Original file line number Diff line number Diff line change
Expand Up @@ -34,16 +34,12 @@ const scale = computed(() => {
return Math.min(width.value / slideWidth.value, height.value / slideHeight.value)
})
const contentStyle = computed(() => {
// For some unknown reason, remove the following line will cause the style not updated
void container.value
return {
'height': `${slideHeight.value}px`,
'width': `${slideWidth.value}px`,
'transform': `translate(-50%, -50%) scale(${scale.value})`,
'--slidev-slide-scale': scale.value,
}
})
const contentStyle = computed(() => ({
'height': `${slideHeight.value}px`,
'width': `${slideWidth.value}px`,
'transform': `translate(-50%, -50%) scale(${scale.value})`,
'--slidev-slide-scale': scale.value,
}))
const containerStyle = computed(() => props.width
? {
Expand Down
24 changes: 2 additions & 22 deletions packages/client/internals/SlideWrapper.vue
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
<script setup lang="ts">
import { computed, defineAsyncComponent, defineComponent, h, ref, toRef } from 'vue'
import { computed, ref, toRef } from 'vue'
import type { CSSProperties, PropType } from 'vue'
import { provideLocal } from '@vueuse/core'
import type { ClicksContext, RenderContext, SlideRoute } from '@slidev/types'
import { injectionClicksContext, injectionCurrentPage, injectionRenderContext, injectionRoute, injectionSlideZoom } from '../constants'
import { getSlideClass } from '../utils'
import { configs } from '../env'
import SlideLoading from './SlideLoading.vue'
import { SlideBottom, SlideTop } from '#slidev/global-layers'
const props = defineProps({
Expand Down Expand Up @@ -46,25 +45,6 @@ const style = computed<CSSProperties>(() => ({
...zoomStyle.value,
'user-select': configs.selectable ? undefined : 'none',
}))
const SlideComponent = computed(() => {
const loadComponent = props.route.component
const { onMounted, onUnmounted } = props.clicksContext
return defineAsyncComponent({
loader: async () => {
const component = await loadComponent()
return defineComponent({
mounted: onMounted,
unmounted: onUnmounted,
beforeUpdate: onUnmounted,
updated: onMounted,
render: () => h(component.default),
})
},
delay: 300,
loadingComponent: SlideLoading,
})
})
</script>

<template>
Expand All @@ -74,7 +54,7 @@ const SlideComponent = computed(() => {
:style="style"
>
<SlideBottom />
<SlideComponent />
<component :is="props.route.component" />
<SlideTop />
</div>
</template>
Expand Down
2 changes: 1 addition & 1 deletion packages/client/internals/SlidesShow.vue
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ const {
function preloadRoute(route: SlideRoute) {
if (route.meta.preload !== false) {
route.meta.__preloaded = true
route.component()
route.load()
}
}
// preload current, prev and next slides
Expand Down
3 changes: 0 additions & 3 deletions packages/client/logic/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,3 @@ export function useRouteQuery<T extends string | string[]>(
},
})
}

// force update collected elements when the route is fully resolved
export const routeForceRefresh = ref(0)
9 changes: 0 additions & 9 deletions packages/client/setup/main.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
import type { AppContext } from '@slidev/types'
import TwoSlashFloatingVue from '@shikijs/vitepress-twoslash/client'
import type { App } from 'vue'
import { nextTick } from 'vue'
import { createRouter, createWebHashHistory, createWebHistory } from 'vue-router'
import { createHead } from '@unhead/vue'
import { routeForceRefresh } from '../logic/route'
import { createVClickDirectives } from '../modules/v-click'
import { createVMarkDirective } from '../modules/v-mark'
import { createVDragDirective } from '../modules/v-drag'
Expand Down Expand Up @@ -44,13 +42,6 @@ export default async function setupMain(app: App) {
router,
}

nextTick(() => {
router.afterEach(async () => {
await nextTick()
routeForceRefresh.value += 1
})
})

for (const setup of setups)
await setup(context)
}
41 changes: 23 additions & 18 deletions packages/slidev/node/virtual/slides.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,34 +6,39 @@ export const templateSlides: VirtualModuleTemplate = {
id: '/@slidev/slides',
async getContent({ data }, { getLayouts }) {
const layouts = await getLayouts()
const imports = [
`import { shallowRef } from 'vue'`,
`import * as __layout__error from '${layouts.error}'`,
const statements = [
`import { defineAsyncComponent, shallowRef } from 'vue'`,
`import SlideError from '${layouts.error}'`,
`import SlideLoading from '@slidev/client/internals/SlideLoading.vue'`,
`const componentsCache = new Array(${data.slides.length})`,
`const getAsyncComponent = (idx, loader) => defineAsyncComponent({`,
` loader,`,
` delay: 300,`,
` loadingComponent: SlideLoading,`,
` errorComponent: SlideError,`,
` onError: e => console.error('Failed to load slide ' + (idx + 1), e) `,
`})`,
]
const slides = data.slides
.map((_, idx) => {
const no = idx + 1
imports.push(`import { meta as f${no} } from '${VIRTUAL_SLIDE_PREFIX}${no}.frontmatter'`)
return `{
no: ${no},
meta: f${no},
component: async () => {
try {
return await import('${VIRTUAL_SLIDE_PREFIX}${no}.md')
}
catch(e) {
console.error('Failed to load slide ${no}:', e)
return __layout__error
}
},
}`
statements.push(
`import { meta as f${no} } from '${VIRTUAL_SLIDE_PREFIX}${no}.frontmatter'`,
// For some unknown reason, import error won't be caught by the error component. Catch it here.
`const load${no} = async () => {`,
` try { return componentsCache[${idx}] ??= await import('${VIRTUAL_SLIDE_PREFIX}${no}.md') }`,
` catch (e) { return SlideError }`,
`}`,
)
return `{ no: ${no}, meta: f${no}, load: load${no}, component: getAsyncComponent(${idx}, load${no}) }`
})
return [
...imports,
...statements,
`const data = [\n${slides.join(',\n')}\n]`,
`if (import.meta.hot) {`,
` import.meta.hot.data.slides ??= shallowRef()`,
` import.meta.hot.data.slides.value = data`,
` import.meta.hot.dispose(() => componentsCache.length = 0)`,
` import.meta.hot.accept()`,
`}`,
`export const slides = import.meta.hot ? import.meta.hot.data.slides : shallowRef(data)`,
Expand Down
38 changes: 24 additions & 14 deletions packages/slidev/node/vite/loaders.ts
Original file line number Diff line number Diff line change
Expand Up @@ -365,7 +365,7 @@ export function createSlidesLoader(
},
},
{
name: 'slidev:layout-transform:pre',
name: 'slidev:slide-transform:pre',
enforce: 'pre',
async transform(code, id) {
if (!id.startsWith(VIRTUAL_SLIDE_PREFIX))
Expand Down Expand Up @@ -428,24 +428,34 @@ export function createSlidesLoader(
}

delete frontmatter.title
const imports = [

const setupTag = code.match(/^<script setup.*>/m)
if (!setupTag)
throw new Error(`[Slidev] Internal error: <script setup> block not found in slide ${index + 1}.`)

const templatePart = code.slice(0, setupTag.index!)
const scriptPart = code.slice(setupTag.index!)

const bodyStart = templatePart.indexOf('<template>') + 10
const bodyEnd = templatePart.lastIndexOf('</template>')
let body = code.slice(bodyStart, bodyEnd).trim()
if (body.startsWith('<div>') && body.endsWith('</div>'))
body = body.slice(5, -6)

return [
templatePart.slice(0, bodyStart),
`<InjectedLayout v-bind="_frontmatterToProps(frontmatter,${index})">\n${body}\n</InjectedLayout>`,
templatePart.slice(bodyEnd),
scriptPart.slice(0, setupTag[0].length),
`import InjectedLayout from "${toAtFS(layouts[layoutName])}"`,
`import frontmatter from "${toAtFS(`${VIRTUAL_SLIDE_PREFIX + (index + 1)}.frontmatter`)}"`,
templateImportContextUtils,
'_provideFrontmatter(frontmatter)',
templateInitContext,
'_provideFrontmatter(frontmatter)',
'$clicksContext.setup()',
templateInjectionMarker,
]

code = code.replace(/(<script setup.*>)/g, `$1\n${imports.join('\n')}\n`)
const injectA = code.indexOf('<template>') + '<template>'.length
const injectB = code.lastIndexOf('</template>')
let body = code.slice(injectA, injectB).trim()
if (body.startsWith('<div>') && body.endsWith('</div>'))
body = body.slice(5, -6)
code = `${code.slice(0, injectA)}\n<InjectedLayout v-bind="_frontmatterToProps(frontmatter,${index})">\n${body}\n</InjectedLayout>\n${code.slice(injectB)}`

return code
scriptPart.slice(setupTag[0].length),
].join('\n')
}

function transformVue(code: string): string {
Expand Down
3 changes: 1 addition & 2 deletions packages/types/src/clicks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,7 @@ export interface ClicksContext {
register: (el: ClicksElement, info: Pick<ClicksInfo, 'delta' | 'max'> | null) => void
unregister: (el: ClicksElement) => void
readonly isMounted: boolean
onMounted: () => void
onUnmounted: () => void
setup: () => void
readonly currentOffset: number
readonly total: number
}
10 changes: 9 additions & 1 deletion packages/types/src/types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { RouteComponent, RouteMeta } from 'vue-router'
import type YAML from 'yaml'
import type { Component } from 'vue'
import type { SlidevConfig } from './config'

export type FrontmatterStyle = 'frontmatter' | 'yaml'
Expand Down Expand Up @@ -126,7 +127,14 @@ export type RenderContext = 'none' | 'slide' | 'overview' | 'presenter' | 'previ
export interface SlideRoute {
no: number
meta: RouteMeta & Required<Pick<RouteMeta, 'slide'>>
component: () => Promise<{ default: RouteComponent }>
/**
* load the slide component itself
*/
load: () => Promise<{ default: RouteComponent }>
/**
* Wrapped async component
*/
component: Component
}

export type LoadedSnippets = Record<string, string>

0 comments on commit 6ea7189

Please sign in to comment.