Skip to content

Commit

Permalink
feat: sync drawing in presenter mode
Browse files Browse the repository at this point in the history
  • Loading branch information
antfu committed Sep 13, 2021
1 parent 6bcb60d commit 7d0fc64
Show file tree
Hide file tree
Showing 10 changed files with 73 additions and 25 deletions.
7 changes: 6 additions & 1 deletion packages/client/env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import { objectMap } from '@antfu/utils'
import _configs from '/@slidev/configs'
// @ts-expect-error
import _serverState from '/@server-ref/state'
// @ts-expect-error
import _serverDrauuState from '/@server-ref/drauu'

export interface ServerState {
page: number
Expand All @@ -15,7 +17,10 @@ export interface ServerState {
}
}

export const serverState = _serverState as Ref<ServerState>
export type ServerRef<T> = Ref<T> & { receive: boolean; send: boolean }

export const serverState = _serverState as ServerRef<ServerState>
export const serverDrauuState = _serverDrauuState as ServerRef<Record<number, string | undefined>>
export const configs = _configs as SlidevConfig

export const slideAspect = configs.aspectRatio ?? (16 / 9)
Expand Down
23 changes: 21 additions & 2 deletions packages/client/internals/DrauuLayer.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<script setup lang="ts">
import { onMounted, ref, watch, inject, onBeforeUnmount } from 'vue'
import { ignorableWatch } from '@vueuse/core'
import { drauuEnabled, drauu, drauuData } from '../logic/drauu'
import { injectionSlideScale } from '../constants'
import { currentPage } from '../logic/nav'
Expand All @@ -8,15 +9,33 @@ const scale = inject(injectionSlideScale)!
const svg = ref<SVGSVGElement>()
onMounted(() => {
let skipNext = false
drauu.mount(svg.value!)
watch(scale, scale => drauu.options.corrdinateScale = 1 / scale, { immediate: true })
const { ignoreUpdates } = ignorableWatch(
drauuData,
() => {
const data = drauuData.value[currentPage.value]
if (data != null)
drauu.load(data)
},
{ deep: true },
)
drauu.on('changed', () => {
drauuData.set(currentPage.value, drauu.dump())
if (skipNext) {
skipNext = false
return
}
ignoreUpdates(() => {
drauuData.value[currentPage.value] = drauu.dump()
})
})
watch(currentPage, (page) => {
const data = drauuData.get(page)
skipNext = true
const data = drauuData.value[page]
if (data)
drauu.load(data)
else
Expand Down
2 changes: 1 addition & 1 deletion packages/client/internals/NavControls.vue
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ if (__DEV__) {
<VerticalDivider />
</template>

<template v-if="!isPresenter && DrauuControls">
<template v-if="DrauuControls">
<button class="icon-btn relative" @click="drauuEnabled = !drauuEnabled">
<carbon:draw />
<div
Expand Down
6 changes: 5 additions & 1 deletion packages/client/internals/Presenter.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<script setup lang="ts">
import { useHead } from '@vueuse/head'
import { ref, computed, reactive, watch, onMounted } from 'vue'
import { useMouse, useTimestamp } from '@vueuse/core'
import { useMouse, useTimestamp, useWindowFocus } from '@vueuse/core'
import { total, currentPage, currentRoute, nextRoute, clicks, useSwipeControls, clicksTotal, hasNext } from '../logic/nav'
import { showOverview } from '../state'
import { configs, themeVars, serverState } from '../env'
Expand Down Expand Up @@ -64,9 +64,13 @@ const nextSlide = computed(() => {
onMounted(() => {
const slidesContainer = main.value!.querySelector('#slide-content')!
const mouse = reactive(useMouse())
const focus = useWindowFocus()
watch(
() => {
if (!focus.value)
return undefined
const rect = slidesContainer.getBoundingClientRect()
const x = (mouse.x - rect.left) / rect.width * 100
const y = (mouse.y - rect.top) / rect.height * 100
Expand Down
3 changes: 1 addition & 2 deletions packages/client/internals/PresenterMouse.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
<script setup lang="ts">
import { serverState } from '../env'
</script>

<template>
Expand All @@ -10,7 +9,7 @@ import { serverState } from '../env'
>
<ph:cursor-fill
class="absolute"
:style="{left: serverState.cursor.x + '%',top: serverState.cursor.y + '%'}"
:style="{ left: `${serverState.cursor.x}%`, top: `${serverState.cursor.y}%` }"
/>
</div>
</template>
18 changes: 14 additions & 4 deletions packages/client/logic/drauu.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { computed, markRaw, reactive, ref } from 'vue'
import { computed, markRaw, nextTick, reactive, ref, watch } from 'vue'
import { Brush, createDrauu, DrawingMode } from 'drauu'
import { currentPage } from './nav'
import { serverDrauuState } from '../env'
import { currentPage, isPresenter } from './nav'

export const brushColors = [
'#ff595e',
Expand Down Expand Up @@ -47,13 +48,22 @@ export const canRedo = ref(false)
export const canClear = ref(false)
export const isDrawing = ref(false)

export const drauuData = new Map<number, string>()
export const drauuData = serverDrauuState

serverDrauuState.send = false

nextTick(() => {
watch(isPresenter, (v) => {
serverDrauuState.send = v
serverDrauuState.receive = !v
}, { immediate: true })
})

export const drauu = markRaw(createDrauu(drauuOptions))

export function clearDrauu() {
drauu.clear()
drauuData.delete(currentPage.value)
drauuData.value[currentPage.value] = ''
}

if (__DEV__) {
Expand Down
2 changes: 1 addition & 1 deletion packages/client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
"@vueuse/head": "^0.6.0",
"@vueuse/motion": "^1.5.6",
"codemirror": "^5.62.2",
"drauu": "^0.0.12",
"drauu": "^0.0.13",
"file-saver": "^2.0.5",
"js-base64": "^3.6.1",
"js-yaml": "^4.1.0",
Expand Down
1 change: 1 addition & 0 deletions packages/slidev/node/plugins/preset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ export async function ViteSlidevPlugin(
page: 0,
clicks: 0,
},
drauu: {},
},
}),
createConfigPlugin(options),
Expand Down
22 changes: 16 additions & 6 deletions packages/slidev/node/plugins/serverRef.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { Plugin } from 'vite'
import type { Ref } from 'vue'
import { getBodyJson } from './loaders'

const PREFIX = '/@server-ref/'
Expand All @@ -7,9 +8,11 @@ export interface ServerRefOptions<T extends Record<string, unknown>> {
dataMap?: T
debounceMs?: number
debug?: boolean
onChanged?: <K extends keyof T>(name: K, data: T[K], timestamp: number) => void
onChanged?: <K extends keyof T>(name: K, data: T[K], timestamp: number, isPatch?: boolean) => void
}

export type ServerRef<T> = Ref<T> & { receive: boolean; send: boolean }

export function VitePluginServerRef(options: ServerRefOptions<any> = {}): Plugin {
const {
dataMap = {},
Expand All @@ -28,9 +31,7 @@ export function VitePluginServerRef(options: ServerRefOptions<any> = {}): Plugin
return next()

const name = req.url.slice(PREFIX.length)
const { data, timestamp } = await getBodyJson(req)

// TODO: handle conflicts
const { data, timestamp, isPatch } = await getBodyJson(req)

const module = server.moduleGraph.getModuleById(PREFIX + name)
if (module)
Expand All @@ -44,10 +45,11 @@ export function VitePluginServerRef(options: ServerRefOptions<any> = {}): Plugin
name,
data,
timestamp,
isPatch,
},
})

options.onChanged?.(name, data, timestamp)
options.onChanged?.(name, data, timestamp, isPatch)

res.write('')
res.end()
Expand All @@ -62,20 +64,28 @@ import { ref, watch } from "vue"
const data = ref(${JSON.stringify(dataMap[name] ?? null)})
data.receive = true
data.send = true
data.paused = false
if (import.meta.hot) {
${debug ? `console.log("[server-ref] [${name}] ref", data)` : ''}
${debug ? `console.log("[server-ref] [${name}] initial", data.value)` : ''}
let skipNext = false
let timer = null
import.meta.hot.on("server-ref", (payload) =>{
import.meta.hot.on("server-ref", (payload) => {
if (!data.receive || data.paused)
return
if (payload.name !== "${name}")
return
skipNext = true
data.value = payload.data
${debug ? `console.log("[server-ref] [${name}] incoming", payload.data)` : ''}
})
watch(data, (v) => {
if (!data.send || data.paused)
return
if (skipNext) {
skipNext = false
return
Expand Down
14 changes: 7 additions & 7 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 7d0fc64

Please sign in to comment.