PPTist/src/views/Mobile/MobileEditor/SlideToolbar.vue
2022-08-19 20:03:03 +08:00

140 lines
3.8 KiB
Vue

<template>
<div class="slide-toolbar">
<div class="remark">
<textarea
:value="remark"
placeholder="点击输入演讲者备注"
@input="$event => handleInputMark($event)"
></textarea>
</div>
<div class="toolbar">
<ButtonGroup class="row">
<Button style="flex: 1;" @click="createSlide()"><IconPlus class="icon" /> 新幻灯片</Button>
<Button style="flex: 1;" @click="copyAndPasteSlide()"><IconCopy class="icon" /> 复制</Button>
<Button style="flex: 1;" @click="deleteSlide()"><IconDelete class="icon" /> 删除</Button>
</ButtonGroup>
<ButtonGroup class="row">
<Button style="flex: 1;" @click="insertTextElement()"><IconFontSize class="icon" /> 文字</Button>
<Button style="flex: 1;">
<FileInput @change="files => insertImageElement(files)">
<IconPicture class="icon" />图片
</FileInput>
</Button>
<Button style="flex: 1;" @click="insertShapeElement('square')"><IconSquare class="icon" /> 矩形</Button>
<Button style="flex: 1;" @click="insertShapeElement('round')"><IconRound class="icon" /> 圆形</Button>
</ButtonGroup>
</div>
<MobileThumbnails />
</div>
</template>
<script lang="ts" setup>
import { computed } from 'vue'
import { storeToRefs } from 'pinia'
import { useSlidesStore } from '@/store'
import useSlideHandler from '@/hooks/useSlideHandler'
import useCreateElement from '@/hooks/useCreateElement'
import { getImageDataURL } from '@/utils/image'
import { ShapePoolItem } from '@/configs/shapes'
import { VIEWPORT_SIZE } from '@/configs/canvas'
import MobileThumbnails from '../MobileThumbnails.vue'
const slidesStore = useSlidesStore()
const { viewportRatio, currentSlide } = storeToRefs(slidesStore)
const { createSlide, copyAndPasteSlide, deleteSlide, } = useSlideHandler()
const { createTextElement, createImageElement, createShapeElement } = useCreateElement()
const insertTextElement = () => {
const width = 400
const height = 56
createTextElement({
left: (VIEWPORT_SIZE - width) / 2,
top: (VIEWPORT_SIZE * viewportRatio.value - height) / 2,
width,
height,
}, { content: '<p>新添加文本</p>' })
}
const insertImageElement = (files: FileList) => {
if (!files || !files[0]) return
getImageDataURL(files[0]).then(dataURL => createImageElement(dataURL))
}
const insertShapeElement = (type: 'square' | 'round') => {
const square: ShapePoolItem = {
viewBox: [200, 200],
path: 'M 0 0 L 200 0 L 200 200 L 0 200 Z',
}
const round: ShapePoolItem = {
viewBox: [200, 200],
path: 'M 100 0 A 50 50 0 1 1 100 200 A 50 50 0 1 1 100 0 Z',
}
const shape = { square, round }
const size = 200
createShapeElement({
left: (VIEWPORT_SIZE - size) / 2,
top: (VIEWPORT_SIZE * viewportRatio.value - size) / 2,
width: size,
height: size,
}, shape[type])
}
const remark = computed(() => currentSlide.value?.remark || '')
const handleInputMark = (e: Event) => {
const value = (e.target as HTMLTextAreaElement).value
slidesStore.updateSlide({ remark: value })
}
</script>
<style lang="scss" scoped>
.slide-toolbar {
height: 230px;
background-color: #fff;
box-shadow: 0 0 15px 0 rgba(0, 0, 0, 0.1);
display: flex;
flex-direction: column;
position: relative;
z-index: 2;
}
.remark {
position: relative;
flex: 1;
border-bottom: 1px solid $borderColor;
line-height: 1.5;
textarea {
width: 100%;
height: 100%;
overflow-y: auto;
resize: none;
border: 0;
outline: 0;
padding: 8px 10px;
font-size: 12px;
@include absolute-0();
}
}
.toolbar {
height: 90px;
border-bottom: 1px solid $borderColor;
padding: 10px;
}
.row {
width: 100%;
display: flex;
align-items: center;
margin-bottom: 5px;
.icon {
margin-right: 3px;
}
}
</style>