1
0
mirror of https://github.com/1Panel-dev/1Panel.git synced 2025-01-18 15:59:16 +08:00

feat: Save the theme color scheme to the client (#7626)

Refs #7074
This commit is contained in:
2025-01-03 10:30:07 +08:00 committed by GitHub
parent a291a50c9f
commit f7c875acda
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -16,29 +16,23 @@
<el-form-item :label="$t('setting.light')" prop="light">
<div class="flex flex-wrap justify-between items-center sm:items-start">
<div class="flex gap-1">
<el-tooltip :content="$t('xpack.theme.classicBlue')" placement="top">
<el-button
color="#005eeb"
circle
dark
:class="form.light === '#005eeb' ? 'selected-white' : ''"
@click="changeLightColor('#005eeb')"
/>
</el-tooltip>
<el-tooltip :content="$t('xpack.theme.freshGreen')" placement="top">
<el-button
color="#238636"
:class="form.light === '#238636' ? 'selected-white' : ''"
circle
dark
@click="changeLightColor('#238636')"
/>
</el-tooltip>
<template v-for="colorConfig in lightColors" :key="colorConfig.color">
<el-tooltip :content="$t(colorConfig.label)" placement="top">
<el-button
:color="colorConfig.color"
:class="form.light === colorConfig.color ? 'selected-white' : ''"
circle
dark
@click="changeLightColor(colorConfig.color)"
/>
</el-tooltip>
</template>
<el-color-picker
v-model="form.light"
class="ml-4"
:predefine="predefineColors"
:predefine="lightPredefineColors"
show-alpha
@change="changeThemeColor('light', form.light)"
/>
</div>
</div>
@ -48,38 +42,23 @@
<div class="flex flex-wrap justify-between items-center sm:items-start">
<div class="flex flex-wrap justify-between items-center mt-4 sm:mt-0">
<div class="flex gap-1">
<el-tooltip :content="$t('xpack.theme.classicBlue')" placement="top">
<el-button
color="#3D8EFF"
circle
dark
:class="form.dark === '#3D8EFF' ? 'selected-white' : ''"
@click="changeDarkColor('#3D8EFF')"
/>
</el-tooltip>
<el-tooltip :content="$t('xpack.theme.lingXiaGold')" placement="top">
<el-button
color="#F0BE96"
:class="form.dark === '#F0BE96' ? 'selected-white' : ''"
circle
dark
@click="changeDarkColor('#F0BE96')"
/>
</el-tooltip>
<el-tooltip :content="$t('xpack.theme.freshGreen')" placement="top">
<el-button
color="#238636"
:class="form.dark === '#238636' ? 'selected-white' : ''"
circle
dark
@click="changeDarkColor('#238636')"
/>
</el-tooltip>
<template v-for="colorConfig in darkColors" :key="colorConfig.color">
<el-tooltip :content="$t(colorConfig.label)" placement="top">
<el-button
:color="colorConfig.color"
:class="form.dark === colorConfig.color ? 'selected-white' : ''"
circle
dark
@click="changeDarkColor(colorConfig.color)"
/>
</el-tooltip>
</template>
<el-color-picker
v-model="form.dark"
class="ml-4"
:predefine="predefineColors"
:predefine="darkPredefineColors"
show-alpha
@change="changeThemeColor('dark', form.dark)"
/>
</div>
</div>
@ -110,7 +89,7 @@ import { initFavicon, updateXpackSettingByKey } from '@/utils/xpack';
import { setPrimaryColor } from '@/utils/theme';
import { GlobalStore } from '@/store';
const emit = defineEmits<{ (e: 'search'): void }>();
const emit = defineEmits<(e: 'search') => void>();
const drawerVisible = ref();
const loading = ref();
@ -132,11 +111,25 @@ const form = reactive({
});
const formRef = ref<FormInstance>();
const predefineColors = ref([
const globalStore = GlobalStore();
const STORAGE_KEY = 'theme-predefine-colors';
const lightPredefineColors = ref([
'#005eeb',
'#238636',
'#3D8EFF',
'#F0BE96',
'#00ced1',
'#c71585',
'#ff4500',
'#ff8c00',
'#ffd700',
]);
const darkPredefineColors = ref([
'#238636',
'#3D8EFF',
'#005eeb',
'#F0BE96',
'#00ced1',
'#c71585',
'#ff4500',
@ -144,16 +137,111 @@ const predefineColors = ref([
'#ffd700',
]);
const globalStore = GlobalStore();
const defaultDarkColors = [
{ color: '#3D8EFF', label: 'xpack.theme.classicBlue' },
{ color: '#F0BE96', label: 'xpack.theme.lingXiaGold' },
{ color: '#238636', label: 'xpack.theme.freshGreen' },
];
const defaultLightColors = [
{ color: '#005eeb', label: 'xpack.theme.classicBlue' },
{ color: '#238636', label: 'xpack.theme.freshGreen' },
];
let darkColors = [...defaultDarkColors];
let lightColors = [...defaultLightColors];
const addColorToTheme = (
colors: { color: string; label: string }[],
newColor: { color: string; label: string },
baseCount = 3,
maxNewColors = 2,
): { color: string; label: string }[] => {
const updatedColors = [...colors];
const extraCount = Math.max(0, colors.length - baseCount);
if (extraCount >= maxNewColors) {
updatedColors.splice(baseCount, 1);
}
updatedColors.push(newColor);
return updatedColors;
};
const defaultColors = {
light: lightPredefineColors.value,
dark: darkPredefineColors.value,
};
const initThemeColors = () => {
try {
const storedColors = localStorage.getItem(STORAGE_KEY);
themeColors.value = storedColors ? JSON.parse(storedColors) : { ...defaultColors };
} catch (error) {
console.error('Failed to parse theme colors from localStorage:', error);
themeColors.value = { ...defaultColors };
} finally {
localStorage.setItem(STORAGE_KEY, JSON.stringify(themeColors.value));
}
};
const themeColors = ref({ ...defaultColors });
const acceptParams = (params: DialogProps): void => {
form.themeColor = params.themeColor;
form.theme = params.theme;
form.dark = form.themeColor.dark;
form.light = form.themeColor.light;
initThemeColors();
lightPredefineColors.value = themeColors.value['light'];
darkPredefineColors.value = themeColors.value['dark'];
lightPredefineColors.value.slice(0, 2).forEach((color) => {
const exists = lightColors.some((item) => item.color === color);
if (!exists) {
lightColors.push({
color,
label: `xpack.theme.customColor`,
});
}
});
darkPredefineColors.value.slice(0, 2).forEach((color) => {
const exists = darkColors.some((item) => item.color === color);
if (!exists) {
darkColors.push({
color,
label: `xpack.theme.customColor`,
});
}
});
drawerVisible.value = true;
};
const updateThemeColors = (theme: 'light' | 'dark', newColors: string[]) => {
themeColors.value[theme] = newColors;
localStorage.setItem(STORAGE_KEY, JSON.stringify(themeColors.value));
lightPredefineColors.value = themeColors.value['light'];
darkPredefineColors.value = themeColors.value['dark'];
};
const addAndRemoveColor = (theme: 'light' | 'dark', newColor: string) => {
const colors = [...themeColors.value[theme]];
colors.unshift(newColor);
colors.pop();
updateThemeColors(theme, colors);
};
const changeThemeColor = (theme: 'light' | 'dark', color: string) => {
if (theme === 'light') {
form.light = color;
const newLightColor = { color: color, label: 'xpack.theme.customColor' };
lightColors = addColorToTheme(lightColors, newLightColor, 2);
} else {
form.dark = color;
const newDarkColor = { color: color, label: 'xpack.theme.customColor' };
darkColors = addColorToTheme(darkColors, newDarkColor);
}
addAndRemoveColor(theme, color);
};
const changeLightColor = (color: string) => {
form.light = color;
};
@ -202,6 +290,10 @@ const onReSet = async () => {
}).then(async () => {
form.themeColor = { light: '#005eeb', dark: '#F0BE96' };
if (globalStore.isProductPro) {
localStorage.setItem(STORAGE_KEY, JSON.stringify(defaultColors));
themeColors.value = { ...defaultColors };
darkColors = [...defaultDarkColors];
lightColors = [...defaultLightColors];
await updateXpackSettingByKey('ThemeColor', JSON.stringify(form.themeColor));
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
loading.value = false;