perf: 提取主题色优化

This commit is contained in:
zxc 2025-03-14 18:28:15 +08:00
parent 373426bfad
commit dbf4a12bff

View File

@ -7,7 +7,7 @@
:tabStyle="{ padding: '8px 12px' }"
/>
<div class="content">
<div class="config-item">
<div class="config-item" v-if="themeStyles.fontNames.length">
<div class="label">字体</div>
<div class="values">
<div class="value-wrap" v-for="(item, index) in themeStyles.fontNames" :key="item">
@ -15,47 +15,42 @@
<div class="handler">
<div class="state" :class="{ 'active': selectedIndex.fontName === index }"></div>
<div class="config-btn" @click="selectedIndex.fontName = index">选择</div>
<div class="config-btn" @click="updateTheme({ fontName: item }); selectedIndex.fontName = index">配置到主题</div>
<div class="config-btn" @click="updateTheme({ fontName: item }); selectedIndex.fontName = index">应用到主题</div>
</div>
</div>
</div>
</div>
<div class="config-item">
<div class="config-item" v-if="themeStyles.fontColors.length">
<div class="label">文字颜色</div>
<div class="values">
<div class="value-wrap" v-for="(item, index) in themeStyles.fontColors" :key="item">
<div class="value" :style="{ backgroundColor: item }"></div>
<div class="value" :style="{ backgroundColor: item, color: getMostReadableColor(item) }">{{ getHexColor(item) }}</div>
<div class="handler">
<div class="state" :class="{ 'active': selectedIndex.fontColor === index }"></div>
<div class="config-btn" @click="selectedIndex.fontColor = index">选择</div>
<div class="config-btn" @click="updateTheme({ fontColor: item }); selectedIndex.fontColor = index">配置到主题</div>
<div class="config-btn" @click="updateTheme({ fontColor: item }); selectedIndex.fontColor = index">应用到主题</div>
</div>
</div>
</div>
</div>
<div class="config-item">
<div class="config-item" v-if="themeStyles.backgroundColors.length">
<div class="label">背景颜色</div>
<div class="values">
<div class="value-wrap" v-for="(item, index) in themeStyles.backgroundColors" :key="item">
<div class="value" :style="{ backgroundColor: item }"></div>
<div class="value" :style="{ backgroundColor: item, color: getMostReadableColor(item) }">{{ getHexColor(item) }}</div>
<div class="handler">
<div class="state" :class="{ 'active': selectedIndex.backgroundColor === index }"></div>
<div class="config-btn" @click="selectedIndex.backgroundColor = index">选择</div>
<div class="config-btn" @click="updateTheme({ backgroundColor: item }); selectedIndex.backgroundColor = index">配置到主题</div>
<div class="config-btn" @click="updateTheme({ backgroundColor: item }); selectedIndex.backgroundColor = index">应用到主题</div>
</div>
</div>
</div>
</div>
<div class="config-item">
<div class="label">主题色</div>
<div class="values">
<div class="value-wrap" v-for="(item, index) in themeStyles.themeColors" :key="item">
<div class="value" :style="{ backgroundColor: item }"></div>
<div class="handler">
<div class="state" :class="{ 'active': selectedIndex.themeColor === index }"></div>
<div class="config-btn" @click="selectedIndex.themeColor = index">选择</div>
<!-- <div class="config-btn" @click="updateTheme({ themeColor: item }); selectedIndex.themeColor = index">配置到主题</div> -->
</div>
<div class="config-item" v-if="themeStyles.themeColors.length">
<div class="label">主题色<span class="tip">点击色块排除不要的颜色</span></div>
<div class="values inline">
<div class="value-wrap" v-for="(item, index) in themeStyles.themeColors" :key="item" @click="removeThemeColor(index)">
<div class="value" :class="{ 'disabled': !selectedIndex.themeColors.includes(index) }" :style="{ backgroundColor: item }"></div>
</div>
</div>
</div>
@ -70,12 +65,14 @@
<script lang="ts" setup>
import { onMounted, ref, watch } from 'vue'
import { storeToRefs } from 'pinia'
import tinycolor from 'tinycolor2'
import { useSlidesStore } from '@/store'
import { FONTS } from '@/configs/font'
import useSlideTheme from '@/hooks/useSlideTheme'
import Tabs from '@/components/Tabs.vue'
import Button from '@/components/Button.vue'
import type { SlideTheme } from '@/types/slides'
import message from '@/utils/message'
const emit = defineEmits<{
(event: 'close'): void
@ -113,7 +110,7 @@ const themeStyles = ref<ReturnType<typeof getSlidesThemeStyles>>({
})
const selectedIndex = ref({
backgroundColor: 0,
themeColor: 0,
themeColors: [0],
fontColor: 0,
fontName: 0,
})
@ -121,24 +118,62 @@ const selectedIndex = ref({
watch(activeTab, () => {
if (activeTab.value === 'single') themeStyles.value = getSlidesThemeStyles(currentSlide.value)
else themeStyles.value = getSlidesThemeStyles(slides.value)
})
onMounted(() => {
themeStyles.value = getSlidesThemeStyles(currentSlide.value)
})
const themeColors = []
for (let i = 0; i < Math.min(themeStyles.value.themeColors.length); i++) {
themeColors.push(i)
}
selectedIndex.value = {
backgroundColor: 0,
fontColor: 0,
fontName: 0,
themeColors,
}
}, { immediate: true })
const updateTheme = (themeProps: Partial<SlideTheme>) => {
slidesStore.setTheme(themeProps)
}
const updateAllThemes = () => {
slidesStore.setTheme({
backgroundColor: themeStyles.value.backgroundColors[selectedIndex.value.backgroundColor],
themeColors: themeStyles.value.themeColors,
fontColor: themeStyles.value.fontColors[selectedIndex.value.fontColor],
fontName: themeStyles.value.fontNames[selectedIndex.value.fontName],
})
let themeColors = themeStyles.value.themeColors.filter((item, index) => selectedIndex.value.themeColors.includes(index))
if (themeColors.length > 6) {
themeColors = themeColors.slice(0, 6)
message.warning('主题色超出数量限制已自动选取前6个')
}
const backgroundColor = themeStyles.value.backgroundColors[selectedIndex.value.backgroundColor]
const fontColor = themeStyles.value.fontColors[selectedIndex.value.fontColor]
const fontName = themeStyles.value.fontNames[selectedIndex.value.fontName]
const data: Partial<SlideTheme> = {}
if (backgroundColor) data.backgroundColor = backgroundColor
if (fontColor) data.fontColor = fontColor
if (fontName) data.fontName = fontName
if (themeColors.length) data.themeColors = themeColors
slidesStore.setTheme(data)
emit('close')
}
const removeThemeColor = (index: number) => {
if (selectedIndex.value.themeColors.includes(index)) {
selectedIndex.value.themeColors = selectedIndex.value.themeColors.filter(i => i !== index)
}
else selectedIndex.value.themeColors.push(index)
}
const getMostReadableColor = (color: string) => {
const colorList = ['#000', '#fff']
return tinycolor.mostReadable(color, colorList, { includeFallbackColors: true }).toRgbString()
}
const getHexColor = (color: string) => {
const c = tinycolor(color)
const alpha = c.getAlpha()
if (alpha < 1) return c.toHex8String().toUpperCase()
return c.toHexString().toUpperCase()
}
</script>
<style lang="scss" scoped>
@ -159,9 +194,56 @@ const updateAllThemes = () => {
font-size: 13px;
}
.label {
margin-bottom: 5px
margin-bottom: 5px;
display: flex;
align-items: center;
.tip {
font-size: 12px;
color: #999;
}
}
.values {
&.inline {
@include flex-grid-layout();
.value-wrap {
@include flex-grid-layout-children(10, 9%);
margin-top: 0 !important;
cursor: pointer;
}
.value {
height: 25px;
padding: 0;
&.disabled {
opacity: 0.2;
position: relative;
&::after {
content: '';
width: 24px;
height: 2px;
position: absolute;
top: 11px;
left: -1px;
transform: rotate(-45deg);
background-color: #000;
}
&::before {
content: '';
width: 24px;
height: 2px;
position: absolute;
top: 11px;
left: -1px;
transform: rotate(45deg);
background-color: #000;
}
}
}
}
.value-wrap {
display: flex;
align-items: center;
@ -197,14 +279,14 @@ const updateAllThemes = () => {
}
.value {
width: 150px;
height: 24px;
height: 25px;
line-height: 25px;
text-align: center;
border: 1px solid $borderColor;
display: flex;
align-items: center;
justify-content: center;
font-size: 12px;
padding: 5px;
padding: 0 5px;
border-radius: $borderRadius;
@include ellipsis-oneline();
}
}
.btns {