Skip to content

Commit b4a2aa5

Browse files
committed
✨ feat: 设置跳转高亮
1 parent f17535d commit b4a2aa5

10 files changed

Lines changed: 483 additions & 381 deletions

File tree

auto-eslint.mjs

Lines changed: 314 additions & 314 deletions
Large diffs are not rendered by default.

electron/main/windows/index.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,13 @@ export const createWindow = (
3232
},
3333
};
3434
// 合并参数
35+
if (options.webPreferences) {
36+
options.webPreferences = Object.assign(
37+
{},
38+
defaultOptions.webPreferences,
39+
options.webPreferences,
40+
);
41+
}
3542
options = Object.assign(defaultOptions, options);
3643
// 创建窗口
3744
const win = new BrowserWindow(options);
Lines changed: 48 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/* auto-generated by NAPI-RS */
22
/* eslint-disable */
33
/** 关闭 Discord RPC */
4-
export declare function disableDiscordRpc(): void;
4+
export declare function disableDiscordRpc(): void
55

66
/**
77
* 禁用媒体控件
@@ -10,7 +10,7 @@ export declare function disableDiscordRpc(): void;
1010
*
1111
* 会在调用 API 失败时抛出错误
1212
*/
13-
export declare function disableSystemMedia(): void;
13+
export declare function disableSystemMedia(): void
1414

