mirror of
https://github.com/pipipi-pikachu/PPTist.git
synced 2025-04-15 02:20:00 +08:00
perf: 提取主题色优化
This commit is contained in:
parent
373426bfad
commit
dbf4a12bff
@ -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 {
|
||||
|
Loading…
x
Reference in New Issue
Block a user