mirror of
https://github.com/pipipi-pikachu/PPTist.git
synced 2025-04-15 02:20:00 +08:00
feat: 全局主题设置支持边框、阴影相关属性
This commit is contained in:
parent
34488b6eb4
commit
99c53c385d
@ -129,9 +129,9 @@ export default () => {
|
||||
}
|
||||
|
||||
// 将当前主题配置应用到全部页面
|
||||
const applyThemeToAllSlides = () => {
|
||||
const applyThemeToAllSlides = (applyAll = false) => {
|
||||
const newSlides: Slide[] = JSON.parse(JSON.stringify(slides.value))
|
||||
const { themeColor, backgroundColor, fontColor, fontName } = theme.value
|
||||
const { themeColor, backgroundColor, fontColor, fontName, outline, shadow } = theme.value
|
||||
|
||||
for (const slide of newSlides) {
|
||||
if (!slide.background || slide.background.type !== 'image') {
|
||||
@ -142,6 +142,11 @@ export default () => {
|
||||
}
|
||||
|
||||
for (const el of slide.elements) {
|
||||
if (applyAll) {
|
||||
if ('outline' in el && el.outline) el.outline = outline
|
||||
if ('shadow' in el && el.shadow) el.shadow = shadow
|
||||
}
|
||||
|
||||
if (el.type === 'shape') el.fill = themeColor
|
||||
else if (el.type === 'line') el.color = themeColor
|
||||
else if (el.type === 'text') {
|
||||
|
@ -5,4 +5,15 @@ export const theme: SlideTheme = {
|
||||
fontColor: '#333',
|
||||
fontName: 'Microsoft Yahei',
|
||||
backgroundColor: '#fff',
|
||||
shadow: {
|
||||
h: 3,
|
||||
v: 3,
|
||||
blur: 2,
|
||||
color: '#808080',
|
||||
},
|
||||
outline: {
|
||||
width: 2,
|
||||
color: '#525252',
|
||||
style: 'solid',
|
||||
},
|
||||
}
|
@ -694,4 +694,6 @@ export interface SlideTheme {
|
||||
themeColor: string
|
||||
fontColor: string
|
||||
fontName: string
|
||||
outline: PPTElementOutline
|
||||
shadow: PPTElementShadow
|
||||
}
|
||||
|
@ -119,7 +119,14 @@
|
||||
|
||||
<Divider />
|
||||
|
||||
<div class="title">全局主题</div>
|
||||
<div class="title">
|
||||
<span>全局主题</span>
|
||||
<span class="more" @click="moreThemeConfigsVisible = !moreThemeConfigsVisible">
|
||||
<span class="text">更多</span>
|
||||
<IconDown v-if="moreThemeConfigsVisible" />
|
||||
<IconRight v-else />
|
||||
</span>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div style="width: 40%;">字体:</div>
|
||||
<Select
|
||||
@ -168,9 +175,89 @@
|
||||
<ColorButton :color="theme.themeColor" />
|
||||
</Popover>
|
||||
</div>
|
||||
|
||||
<template v-if="moreThemeConfigsVisible">
|
||||
<div class="row">
|
||||
<div style="width: 40%;">边框样式:</div>
|
||||
<Select
|
||||
style="width: 60%;"
|
||||
:value="theme.outline.style || ''"
|
||||
@update:value="value => updateTheme({ outline: { ...theme.outline, style: value as 'dashed' | 'solid' } })"
|
||||
:options="[
|
||||
{ label: '实线边框', value: 'solid' },
|
||||
{ label: '虚线边框', value: 'dashed' },
|
||||
]"
|
||||
/>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div style="width: 40%;">边框颜色:</div>
|
||||
<Popover trigger="click" style="width: 60%;">
|
||||
<template #content>
|
||||
<ColorPicker
|
||||
:modelValue="theme.outline.color"
|
||||
@update:modelValue="value => updateTheme({ outline: { ...theme.outline, color: value } })"
|
||||
/>
|
||||
</template>
|
||||
<ColorButton :color="theme.outline.color || '#000'" />
|
||||
</Popover>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div style="width: 40%;">边框粗细:</div>
|
||||
<NumberInput
|
||||
:value="theme.outline.width || 0"
|
||||
@update:value="value => updateTheme({ outline: { ...theme.outline, width: value } })"
|
||||
style="width: 60%;"
|
||||
/>
|
||||
</div>
|
||||
<div class="row" style="height: 30px;">
|
||||
<div style="width: 40%;">水平阴影:</div>
|
||||
<Slider
|
||||
style="width: 60%;"
|
||||
:min="-10"
|
||||
:max="10"
|
||||
:step="1"
|
||||
:value="theme.shadow.h"
|
||||
@update:value="value => updateTheme({ shadow: { ...theme.shadow, h: value as number } })"
|
||||
/>
|
||||
</div>
|
||||
<div class="row" style="height: 30px;">
|
||||
<div style="width: 40%;">垂直阴影:</div>
|
||||
<Slider
|
||||
style="width: 60%;"
|
||||
:min="-10"
|
||||
:max="10"
|
||||
:step="1"
|
||||
:value="theme.shadow.v"
|
||||
@update:value="value => updateTheme({ shadow: { ...theme.shadow, v: value as number } })"
|
||||
/>
|
||||
</div>
|
||||
<div class="row" style="height: 30px;">
|
||||
<div style="width: 40%;">模糊距离:</div>
|
||||
<Slider
|
||||
style="width: 60%;"
|
||||
:min="1"
|
||||
:max="20"
|
||||
:step="1"
|
||||
:value="theme.shadow.blur"
|
||||
@update:value="value => updateTheme({ shadow: { ...theme.shadow, blur: value as number } })"
|
||||
/>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div style="width: 40%;">阴影颜色:</div>
|
||||
<Popover trigger="click" style="width: 60%;">
|
||||
<template #content>
|
||||
<ColorPicker
|
||||
:modelValue="theme.shadow.color"
|
||||
@update:modelValue="value => updateTheme({ shadow: { ...theme.shadow, color: value } })"
|
||||
/>
|
||||
</template>
|
||||
<ColorButton :color="theme.shadow.color" />
|
||||
</Popover>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<div class="row">
|
||||
<Button style="flex: 1;" @click="applyThemeToAllSlides()">应用主题到全部</Button>
|
||||
<Button style="flex: 1;" @click="applyThemeToAllSlides(moreThemeConfigsVisible)">应用主题到全部</Button>
|
||||
</div>
|
||||
|
||||
<Divider />
|
||||
@ -203,7 +290,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed } from 'vue'
|
||||
import { computed, ref } from 'vue'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useMainStore, useSlidesStore } from '@/store'
|
||||
import type { SlideBackground, SlideTheme } from '@/types/slides'
|
||||
@ -221,11 +308,14 @@ import Slider from '@/components/Slider.vue'
|
||||
import Button from '@/components/Button.vue'
|
||||
import Select from '@/components/Select.vue'
|
||||
import Popover from '@/components/Popover.vue'
|
||||
import NumberInput from '@/components/NumberInput.vue'
|
||||
|
||||
const slidesStore = useSlidesStore()
|
||||
const { availableFonts } = storeToRefs(useMainStore())
|
||||
const { slides, currentSlide, viewportRatio, theme } = storeToRefs(slidesStore)
|
||||
|
||||
const moreThemeConfigsVisible = ref(false)
|
||||
|
||||
const background = computed(() => {
|
||||
if (!currentSlide.value.background) {
|
||||
return {
|
||||
@ -322,7 +412,18 @@ const updateViewportRatio = (value: number) => {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.title {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 10px;
|
||||
|
||||
.more {
|
||||
cursor: pointer;
|
||||
|
||||
.text {
|
||||
font-size: 12px;
|
||||
margin-right: 3px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.background-image-wrapper {
|
||||
margin-bottom: 10px;
|
||||
|
@ -67,6 +67,7 @@ withDefaults(defineProps<{
|
||||
})
|
||||
|
||||
const slidesStore = useSlidesStore()
|
||||
const { theme } = storeToRefs(slidesStore)
|
||||
const { handleElement } = storeToRefs(useMainStore())
|
||||
|
||||
const outline = ref<PPTElementOutline>()
|
||||
@ -90,7 +91,7 @@ const updateOutline = (outlineProps: Partial<PPTElementOutline>) => {
|
||||
const toggleOutline = (checked: boolean) => {
|
||||
if (!handleElement.value) return
|
||||
if (checked) {
|
||||
const _outline: PPTElementOutline = { width: 2, color: '#000', style: 'solid' }
|
||||
const _outline: PPTElementOutline = theme.value.outline
|
||||
slidesStore.updateElement({ id: handleElement.value.id, props: { outline: _outline } })
|
||||
}
|
||||
else {
|
||||
@ -103,6 +104,7 @@ const toggleOutline = (checked: boolean) => {
|
||||
<style lang="scss" scoped>
|
||||
.row {
|
||||
width: 100%;
|
||||
height: 30px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 10px;
|
||||
|
@ -70,6 +70,7 @@ import Slider from '@/components/Slider.vue'
|
||||
import Popover from '@/components/Popover.vue'
|
||||
|
||||
const slidesStore = useSlidesStore()
|
||||
const { theme } = storeToRefs(slidesStore)
|
||||
const { handleElement } = storeToRefs(useMainStore())
|
||||
|
||||
const shadow = ref<PPTElementShadow>()
|
||||
@ -93,7 +94,7 @@ const updateShadow = (shadowProps: Partial<PPTElementShadow>) => {
|
||||
const toggleShadow = (checked: boolean) => {
|
||||
if (!handleElement.value) return
|
||||
if (checked) {
|
||||
const _shadow: PPTElementShadow = { h: 1, v: 1, blur: 2, color: '#000' }
|
||||
const _shadow: PPTElementShadow = theme.value.shadow
|
||||
slidesStore.updateElement({ id: handleElement.value.id, props: { shadow: _shadow } })
|
||||
}
|
||||
else {
|
||||
@ -106,6 +107,7 @@ const toggleShadow = (checked: boolean) => {
|
||||
<style lang="scss" scoped>
|
||||
.row {
|
||||
width: 100%;
|
||||
height: 30px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 10px;
|
||||
|
Loading…
x
Reference in New Issue
Block a user