1515
/** Discord 配置参数 */
1616
export interface DiscordConfigPayload {
@@ -19,23 +19,22 @@ export interface DiscordConfigPayload {
1919
*
2020
* 注意暂停时进度会固定为 0
2121
*/
22-
showWhenPaused: boolean;
22+
showWhenPaused: boolean
2323
/** 显示模式,参考 [`DiscordDisplayMode`] */
24-
displayMode?: DiscordDisplayMode;
24+
displayMode?: DiscordDisplayMode
2525
}
2626

2727
/**
2828
* Discord 显示模式枚举
2929
*
3030
* 不打开详细信息面板时,在用户名下方显示的小字
3131
*/
32-
export type DiscordDisplayMode =
33-
/** Listening to SPlayer */
34-
| "Name"
35-
/** Listening to Rick Astley */
36-
| "State"
37-
/** Listening to Never Gonna Give You Up */
38-
| "Details";
32+
export type DiscordDisplayMode = /** Listening to SPlayer */
33+
'Name'|
34+
/** Listening to Rick Astley */
35+
'State'|
36+
/** Listening to Never Gonna Give You Up */
37+
'Details';
3938

4039
/**
4140
* 启用 Discord RPC
@@ -44,7 +43,7 @@ export type DiscordDisplayMode =
4443
*
4544
* 启用后会立刻尝试连接,如果 Discord 未启动,或因为其他未知原因连接失败,会每 5 秒尝试连接一次
4645
*/
47-
export declare function enableDiscordRpc(): void;
46+
export declare function enableDiscordRpc(): void
4847

4948
/**
5049
* 启用媒体控件
@@ -53,7 +52,7 @@ export declare function enableDiscordRpc(): void;
5352
*
5453
* 会在调用 API 失败时抛出错误
5554
*/
56-
export declare function enableSystemMedia(): void;
55+
export declare function enableSystemMedia(): void
5756

5857
/**
5958
* 初始化插件
@@ -70,20 +69,20 @@ export declare function enableSystemMedia(): void;
7069
*
7170
* 如果其他 API 调用失败,则只会打印日志并静默失败
7271
*/
73-
export declare function initialize(logDir: string): void;
72+
export declare function initialize(logDir: string): void
7473

7574
export interface MetadataParam {
76-
songName: string;
77-
authorName: string;
78-
albumName: string;
75+
songName: string
76+
authorName: string
77+
albumName: string
7978
/** 封面的原始字节数据,适用于除 Discord RPC 之外的其他平台 */
80-
coverData?: Buffer;
79+
coverData?: Buffer
8180
/**
8281
* 封面的 HTTP URL,更新 Discord RPC 时必传,其他平台可不传
8382
*
8483
* Linux 平台在没有提供 `cover_data` 时会使用它
8584
*/
86-
originalCoverUrl?: string;
85+
originalCoverUrl?: string
8786
/**
8887
* 网易云音乐中对应的曲目 ID
8988
*
@@ -92,25 +91,26 @@ export interface MetadataParam {
9291
* - 生成 Discord RPC 的按钮链接
9392
* - MacOS 和 Linux 会使用此值来填充唯一的曲目 ID
9493
*/
95-
ncmId?: number;
94+
ncmId?: number
9695
/**
9796
* 当前歌曲时长,单位是毫秒
9897
*
9998
* 用于 Linux、MacOS、Discord RPC 的元数据更新。Windows 使用 [`TimelinePayload`] 的
10099
* `total_time` 字段。
101100
*/
102-
duration?: number;
101+
duration?: number
103102
}
104103

105-
export type PlaybackStatus = "Playing" | "Paused";
104+
export type PlaybackStatus = 'Playing'|
105+
'Paused';
106106

107107
export interface PlayModePayload {
108-
isShuffling: boolean;
109-
repeatMode: RepeatMode;
108+
isShuffling: boolean
109+
repeatMode: RepeatMode
110110
}
111111

112112
export interface PlayStatePayload {
113-
status: PlaybackStatus;
113+
status: PlaybackStatus
114114
}
115115

116116
/**
@@ -124,34 +124,35 @@ export interface PlayStatePayload {
124124
*
125125
* 如果 N-API 创建线程安全函数失败,会抛出错误。通常不应该发生,除非 JS 环境已经销毁了
126126
*/
127-
export declare function registerEventHandler(callback: (arg: SystemMediaEvent) => void): void;
127+
export declare function registerEventHandler(callback: (arg: SystemMediaEvent) => void): void
128128

129-
export type RepeatMode = "None" | "Track" | "List";
129+
export type RepeatMode = 'None'|
130+
'Track'|
131+
'List';
130132

131133
/** 关闭插件,清理资源 */
132-
export declare function shutdown(): void;
134+
export declare function shutdown(): void
133135

134136
export interface SystemMediaEvent {
135-
type: SystemMediaEventType;
136-
positionMs?: number;
137+
type: SystemMediaEventType
138+
positionMs?: number
137139
}
138140

139-
export type SystemMediaEventType =
140-
| "Play"
141-
| "Pause"
142-
| "Stop"
143-
| "NextSong"
144-
| "PreviousSong"
145-
| "ToggleShuffle"
146-
| "ToggleRepeat"
147-
/** 绝对位置,毫秒 */
148-
| "Seek";
141+
export type SystemMediaEventType = 'Play'|
142+
'Pause'|
143+
'Stop'|
144+
'NextSong'|
145+
'PreviousSong'|
146+
'ToggleShuffle'|
147+
'ToggleRepeat'|
148+
/** 绝对位置,毫秒 */
149+
'Seek';
149150

150151
export interface TimelinePayload {
151152
/** 单位是毫秒 */
152-
currentTime: number;
153+
currentTime: number
153154
/** 单位是毫秒 */
154-
totalTime: number;
155+
totalTime: number
155156
}
156157

157158
/**
@@ -162,7 +163,7 @@ export interface TimelinePayload {
162163
* * `payload` - 配置信息,可以配置是否在暂停后也显示 Discord Activity 和 状态显示风格。详情请查看
163164
* [`DiscordConfigPayload`]
164165
*/
165-
export declare function updateDiscordConfig(payload: DiscordConfigPayload): void;
166+
export declare function updateDiscordConfig(payload: DiscordConfigPayload): void
166167

167168
/**
168169
* 更新歌曲元数据
@@ -173,7 +174,7 @@ export declare function updateDiscordConfig(payload: DiscordConfigPayload): void
173174
*
174175
* 更新 Discord RPC 的元数据时,必须提供 `original_cover_url`
175176
*/
176-
export declare function updateMetadata(payload: MetadataParam): void;
177+
export declare function updateMetadata(payload: MetadataParam): void
177178

178179
/**
179180
* 更新播放模式
@@ -182,14 +183,14 @@ export declare function updateMetadata(payload: MetadataParam): void;
182183
*
183184
* 只会更新媒体控件的信息,不会更新 Discord RPC 上的信息
184185
*/
185-
export declare function updatePlayMode(payload: PlayModePayload): void;
186+
export declare function updatePlayMode(payload: PlayModePayload): void
186187

187188
/**
188189
* 更新播放状态 (播放/暂停)
189190
*
190191
* 同时也会更新 Discord 的播放状态 (如果启用了 Discord RPC)
191192
*/
192-
export declare function updatePlayState(payload: PlayStatePayload): void;
193+
export declare function updatePlayState(payload: PlayStatePayload): void
193194

194195
/**
195196
* 更新进度信息
@@ -200,4 +201,4 @@ export declare function updatePlayState(payload: PlayStatePayload): void;
200201
*
201202
* Discord RPC 实现的进度更新有节流,调用此函数无需担心 Discord RPC 的速率限制
202203
*/
203-
export declare function updateTimeline(payload: TimelinePayload): void;
204+
export declare function updateTimeline(payload: TimelinePayload): void

src/App.vue

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
<template>
2-
<Provider>
2+
<Provider v-if="!isDesktopLyric">
33
<router-view />
44
</Provider>
5+
<router-view v-else />
56
</template>
7+
8+
<script setup lang="ts">
9+
const isDesktopLyric = location.hash.includes("desktop-lyric");
10+
</script>

src/components/Setting/MainSetting.vue

Lines changed: 49 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -68,24 +68,53 @@
6868
>
6969
<Transition name="fade" mode="out-in" @after-leave="setScrollbar?.scrollTo({ top: 0 })">
7070
<!-- 常规 -->
71-
<UniversalSetting v-if="activeKey === 'general'" :groups="generalConfig.groups" />
71+
<UniversalSetting
72+
v-if="activeKey === 'general'"
73+
:groups="generalConfig.groups"
74+
:highlight-key="highlightKey"
75+
/>
7276
<!-- 播放 -->
73-
<UniversalSetting v-else-if="activeKey === 'play'" :groups="playConfig.groups" />
77+
<UniversalSetting
78+
v-else-if="activeKey === 'play'"
79+
:groups="playConfig.groups"
80+
:highlight-key="highlightKey"
81+
/>
7482
<!-- 歌词 -->
75-
<UniversalSetting v-else-if="activeKey === 'lyrics'" :groups="lyricConfig.groups" />
83+
<UniversalSetting
84+
v-else-if="activeKey === 'lyrics'"
85+
:groups="lyricConfig.groups"
86+
:highlight-key="highlightKey"
87+
/>
7688
<!-- 快捷键 -->
77-
<UniversalSetting v-else-if="activeKey === 'keyboard'" :groups="keyboardConfig.groups" />
89+
<UniversalSetting
90+
v-else-if="activeKey === 'keyboard'"
91+
:groups="keyboardConfig.groups"
92+
:highlight-key="highlightKey"
93+
/>
7894
<!-- 本地 -->
79-
<UniversalSetting v-else-if="activeKey === 'local'" :groups="localConfig.groups" />
95+
<UniversalSetting
96+
v-else-if="activeKey === 'local'"
97+
:groups="localConfig.groups"
98+
:highlight-key="highlightKey"
99+
/>
80100
<!-- 第三方 -->
81-
<UniversalSetting v-else-if="activeKey === 'third'" :groups="thirdConfig.groups" />
101+
<UniversalSetting
102+
v-else-if="activeKey === 'third'"
103+
:groups="thirdConfig.groups"
104+
:highlight-key="highlightKey"
105+
/>
82106
<!-- 流媒体 -->
83107
<UniversalSetting
84108
v-else-if="activeKey === 'streaming'"
85109
:groups="streamingConfig.groups"
110+
:highlight-key="highlightKey"
86111
/>
87112
<!-- 其他 -->
88-
<UniversalSetting v-else-if="activeKey === 'other'" :groups="otherConfig.groups" />
113+
<UniversalSetting
114+
v-else-if="activeKey === 'other'"
115+
:groups="otherConfig.groups"
116+
:highlight-key="highlightKey"
117+
/>
89118
<!-- 关于 -->
90119
<AboutSetting v-else-if="activeKey === 'about'" />
91120
<!-- 空白 -->
@@ -193,6 +222,7 @@ watch(
193222
{ immediate: true },
194223
);
195224
225+
const highlightKey = ref<string>();
196226
const isSearchActive = ref(false);
197227
198228
// 搜索选项
@@ -240,6 +270,8 @@ const handleSearch = (value: string | number) => {
240270
if (!value) return;
241271
const keyStr = String(value);
242272
const [targetTab, targetKey] = keyStr.split("::");
273+
// 标记正在跳转
274+
highlightKey.value = targetKey;
243275
// 切换到对应标签页
244276
if (activeKey.value !== targetTab) {
245277
activeKey.value = targetTab as SettingType;
@@ -249,11 +281,18 @@ const handleSearch = (value: string | number) => {
249281
showLeftMenu.value = false;
250282
}
251283
nextTick(() => {
252-
useTimeoutFn(() => {
284+
setTimeout(() => {
253285
const element = document.getElementById(`setting-${targetKey}`);
254-
if (element) {
255-
element.scrollIntoView({ behavior: "smooth", block: "center" });
286+
if (!element) {
287+
highlightKey.value = undefined;
288+
return;
256289
}
290+
// 滚动到元素位置
291+
element.scrollIntoView({ block: "center" });
292+
// 清理跳转标记
293+
setTimeout(() => {
294+
highlightKey.value = undefined;
295+
}, 2500);
257296
}, 300);
258297
});
259298
};

src/components/Setting/SettingItemRenderer.vue

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
<template>
2-
<div :id="'setting-' + item.key" class="setting-item-wrapper">
2+
<div
3+
:id="'setting-' + item.key"
4+
class="setting-item-wrapper"
5+
:class="{ highlighted: highlighted }"
6+
>
37
<template v-if="item.noWrapper">
48
<component
59
v-if="item.type === 'custom' && item.component"
@@ -164,6 +168,7 @@ defineOptions({
164168
165169
const props = defineProps<{
166170
item: SettingItem;
171+
highlighted?: boolean;
167172
}>();
168173
169174
// 数据双向绑定处理
@@ -281,10 +286,32 @@ const activeActions = computed(() => {
281286
&:last-child {
282287
margin-bottom: 0;
283288
}
289+
&.highlighted {
290+
.set-item {
291+
&::after {
292+
animation: highlight-pulse 2.5s cubic-bezier(0.4, 0, 0.2, 1);
293+
animation-delay: 0.5s;
294+
}
295+
}
296+
}
284297
}
285298
.set-item {
286299
width: 100%;
287300
border-radius: 8px;
301+
overflow: hidden;
302+
position: relative;
303+
&::after {
304+
content: "";
305+
position: absolute;
306+
top: 0;
307+
left: 0;
308+
right: 0;
309+
bottom: 0;
310+
background-color: rgba(var(--primary), 0.25);
311+
z-index: 1;
312+
opacity: 0;
313+
pointer-events: none;
314+
}
288315
}
289316
:deep(.n-card__content) {
290317
display: flex;

0 commit comments

Comments
 (0)