File size: 4,051 Bytes
89ce340 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 |
<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 type { ShapePoolItem } from '@/configs/shapes'
import MobileThumbnails from '../MobileThumbnails.vue'
import FileInput from '@/components/FileInput.vue'
import Button from '@/components/Button.vue'
import ButtonGroup from '@/components/ButtonGroup.vue'
const slidesStore = useSlidesStore()
const { viewportRatio, currentSlide, viewportSize } = storeToRefs(slidesStore)
const { createSlide, copyAndPasteSlide, deleteSlide, } = useSlideHandler()
const { createTextElement, createImageElement, createShapeElement } = useCreateElement()
const insertTextElement = () => {
const width = 400
const height = 56
createTextElement({
left: (viewportSize.value - width) / 2,
top: (viewportSize.value * 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: (viewportSize.value - size) / 2,
top: (viewportSize.value * 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;
box-sizing: border-box;
@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> |