1
0
Fork 0
mirror of https://gitlab.com/bramw/baserow.git synced 2025-04-26 13:44:41 +00:00
bramw_baserow/web-frontend/modules/builder/components/page/PagePreview.vue
2023-08-08 13:28:03 +00:00

152 lines
4.5 KiB
Vue

<template>
<div
class="page-preview__wrapper"
@click.self="actionSelectElement({ element: null })"
>
<PreviewNavigationBar :page="page" :style="{ maxWidth }" />
<div ref="preview" class="page-preview" :style="{ 'max-width': maxWidth }">
<div ref="previewScaled" class="page-preview__scaled">
<ElementPreview
v-for="(element, index) in elements"
:key="element.id"
is-root-element
:element="element"
:is-first-element="index === 0"
:is-last-element="index === elements.length - 1"
:placements="[PLACEMENTS.BEFORE, PLACEMENTS.AFTER]"
:placements-disabled="getPlacementsDisabled(index)"
:is-copying="copyingElementIndex === index"
@move="moveElement(element, index, $event)"
/>
</div>
</div>
</div>
</template>
<script>
import { mapGetters, mapActions } from 'vuex'
import ElementPreview from '@baserow/modules/builder/components/elements/ElementPreview'
import { notifyIf } from '@baserow/modules/core/utils/error'
import PreviewNavigationBar from '@baserow/modules/builder/components/page/PreviewNavigationBar'
import { PLACEMENTS } from '@baserow/modules/builder/enums'
export default {
name: 'PagePreview',
components: { ElementPreview, PreviewNavigationBar },
data() {
return {
// The element that is currently being copied
copyingElementIndex: null,
// The resize observer to resize the preview when the wrapper size change
resizeObserver: null,
}
},
computed: {
PLACEMENTS: () => PLACEMENTS,
...mapGetters({
page: 'page/getSelected',
deviceTypeSelected: 'page/getDeviceTypeSelected',
elements: 'element/getRootElements',
elementSelected: 'element/getSelected',
}),
deviceType() {
return this.deviceTypeSelected
? this.$registry.get('device', this.deviceTypeSelected)
: null
},
maxWidth() {
return this.deviceType?.maxWidth
? `${this.deviceType.maxWidth}px`
: 'unset'
},
},
watch: {
deviceType(value) {
this.$nextTick(() => {
this.updatePreviewScale(value)
})
},
},
mounted() {
this.resizeObserver = new ResizeObserver(() => {
this.onWindowResized()
})
this.resizeObserver.observe(this.$el)
this.onWindowResized()
},
destroyed() {
this.resizeObserver.unobserve(this.$el)
},
methods: {
...mapActions({
actionMoveElement: 'element/move',
actionSelectElement: 'element/select',
actionUpdateElement: 'element/update',
}),
onWindowResized() {
this.$nextTick(() => {
this.updatePreviewScale(this.deviceType)
})
},
updatePreviewScale(deviceType) {
// The widths are the minimum width the preview must have. If the preview dom
// element becomes smaller than the target, it will be scaled down so that the
// actual width remains the same, and it will preview the correct device.
const { clientWidth: currentWidth, clientHeight: currentHeight } =
this.$refs.preview
const targetWidth = deviceType?.minWidth
let scale = 1
if (currentWidth < targetWidth) {
// Round scale at 2 decimals
scale = Math.round((currentWidth / targetWidth) * 100) / 100
}
const previewScaled = this.$refs.previewScaled
previewScaled.style.transform = `scale(${scale})`
previewScaled.style.transformOrigin = `0 0`
previewScaled.style.width = `${currentWidth / scale}px`
previewScaled.style.height = `${currentHeight / scale}px`
},
async moveElement(element, index, placement) {
const elementToMoveId = element.id
// BeforeElementId remains null if we are moving the element at the end of the
// list
let beforeElementId = null
if (placement === PLACEMENTS.BEFORE) {
beforeElementId = this.elements[index - 1].id
} else if (index + 2 < this.elements.length) {
beforeElementId = this.elements[index + 2].id
}
try {
await this.actionMoveElement({
pageId: this.page.id,
elementId: elementToMoveId,
beforeElementId,
})
} catch (error) {
notifyIf(error)
}
},
getPlacementsDisabled(index) {
const placementsDisabled = []
if (index === 0) {
placementsDisabled.push(PLACEMENTS.BEFORE)
}
if (index === this.elements.length - 1) {
placementsDisabled.push(PLACEMENTS.AFTER)
}
return placementsDisabled
},
},
}
</script>