This commit is contained in:
pipipi-pikachu 2021-01-09 19:51:01 +08:00
parent 395df00bd2
commit 045f361e14
13 changed files with 254 additions and 58 deletions

View File

@ -17,6 +17,9 @@
.ant-radio-group {
font-size: 13px !important;
}
.ant-select-selection-item {
font-size: 13px;
}
.ant-select-item-option-content {
font-size: 13px !important;
}

View File

@ -12,10 +12,12 @@ export default (background: Ref<SlideBackground | undefined>) => {
return {
backgroundImage: `url(${value}`,
backgroundRepeat: 'repeat',
backgroundSize: 'initial',
}
}
return {
backgroundImage: `url(${value}`,
backgroundRepeat: 'no-repeat',
backgroundSize: size,
}
}

View File

@ -153,7 +153,7 @@ export interface PPTAnimation {
export interface SlideBackground {
type: 'solid' | 'image';
value: string;
size?: 'cover' | 'contain' | 'repeat';
size?: 'cover' | 'contain' | 'repeat' | 'initial';
}
export interface Slide {

View File

@ -43,7 +43,6 @@ export default defineComponent({
width: 100%;
height: 100%;
background-position: center;
background-size: cover;
position: absolute;
}
</style>

View File

@ -1,29 +1,45 @@
<template>
<div class="canvas-tool">
<div class="left-handler">
<IconFont type="icon-undo" class="handler-item" :class="{ 'disable': !canUndo }" @click="undo()" />
<IconFont type="icon-redo" class="handler-item" :class="{ 'disable': !canRedo }" @click="redo()" />
<Tooltip :mouseLeaveDelay="0" :mouseEnterDelay="0.5" title="撤销">
<IconFont type="icon-undo" class="handler-item" :class="{ 'disable': !canUndo }" @click="undo()" />
</Tooltip>
<Tooltip :mouseLeaveDelay="0" :mouseEnterDelay="0.5" title="重做">
<IconFont type="icon-redo" class="handler-item" :class="{ 'disable': !canRedo }" @click="redo()" />
</Tooltip>
</div>
<div class="add-element-handler">
<IconFont type="icon-font-size" class="handler-item" @click="drawText()" />
<Tooltip :mouseLeaveDelay="0" :mouseEnterDelay="0.5" title="插入文字">
<IconFont type="icon-font-size" class="handler-item" @click="drawText()" />
</Tooltip>
<FileInput @change="files => insertImageElement(files)">
<IconFont type="icon-image" class="handler-item" />
<Tooltip :mouseLeaveDelay="0" :mouseEnterDelay="0.5" title="插入图片">
<IconFont type="icon-image" class="handler-item" />
</Tooltip>
</FileInput>
<Popover trigger="click" v-model:visible="isOpenShapePool">
<template #content>
<ShapePool @select="shape => drawShape(shape)" />
</template>
<IconFont type="icon-star" class="handler-item" />
<Tooltip :mouseLeaveDelay="0" :mouseEnterDelay="0.5" title="插入形状">
<IconFont type="icon-star" class="handler-item" />
</Tooltip>
</Popover>
<Popover trigger="click" v-model:visible="isOpenLinePool">
<template #content>
<LinePool @select="line => drawLine(line)" />
</template>
<IconFont type="icon-line" class="handler-item" />
<Tooltip :mouseLeaveDelay="0" :mouseEnterDelay="0.5" title="插入线条">
<IconFont type="icon-line" class="handler-item" />
</Tooltip>
</Popover>
<IconFont type="icon-table" class="handler-item" />
<IconFont type="icon-piechart" class="handler-item" />
<Tooltip :mouseLeaveDelay="0" :mouseEnterDelay="0.5" title="插入表格">
<IconFont type="icon-table" class="handler-item" />
</Tooltip>
<Tooltip :mouseLeaveDelay="0" :mouseEnterDelay="0.5" title="插入图表">
<IconFont type="icon-piechart" class="handler-item" />
</Tooltip>
</div>
<div class="right-handler">

View File

@ -4,7 +4,6 @@
<div class="menu-item">文件</div>
<div class="menu-item">编辑</div>
<div class="menu-item">设置</div>
<div class="menu-item">素材</div>
<div class="menu-item">演示</div>
<div class="menu-item">帮助</div>
</div>

View File

@ -26,8 +26,8 @@
<Divider />
<ButtonGroup class="row">
<Button :disabled="!canCombine" @click="combineElements()" style="flex: 1;">组合</Button>
<Button :disabled="canCombine" @click="uncombineElements()" style="flex: 1;">取消组合</Button>
<Button :disabled="!canCombine" @click="combineElements()" style="flex: 1;"><IconFont type="icon-group" />组合</Button>
<Button :disabled="canCombine" @click="uncombineElements()" style="flex: 1;"><IconFont type="icon-ungroup" />取消组合</Button>
</ButtonGroup>
</div>
</template>

View File

@ -1,13 +1,178 @@
<template>
<div class="slide-style-panel">
<div>背景填充</div>
<div class="title">背景填充</div>
<div class="row">
<Select
style="flex: 10;"
:value="background.type"
@change="value => updateBackgroundType(value)"
>
<SelectOption value="solid">纯色填充</SelectOption>
<SelectOption value="image">图片填充</SelectOption>
</Select>
<div style="flex: 1;"></div>
<Popover trigger="click" v-if="background.type === 'solid'">
<template #content>
<ColorPicker
:modelValue="background.value"
@update:modelValue="value => updateBackground({ value })"
/>
</template>
<ColorButton :color="background.value" style="flex: 10;" />
</Popover>
<Select
style="flex: 10;"
:value="background.size || 'cover'"
@change="value => updateBackground({ size: value })"
v-else
>
<SelectOption value="initial">原始大小</SelectOption>
<SelectOption value="contain">缩放</SelectOption>
<SelectOption value="repeat">拼贴</SelectOption>
<SelectOption value="cover">缩放铺满</SelectOption>
</Select>
</div>
<div class="background-image-wrapper" v-if="background.type === 'image'">
<FileInput @change="files => uploadBackgroundImage(files)">
<div class="background-image">
<div
class="content"
:style="backgroundStyle"
>
<IconFont type="icon-plus" />
</div>
</div>
</FileInput>
</div>
<div class="row"><Button style="flex: 1;" @click="applyAllSlide()">应用到全部</Button></div>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
import { computed, defineComponent, Ref } from 'vue'
import { useStore } from 'vuex'
import { MutationTypes, State } from '@/store'
import { Slide, SlideBackground } from '@/types/slides'
import useHistorySnapshot from '@/hooks/useHistorySnapshot'
import ColorButton from './common/ColorButton.vue'
import { getImageDataURL } from '@/utils/image'
import useSlideBackgroundStyle from '@/hooks/useSlideBackgroundStyle'
export default defineComponent({
name: 'slide-style-panel',
components: {
ColorButton,
},
setup() {
const store = useStore<State>()
const slides = computed(() => store.state.slides)
const currentSlide: Ref<Slide> = computed(() => store.getters.currentSlide)
const background = computed(() => {
if(!currentSlide.value.background) {
return {
type: 'solid',
value: '#fff',
} as SlideBackground
}
return currentSlide.value.background
})
const { backgroundStyle } = useSlideBackgroundStyle(background)
const { addHistorySnapshot } = useHistorySnapshot()
const updateBackgroundType = (type: 'solid' | 'image') => {
if(type === 'solid') {
const background: SlideBackground = {
type: 'solid',
value: '#fff',
}
store.commit(MutationTypes.UPDATE_SLIDE, { background })
}
else {
const background: SlideBackground = {
type: 'image',
value: '',
size: 'cover',
}
store.commit(MutationTypes.UPDATE_SLIDE, { background })
}
addHistorySnapshot()
}
const updateBackground = (props: Partial<SlideBackground>) => {
store.commit(MutationTypes.UPDATE_SLIDE, { background: { ...background.value, ...props } })
addHistorySnapshot()
}
const uploadBackgroundImage = (files: File[]) => {
const imageFile = files[0]
if(!imageFile) return
getImageDataURL(imageFile).then(dataURL => updateBackground({ value: dataURL }))
}
const applyAllSlide = () => {
const newSlides = slides.value.map(slide => {
return {
...slide,
background: currentSlide.value.background,
}
})
store.commit(MutationTypes.SET_SLIDES, newSlides)
addHistorySnapshot()
}
return {
background,
backgroundStyle,
updateBackgroundType,
updateBackground,
uploadBackgroundImage,
applyAllSlide,
}
},
})
</script>
</script>
<style lang="scss" scoped>
.row {
width: 100%;
display: flex;
align-items: center;
margin-bottom: 10px;
}
.title {
margin-bottom: 10px;
}
.background-image-wrapper {
margin-bottom: 10px;
}
.background-image {
height: 0;
padding-bottom: 56.25%;
border: 1px dashed $borderColor;
border-radius: $borderRadius;
position: relative;
transition: all .2s;
&:hover {
border-color: $themeColor;
color: $themeColor;
}
.content {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
display: flex;
justify-content: center;
align-items: center;
background-position: center;
cursor: pointer;
}
}
</style>

View File

@ -0,0 +1,38 @@
<template>
<Button class="color-btn">
<div class="color-block" :style="{ backgroundColor: color }"></div>
<IconFont type="icon-down" class="color-btn-icon" />
</Button>
</template>
<script lang="ts">
export default {
name: 'color-button',
props: {
color: {
type: String,
required: true,
},
},
}
</script>
<style lang="scss" scoped>
.color-btn {
display: flex;
align-items: center;
justify-content: center;
padding: 0 !important;
}
.color-block {
height: 20px;
margin-left: 8px;
flex: 1;
}
.color-btn-icon {
width: 30px;
font-size: 12px;
margin-top: 2px;
color: #bfbfbf;
}
</style>

View File

@ -30,10 +30,7 @@
@update:modelValue="value => updateOutline({ color: value })"
/>
</template>
<Button class="color-btn" style="flex: 3;">
<div class="color-block" :style="{ backgroundColor: outline.color }"></div>
<IconFont type="icon-down" class="color-btn-icon" />
</Button>
<ColorButton :color="outline.color" style="flex: 3;" />
</Popover>
</div>
<div class="row">
@ -55,8 +52,13 @@ import { MutationTypes, State } from '@/store'
import { PPTElement, PPTElementOutline } from '@/types/slides'
import useHistorySnapshot from '@/hooks/useHistorySnapshot'
import ColorButton from './ColorButton.vue'
export default defineComponent({
name: 'element-outline',
components: {
ColorButton,
},
setup() {
const store = useStore<State>()
const handleElement: Ref<PPTElement> = computed(() => store.getters.handleElement)
@ -104,22 +106,6 @@ export default defineComponent({
align-items: center;
margin-bottom: 10px;
}
.color-btn {
display: flex;
align-items: center;
padding: 0 !important;
}
.color-block {
width: 100px;
height: 20px;
background-color: #777;
margin: 0 8px;
}
.color-btn-icon {
font-size: 12px;
margin-top: 2px;
color: #bfbfbf;
}
.switch-wrapper {
text-align: right;
}

View File

@ -49,10 +49,7 @@
@update:modelValue="value => updateShadow({ color: value })"
/>
</template>
<Button class="color-btn" style="flex: 3;">
<div class="color-block"></div>
<IconFont type="icon-down" class="color-btn-icon" />
</Button>
<ColorButton :color="shadow.color" style="flex: 3;" />
</Popover>
</div>
</template>
@ -66,8 +63,13 @@ import { MutationTypes, State } from '@/store'
import { PPTElement, PPTElementShadow } from '@/types/slides'
import useHistorySnapshot from '@/hooks/useHistorySnapshot'
import ColorButton from './ColorButton.vue'
export default defineComponent({
name: 'element-shadow',
components: {
ColorButton,
},
setup() {
const store = useStore<State>()
const handleElement: Ref<PPTElement> = computed(() => store.getters.handleElement)
@ -115,22 +117,6 @@ export default defineComponent({
align-items: center;
margin-bottom: 10px;
}
.color-btn {
display: flex;
align-items: center;
padding: 0 !important;
}
.color-block {
width: 100px;
height: 20px;
background-color: #777;
margin: 0 8px;
}
.color-btn-icon {
font-size: 12px;
margin-top: 2px;
color: #bfbfbf;
}
.switch-wrapper {
text-align: right;
}

View File

@ -67,8 +67,9 @@ export default defineComponent({
transform-origin: 0 0;
}
.background {
width: 100%;
height: 100%;
background-position: center;
background-size: cover;
position: absolute;
}
</style>

View File

@ -69,8 +69,9 @@ export default defineComponent({
transform-origin: 0 0;
}
.background {
width: 100%;
height: 100%;
background-position: center;
background-size: cover;
position: absolute;
}
</style>