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' }"
|
:tabStyle="{ padding: '8px 12px' }"
|
||||||
/>
|
/>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<div class="config-item">
|
<div class="config-item" v-if="themeStyles.fontNames.length">
|
||||||
<div class="label">字体:</div>
|
<div class="label">字体:</div>
|
||||||
<div class="values">
|
<div class="values">
|
||||||
<div class="value-wrap" v-for="(item, index) in themeStyles.fontNames" :key="item">
|
<div class="value-wrap" v-for="(item, index) in themeStyles.fontNames" :key="item">
|
||||||
@ -15,47 +15,42 @@
|
|||||||
<div class="handler">
|
<div class="handler">
|
||||||
<div class="state" :class="{ 'active': selectedIndex.fontName === index }">√</div>
|
<div class="state" :class="{ 'active': selectedIndex.fontName === index }">√</div>
|
||||||
<div class="config-btn" @click="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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="config-item">
|
<div class="config-item" v-if="themeStyles.fontColors.length">
|
||||||
<div class="label">文字颜色:</div>
|
<div class="label">文字颜色:</div>
|
||||||
<div class="values">
|
<div class="values">
|
||||||
<div class="value-wrap" v-for="(item, index) in themeStyles.fontColors" :key="item">
|
<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="handler">
|
||||||
<div class="state" :class="{ 'active': selectedIndex.fontColor === index }">√</div>
|
<div class="state" :class="{ 'active': selectedIndex.fontColor === index }">√</div>
|
||||||
<div class="config-btn" @click="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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="config-item">
|
<div class="config-item" v-if="themeStyles.backgroundColors.length">
|
||||||
<div class="label">背景颜色:</div>
|
<div class="label">背景颜色:</div>
|
||||||
<div class="values">
|
<div class="values">
|
||||||
<div class="value-wrap" v-for="(item, index) in themeStyles.backgroundColors" :key="item">
|
<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="handler">
|
||||||
<div class="state" :class="{ 'active': selectedIndex.backgroundColor === index }">√</div>
|
<div class="state" :class="{ 'active': selectedIndex.backgroundColor === index }">√</div>
|
||||||
<div class="config-btn" @click="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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="config-item">
|
<div class="config-item" v-if="themeStyles.themeColors.length">
|
||||||
<div class="label">主题色:</div>
|
<div class="label">主题色:<span class="tip">(点击色块排除不要的颜色)</span></div>
|
||||||
<div class="values">
|
<div class="values inline">
|
||||||
<div class="value-wrap" v-for="(item, index) in themeStyles.themeColors" :key="item">
|
<div class="value-wrap" v-for="(item, index) in themeStyles.themeColors" :key="item" @click="removeThemeColor(index)">
|
||||||
<div class="value" :style="{ backgroundColor: item }"></div>
|
<div class="value" :class="{ 'disabled': !selectedIndex.themeColors.includes(index) }" :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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -70,12 +65,14 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onMounted, ref, watch } from 'vue'
|
import { onMounted, ref, watch } from 'vue'
|
||||||
import { storeToRefs } from 'pinia'
|
import { storeToRefs } from 'pinia'
|
||||||
|
import tinycolor from 'tinycolor2'
|
||||||
import { useSlidesStore } from '@/store'
|
import { useSlidesStore } from '@/store'
|
||||||
import { FONTS } from '@/configs/font'
|
import { FONTS } from '@/configs/font'
|
||||||
import useSlideTheme from '@/hooks/useSlideTheme'
|
import useSlideTheme from '@/hooks/useSlideTheme'
|
||||||
import Tabs from '@/components/Tabs.vue'
|
import Tabs from '@/components/Tabs.vue'
|
||||||
import Button from '@/components/Button.vue'
|
import Button from '@/components/Button.vue'
|
||||||
import type { SlideTheme } from '@/types/slides'
|
import type { SlideTheme } from '@/types/slides'
|
||||||
|
import message from '@/utils/message'
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(event: 'close'): void
|
(event: 'close'): void
|
||||||
@ -113,7 +110,7 @@ const themeStyles = ref<ReturnType<typeof getSlidesThemeStyles>>({
|
|||||||
})
|
})
|
||||||
const selectedIndex = ref({
|
const selectedIndex = ref({
|
||||||
backgroundColor: 0,
|
backgroundColor: 0,
|
||||||
themeColor: 0,
|
themeColors: [0],
|
||||||
fontColor: 0,
|
fontColor: 0,
|
||||||
fontName: 0,
|
fontName: 0,
|
||||||
})
|
})
|
||||||
@ -121,24 +118,62 @@ const selectedIndex = ref({
|
|||||||
watch(activeTab, () => {
|
watch(activeTab, () => {
|
||||||
if (activeTab.value === 'single') themeStyles.value = getSlidesThemeStyles(currentSlide.value)
|
if (activeTab.value === 'single') themeStyles.value = getSlidesThemeStyles(currentSlide.value)
|
||||||
else themeStyles.value = getSlidesThemeStyles(slides.value)
|
else themeStyles.value = getSlidesThemeStyles(slides.value)
|
||||||
})
|
|
||||||
onMounted(() => {
|
const themeColors = []
|
||||||
themeStyles.value = getSlidesThemeStyles(currentSlide.value)
|
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>) => {
|
const updateTheme = (themeProps: Partial<SlideTheme>) => {
|
||||||
slidesStore.setTheme(themeProps)
|
slidesStore.setTheme(themeProps)
|
||||||
}
|
}
|
||||||
|
|
||||||
const updateAllThemes = () => {
|
const updateAllThemes = () => {
|
||||||
slidesStore.setTheme({
|
let themeColors = themeStyles.value.themeColors.filter((item, index) => selectedIndex.value.themeColors.includes(index))
|
||||||
backgroundColor: themeStyles.value.backgroundColors[selectedIndex.value.backgroundColor],
|
if (themeColors.length > 6) {
|
||||||
themeColors: themeStyles.value.themeColors,
|
themeColors = themeColors.slice(0, 6)
|
||||||
fontColor: themeStyles.value.fontColors[selectedIndex.value.fontColor],
|
message.warning('主题色超出数量限制,已自动选取前6个')
|
||||||
fontName: themeStyles.value.fontNames[selectedIndex.value.fontName],
|
}
|
||||||
})
|
|
||||||
|
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')
|
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>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@ -159,9 +194,56 @@ const updateAllThemes = () => {
|
|||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
}
|
}
|
||||||
.label {
|
.label {
|
||||||
margin-bottom: 5px
|
margin-bottom: 5px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.tip {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.values {
|
.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 {
|
.value-wrap {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@ -197,14 +279,14 @@ const updateAllThemes = () => {
|
|||||||
}
|
}
|
||||||
.value {
|
.value {
|
||||||
width: 150px;
|
width: 150px;
|
||||||
height: 24px;
|
height: 25px;
|
||||||
|
line-height: 25px;
|
||||||
|
text-align: center;
|
||||||
border: 1px solid $borderColor;
|
border: 1px solid $borderColor;
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
padding: 5px;
|
padding: 0 5px;
|
||||||
border-radius: $borderRadius;
|
border-radius: $borderRadius;
|
||||||
|
@include ellipsis-oneline();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.btns {
|
.btns {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user