Skip to content

Commit

Permalink
refactor: DOM structure (#1556)
Browse files Browse the repository at this point in the history
  • Loading branch information
KermanX authored May 2, 2024
1 parent e03fd38 commit d83edd8
Show file tree
Hide file tree
Showing 23 changed files with 152 additions and 219 deletions.
19 changes: 13 additions & 6 deletions packages/client/composables/useNav.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ export interface SlidevContextNav {
/** Go to previous slide */
prevSlide: (lastClicks?: boolean) => Promise<void>
/** Go to slide */
go: (page: number | string, clicks?: number) => Promise<void>
go: (page: number | string, clicks?: number, force?: boolean) => Promise<void>
/** Go to the first slide */
goFirst: () => Promise<void>
/** Go to the last slide */
Expand Down Expand Up @@ -181,14 +181,14 @@ export function useNavBase(
return go(total.value)
}

async function go(page: number | string, clicks: number = 0) {
async function go(page: number | string, clicks: number = 0, force = false) {
skipTransition.value = false
const pageChanged = currentSlideNo.value !== page
const clicksChanged = clicks !== queryClicks.value
const meta = getSlide(page)?.meta
const clicksStart = meta?.slide?.frontmatter.clicksStart ?? 0
clicks = clamp(clicks, clicksStart, meta?.__clicksContext?.total ?? CLICKS_MAX)
if (pageChanged || clicksChanged) {
if (force || pageChanged || clicksChanged) {
await router?.push({
path: getSlidePath(page, isPresenter.value),
query: {
Expand Down Expand Up @@ -380,9 +380,16 @@ export const useNav = createSharedComposable((): SlidevContextNavFull => {
watch(
[nav.total, state.currentRoute],
async () => {
if (state.hasPrimarySlide.value && !getSlide(state.currentRoute.value.params.no as string)) {
// The current slide may has been removed. Redirect to the last slide.
await nav.goLast()
const no = state.currentRoute.value.params.no as string
if (state.hasPrimarySlide.value && !getSlide(no)) {
if (no && no !== 'index.html') {
// The current slide may has been removed. Redirect to the last slide.
await nav.go(nav.total.value, 0, true)
}
else {
// Redirect to the first slide
await nav.go(1, 0, true)
}
}
},
{ flush: 'pre', immediate: true },
Expand Down
1 change: 0 additions & 1 deletion packages/client/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ export const injectionSlideScale = '$$slidev-slide-scale' as unknown as Injectio
export const injectionSlidevContext = '$$slidev-context' as unknown as InjectionKey<UnwrapNestedRefs<SlidevContext>>
export const injectionRoute = '$$slidev-route' as unknown as InjectionKey<SlideRoute>
export const injectionRenderContext = '$$slidev-render-context' as unknown as InjectionKey<Ref<RenderContext>>
export const injectionActive = '$$slidev-active' as unknown as InjectionKey<Ref<boolean>>
export const injectionFrontmatter = '$$slidev-fontmatter' as unknown as InjectionKey<Record<string, any>>
export const injectionSlideZoom = '$$slidev-slide-zoom' as unknown as InjectionKey<ComputedRef<number>>

Expand Down
2 changes: 2 additions & 0 deletions packages/client/env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,5 @@ export const slideHeight = computed(() => Math.ceil(slideWidth.value / slideAspe
export const themeVars = computed(() => {
return objectMap(configs.themeConfig || {}, (k, v) => [`--slidev-theme-${k}`, v])
})

export const slidesTitle = configs.titleTemplate.replace('%s', configs.title || 'Slidev')
12 changes: 10 additions & 2 deletions packages/client/internals/Controls.vue
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
<script setup lang="ts">
import { shallowRef } from 'vue'
import { showInfoDialog, showOverview, showRecordingDialog } from '../state'
import { showInfoDialog, showRecordingDialog } from '../state'
import { configs } from '../env'
import { useNav } from '../composables/useNav'
import QuickOverview from './QuickOverview.vue'
import InfoDialog from './InfoDialog.vue'
import Goto from './Goto.vue'
import ContextMenu from './ContextMenu.vue'
const { isEmbedded } = useNav()
const drawingEnabled = __SLIDEV_FEATURE_DRAWINGS__ && !configs.drawings.presenterOnly && !isEmbedded.value
const DrawingControls = shallowRef<any>()
if (drawingEnabled)
import('../internals/DrawingControls.vue').then(v => DrawingControls.value = v.default)
const WebCamera = shallowRef<any>()
const RecordingDialog = shallowRef<any>()
if (__SLIDEV_FEATURE_RECORD__) {
Expand All @@ -16,7 +23,8 @@ if (__SLIDEV_FEATURE_RECORD__) {
</script>

<template>
<QuickOverview v-model="showOverview" />
<DrawingControls v-if="drawingEnabled && DrawingControls" />
<QuickOverview />
<Goto />
<WebCamera v-if="WebCamera" />
<RecordingDialog v-if="RecordingDialog" v-model="showRecordingDialog" />
Expand Down
2 changes: 1 addition & 1 deletion packages/client/internals/DrawingControls.vue
Original file line number Diff line number Diff line change
Expand Up @@ -136,4 +136,4 @@ function setBrushColor(color: typeof brush.color) {
.v-popper--theme-menu .v-popper__arrow-inner {
--uno: border-main;
}
</style>../composables/drawings
</style>
2 changes: 1 addition & 1 deletion packages/client/internals/DrawingLayer.vue
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,4 @@ onBeforeUnmount(() => {
class="w-full h-full absolute top-0"
:class="{ 'pointer-events-none': !drawingEnabled, 'touch-none': drawingEnabled }"
/>
</template>../composables/drawings
</template>
2 changes: 1 addition & 1 deletion packages/client/internals/DrawingPreview.vue
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@ const { drawingState } = useDrawings()
class="w-full h-full absolute top-0 pointer-events-none"
v-html="drawingState[page]"
/>
</template>../composables/drawings
</template>
6 changes: 1 addition & 5 deletions packages/client/internals/NavControls.vue
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,6 @@ const barStyle = computed(() => props.persist
const RecordingControls = shallowRef<any>()
if (__SLIDEV_FEATURE_RECORD__)
import('./RecordingControls.vue').then(v => RecordingControls.value = v.default)
const DrawingControls = shallowRef<any>()
if (__SLIDEV_FEATURE_DRAWINGS__)
import('./DrawingControls.vue').then(v => DrawingControls.value = v.default)
</script>

<template>
Expand Down Expand Up @@ -179,4 +175,4 @@ if (__SLIDEV_FEATURE_DRAWINGS__)
<CustomNavControls />
</div>
</nav>
</template>../composables/drawings
</template>
2 changes: 1 addition & 1 deletion packages/client/internals/NoteDisplay.vue
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const emit = defineEmits<{
(type: 'markerClick', e: MouseEvent, clicks: number): void
}>()
const withClicks = computed(() => props.clicksContext?.current != null && props.noteHtml?.includes('slidev-note-click-mark'))
const withClicks = computed(() => props.clicksContext != null && props.noteHtml?.includes('slidev-note-click-mark'))
const noteDisplay = ref<HTMLElement | null>(null)
const CLASS_FADE = 'slidev-note-fade'
Expand Down
24 changes: 8 additions & 16 deletions packages/client/internals/QuickOverview.vue
Original file line number Diff line number Diff line change
@@ -1,25 +1,20 @@
<script setup lang="ts">
import { useEventListener, useVModel } from '@vueuse/core'
import { useEventListener } from '@vueuse/core'
import { computed, ref, watchEffect } from 'vue'
import { breakpoints, showOverview, windowSize } from '../state'
import { currentOverviewPage, overviewRowCount } from '../logic/overview'
import { createFixedClicks } from '../composables/useClicks'
import { getSlideClass } from '../utils'
import { CLICKS_MAX } from '../constants'
import { useNav } from '../composables/useNav'
import SlideContainer from './SlideContainer.vue'
import SlideWrapper from './SlideWrapper.vue'
import DrawingPreview from './DrawingPreview.vue'
import IconButton from './IconButton.vue'
const props = defineProps<{ modelValue: boolean }>()
const emit = defineEmits(['update:modelValue'])
const value = useVModel(props, 'modelValue', emit)
const { currentSlideNo, go: goSlide, slides } = useNav()
function close() {
value.value = false
showOverview.value = false
}
function go(page: number) {
Expand Down Expand Up @@ -117,10 +112,10 @@ setTimeout(() => {
leave-to-class="opacity-0 scale-102 !backdrop-blur-0px"
>
<div
v-if="value || activeSlidesLoaded"
v-show="value"
class="bg-main !bg-opacity-75 p-16 py-20 overflow-y-auto backdrop-blur-5px fixed left-0 right-0 top-0 h-[calc(var(--vh,1vh)*100)]"
@click="close()"
v-if="showOverview || activeSlidesLoaded"
v-show="showOverview"
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"
@click="close"
>
<div
class="grid gap-y-4 gap-x-8 w-full"
Expand All @@ -142,10 +137,7 @@ setTimeout(() => {
class="pointer-events-none"
>
<SlideWrapper
:is="route.component"
v-if="route?.component"
:clicks-context="createFixedClicks(route, CLICKS_MAX)"
:class="getSlideClass(route)"
:route="route"
render-context="overview"
/>
Expand All @@ -168,12 +160,12 @@ setTimeout(() => {
</div>
</div>
</Transition>
<div v-if="value" class="fixed top-4 right-4 text-gray-400 flex flex-col items-center gap-2">
<div v-if="showOverview" class="fixed top-4 right-4 z-20 text-gray-400 flex flex-col items-center gap-2">
<IconButton title="Close" class="text-2xl" @click="close">
<carbon:close />
</IconButton>
<IconButton
v-if="__DEV__"
v-if="__SLIDEV_FEATURE_PRESENTER__"
as="a"
title="Slides Overview"
target="_blank"
Expand Down
2 changes: 1 addition & 1 deletion packages/client/internals/Settings.vue
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const items: SelectionItem<number>[] = [
</script>

<template>
<div class="text-sm">
<div class="text-sm select-none">
<SelectList v-model="slideScale" title="Scale" :items="items" />
</div>
</template>
74 changes: 28 additions & 46 deletions packages/client/internals/SlideContainer.vue
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
<script setup lang="ts">
import { provideLocal, useElementSize, useStyleTag } from '@vueuse/core'
import { computed, ref, watchEffect } from 'vue'
import { configs, slideAspect, slideHeight, slideWidth } from '../env'
import { computed, ref } from 'vue'
import { injectionSlideElement, injectionSlideScale } from '../constants'
import { slideAspect, slideHeight, slideWidth } from '../env'
import { useNav } from '../composables/useNav'
import { slideScale } from '../state'
const props = defineProps({
width: {
Expand All @@ -12,83 +13,64 @@ const props = defineProps({
meta: {
default: () => ({}) as any,
},
scale: {
type: [Number, String],
},
isMain: {
type: Boolean,
default: false,
},
})
const { clicksDirection, isPrintMode } = useNav()
const { isPrintMode } = useNav()
const root = ref<HTMLDivElement | null>(null)
const rootSize = useElementSize(root)
const container = ref<HTMLDivElement | null>(null)
const containerSize = useElementSize(container)
const slideElement = ref<HTMLElement | null>(null)
const width = computed(() => props.width ? props.width : rootSize.width.value)
const height = computed(() => props.width ? props.width / slideAspect.value : rootSize.height.value)
if (props.width) {
watchEffect(() => {
if (root.value) {
root.value.style.width = `${width.value}px`
root.value.style.height = `${height.value}px`
}
})
}
const screenAspect = computed(() => width.value / height.value)
const width = computed(() => props.width ?? containerSize.width.value)
const height = computed(() => props.width ? props.width / slideAspect.value : containerSize.height.value)
const scale = computed(() => {
if (props.scale && !isPrintMode.value)
return +props.scale
if (screenAspect.value < slideAspect.value)
return width.value / slideWidth.value
return height.value * slideAspect.value / slideWidth.value
if (slideScale.value && !isPrintMode.value)
return +slideScale.value
return Math.min(width.value / slideWidth.value, height.value / slideHeight.value)
})
const style = computed(() => ({
const contentStyle = computed(() => ({
'height': `${slideHeight.value}px`,
'width': `${slideWidth.value}px`,
'transform': `translate(-50%, -50%) scale(${scale.value})`,
'--slidev-slide-scale': scale.value,
}))
const className = computed(() => ({
'select-none': !configs.selectable,
'slidev-nav-go-forward': clicksDirection.value > 0,
'slidev-nav-go-backward': clicksDirection.value < 0,
}))
if (props.isMain) {
useStyleTag(computed(() => `
:root {
--slidev-slide-scale: ${scale.value};
const containerStyle = computed(() => props.width
? {
width: `${props.width}px`,
height: `${props.width / slideAspect.value}px`,
}
`))
}
: {},
)
if (props.isMain)
useStyleTag(computed(() => `:root { --slidev-slide-scale: ${scale.value}; }`))
provideLocal(injectionSlideScale, scale)
provideLocal(injectionSlideElement, slideElement)
</script>

<template>
<div id="slide-container" ref="root" class="slidev-slides-container" :class="className">
<div id="slide-content" ref="slideElement" class="slidev-slide-content" :style="style">
<div :id="isMain ? 'slide-container' : undefined" ref="container" class="slidev-slide-container" :style="containerStyle">
<div :id="isMain ? 'slide-content' : undefined" ref="slideElement" class="slidev-slide-content" :style="contentStyle">
<slot />
</div>
<slot name="controls" />
</div>
</template>

<style lang="postcss">
#slide-container {
@apply relative overflow-hidden break-after-page;
<style scoped lang="postcss">
.slidev-slide-container {
@apply relative w-full h-full overflow-hidden;
}
#slide-content {
@apply relative overflow-hidden bg-main absolute left-1/2 top-1/2;
.slidev-slide-content {
@apply absolute left-1/2 top-1/2 overflow-hidden bg-main;
}
</style>
Loading

0 comments on commit d83edd8

Please sign in to comment.