Skip to content

Commit 58e0f40

Browse files
authored
Merge pull request #770 from imsyy/dev-theme
✨ feat: 新增自定义背景图
2 parents 5f9300b + c940bb0 commit 58e0f40

File tree

20 files changed

+1150
-278
lines changed

20 files changed

+1150
-278
lines changed

components.d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@ declare module 'vue' {
148148
Provider: typeof import('./src/components/Global/Provider.vue')['default']
149149
RouterLink: typeof import('vue-router')['RouterLink']
150150
RouterView: typeof import('vue-router')['RouterView']
151+
ScalingModal: typeof import('./src/components/Modal/ScalingModal.vue')['default']
151152
SearchDefault: typeof import('./src/components/Search/SearchDefault.vue')['default']
152153
SearchInp: typeof import('./src/components/Search/SearchInp.vue')['default']
153154
SearchInpMenu: typeof import('./src/components/Menu/SearchInpMenu.vue')['default']
@@ -168,6 +169,7 @@ declare module 'vue' {
168169
StreamingSetting: typeof import('./src/components/Setting/StreamingSetting.vue')['default']
169170
SvgIcon: typeof import('./src/components/Global/SvgIcon.vue')['default']
170171
TextContainer: typeof import('./src/components/Global/TextContainer.vue')['default']
172+
ThemeConfig: typeof import('./src/components/Modal/ThemeConfig.vue')['default']
171173
ThirdSetting: typeof import('./src/components/Setting/ThirdSetting.vue')['default']
172174
UpdateApp: typeof import('./src/components/Modal/UpdateApp.vue')['default']
173175
UpdatePlaylist: typeof import('./src/components/Modal/UpdatePlaylist.vue')['default']

src/assets/data/themeColor.json

Lines changed: 80 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -4,50 +4,105 @@
44
"name": "默认",
55
"color": "#fe7971"
66
},
7-
"orange": {
8-
"label": "orange",
9-
"name": "橙色",
10-
"color": "#ff8c00"
11-
},
12-
"blue": {
13-
"label": "blue",
14-
"name": "蓝色",
15-
"color": "#3b5998"
7+
"red": {
8+
"label": "red",
9+
"name": "红色",
10+
"color": "#F44336"
1611
},
1712
"pink": {
1813
"label": "pink",
1914
"name": "粉色",
20-
"color": "#e91e63"
15+
"color": "#E91E63"
2116
},
22-
"brown": {
23-
"label": "brown",
24-
"name": "棕色",
25-
"color": "#795548"
17+
"purple": {
18+
"label": "purple",
19+
"name": "紫色",
20+
"color": "#9C27B0"
21+
},
22+
"deepPurple": {
23+
"label": "deepPurple",
24+
"name": "深紫色",
25+
"color": "#673AB7"
2626
},
2727
"indigo": {
2828
"label": "indigo",
2929
"name": "靛青色",
30-
"color": "#3f51b5"
30+
"color": "#3F51B5"
31+
},
32+
"blue": {
33+
"label": "blue",
34+
"name": "蓝色",
35+
"color": "#2196F3"
36+
},
37+
"lightBlue": {
38+
"label": "lightBlue",
39+
"name": "淡蓝色",
40+
"color": "#03A9F4"
41+
},
42+
"cyan": {
43+
"label": "cyan",
44+
"name": "青色",
45+
"color": "#00BCD4"
46+
},
47+
"teal": {
48+
"label": "teal",
49+
"name": "水鸭青",
50+
"color": "#009688"
3151
},
3252
"green": {
3353
"label": "green",
3454
"name": "绿色",
35-
"color": "#2ecc71"
55+
"color": "#4CAF50"
3656
},
37-
"purple": {
38-
"label": "purple",
39-
"name": "紫色",
40-
"color": "#9c27b0"
57+
"lightGreen": {
58+
"label": "lightGreen",
59+
"name": "浅绿色",
60+
"color": "#8BC34A"
61+
},
62+
"lime": {
63+
"label": "lime",
64+
"name": "柠檬绿",
65+
"color": "#CDDC39"
4166
},
4267
"yellow": {
4368
"label": "yellow",
4469
"name": "黄色",
45-
"color": "#FBC02D"
70+
"color": "#FFEB3B"
4671
},
47-
"teal": {
48-
"label": "teal",
49-
"name": "青色",
50-
"color": "#009688"
72+
"amber": {
73+
"label": "amber",
74+
"name": "琥珀色",
75+
"color": "#FFC107"
76+
},
77+
"orange": {
78+
"label": "orange",
79+
"name": "橙色",
80+
"color": "#FF9800"
81+
},
82+
"deepOrange": {
83+
"label": "deepOrange",
84+
"name": "深橙色",
85+
"color": "#FF5722"
86+
},
87+
"brown": {
88+
"label": "brown",
89+
"name": "棕色",
90+
"color": "#795548"
91+
},
92+
"grey": {
93+
"label": "grey",
94+
"name": "灰色",
95+
"color": "#9E9E9E"
96+
},
97+
"blueGrey": {
98+
"label": "blueGrey",
99+
"name": "蓝灰色",
100+
"color": "#607D8B"
101+
},
102+
"solid": {
103+
"label": "solid",
104+
"name": "纯色",
105+
"color": "#9e9e9e"
51106
},
52107
"custom": {
53108
"label": "custom",

src/assets/icons/Palette.svg

Lines changed: 1 addition & 0 deletions
Loading

src/components/Global/Provider.vue

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ import {
3939
GlobalThemeOverrides,
4040
} from "naive-ui";
4141
import { useSettingStore, useStatusStore } from "@/stores";
42-
import { setColorSchemes } from "@/utils/color";
42+
import { setColorSchemes, MONOTONOUS_THEME } from "@/utils/color";
4343
import { useCustomCode } from "@/composables/useCustomCode";
4444
// import { rgbToHex } from "@imsyy/color-utils";
4545
import themeColor from "@/assets/data/themeColor.json";
@@ -59,6 +59,8 @@ let lastThemeCacheKey: string | null = null;
5959
6060
// 获取明暗模式
6161
const theme = computed(() => {
62+
// 图片模式强制深色
63+
if (statusStore.themeBackgroundMode === "image") return darkTheme;
6264
return settingStore.themeMode === "auto"
6365
? // 跟随系统
6466
osTheme.value === "dark"
@@ -73,19 +75,35 @@ const theme = computed(() => {
7375
// 获取当前主题色数据
7476
const getThemeMainColor = () => {
7577
const themeType = theme.value ? "dark" : "light";
78+
// 背景图模式
79+
if (statusStore.themeBackgroundMode === "image") {
80+
const { themeColor, useCustomColor, customColor, isSolid } = statusStore.backgroundConfig;
81+
// 纯色覆盖
82+
if (isSolid) return setColorSchemes(MONOTONOUS_THEME, themeType);
83+
const color = useCustomColor ? customColor : themeColor;
84+
// 强制使用 dark 模式生成
85+
if (color) return setColorSchemes(color, "dark");
86+
}
87+
// 封面模式
7688
if (settingStore.themeFollowCover && statusStore.songCoverTheme) {
7789
const coverColor = statusStore.songCoverTheme;
7890
if (!coverColor) return {};
7991
return setColorSchemes(coverColor, themeType);
92+
} else if (settingStore.themeColorType === "solid") {
93+
// 纯色预设
94+
return setColorSchemes(MONOTONOUS_THEME, themeType);
8095
} else if (settingStore.themeColorType !== "custom") {
96+
// 预设模式
8197
return setColorSchemes(themeColor[settingStore.themeColorType].color, themeType);
8298
} else {
99+
// 自定义模式
83100
return setColorSchemes(settingStore.themeCustomColor, themeType);
84101
}
85102
};
86103
87104
// 更改全局主题
88105
const changeGlobalTheme = () => {
106+
applyThemeBackgroundMode();
89107
try {
90108
// 获取配色方案
91109
const colorSchemes = getThemeMainColor();
@@ -261,6 +279,15 @@ const NaiveProviderContent = defineComponent({
261279
},
262280
});
263281
282+
// 应用背景模式类名
283+
const applyThemeBackgroundMode = () => {
284+
if (statusStore.themeBackgroundMode === "image") {
285+
document.documentElement.classList.add("image");
286+
} else {
287+
document.documentElement.classList.remove("image");
288+
}
289+
};
290+
264291
// 监听设置更改
265292
watch(
266293
() => [
@@ -269,6 +296,11 @@ watch(
269296
settingStore.themeGlobalColor,
270297
settingStore.globalFont,
271298
statusStore.songCoverTheme?.main,
299+
statusStore.themeBackgroundMode,
300+
statusStore.backgroundConfig.themeColor,
301+
statusStore.backgroundConfig.useCustomColor,
302+
statusStore.backgroundConfig.customColor,
303+
statusStore.backgroundConfig.isSolid,
272304
theme.value,
273305
],
274306
() => changeGlobalTheme(),

src/components/Layout/Nav.vue

Lines changed: 16 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
<!-- 用户 -->
2727
<User v-if="settingStore.useOnlineService" />
2828
<!-- 设置菜单 -->
29-
<n-dropdown :options="setOptions" trigger="click" show-arrow @select="setSelect">
29+
<n-dropdown :options="setOptions" trigger="click" @select="setSelect">
3030
<n-button :focusable="false" title="设置" tertiary circle>
3131
<template #icon>
3232
<SvgIcon name="Settings" />
@@ -131,14 +131,15 @@
131131

132132
<script setup lang="ts">
133133
import type { DropdownOption } from "naive-ui";
134-
import { useSettingStore } from "@/stores";
134+
import { useSettingStore, useStatusStore } from "@/stores";
135135
import { renderIcon } from "@/utils/helper";
136-
import { openSetting } from "@/utils/modal";
136+
import { openSetting, openThemeConfig, openScalingModal } from "@/utils/modal";
137137
import { isDev, isElectron } from "@/utils/env";
138138
import { useMobile } from "@/composables/useMobile";
139139
140140
const router = useRouter();
141141
const settingStore = useSettingStore();
142+
const statusStore = useStatusStore();
142143
const { isDesktop, isSmallScreen } = useMobile();
143144
144145
const showCloseModal = ref(false);
@@ -150,23 +151,6 @@ const useBorderless = ref(true);
150151
const isMax = ref(false);
151152
// 是否显示侧边栏
152153
const showAside = ref(false);
153-
// 当前缩放系数
154-
const currentZoomFactor = ref(1.0);
155-
156-
// 缩放系数选项
157-
const zoomFactorList = [0.5, 0.6, 0.7, 0.8, 0.9, 1, 1.1, 1.2, 1.3, 1.4, 1.5, 1.75, 2];
158-
159-
// 缩放选项列表
160-
const zoomOptions = computed<DropdownOption[]>(() =>
161-
zoomFactorList.map((factor) => {
162-
const isSelected = Math.abs(currentZoomFactor.value - factor) < 0.01;
163-
return {
164-
label: `${Math.round(factor * 100)}%`,
165-
key: `zoom-${factor}`,
166-
icon: isSelected ? renderIcon("Check") : undefined,
167-
};
168-
}),
169-
);
170154
171155
// 最小化
172156
const min = () => window.electron.ipcRenderer.send("win-min");
@@ -209,6 +193,7 @@ const setOptions = computed<DropdownOption[]>(() => [
209193
? "深色模式"
210194
: "跟随系统",
211195
key: "themeMode",
196+
disabled: !!statusStore.backgroundImageUrl,
212197
icon: renderIcon(
213198
settingStore.themeMode === "auto"
214199
? "LightTheme"
@@ -217,12 +202,16 @@ const setOptions = computed<DropdownOption[]>(() => [
217202
: "AutoTheme",
218203
),
219204
},
205+
{
206+
label: "主题配置",
207+
key: "themeConfig",
208+
icon: renderIcon("Palette"),
209+
},
220210
{
221211
key: "zoom",
222212
label: "界面缩放",
223213
icon: renderIcon("ZoomIn"),
224214
show: isElectron,
225-
children: zoomOptions.value,
226215
},
227216
{
228217
key: "divider-1",
@@ -255,22 +244,18 @@ const setSelect = (key: string) => {
255244
case "themeMode":
256245
settingStore.setThemeMode();
257246
break;
247+
case "themeConfig":
248+
openThemeConfig();
249+
break;
250+
case "zoom":
251+
openScalingModal();
252+
break;
258253
case "setting":
259254
openSetting();
260255
break;
261256
case "dev-tools":
262257
window.electron.ipcRenderer.send("open-dev-tools");
263258
break;
264-
default:
265-
// 处理缩放选项
266-
if (key.startsWith("zoom-")) {
267-
const factor = parseFloat(key.replace("zoom-", ""));
268-
if (!isNaN(factor)) {
269-
window.electron.ipcRenderer.invoke("set-zoom-factor", factor);
270-
currentZoomFactor.value = factor;
271-
}
272-
}
273-
break;
274259
}
275260
};
276261
@@ -280,8 +265,6 @@ onMounted(async () => {
280265
// 获取无边框窗口配置
281266
const windowConfig = await window.api.store.get("window");
282267
useBorderless.value = windowConfig?.useBorderless ?? true;
283-
// 获取当前缩放系数
284-
currentZoomFactor.value = await window.electron.ipcRenderer.invoke("get-zoom-factor");
285268
// 获取窗口状态
286269
isMax.value = window.electron.ipcRenderer.sendSync("win-state");
287270
window.electron.ipcRenderer.on("win-state-change", (_event, value: boolean) => {

src/components/List/SongList.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -469,7 +469,7 @@ onBeforeUnmount(() => {
469469
padding: 8px 12px;
470470
// margin-right: 4px;
471471
border: 1px solid transparent;
472-
background-color: var(--background-hex);
472+
// background-color: var(--background-hex);
473473
.n-text {
474474
opacity: 0.6;
475475
}

0 commit comments

Comments
 (0)