1. 支持暗黑主题 2. 调整插件页面ui

This commit is contained in:
sqj
2025-10-03 15:42:22 +08:00
parent 6ee7e6dc99
commit 15a76a5313
28 changed files with 1854 additions and 808 deletions

119
README.md
View File

@@ -27,16 +27,7 @@ Ceru Music 是基于 Electron 和 Vue 开发的跨平台桌面音乐播放器工
```ast
CeruMuisc/
├── .github/
│ └── workflows/
│ ├── auto-sync-release.yml
│ ├── deploydocs.yml
│ ├── main.yml
│ ├── sync-releases-to-webdav.yml
│ └── uploadpan.yml
├── scripts/
│ ├── auth-test.js
│ ├── genAst.js
│ └── test-alist.js
├── src/
│ ├── common/
│ │ ├── types/
@@ -56,6 +47,7 @@ CeruMuisc/
│ │ │ ├── autoUpdate.ts
│ │ │ ├── directorySettings.ts
│ │ │ ├── musicCache.ts
│ │ │ ├── pluginNotice.ts
│ │ │ └── songList.ts
│ │ ├── services/
│ │ │ ├── music/
@@ -77,91 +69,10 @@ CeruMuisc/
│ │ │ ├── songList/
│ │ │ │ ├── ManageSongList.ts
│ │ │ │ └── PlayListSongs.ts
│ │ │ ── ai-service.ts
│ │ │ ── ai-service.ts
│ │ │ └── ConfigManager.ts
│ │ ├── utils/
│ │ │ ├── musicSdk/
│ │ │ │ ├── kg/
│ │ │ │ │ ├── temp/
│ │ │ │ │ │ ├── musicSearch-new.js
│ │ │ │ │ │ └── songList-new.js
│ │ │ │ │ ├── vendors/
│ │ │ │ │ │ └── infSign.min.js
│ │ │ │ │ ├── album.js
│ │ │ │ │ ├── api-test.js
│ │ │ │ │ ├── comment.js
│ │ │ │ │ ├── hotSearch.js
│ │ │ │ │ ├── index.js
│ │ │ │ │ ├── leaderboard.js
│ │ │ │ │ ├── lyric.js
│ │ │ │ │ ├── musicInfo.js
│ │ │ │ │ ├── musicSearch.js
│ │ │ │ │ ├── pic.js
│ │ │ │ │ ├── singer.js
│ │ │ │ │ ├── songList.js
│ │ │ │ │ ├── tipSearch.js
│ │ │ │ │ └── util.js
│ │ │ │ ├── kw/
│ │ │ │ │ ├── album.js
│ │ │ │ │ ├── api-temp.js
│ │ │ │ │ ├── api-test.js
│ │ │ │ │ ├── comment.js
│ │ │ │ │ ├── hotSearch.js
│ │ │ │ │ ├── index.js
│ │ │ │ │ ├── kwdecode.ts
│ │ │ │ │ ├── leaderboard.js
│ │ │ │ │ ├── lyric.js
│ │ │ │ │ ├── musicSearch.js
│ │ │ │ │ ├── pic.js
│ │ │ │ │ ├── songList.js
│ │ │ │ │ ├── tipSearch.js
│ │ │ │ │ └── util.js
│ │ │ │ ├── mg/
│ │ │ │ │ ├── temp/
│ │ │ │ │ │ └── leaderboard-old.js
│ │ │ │ │ ├── utils/
│ │ │ │ │ │ ├── index.js
│ │ │ │ │ │ └── mrc.js
│ │ │ │ │ ├── album.js
│ │ │ │ │ ├── api-test.js
│ │ │ │ │ ├── comment.js
│ │ │ │ │ ├── hotSearch.js
│ │ │ │ │ ├── index.js
│ │ │ │ │ ├── leaderboard.js
│ │ │ │ │ ├── lyric.js
│ │ │ │ │ ├── musicInfo.js
│ │ │ │ │ ├── musicSearch.js
│ │ │ │ │ ├── pic.js
│ │ │ │ │ ├── songId.js
│ │ │ │ │ ├── songList.js
│ │ │ │ │ └── tipSearch.js
│ │ │ │ ├── tx/
│ │ │ │ │ ├── api-test.js
│ │ │ │ │ ├── comment.js
│ │ │ │ │ ├── hotSearch.js
│ │ │ │ │ ├── index.js
│ │ │ │ │ ├── leaderboard.js
│ │ │ │ │ ├── lyric.js
│ │ │ │ │ ├── musicInfo.js
│ │ │ │ │ ├── musicSearch.js
│ │ │ │ │ ├── singer.js
│ │ │ │ │ ├── songList.js
│ │ │ │ │ └── tipSearch.js
│ │ │ │ ├── wy/
│ │ │ │ │ ├── utils/
│ │ │ │ │ │ ├── crypto.js
│ │ │ │ │ │ └── index.js
│ │ │ │ │ ├── api-test.js
│ │ │ │ │ ├── comment.js
│ │ │ │ │ ├── hotSearch.js
│ │ │ │ │ ├── index.js
│ │ │ │ │ ├── leaderboard.js
│ │ │ │ │ ├── lyric.js
│ │ │ │ │ ├── musicDetail.js
│ │ │ │ │ ├── musicInfo.js
│ │ │ │ │ ├── musicSearch.js
│ │ │ │ │ ├── singer.js
│ │ │ │ │ ├── songList.js
│ │ │ │ │ └── tipSearch.js
│ │ │ │ ├── api-source-info.ts
│ │ │ │ ├── index.js
│ │ │ │ ├── options.js
@@ -190,6 +101,16 @@ CeruMuisc/
│ │ │ ├── components/
│ │ │ │ ├── AI/
│ │ │ │ │ └── FloatBall.vue
│ │ │ │ ├── ContextMenu/
│ │ │ │ │ ├── composables.ts
│ │ │ │ │ ├── ContextMenu.vue
│ │ │ │ │ ├── demo.vue
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── README.md
│ │ │ │ │ ├── types.ts
│ │ │ │ │ └── utils.ts
│ │ │ │ ├── layout/
│ │ │ │ │ └── HomeLayout.vue
│ │ │ │ ├── Music/
│ │ │ │ │ └── SongVirtualList.vue
│ │ │ │ ├── Play/
@@ -200,14 +121,14 @@ CeruMuisc/
│ │ │ │ │ ├── PlaylistDrawer.vue
│ │ │ │ │ ├── PlayMusic.vue
│ │ │ │ │ └── ShaderBackground.vue
│ │ │ │ ├── Search/
│ │ │ │ │ └── SearchComponent.vue
│ │ │ │ ├── Settings/
│ │ │ │ │ ├── AIFloatBallSettings.vue
│ │ │ │ │ ├── DirectorySettings.vue
│ │ │ │ │ ├── MusicCache.vue
│ │ │ │ │ ├── PlaylistSettings.vue
│ │ │ │ │ ├── plugins.vue
│ │ │ │ │ └── UpdateSettings.vue
│ │ │ │ ├── PluginNoticeDialog.vue
│ │ │ │ ├── ThemeSelector.vue
│ │ │ │ ├── TitleBarControls.vue
│ │ │ │ ├── UpdateExample.vue
@@ -215,8 +136,6 @@ CeruMuisc/
│ │ │ │ └── Versions.vue
│ │ │ ├── composables/
│ │ │ │ └── useAutoUpdate.ts
│ │ │ ├── layout/
│ │ │ │ └── index.vue
│ │ │ ├── router/
│ │ │ │ └── index.ts
│ │ │ ├── services/
@@ -255,10 +174,10 @@ CeruMuisc/
│ │ │ │ │ ├── recent.vue
│ │ │ │ │ └── search.vue
│ │ │ │ ├── settings/
│ │ │ │ │ ── index.vue
│ │ │ │ │ └── plugins.vue
│ │ │ │ └── welcome/
│ │ │ │ └── index.vue
│ │ │ │ │ ── index.vue
│ │ │ │ ├── welcome/
│ │ │ │ │ └── index.vue
│ │ │ │ └── ThemeDemo.vue
│ │ │ ├── App.vue
│ │ │ ├── env.d.ts
│ │ │ └── main.ts

View File

@@ -8,3 +8,9 @@
| **群友**:🍀 | 5 |
| **群友**:涟漪 | 50 |
| **作者朋友** | 188 |
| **群友**:我叫阿狸 | 3 |
| RiseSun | 9.9 |
| **b站小友**:光牙阿普斯木兰 | 5 |
| 青禾 | 8.8 |
据不完全统计 如有疏漏可联系sqj@shiqianjiang.cn

View File

@@ -12,5 +12,5 @@
- [x] 软件能不能记住上次打开的窗口大小,每次都要手动拉
- [x] 歌单右键菜单
- [x] 播放列表滚动条适配
- [ ] 暗色主题
- [x] 暗色主题
- [x] 歌单页支持修改封面

View File

@@ -2,7 +2,29 @@
## 日志
- ###### 2025-10-3 (v1.3.12)
1. 支持暗黑主题
2. 调整插件页面ui
- ###### 2025-9-29 (v1.3.11)
1. 新增插件在线导入
- ###### 2025-9-28 (v1.3.10)
1. 优化播放列表
2. 单击播放
3. 右键菜单
4. 调整播放进度调粗细
- ###### 2025-09-27 (v1.3.9)
1. debug:flac格式使用ffmpeg
2. 修复高音质下载失效
- ###### 2025-9-26 (v1.3.8)
1. 写入歌曲tag信息
2. 歌曲下载 选择音质
3. 歌单 头部自动压缩

View File

@@ -81,4 +81,4 @@ publish:
provider: generic
url: https://update.ceru.shiqianjiang.cn
electronDownload:
mirror: https://npmmirror.com/mirrors/electron/
mirror: https://npmmirror.com/mirrors/electron/

View File

@@ -37,6 +37,11 @@ declare module 'vue' {
TContent: typeof import('tdesign-vue-next')['Content']
TDialog: typeof import('tdesign-vue-next')['Dialog']
TDivider: typeof import('tdesign-vue-next')['Divider']
TDrawer: typeof import('tdesign-vue-next')['Drawer']
TDropdown: typeof import('tdesign-vue-next')['Dropdown']
TEmpty: typeof import('tdesign-vue-next')['Empty']
TForm: typeof import('tdesign-vue-next')['Form']
TFormItem: typeof import('tdesign-vue-next')['FormItem']
ThemeSelector: typeof import('./src/components/ThemeSelector.vue')['default']
TIcon: typeof import('tdesign-vue-next')['Icon']
TImage: typeof import('tdesign-vue-next')['Image']
@@ -44,11 +49,16 @@ declare module 'vue' {
TitleBarControls: typeof import('./src/components/TitleBarControls.vue')['default']
TLayout: typeof import('tdesign-vue-next')['Layout']
TLoading: typeof import('tdesign-vue-next')['Loading']
TOption: typeof import('tdesign-vue-next')['Option']
TRadioButton: typeof import('tdesign-vue-next')['RadioButton']
TRadioGroup: typeof import('tdesign-vue-next')['RadioGroup']
TSelect: typeof import('tdesign-vue-next')['Select']
TSlider: typeof import('tdesign-vue-next')['Slider']
TSwitch: typeof import('tdesign-vue-next')['Switch']
TTabPanel: typeof import('tdesign-vue-next')['TabPanel']
TTabs: typeof import('tdesign-vue-next')['Tabs']
TTag: typeof import('tdesign-vue-next')['Tag']
TTextarea: typeof import('tdesign-vue-next')['Textarea']
TTooltip: typeof import('tdesign-vue-next')['Tooltip']
UpdateExample: typeof import('./src/components/UpdateExample.vue')['default']
UpdateProgress: typeof import('./src/components/UpdateProgress.vue')['default']

View File

@@ -25,6 +25,7 @@ import './assets/theme/cyan.css'
onMounted(() => {
userInfo.init()
setupSystemThemeListener()
loadSavedTheme()
// 应用启动后延迟3秒检查更新避免影响启动速度
@@ -44,24 +45,70 @@ const themes = [
const loadSavedTheme = () => {
const savedTheme = localStorage.getItem('selected-theme')
const savedDarkMode = localStorage.getItem('dark-mode')
let themeName = 'default'
let isDarkMode = false
if (savedTheme && themes.some((t) => t.name === savedTheme)) {
applyTheme(savedTheme)
themeName = savedTheme
}
if (savedDarkMode !== null) {
isDarkMode = savedDarkMode === 'true'
} else {
// 如果没有保存的设置,检测系统偏好
isDarkMode = detectSystemTheme()
}
applyTheme(themeName, isDarkMode)
}
const applyTheme = (themeName) => {
const applyTheme = (themeName, darkMode = false) => {
const documentElement = document.documentElement
// 移除之前的主题
// 移除之前的主题属性
documentElement.removeAttribute('theme-mode')
documentElement.removeAttribute('data-theme')
// 应用主题(如果不是默认主题)
// 应用主题色彩
if (themeName !== 'default') {
documentElement.setAttribute('theme-mode', themeName)
}
// 应用明暗模式
if (darkMode) {
documentElement.setAttribute('data-theme', 'dark')
} else {
documentElement.setAttribute('data-theme', 'light')
}
// 保存到本地存储
localStorage.setItem('selected-theme', themeName)
localStorage.setItem('dark-mode', darkMode.toString())
}
// 检测系统主题偏好
const detectSystemTheme = () => {
if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
return true
}
return false
}
// 监听系统主题变化
const setupSystemThemeListener = () => {
if (window.matchMedia) {
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)')
mediaQuery.addEventListener('change', (e) => {
const savedDarkMode = localStorage.getItem('dark-mode')
// 如果用户没有手动设置暗色模式,则跟随系统主题
if (savedDarkMode === null) {
const savedTheme = localStorage.getItem('selected-theme') || 'default'
applyTheme(savedTheme, e.matches)
}
})
}
}
</script>

View File

@@ -60,22 +60,22 @@ body {
}
&::-webkit-scrollbar-track {
background: #f1f5f9;
background: var(--td-scroll-track-color);
border-radius: 0.1875rem;
}
&::-webkit-scrollbar-thumb {
background: #cbd5e1;
background: var(--td-scrollbar-color);
border-radius: 0.1875rem;
transition: background-color 0.2s ease;
&:hover {
background: #94a3b8;
background: var(--td-scrollbar-hover-color);
}
}
/* Firefox 滚动条样式 */
scrollbar-width: thin;
scrollbar-color: #cbd5e1 #f1f5f9;
scrollbar-color: var(--td-scrollbar-color) var(--td-scroll-track-color);
}
.t-dialog__mask {
backdrop-filter: blur(5px);

View File

@@ -1,15 +1,19 @@
:root,
:root[theme-mode='light'] {
--td-brand-color-1: #e2fae2;
--td-brand-color-2: #c5f4cb;
--td-brand-color-3: #91dca1;
--td-brand-color-4: #55c277;
--td-brand-color-5: #2ba55b;
--td-brand-color-6: #008942;
--td-brand-color-7: #006d33;
--td-brand-color-8: #005426;
--td-brand-color-9: #003c19;
--td-brand-color-10: #00260d;
:root[data-theme='light'],
:root:not([data-theme]) {
--hover-nav-color: #f3f4f6;
--hover-nav-text: #6b7280;
--hover-nav-text-hover: #111827;
--td-brand-color-1: #ddfbdd;
--td-brand-color-2: #bdf6c3;
--td-brand-color-3: #80df94;
--td-brand-color-4: #03de6d;
--td-brand-color-5: #00a74d;
--td-brand-color-6: #00893e;
--td-brand-color-7: #006d2f;
--td-brand-color-8: #005423;
--td-brand-color-9: #003c16;
--td-brand-color-10: #00260b;
--td-brand-color-light: var(--td-brand-color-1);
--td-brand-color-focus: var(--td-brand-color-2);
--td-brand-color-disabled: var(--td-brand-color-3);
@@ -64,16 +68,16 @@
--td-success-color-active: var(--td-success-color-6);
--td-success-color-disabled: var(--td-success-color-3);
--td-success-color-light: var(--td-success-color-1);
--td-gray-color-1: #f0f4f1;
--td-gray-color-2: #e9efeb;
--td-gray-color-3: #e1eae4;
--td-gray-color-4: #d4dfd8;
--td-gray-color-5: #bdc8c1;
--td-gray-color-6: #9ca8a1;
--td-gray-color-7: #808d86;
--td-gray-color-8: #6d7873;
--td-gray-color-9: #565f5b;
--td-gray-color-10: #454c48;
--td-gray-color-1: #f3f3f3;
--td-gray-color-2: #eee;
--td-gray-color-3: #e7e7e7;
--td-gray-color-4: #dcdcdc;
--td-gray-color-5: #c5c5c5;
--td-gray-color-6: #a6a6a6;
--td-gray-color-7: #8b8b8b;
--td-gray-color-8: #777;
--td-gray-color-9: #5e5e5e;
--td-gray-color-10: #4b4b4b;
--td-gray-color-11: #383838;
--td-gray-color-12: #2c2c2c;
--td-gray-color-13: #242424;
@@ -133,21 +137,273 @@
--td-shadow-inset-right: inset 0.5px 0 0 #dcdcdc;
--td-shadow-inset-bottom: inset 0 -0.5px 0 #dcdcdc;
--td-shadow-inset-left: inset -0.5px 0 0 #dcdcdc;
--td-mask-active: rgba(255, 255, 255, 0.6);
--td-mask-active: rgba(0, 0, 0, 0.6);
--td-mask-disabled: rgba(255, 255, 255, 0.6);
/* 通用颜色变量 - 亮色主题 */
--theme-bg-primary: #ffffff;
--theme-bg-secondary: #f8f9fa;
--theme-bg-tertiary: #fafafa;
--theme-text-primary: #111827;
--theme-text-secondary: #6b7280;
--theme-text-tertiary: #9ca3af;
--theme-text-muted: #9ca3af;
--theme-text-disabled: #666666;
--theme-border-light: #f3f4f6;
--theme-border-medium: #e5e7eb;
--theme-border-strong: #f3f3f3;
--theme-border: #e5e7eb;
--theme-hover-bg: #f9fafb;
--theme-overlay: rgba(0, 0, 0, 0.7);
--theme-shadow-light: 0 2px 8px rgba(0, 0, 0, 0.06);
--theme-shadow-medium: 0 2px 8px rgba(0, 0, 0, 0.1);
--theme-shadow-hover: 0 8px 25px rgba(0, 0, 0, 0.12), 0 4px 10px rgba(0, 0, 0, 0.08);
--theme-card-bg: #ffffff;
--theme-card-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
--theme-card-shadow-hover: 0 8px 25px rgba(0, 0, 0, 0.15);
--theme-header-bg: #f9fafb;
--theme-badge-bg: #f3f4f6;
--theme-tips-bg: linear-gradient(135deg, #f8fafc, #f1f5f9);
--theme-warning-bg: #fef3c7;
--theme-warning-text: #d97706;
--theme-code-bg: rgba(255, 255, 255, 0.6);
--theme-code-hover-bg: rgba(255, 255, 255, 0.9);
--theme-note-bg: rgba(255, 255, 255, 0.5);
/* Find 页面专用变量 - 亮色主题 */
--find-bg-primary: var(--theme-bg-primary);
--find-bg-secondary: var(--theme-bg-secondary);
--find-text-primary: var(--theme-text-primary);
--find-text-secondary: var(--theme-text-secondary);
--find-text-muted: var(--theme-text-muted);
--find-card-bg: var(--theme-bg-primary);
--find-song-count-bg: rgba(156, 163, 175, 0.1);
--find-card-info-bg: rgba(255, 255, 255, 0.95);
--find-card-shadow: var(--theme-shadow-light), 0 1px 4px rgba(0, 0, 0, 0.04);
--find-card-shadow-hover: var(--theme-shadow-hover);
--find-song-bg: var(--theme-bg-primary);
--find-song-hover-bg: var(--theme-hover-bg);
--find-border-color: var(--theme-border-light);
--find-meta-border: rgba(229, 231, 235, 0.5);
/* HomeLayout 页面专用变量 - 亮色主题 */
--home-nav-btn-color: #3d4043;
--home-nav-btn-hover: var(--theme-text-primary);
--home-source-selector-hover: var(--theme-border-light);
--home-source-list-bg: var(--theme-bg-primary);
--home-source-list-border: var(--theme-border-medium);
--home-source-list-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
--home-source-item-hover: var(--theme-border-light);
--home-scrollbar-track: #f1f5f9;
--home-scrollbar-thumb: #cbd5e1;
--home-scrollbar-thumb-hover: #94a3b8;
--home-scrollbar-color: #cbd5e1 #f1f5f9;
/* List 页面专用变量 - 亮色主题 */
--list-bg-primary: var(--theme-bg-tertiary);
--list-content-bg: var(--theme-bg-primary);
--list-header-bg: var(--theme-bg-primary);
--list-header-shadow: var(--theme-shadow-medium);
--list-content-shadow: var(--theme-shadow-light);
--list-title-color: var(--theme-text-primary);
--list-author-color: var(--theme-text-secondary);
--list-stats-color: var(--theme-text-muted);
--list-loading-text: var(--theme-text-disabled);
--list-loading-border: var(--theme-border-strong);
--list-loading-spinner: var(--td-brand-color);
--list-cover-overlay: var(--theme-overlay);
/* SongVirtualList 组件专用变量 - 亮色主题 */
--song-list-header-bg: #fafafa;
--song-list-header-border: #e9e9e9;
--song-list-header-text: #999999;
--song-list-content-bg: var(--theme-bg-primary);
--song-list-item-border: #f5f5f5;
--song-list-item-hover: #f5f5f5;
--song-list-item-current: #f0f7ff;
--song-list-item-playing: #e6f7ff;
--song-list-track-number: #999999;
--song-list-title-color: #333333;
--song-list-title-hover: var(--td-brand-color);
--song-list-artist-color: #999999;
--song-list-album-color: #999999;
--song-list-album-hover: var(--td-brand-color);
--song-list-duration-color: #999999;
--song-list-btn-color: #cccccc;
--song-list-btn-hover: var(--td-brand-color);
--song-list-btn-bg-hover: var(--td-brand-color-light);
--song-list-quality-bg: #fff7e6;
--song-list-quality-color: #fa8c16;
/* Search 页面专用变量 - 亮色主题 */
--search-bg: var(--theme-bg-tertiary);
--search-title-color: #333333;
--search-keyword-color: var(--td-brand-color);
--search-info-color: #999999;
--search-content-bg: var(--theme-bg-primary);
--search-content-shadow: var(--theme-shadow-light);
--search-empty-title: #333333;
--search-empty-text: #999999;
--search-loading-text: #666666;
--search-loading-border: #f3f3f3;
--search-loading-spinner: var(--td-brand-color);
/* Recent 页面专用变量 - 亮色主题 */
--recent-bg: var(--theme-bg-tertiary);
--recent-title-color: #111827;
--recent-subtitle-color: #6b7280;
--recent-section-title: #111827;
--recent-card-bg: var(--theme-bg-primary);
--recent-card-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
--recent-card-shadow-hover: 0 4px 12px rgba(0, 0, 0, 0.15);
--recent-playlist-title: #111827;
--recent-playlist-desc: #6b7280;
--recent-playlist-meta: #9ca3af;
--recent-song-item-border: #f3f4f6;
--recent-song-item-hover: #f9fafb;
--recent-song-index: #6b7280;
--recent-song-title: #111827;
--recent-song-artist: #6b7280;
--recent-song-stats: #6b7280;
--recent-song-duration: #6b7280;
--recent-empty-icon: #d1d5db;
--recent-empty-title: #111827;
--recent-empty-text: #6b7280;
/* Local 页面专用变量 - 亮色主题 */
--local-bg: var(--theme-bg-tertiary);
--local-text-primary: var(--theme-text-primary);
--local-text-secondary: var(--theme-text-secondary);
--local-text-tertiary: var(--theme-text-tertiary);
--local-card-bg: var(--theme-card-bg);
--local-card-shadow: var(--theme-card-shadow);
--local-card-shadow-hover: var(--theme-card-shadow-hover);
--local-border: var(--theme-border);
--local-hover-bg: var(--theme-hover-bg);
--local-header-bg: var(--theme-header-bg);
--local-badge-bg: var(--theme-badge-bg);
--local-tips-bg: var(--theme-tips-bg);
--local-warning-bg: var(--theme-warning-bg);
--local-warning-text: var(--theme-warning-text);
--local-code-bg: var(--theme-code-bg);
--local-code-hover-bg: var(--theme-code-hover-bg);
--local-note-bg: var(--theme-note-bg);
/* Welcome 页面专用变量 - 亮色主题 */
--welcome-bg: #ffffff;
--welcome-subtitle-color: #666666;
--welcome-loading-text: #888888;
--welcome-progress-bg: #f0f0f0;
--welcome-tag-bg: #b8f1ce;
--welcome-tag-border: #e9ecef;
--welcome-tag-color: #333333;
--welcome-version-color: #9e9e9e;
/* TitleBarControls 组件专用变量 - 亮色主题 */
--titlebar-icon-color: #111827;
--titlebar-icon-hover: #111827;
--titlebar-btn-hover-bg: #f3f4f6;
--titlebar-close-hover-bg: #fee2e2;
--titlebar-close-hover-color: #dc2626;
/* Settings 页面专用变量 - 亮色主题 */
--settings-main-bg: #f8fafc;
--settings-header-bg: #ffffff;
--settings-sidebar-bg: #ffffff;
--settings-sidebar-border: #e2e8f0;
--settings-nav-hover-bg: #f1f5f9;
--settings-nav-active-bg: var(--td-brand-color-1);
--settings-nav-active-border: var(--td-brand-color-5);
--settings-nav-icon-color: #64748b;
--settings-nav-icon-active: var(--td-brand-color-5);
--settings-nav-label-color: #334155;
--settings-nav-label-active: var(--td-brand-color-6);
--settings-nav-desc-color: #64748b;
--settings-content-bg: #f8fafc;
--settings-group-bg: #ffffff;
--settings-group-border: #e2e8f0;
--settings-group-shadow: rgba(0, 0, 0, 0.1);
--settings-text-primary: #1e293b;
--settings-text-secondary: #64748b;
--settings-preview-bg: #f8fafc;
--settings-preview-border: #e2e8f0;
--settings-mock-titlebar-bg: #f6f6f6;
--settings-mock-titlebar-border: #d1d5db;
--settings-feature-bg: #f8fafc;
--settings-feature-border: #e2e8f0;
--settings-api-tips-bg: #f8fafc;
--settings-api-tips-border: #e2e8f0;
--settings-source-card-bg: #ffffff;
--settings-source-card-border: #e2e8f0;
--settings-source-card-hover-border: var(--td-brand-color-3);
--settings-source-card-active-border: var(--td-brand-color-5);
--settings-source-card-active-bg: var(--td-brand-color-1);
--settings-source-icon-bg: #f1f5f9;
--settings-quality-container-bg: #f8fafc;
--settings-quality-container-border: #e2e8f0;
--settings-status-item-bg: #f8fafc;
--settings-status-item-border: #e2e8f0;
--settings-plugin-prompt-bg: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);
--settings-plugin-prompt-border: #cbd5e1;
--settings-tech-item-bg: #f8fafc;
--settings-tech-item-border: #e2e8f0;
--settings-developer-item-bg: #f8fafc;
--settings-developer-item-border: #e2e8f0;
--settings-tag-option-bg: #f8fafc;
--settings-tag-option-border: #e2e8f0;
--settings-tag-status-bg: #f8fafc;
--settings-tag-status-border: #e2e8f0;
/* Plugins 组件专用变量 - 亮色主题 */
--plugins-bg: var(--theme-bg-tertiary);
--plugins-container-bg: var(--theme-bg-primary);
--plugins-header-bg: var(--theme-bg-primary);
--plugins-text-primary: var(--theme-text-primary);
--plugins-text-secondary: var(--theme-text-secondary);
--plugins-text-muted: var(--theme-text-muted);
--plugins-border: var(--theme-border);
--plugins-card-bg: var(--theme-card-bg);
--plugins-card-shadow: var(--theme-card-shadow);
--plugins-card-shadow-hover: var(--theme-card-shadow-hover);
--plugins-card-selected-bg: #e8f5e8;
--plugins-card-selected-border: #28a745;
--plugins-loading-spinner: var(--td-brand-color);
--plugins-error-color: #dc3545;
--plugins-success-color: #28a745;
--plugins-console-bg: #1e1e1e;
--plugins-console-header-bg: #2d2d2d;
--plugins-console-border: #404040;
--plugins-console-text: #ffffff;
--plugins-console-prompt: var(--td-brand-color);
--plugins-console-path: #8a8a8a;
--plugins-console-time: #666666;
--plugins-console-scrollbar-track: #2d2d2d;
--plugins-console-scrollbar-thumb: #555555;
--plugins-console-scrollbar-thumb-hover: #666666;
--plugins-log-error: #ff6b6b;
--plugins-log-warn: #ffd93d;
--plugins-log-info: #74b9ff;
--plugins-log-debug: #a29bfe;
--plugins-mac-close: #ff5f57;
--plugins-mac-minimize: #ffbd2e;
--plugins-mac-maximize: #28ca42;
}
:root[theme-mode='dark'] {
--td-brand-color-1: #2ba55b20;
--td-brand-color-2: #003c19;
--td-brand-color-3: #005426;
--td-brand-color-4: #006d33;
--td-brand-color-5: #008942;
--td-brand-color-6: #2ba55b;
--td-brand-color-7: #4cd47c;
--td-brand-color-8: #91dca1;
--td-brand-color-9: #c5f4cb;
--td-brand-color-10: #e2fae2;
:root[data-theme='dark'] {
--hover-nav-color: #ffffff18;
--hover-nav-text: #a5a5a5;
--hover-nav-text-hover: #f3f4f6;
--td-brand-color-1: #00a74d20;
--td-brand-color-2: #003c16;
--td-brand-color-3: #005423;
--td-brand-color-4: #006d2f;
--td-brand-color-5: #00893e;
--td-brand-color-6: #00a74d;
--td-brand-color-7: #03de6d;
--td-brand-color-8: #80df94;
--td-brand-color-9: #bdf6c3;
--td-brand-color-10: #ddfbdd;
--td-brand-color-light: var(--td-brand-color-1);
--td-brand-color-focus: var(--td-brand-color-2);
--td-brand-color-disabled: var(--td-brand-color-3);
@@ -184,16 +440,16 @@
--td-success-color-8: #80d2b6;
--td-success-color-9: #b4e1d3;
--td-success-color-10: #deede8;
--td-gray-color-1: #f0f4f1;
--td-gray-color-2: #e9efeb;
--td-gray-color-3: #e1eae4;
--td-gray-color-4: #d4dfd8;
--td-gray-color-5: #bdc8c1;
--td-gray-color-6: #9ca8a1;
--td-gray-color-7: #808d86;
--td-gray-color-8: #6d7873;
--td-gray-color-9: #565f5b;
--td-gray-color-10: #454c48;
--td-gray-color-1: #f3f3f3;
--td-gray-color-2: #eee;
--td-gray-color-3: #e7e7e7;
--td-gray-color-4: #dcdcdc;
--td-gray-color-5: #c5c5c5;
--td-gray-color-6: #a6a6a6;
--td-gray-color-7: #8b8b8b;
--td-gray-color-8: #777;
--td-gray-color-9: #5e5e5e;
--td-gray-color-10: #4b4b4b;
--td-gray-color-11: #383838;
--td-gray-color-12: #2c2c2c;
--td-gray-color-13: #242424;
@@ -244,8 +500,259 @@
--td-bg-color-specialcomponent: transparent;
--td-border-level-1-color: var(--td-gray-color-11);
--td-border-level-2-color: var(--td-gray-color-9);
--td-mask-active: rgba(0, 0, 0, 0.1);
--td-mask-active: rgba(0, 0, 0, 0.4);
--td-mask-disabled: rgba(0, 0, 0, 0.6);
/* 通用颜色变量 - 暗色主题 */
--theme-bg-primary: #2d2d2d;
--theme-bg-secondary: #1a1a1a;
--theme-bg-tertiary: #1a1a1a;
--theme-text-primary: #ffffff;
--theme-text-secondary: #b3b3b3;
--theme-text-tertiary: #8a8a8a;
--theme-text-muted: #8a8a8a;
--theme-text-disabled: #b3b3b3;
--theme-border-light: #404040;
--theme-border-medium: #404040;
--theme-border-strong: #404040;
--theme-border: #404040;
--theme-hover-bg: #3a3a3a;
--theme-overlay: rgba(0, 0, 0, 0.8);
--theme-shadow-light: 0 2px 8px rgba(0, 0, 0, 0.2);
--theme-shadow-medium: 0 2px 8px rgba(0, 0, 0, 0.3);
--theme-shadow-hover: 0 8px 25px rgba(0, 0, 0, 0.4), 0 4px 10px rgba(0, 0, 0, 0.3);
--theme-card-bg: #2d2d2d;
--theme-card-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
--theme-card-shadow-hover: 0 8px 25px rgba(0, 0, 0, 0.4);
--theme-header-bg: #2a2a2a;
--theme-badge-bg: #404040;
--theme-tips-bg: linear-gradient(135deg, #2a2a2a, #333333);
--theme-warning-bg: #4a3a2a;
--theme-warning-text: #ffa726;
--theme-code-bg: rgba(255, 255, 255, 0.1);
--theme-code-hover-bg: rgba(255, 255, 255, 0.15);
--theme-note-bg: rgba(255, 255, 255, 0.08);
/* Find 页面专用变量 - 暗色主题 */
--find-bg-primary: var(--theme-bg-secondary);
--find-bg-secondary: var(--theme-bg-primary);
--find-text-primary: var(--theme-text-primary);
--find-text-secondary: var(--theme-text-secondary);
--find-text-muted: var(--theme-text-muted);
--find-card-bg: var(--theme-bg-primary);
--find-song-count-bg: rgba(255, 255, 255, 0.1);
--find-card-info-bg: rgba(45, 45, 45, 0.95);
--find-card-shadow: var(--theme-shadow-medium), 0 1px 4px rgba(0, 0, 0, 0.2);
--find-card-shadow-hover: var(--theme-shadow-hover);
--find-song-bg: var(--theme-bg-primary);
--find-song-hover-bg: var(--theme-hover-bg);
--find-border-color: var(--theme-border-light);
--find-meta-border: rgba(64, 64, 64, 0.5);
/* HomeLayout 页面专用变量 - 暗色主题 */
--home-nav-btn-color: var(--theme-text-secondary);
--home-nav-btn-hover: var(--theme-text-primary);
--home-source-selector-hover: var(--theme-hover-bg);
--home-source-list-bg: var(--theme-bg-primary);
--home-source-list-border: var(--theme-border-light);
--home-source-list-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.3);
--home-source-item-hover: var(--theme-hover-bg);
--home-scrollbar-track: var(--theme-bg-primary);
--home-scrollbar-thumb: #4a4a4a;
--home-scrollbar-thumb-hover: #5a5a5a;
--home-scrollbar-color: #4a4a4a var(--theme-bg-primary);
/* List 页面专用变量 - 暗色主题 */
--list-bg-primary: var(--theme-bg-tertiary);
--list-content-bg: var(--theme-bg-primary);
--list-header-bg: var(--theme-bg-primary);
--list-header-shadow: var(--theme-shadow-medium);
--list-content-shadow: var(--theme-shadow-light);
--list-title-color: var(--theme-text-primary);
--list-author-color: var(--theme-text-secondary);
--list-stats-color: var(--theme-text-muted);
--list-loading-text: var(--theme-text-disabled);
--list-loading-border: var(--theme-border-strong);
--list-loading-spinner: var(--td-brand-color);
--list-cover-overlay: var(--theme-overlay);
/* SongVirtualList 组件专用变量 - 暗色主题 */
--song-list-header-bg: #2a2a2a;
--song-list-header-border: #404040;
--song-list-header-text: #8a8a8a;
--song-list-content-bg: var(--theme-bg-primary);
--song-list-item-border: #3a3a3a;
--song-list-item-hover: var(--theme-hover-bg);
--song-list-item-current: #1a3a5a;
--song-list-item-playing: #1a4a6a;
--song-list-track-number: #8a8a8a;
--song-list-title-color: var(--theme-text-primary);
--song-list-title-hover: var(--td-brand-color);
--song-list-artist-color: var(--theme-text-muted);
--song-list-album-color: var(--theme-text-muted);
--song-list-album-hover: var(--td-brand-color);
--song-list-duration-color: var(--theme-text-muted);
--song-list-btn-color: #666666;
--song-list-btn-hover: var(--td-brand-color);
--song-list-btn-bg-hover: var(--td-brand-color-light);
--song-list-quality-bg: #3a2a1a;
--song-list-quality-color: #fa8c16;
/* Search 页面专用变量 - 暗色主题 */
--search-bg: var(--theme-bg-tertiary);
--search-title-color: var(--theme-text-primary);
--search-keyword-color: var(--td-brand-color);
--search-info-color: var(--theme-text-muted);
--search-content-bg: var(--theme-bg-primary);
--search-content-shadow: var(--theme-shadow-light);
--search-empty-title: var(--theme-text-primary);
--search-empty-text: var(--theme-text-muted);
--search-loading-text: var(--theme-text-secondary);
--search-loading-border: var(--theme-border-light);
--search-loading-spinner: var(--td-brand-color);
/* Recent 页面专用变量 - 暗色主题 */
--recent-bg: var(--theme-bg-tertiary);
--recent-title-color: var(--theme-text-primary);
--recent-subtitle-color: var(--theme-text-secondary);
--recent-section-title: var(--theme-text-primary);
--recent-card-bg: var(--theme-bg-primary);
--recent-card-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
--recent-card-shadow-hover: 0 4px 12px rgba(0, 0, 0, 0.4);
--recent-playlist-title: var(--theme-text-primary);
--recent-playlist-desc: var(--theme-text-secondary);
--recent-playlist-meta: var(--theme-text-muted);
--recent-song-item-border: var(--theme-border-light);
--recent-song-item-hover: var(--theme-hover-bg);
--recent-song-index: var(--theme-text-secondary);
--recent-song-title: var(--theme-text-primary);
--recent-song-artist: var(--theme-text-secondary);
--recent-song-stats: var(--theme-text-secondary);
--recent-song-duration: var(--theme-text-secondary);
--recent-empty-icon: #666666;
--recent-empty-title: var(--theme-text-primary);
--recent-empty-text: var(--theme-text-secondary);
/* Local 页面专用变量 - 暗色主题 */
--local-bg: var(--theme-bg-tertiary);
--local-text-primary: var(--theme-text-primary);
--local-text-secondary: var(--theme-text-secondary);
--local-text-tertiary: var(--theme-text-tertiary);
--local-card-bg: var(--theme-card-bg);
--local-card-shadow: var(--theme-card-shadow);
--local-card-shadow-hover: var(--theme-card-shadow-hover);
--local-border: var(--theme-border);
--local-hover-bg: var(--theme-hover-bg);
--local-header-bg: var(--theme-header-bg);
--local-badge-bg: var(--theme-badge-bg);
--local-tips-bg: var(--theme-tips-bg);
--local-warning-bg: var(--theme-warning-bg);
--local-warning-text: var(--theme-warning-text);
--local-code-bg: var(--theme-code-bg);
--local-code-hover-bg: var(--theme-code-hover-bg);
--local-note-bg: var(--theme-note-bg);
/* Welcome 页面专用变量 - 暗色主题 */
--welcome-bg: #1a1a1a;
--welcome-subtitle-color: #999999;
--welcome-loading-text: #aaaaaa;
--welcome-progress-bg: #333333;
--welcome-tag-bg: #2d2d2d;
--welcome-tag-border: #404040;
--welcome-tag-color: #cccccc;
--welcome-version-color: #666666;
/* TitleBarControls 组件专用变量 - 暗色主题 */
--titlebar-icon-color: #ffffff;
--titlebar-icon-hover: #ffffff;
--titlebar-btn-hover-bg: #3a3a3a;
--titlebar-close-hover-bg: #4a2a2a;
--titlebar-close-hover-color: #ff6b6b;
/* Settings 页面专用变量 - 暗色主题 */
--settings-main-bg: #1a1a1a;
--settings-header-bg: #2d2d2d;
--settings-sidebar-bg: #2d2d2d;
--settings-sidebar-border: #404040;
--settings-nav-hover-bg: #3a3a3a;
--settings-nav-active-bg: var(--td-brand-color-1);
--settings-nav-active-border: var(--td-brand-color-5);
--settings-nav-icon-color: #8a8a8a;
--settings-nav-icon-active: var(--td-brand-color-5);
--settings-nav-label-color: #ffffff;
--settings-nav-label-active: var(--td-brand-color-6);
--settings-nav-desc-color: #8a8a8a;
--settings-content-bg: #1a1a1a;
--settings-group-bg: #2d2d2d;
--settings-group-border: #404040;
--settings-group-shadow: rgba(0, 0, 0, 0.3);
--settings-text-primary: #ffffff;
--settings-text-secondary: #b3b3b3;
--settings-text-tertiary: #8a8a8a;
--settings-footer-bg: #2d2d2d;
--settings-version-bg: #404040;
--settings-preview-bg: #2a2a2a;
--settings-preview-border: #404040;
--settings-mock-titlebar-bg: #333333;
--settings-mock-titlebar-border: #555555;
--settings-feature-bg: #2a2a2a;
--settings-feature-border: #404040;
--settings-api-tips-bg: #2a2a2a;
--settings-api-tips-border: #404040;
--settings-source-card-bg: #2d2d2d;
--settings-source-card-border: #404040;
--settings-source-card-hover-border: var(--td-brand-color-3);
--settings-source-card-active-border: var(--td-brand-color-5);
--settings-source-card-active-bg: var(--td-brand-color-1);
--settings-source-icon-bg: #3a3a3a;
--settings-quality-container-bg: #2a2a2a;
--settings-quality-container-border: #404040;
--settings-status-item-bg: #2a2a2a;
--settings-status-item-border: #404040;
--settings-plugin-prompt-bg: linear-gradient(135deg, #2a2a2a 0%, #333333 100%);
--settings-plugin-prompt-border: #555555;
--settings-tech-item-bg: #2a2a2a;
--settings-tech-item-border: #404040;
--settings-developer-item-bg: #2a2a2a;
--settings-developer-item-border: #404040;
--settings-tag-option-bg: #2a2a2a;
--settings-tag-option-border: #404040;
--settings-tag-status-bg: #2a2a2a;
--settings-tag-status-border: #404040;
/* Plugins 组件专用变量 - 暗色主题 */
--plugins-bg: var(--theme-bg-tertiary);
--plugins-container-bg: var(--theme-bg-primary);
--plugins-header-bg: var(--theme-bg-primary);
--plugins-text-primary: var(--theme-text-primary);
--plugins-text-secondary: var(--theme-text-secondary);
--plugins-text-muted: var(--theme-text-muted);
--plugins-border: var(--theme-border);
--plugins-card-bg: var(--theme-card-bg);
--plugins-card-shadow: var(--theme-card-shadow);
--plugins-card-shadow-hover: var(--theme-card-shadow-hover);
--plugins-card-selected-bg: #1a3a1a;
--plugins-card-selected-border: #28a745;
--plugins-loading-spinner: var(--td-brand-color);
--plugins-error-color: #ff6b6b;
--plugins-success-color: #4ade80;
--plugins-console-bg: #0d1117;
--plugins-console-header-bg: #161b22;
--plugins-console-border: #30363d;
--plugins-console-text: #f0f6fc;
--plugins-console-prompt: var(--td-brand-color);
--plugins-console-path: #7d8590;
--plugins-console-time: #6e7681;
--plugins-console-scrollbar-track: #161b22;
--plugins-console-scrollbar-thumb: #30363d;
--plugins-console-scrollbar-thumb-hover: #484f58;
--plugins-log-error: #ff7b72;
--plugins-log-warn: #f0d852;
--plugins-log-info: #79c0ff;
--plugins-log-debug: #d2a8ff;
--plugins-mac-close: #ff5f57;
--plugins-mac-minimize: #ffbd2e;
--plugins-mac-maximize: #28ca42;
}
:root {

View File

@@ -1,4 +1,5 @@
:root[theme-mode='blue'] {
:root[theme-mode='blue'],
:root[theme-mode='blue'][data-theme='light'] {
--td-brand-color-1: #ecf4ff;
--td-brand-color-2: #cde5ff;
--td-brand-color-3: #9aceff;
@@ -136,7 +137,7 @@
--td-mask-disabled: rgba(255, 255, 255, 0.6);
}
:root[theme-mode='dark'] {
:root[theme-mode='blue'][data-theme='dark'] {
--td-brand-color-1: #3198e220;
--td-brand-color-2: #003355;
--td-brand-color-3: #004a77;

View File

@@ -1,4 +1,5 @@
:root[theme-mode='cyan'] {
:root[theme-mode='cyan'][data-theme='light'],
:root[theme-mode='cyan']:not([data-theme]) {
--td-brand-color-1: #e3fcf8;
--td-brand-color-2: #beefe9;
--td-brand-color-3: #86dad1;
@@ -136,7 +137,7 @@
--td-mask-disabled: rgba(255, 255, 255, 0.6);
}
:root[theme-mode='dark'] {
:root[theme-mode='cyan'][data-theme='dark'] {
--td-brand-color-1: #00a59b20;
--td-brand-color-2: #003b36;
--td-brand-color-3: #00524c;

View File

@@ -1,4 +1,5 @@
:root[theme-mode='orange'] {
:root[theme-mode='orange'][data-theme='light'],
:root[theme-mode='orange']:not([data-theme]) {
--td-brand-color-1: #fff1ea;
--td-brand-color-2: #ffd9c5;
--td-brand-color-3: #ffb991;
@@ -136,7 +137,7 @@
--td-mask-disabled: rgba(255, 255, 255, 0.6);
}
:root[theme-mode='dark'] {
:root[theme-mode='orange'][data-theme='dark'] {
--td-brand-color-1: #e4722820;
--td-brand-color-2: #552100;
--td-brand-color-3: #753000;

View File

@@ -1,4 +1,5 @@
:root[theme-mode='pink'] {
:root[theme-mode='pink'][data-theme='light'],
:root[theme-mode='pink']:not([data-theme]) {
--td-brand-color-1: #fff0f1;
--td-brand-color-2: #ffd8dd;
--td-brand-color-3: #ffb7c1;
@@ -136,7 +137,7 @@
--td-mask-disabled: rgba(255, 255, 255, 0.6);
}
:root[theme-mode='dark'] {
:root[theme-mode='pink'][data-theme='dark'] {
--td-brand-color-1: #ff547920;
--td-brand-color-2: #690021;
--td-brand-color-3: #8d1135;

View File

@@ -104,7 +104,7 @@
</template>
<script setup lang="ts">
import { ref, computed, onMounted, nextTick, toRaw } from 'vue'
import { ref, computed, onMounted, onUnmounted, nextTick, toRaw } from 'vue'
import {
DownloadIcon,
PlayCircleIcon,
@@ -432,6 +432,14 @@ onMounted(() => {
// 加载歌单列表
loadPlaylists()
// 监听歌单变化事件
window.addEventListener('playlist-updated', loadPlaylists)
})
onUnmounted(() => {
// 清理事件监听器
window.removeEventListener('playlist-updated', loadPlaylists)
})
</script>
@@ -456,10 +464,10 @@ onMounted(() => {
display: grid;
grid-template-columns: 60px 1fr 200px 60px 80px;
padding: 8px 20px;
background: #fafafa;
border-bottom: 1px solid #e9e9e9;
background: var(--song-list-header-bg);
border-bottom: 1px solid var(--song-list-header-border);
font-size: 12px;
color: #999;
color: var(--song-list-header-text);
flex-shrink: 0;
height: 40px;
box-sizing: border-box;
@@ -501,7 +509,7 @@ onMounted(() => {
}
.virtual-scroll-container {
background: #fff;
background: var(--song-list-content-bg);
overflow-y: auto;
position: relative;
flex: 1;
@@ -522,24 +530,32 @@ onMounted(() => {
display: grid;
grid-template-columns: 60px 1fr 200px 60px 80px;
padding: 8px 20px;
border-bottom: 1px solid #f5f5f5;
border-bottom: 1px solid var(--song-list-item-border);
cursor: pointer;
transition: background-color 0.2s ease;
height: 64px;
&:hover,
&.is-hovered {
background: #f5f5f5;
background: var(--song-list-item-hover);
.col-title .song-info .song-title {
color: var(--song-list-title-hover);
}
.col-album .album-name {
color: var(--song-list-album-hover);
}
}
&.is-current {
background: #f0f7ff;
color: #507daf;
background: var(--song-list-item-current);
color: var(--song-list-btn-hover);
}
&.is-playing {
background: #e6f7ff;
color: #507daf;
background: var(--song-list-item-playing);
color: var(--song-list-btn-hover);
}
.col-index {
@@ -550,7 +566,7 @@ onMounted(() => {
.track-number {
font-size: 14px;
color: #999;
color: var(--song-list-track-number);
font-variant-numeric: tabular-nums;
width: 100%;
text-align: center;
@@ -560,7 +576,7 @@ onMounted(() => {
background: none;
border: none;
cursor: pointer;
color: #507daf;
color: var(--song-list-btn-hover);
font-size: 16px;
padding: 8px;
border-radius: 50%;
@@ -573,8 +589,8 @@ onMounted(() => {
font-style: none;
&:hover {
background: rgba(80, 125, 175, 0.1);
color: #3a5d8f;
background: var(--song-list-btn-bg-hover);
color: var(--song-list-btn-hover);
}
i {
@@ -616,21 +632,18 @@ onMounted(() => {
.song-title {
font-size: 14px;
color: #333;
color: var(--song-list-title-color);
margin-bottom: 4px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
line-height: 1.2;
&:hover {
color: #507daf;
}
transition: color 0.2s ease;
}
.song-artist {
font-size: 12px;
color: #999;
color: var(--song-list-artist-color);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
@@ -640,8 +653,8 @@ onMounted(() => {
gap: 4px;
.quality-tag {
background: #fff7e6;
color: #fa8c16;
background: var(--song-list-quality-bg);
color: var(--song-list-quality-color);
padding: 1px 4px;
border-radius: 2px;
font-size: 10px;
@@ -659,16 +672,13 @@ onMounted(() => {
.album-name {
font-size: 12px;
color: #999;
color: var(--song-list-album-color);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
width: 100%;
&:hover {
color: #507daf;
cursor: pointer;
}
transition: color 0.2s ease;
cursor: pointer;
}
}
@@ -682,7 +692,7 @@ onMounted(() => {
background: none;
border: none;
cursor: pointer;
color: #ccc;
color: var(--song-list-btn-color);
padding: 8px;
border-radius: 50%;
transition: all 0.2s;
@@ -693,8 +703,8 @@ onMounted(() => {
justify-content: center;
&:hover {
color: #507daf;
background: rgba(80, 125, 175, 0.1);
color: var(--song-list-btn-hover);
background: var(--song-list-btn-bg-hover);
}
i {
@@ -719,7 +729,7 @@ onMounted(() => {
.duration {
font-size: 12px;
color: #999;
color: var(--song-list-duration-color);
font-variant-numeric: tabular-nums;
min-width: 35px;
text-align: center;
@@ -735,7 +745,7 @@ onMounted(() => {
background: none;
border: none;
cursor: pointer;
color: #ccc;
color: var(--song-list-btn-color);
padding: 6px;
border-radius: 50%;
transition: all 0.2s;
@@ -746,8 +756,8 @@ onMounted(() => {
justify-content: center;
&:hover {
color: #507daf;
background: rgba(80, 125, 175, 0.1);
color: var(--song-list-btn-hover);
background: var(--song-list-btn-bg-hover);
}
i {

View File

@@ -5,7 +5,7 @@
<div class="plugin-actions-hearder">
<h2>插件管理</h2>
<div class="plugin-actions">
<div class="plugin-actions" style="flex-direction: row">
<t-button theme="primary" @click="plugTypeDialog = true">
<template #icon><t-icon name="add" /></template> 添加插件
</t-button>
@@ -597,38 +597,62 @@ onMounted(async () => {
.page {
display: flex;
flex-direction: column;
height: 100vh;
// height: 100%;
// max-height: 100vh;
background: var(--plugins-bg);
color: var(--plugins-text-primary);
overflow: hidden;
h2 {
font-weight: 600;
color: var(--plugins-text-primary);
margin: 0 0 16px 0;
}
}
.header {
-webkit-app-region: drag;
display: flex;
align-items: center;
background-color: #fff;
background-color: var(--plugins-header-bg);
padding: 1.5rem;
position: sticky;
z-index: 1000;
top: 0;
left: 0;
right: 0;
border-bottom: 1px solid var(--plugins-border);
flex-shrink: 0;
}
.plugins-container {
flex: 1;
padding: 20px;
padding: 24px;
box-sizing: border-box;
display: flex;
flex-direction: column;
overflow-y: auto;
overflow: hidden;
min-height: 0;
background: var(--plugins-bg);
}
.plugin-actions-hearder {
margin-bottom: 24px;
flex-shrink: 0;
h2 {
margin-bottom: 16px;
font-size: 24px;
font-weight: 600;
color: var(--plugins-text-primary);
}
}
.plugin-actions {
display: flex;
margin-top: 10px;
margin-bottom: 20px;
gap: 12px;
margin-top: 16px;
}
.loading {
@@ -636,17 +660,25 @@ onMounted(async () => {
flex-direction: column;
align-items: center;
justify-content: center;
padding: 40px 0;
padding: 60px 0;
background: var(--plugins-container-bg);
border-radius: 12px;
margin: 20px 0;
}
.spinner {
width: 30px;
height: 30px;
border: 3px solid rgba(0, 0, 0, 0.1);
width: 32px;
height: 32px;
border: 3px solid var(--plugins-border);
border-radius: 50%;
border-top-color: var(--color-primary, #007bff);
border-top-color: var(--plugins-loading-spinner);
animation: spin 1s ease-in-out infinite;
margin-bottom: 10px;
margin-bottom: 16px;
}
.loading span {
color: var(--plugins-text-secondary);
font-size: 14px;
}
.error-state {
@@ -654,15 +686,26 @@ onMounted(async () => {
flex-direction: column;
align-items: center;
justify-content: center;
padding: 40px 0;
color: #666;
padding: 60px 0;
color: var(--plugins-text-secondary);
background: var(--plugins-container-bg);
border-radius: 12px;
margin: 20px 0;
}
.error-state p {
color: var(--plugins-text-primary);
font-size: 16px;
margin: 8px 0;
}
.error-message {
color: #dc3545;
margin-bottom: 15px;
color: var(--plugins-error-color);
margin-bottom: 20px;
text-align: center;
max-width: 80%;
font-size: 14px;
line-height: 1.5;
}
@keyframes spin {
@@ -676,103 +719,167 @@ onMounted(async () => {
flex-direction: column;
align-items: center;
justify-content: center;
padding: 40px 0;
color: #666;
padding: 60px 0;
color: var(--plugins-text-secondary);
background: var(--plugins-container-bg);
border-radius: 12px;
margin: 20px 0;
}
.empty-state p {
color: var(--plugins-text-primary);
font-size: 16px;
margin: 8px 0;
}
.hint {
font-size: 0.9em;
color: #999;
font-size: 14px;
color: var(--plugins-text-muted);
line-height: 1.5;
}
.plugin-list {
display: flex;
flex-direction: column;
gap: 15px;
gap: 16px;
flex: 1;
overflow-y: auto;
// overflow-y: auto;
// overflow-x: hidden;
min-height: 0;
max-height: 100%;
/* 自定义滚动条 */
&::-webkit-scrollbar {
width: 6px;
}
&::-webkit-scrollbar-track {
background: var(--plugins-bg);
border-radius: 3px;
}
&::-webkit-scrollbar-thumb {
background: var(--plugins-border);
border-radius: 3px;
&:hover {
background: var(--plugins-text-muted);
}
}
}
.plugin-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 15px;
border-radius: 8px;
background-color: #fefefe;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
align-items: flex-start;
padding: 20px;
border-radius: 12px;
background-color: var(--plugins-card-bg);
box-shadow: var(--plugins-card-shadow);
transition: all 0.3s ease;
border: 2px solid transparent;
position: relative;
// &:hover {
// box-shadow: var(--plugins-card-shadow-hover);
// transform: translateY(-2px);
// }
}
.plugin-item.selected {
background-color: #e8f5e8;
border: 2px solid #28a745;
background-color: var(--plugins-card-selected-bg);
border: 2px solid var(--plugins-card-selected-border);
// &::before {
// content: '';
// position: absolute;
// top: 0;
// left: 0;
// right: 0;
// height: 3px;
// background: linear-gradient(90deg, var(--plugins-card-selected-border), var(--td-brand-color));
// border-radius: 12px 12px 0 0;
// }
}
.plugin-info {
flex: 1;
margin-right: 20px;
}
.plugin-info h3 {
margin: 0 0 5px 0;
font-size: 1.1em;
margin: 0 0 8px 0;
font-size: 18px;
font-weight: 600;
display: flex;
align-items: center;
gap: 8px;
gap: 12px;
color: var(--plugins-text-primary);
line-height: 1.4;
}
.version {
font-size: 0.8em;
color: #666;
font-weight: normal;
font-size: 12px;
color: var(--plugins-text-muted);
font-weight: 500;
background: var(--plugins-border);
padding: 2px 8px;
border-radius: 6px;
}
.current-tag {
background-color: var(--td-brand-color-5);
background: linear-gradient(135deg, var(--td-brand-color-5), var(--td-brand-color-6));
color: white;
padding: 2px 8px;
border-radius: 12px;
font-size: 0.75em;
font-weight: normal;
padding: 4px 12px;
border-radius: 16px;
font-size: 12px;
font-weight: 500;
box-shadow: 0 2px 4px rgba(0, 167, 77, 0.2);
}
.author {
margin: 0 0 5px 0;
font-size: 0.9em;
color: #666;
margin: 0 0 8px 0;
font-size: 14px;
color: var(--plugins-text-secondary);
}
.description {
margin: 0 0 8px 0;
font-size: 0.9em;
margin: 0 0 12px 0;
font-size: 14px;
color: var(--plugins-text-secondary);
line-height: 1.5;
max-width: 500px;
}
.plugin-sources {
display: flex;
flex-wrap: wrap;
gap: 5px;
gap: 8px;
align-items: center;
margin-top: 5px;
margin-top: 8px;
}
.source-label {
font-size: 0.85em;
color: #666;
font-size: 13px;
color: var(--plugins-text-muted);
font-weight: 500;
}
.source-tag {
background-color: var(--color-primary, #007bff);
background: linear-gradient(135deg, var(--td-brand-color-4), var(--td-brand-color-5));
color: white;
padding: 2px 8px;
padding: 4px 10px;
border-radius: 12px;
font-size: 0.8em;
font-size: 12px;
font-weight: 500;
box-shadow: 0 1px 3px rgba(0, 167, 77, 0.2);
}
.plugin-actions {
display: flex;
flex-direction: column;
gap: 8px;
min-width: 120px;
}
/* 日志弹窗样式 */
@@ -780,15 +887,16 @@ onMounted(async () => {
height: 80vh;
.t-dialog {
background: #1e1e1e;
background: var(--plugins-console-bg);
border-radius: 12px;
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.4);
box-shadow: var(--plugins-dialog-shadow, 0 20px 60px rgba(0, 0, 0, 0.4));
overflow: hidden;
border: 1px solid var(--plugins-console-border);
}
.t-dialog__header {
background: #2d2d2d;
border-bottom: 1px solid #404040;
background: var(--plugins-console-header-bg);
border-bottom: 1px solid var(--plugins-console-border);
padding: 0;
border-radius: 12px 12px 0 0;
overflow: hidden;
@@ -796,12 +904,11 @@ onMounted(async () => {
.t-dialog__body {
padding: 0;
background: #1e1e1e;
border-left: 2px solid #272727;
border-right: 2px solid #272727;
border-bottom: 2px solid #272727;
background: var(--plugins-console-bg);
border-left: 2px solid var(--plugins-console-border);
border-right: 2px solid var(--plugins-console-border);
border-bottom: 2px solid var(--plugins-console-border);
border-radius: 0 0 12px 12px;
// max-height: 600px;
overflow: hidden;
}
}
@@ -810,7 +917,10 @@ onMounted(async () => {
display: flex;
align-items: center;
padding: 12px 20px;
background: linear-gradient(135deg, #2d2d2d 0%, #1e1e1e 100%);
background: var(
--plugins-dialog-header-bg,
linear-gradient(135deg, var(--plugins-console-header-bg) 0%, var(--plugins-console-bg) 100%)
);
min-height: 48px;
width: 100%;
@@ -818,14 +928,14 @@ onMounted(async () => {
display: flex;
align-items: center;
gap: 8px;
color: #ffffff;
color: var(--plugins-console-text);
font-weight: 600;
font-size: 14px;
flex: 1;
.iconfont {
font-size: 16px;
color: #00d4aa;
color: var(--plugins-console-prompt);
}
}
@@ -836,15 +946,15 @@ onMounted(async () => {
:deep(.t-button) {
background: rgba(255, 255, 255, 0.1);
border: 1px solid rgba(255, 255, 255, 0.2);
color: #ffffff;
border: 1px solid var(--plugins-console-border);
color: var(--plugins-console-text);
font-size: 12px;
padding: 4px 12px;
height: auto;
&:hover {
background: rgba(255, 255, 255, 0.2) !important;
border-color: rgba(255, 255, 255, 0.3);
border-color: var(--plugins-console-prompt);
}
.t-icon {
@@ -866,7 +976,7 @@ onMounted(async () => {
transition: all 0.2s ease;
&.close {
background: #ff5f57;
background: var(--plugins-mac-close);
&:hover {
background: #ff3b30;
@@ -874,7 +984,7 @@ onMounted(async () => {
}
&.minimize {
background: #ffbd2e;
background: var(--plugins-mac-minimize);
&:hover {
background: #ff9500;
@@ -882,7 +992,7 @@ onMounted(async () => {
}
&.maximize {
background: #28ca42;
background: var(--plugins-mac-maximize);
&:hover {
background: #30d158;
@@ -893,21 +1003,20 @@ onMounted(async () => {
}
.console-container {
background: #1e1e1e;
color: #ffffff;
background: var(--plugins-console-bg);
color: var(--plugins-console-text);
font-family: 'SF Mono', 'Monaco', 'Inconsolata', 'Fira Code', 'Consolas', monospace;
font-size: 13px;
line-height: 1.4;
height: calc(80vh - 64px - 48px);
// max-height: 500px;
min-height: 300px;
display: flex;
flex-direction: column;
}
.console-header {
background: #2d2d2d;
border-bottom: 1px solid #404040;
background: var(--plugins-console-header-bg);
border-bottom: 1px solid var(--plugins-console-border);
padding: 8px 16px;
flex-shrink: 0;
@@ -916,17 +1025,18 @@ onMounted(async () => {
align-items: center;
gap: 12px;
font-size: 12px;
.console-prompt {
color: var(--td-brand-color-5);
color: var(--plugins-console-prompt);
font-weight: bold;
}
.console-path {
color: #8a8a8a;
color: var(--plugins-console-path);
}
.console-time {
color: #666666;
color: var(--plugins-console-time);
margin-left: auto;
}
}
@@ -935,9 +1045,9 @@ onMounted(async () => {
.console-content {
flex: 1;
overflow-y: auto;
scrollbar-color: #555555 #2d2d2d;
scrollbar-color: var(--plugins-console-scrollbar-thumb) var(--plugins-console-scrollbar-track);
padding: 16px;
background: #1e1e1e;
background: var(--plugins-console-bg);
position: relative;
&.loading {
@@ -952,15 +1062,15 @@ onMounted(async () => {
}
&::-webkit-scrollbar-track {
background: #2d2d2d;
background: var(--plugins-console-scrollbar-track);
}
&::-webkit-scrollbar-thumb {
background: #555555;
background: var(--plugins-console-scrollbar-thumb);
border-radius: 4px;
&:hover {
background: #666666;
background: var(--plugins-console-scrollbar-thumb-hover);
}
}
}
@@ -970,13 +1080,13 @@ onMounted(async () => {
flex-direction: column;
align-items: center;
gap: 12px;
color: #8a8a8a;
color: var(--plugins-console-path);
.loading-spinner {
width: 20px;
height: 20px;
border: 2px solid #404040;
border-top: 2px solid #00d4aa;
border: 2px solid var(--plugins-console-border);
border-top: 2px solid var(--plugins-console-prompt);
border-radius: 50%;
animation: spin 1s linear infinite;
}
@@ -986,11 +1096,11 @@ onMounted(async () => {
display: flex;
align-items: center;
gap: 8px;
color: #ff6b6b;
color: var(--plugins-log-error);
padding: 12px;
background: rgba(255, 107, 107, 0.1);
border-radius: 6px;
border-left: 4px solid #ff6b6b;
border-left: 4px solid var(--plugins-log-error);
.error-icon {
font-size: 16px;
@@ -1003,7 +1113,7 @@ onMounted(async () => {
align-items: center;
justify-content: center;
gap: 8px;
color: #8a8a8a;
color: var(--plugins-console-path);
height: 200px;
.empty-icon {
@@ -1025,7 +1135,7 @@ onMounted(async () => {
}
.log-timestamp {
color: #666666;
color: var(--plugins-console-time);
font-size: 11px;
width: 80px;
text-align: center;
@@ -1044,47 +1154,47 @@ onMounted(async () => {
/* 不同日志级别的颜色 */
&.log-error {
.log-content {
color: #ff6b6b;
color: var(--plugins-log-error);
}
.log-timestamp {
color: #ff6b6b;
color: var(--plugins-log-error);
}
}
&.log-warn {
.log-content {
color: #ffd93d;
color: var(--plugins-log-warn);
}
.log-timestamp {
color: #ffd93d;
color: var(--plugins-log-warn);
}
}
&.log-info {
.log-content {
color: #74b9ff;
color: var(--plugins-log-info);
}
.log-timestamp {
color: #74b9ff;
color: var(--plugins-log-info);
}
}
&.log-debug {
.log-content {
color: #a29bfe;
color: var(--plugins-log-debug);
}
.log-timestamp {
color: #a29bfe;
color: var(--plugins-log-debug);
}
}
&.log-default {
.log-content {
color: #ffffff;
color: var(--plugins-console-text);
}
}
}
@@ -1102,26 +1212,49 @@ onMounted(async () => {
/* 导入方式选择样式 */
.import-method-container {
padding: 10px 0;
padding: 16px 0;
}
.online-input-container {
margin-top: 15px;
margin-top: 16px;
}
.hint-text {
font-size: 12px;
color: #666;
font-size: 13px;
color: var(--plugins-text-muted);
margin-top: 8px;
line-height: 1.4;
line-height: 1.5;
}
.local-hint-container {
margin-top: 15px;
margin-top: 16px;
padding: 12px;
background: var(--plugins-border);
border-radius: 8px;
}
/* 响应式设计 */
@media (max-width: 768px) {
.plugins-container {
padding: 16px;
}
.plugin-item {
flex-direction: column;
align-items: stretch;
gap: 16px;
.plugin-info {
margin-right: 0;
}
.plugin-actions {
flex-direction: row;
justify-content: flex-end;
min-width: auto;
}
}
:deep(.log-dialog) {
.t-dialog {
width: 95% !important;

View File

@@ -1,54 +1,35 @@
<!--
主题选择器组件 - 支持暗色模式切换
-->
<template>
<div class="theme-selector">
<div class="theme-selector-trigger" @click="toggleDropdown">
<div class="current-theme">
<div class="theme-color-preview" :style="{ backgroundColor: currentThemeColor }"></div>
<span class="theme-name">{{ currentThemeName }}</span>
</div>
<svg
class="dropdown-icon"
:class="{ rotated: isDropdownOpen }"
viewBox="0 0 24 24"
width="16"
height="16"
<div class="theme-options">
<div
v-for="theme in themes"
:key="theme.name"
class="theme-option"
:class="{ active: currentTheme === theme.name }"
@click="selectTheme(theme.name)"
>
<path d="M7 10l5 5 5-5z" fill="currentColor" />
</svg>
<div class="theme-preview" :style="{ backgroundColor: theme.color }"></div>
<span class="theme-label">{{ theme.label }}</span>
</div>
</div>
<transition name="dropdown">
<div v-if="isDropdownOpen" class="theme-dropdown">
<div
v-for="theme in themes"
:key="theme.name"
class="theme-option"
:class="{ active: currentTheme === theme.name }"
@click="selectTheme(theme.name)"
>
<div class="theme-color-dot" :style="{ backgroundColor: theme.color }"></div>
<span class="theme-label">{{ theme.label }}</span>
<svg
v-if="currentTheme === theme.name"
class="check-icon"
viewBox="0 0 24 24"
width="16"
height="16"
>
<path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z" fill="currentColor" />
</svg>
</div>
</div>
</transition>
<div class="dark-mode-toggle">
<label class="toggle-switch">
<input type="checkbox" :checked="isDarkMode" @change="toggleDarkMode" />
<span class="slider"></span>
<span class="toggle-label">暗色模式</span>
</label>
</div>
</div>
</template>
<script setup>
import { ref, computed, onMounted, onUnmounted } from 'vue'
<script setup lang="ts">
import { ref, onMounted } from 'vue'
const isDropdownOpen = ref(false)
const currentTheme = ref('default')
// 基于现有主题文件的配置
// 主题配置
const themes = [
{ name: 'default', label: '默认', color: '#2ba55b' },
{ name: 'pink', label: '粉色', color: '#fc5e7e' },
@@ -57,209 +38,203 @@ const themes = [
{ name: 'orange', label: '橙色', color: '#fb9458' }
]
const loadSavedTheme = () => {
const savedTheme = localStorage.getItem('selected-theme')
if (savedTheme && themes.some((t) => t.name === savedTheme)) {
currentTheme.value = savedTheme
applyTheme(savedTheme)
}
}
const currentTheme = ref('default')
const isDarkMode = ref(false)
const applyTheme = (themeName) => {
// 应用主题
const applyTheme = (themeName: string, darkMode: boolean = false) => {
const documentElement = document.documentElement
// 移除之前的主题
// 移除之前的主题属性
documentElement.removeAttribute('theme-mode')
documentElement.removeAttribute('data-theme')
// 应用主题(如果不是默认主题)
// 应用主题色彩
if (themeName !== 'default') {
documentElement.setAttribute('theme-mode', themeName)
}
// 保存到本地存储
localStorage.setItem('selected-theme', themeName)
}
const currentThemeColor = computed(() => {
const theme = themes.find((t) => t.name === currentTheme.value)
return theme ? theme.color : '#2ba55b'
})
const currentThemeName = computed(() => {
const theme = themes.find((t) => t.name === currentTheme.value)
return theme ? theme.label : '默认'
})
const toggleDropdown = () => {
isDropdownOpen.value = !isDropdownOpen.value
}
const selectTheme = (themeName) => {
if (themeName === currentTheme.value) {
isDropdownOpen.value = false
return
// 应用明暗模式
if (darkMode) {
documentElement.setAttribute('data-theme', 'dark')
} else {
documentElement.setAttribute('data-theme', 'light')
}
currentTheme.value = themeName
applyTheme(themeName)
isDropdownOpen.value = false
// 保存到本地存储
localStorage.setItem('selected-theme', themeName)
localStorage.setItem('dark-mode', darkMode.toString())
}
const handleClickOutside = (event) => {
const themeSelector = event.target.closest('.theme-selector')
if (!themeSelector) {
isDropdownOpen.value = false
// 选择主题
const selectTheme = (themeName: string) => {
currentTheme.value = themeName
applyTheme(themeName, isDarkMode.value)
}
// 切换暗色模式
const toggleDarkMode = () => {
isDarkMode.value = !isDarkMode.value
applyTheme(currentTheme.value, isDarkMode.value)
}
// 检测系统主题偏好
const detectSystemTheme = () => {
if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
return true
}
return false
}
// 加载保存的设置
const loadSavedSettings = () => {
const savedTheme = localStorage.getItem('selected-theme')
const savedDarkMode = localStorage.getItem('dark-mode')
if (savedTheme && themes.some((t) => t.name === savedTheme)) {
currentTheme.value = savedTheme
}
if (savedDarkMode !== null) {
isDarkMode.value = savedDarkMode === 'true'
} else {
// 如果没有保存的设置,检测系统偏好
isDarkMode.value = detectSystemTheme()
}
applyTheme(currentTheme.value, isDarkMode.value)
}
// 监听系统主题变化
const setupSystemThemeListener = () => {
if (window.matchMedia) {
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)')
mediaQuery.addEventListener('change', (e) => {
const savedDarkMode = localStorage.getItem('dark-mode')
// 如果用户没有手动设置暗色模式,则跟随系统主题
if (savedDarkMode === null) {
isDarkMode.value = e.matches
applyTheme(currentTheme.value, isDarkMode.value)
}
})
}
}
onMounted(() => {
loadSavedTheme()
document.addEventListener('click', handleClickOutside)
})
onUnmounted(() => {
document.removeEventListener('click', handleClickOutside)
setupSystemThemeListener()
loadSavedSettings()
})
</script>
<style scoped>
.theme-selector {
position: relative;
display: inline-block;
width: 200px;
padding: 16px;
background: var(--td-bg-color-container);
border-radius: var(--td-radius-medium);
border: 1px solid var(--td-border-level-1-color);
}
.theme-selector-trigger {
.theme-options {
display: flex;
align-items: center;
gap: 8px;
padding: 8px 12px;
background: var(--td-bg-color-container, #ffffff);
border: 1px solid var(--td-component-border, #e2e8f0);
border-radius: var(--td-radius-medium, 6px);
cursor: pointer;
transition: all 0.2s ease;
min-width: 120px;
}
.theme-selector-trigger:hover {
background: var(--td-bg-color-container-hover, #f8fafc);
border-color: var(--td-brand-color-hover, #cbd5e1);
}
.current-theme {
display: flex;
align-items: center;
gap: 8px;
flex: 1;
}
.theme-color-preview {
width: 16px;
height: 16px;
border-radius: 50%;
border: 2px solid var(--td-bg-color-container, #ffffff);
box-shadow: 0 0 0 1px var(--td-component-border, #e2e8f0);
}
.theme-name {
font-size: 14px;
color: var(--td-text-color-primary, #1e293b);
font-weight: 500;
}
.dropdown-icon {
color: var(--td-text-color-secondary, #64748b);
transition: transform 0.2s ease;
}
.dropdown-icon.rotated {
transform: rotate(180deg);
}
.theme-dropdown {
position: absolute;
top: 100%;
left: 0;
right: 0;
margin-top: 4px;
background: var(--td-bg-color-container, #ffffff);
border: 1px solid var(--td-component-border, #e2e8f0);
border-radius: var(--td-radius-medium, 6px);
box-shadow: var(
--td-shadow-2,
0 4px 6px -1px rgba(0, 0, 0, 0.1),
0 2px 4px -1px rgba(0, 0, 0, 0.06)
);
z-index: 1000;
overflow: hidden;
gap: 12px;
margin-bottom: 16px;
flex-wrap: wrap;
}
.theme-option {
display: flex;
flex-direction: column;
align-items: center;
gap: 12px;
padding: 12px 16px;
gap: 8px;
padding: 12px;
border-radius: var(--td-radius-medium);
cursor: pointer;
transition: background-color 0.2s ease;
transition: all 0.2s ease;
border: 2px solid transparent;
}
.theme-option:hover {
background: var(--td-bg-color-container-hover, #f8fafc);
background: var(--td-bg-color-container-hover);
}
.theme-option.active {
background: var(--td-brand-color-light, #eff6ff);
color: var(--td-text-color-primary, #1e293b);
border-color: var(--td-brand-color);
background: var(--td-brand-color-light);
}
.theme-color-dot {
width: 20px;
height: 20px;
border-radius: 50%;
border: 2px solid var(--td-bg-color-container, #ffffff);
box-shadow: 0 0 0 1px var(--td-component-border, #e2e8f0);
.theme-preview {
width: 32px;
height: 32px;
border-radius: var(--td-radius-circle);
border: 2px solid var(--td-border-level-1-color);
}
.theme-label {
flex: 1;
font-size: 14px;
color: var(--td-text-color-primary, #1e293b);
font-size: var(--td-font-size-body-small);
color: var(--td-text-color-primary);
font-weight: 500;
}
.check-icon {
color: var(--td-brand-color, #3b82f6);
.dark-mode-toggle {
padding-top: 16px;
border-top: 1px solid var(--td-border-level-1-color);
}
/* 下拉动画 */
.dropdown-enter-active,
.dropdown-leave-active {
transition: all 0.2s ease;
.toggle-switch {
display: flex;
align-items: center;
gap: 12px;
cursor: pointer;
}
.dropdown-enter-from {
opacity: 0;
transform: translateY(-8px) scale(0.95);
.toggle-switch input {
display: none;
}
.dropdown-leave-to {
opacity: 0;
transform: translateY(-8px) scale(0.95);
.slider {
position: relative;
width: 44px;
height: 24px;
background: var(--td-bg-color-component);
border-radius: 12px;
transition: background-color 0.2s ease;
border: 1px solid var(--td-border-level-1-color);
}
/* 响应式设计 */
@media (max-width: 640px) {
.theme-selector-trigger {
min-width: 100px;
padding: 6px 10px;
}
.slider::before {
content: '';
position: absolute;
top: 2px;
left: 2px;
width: 18px;
height: 18px;
background: var(--td-bg-color-container);
border-radius: 50%;
transition: transform 0.2s ease;
box-shadow: var(--td-shadow-1);
}
.theme-name {
font-size: 13px;
}
.toggle-switch input:checked + .slider {
background: var(--td-brand-color);
}
.theme-option {
padding: 10px 14px;
}
.toggle-switch input:checked + .slider::before {
transform: translateX(20px);
}
.toggle-label {
font-size: var(--td-font-size-body-medium);
color: var(--td-text-color-primary);
font-weight: 500;
}
/* 暗色模式下的特殊样式 */
:root[theme-mode='dark'] .theme-selector {
background: var(--td-bg-color-container);
border-color: var(--td-border-level-1-color);
}
:root[theme-mode='dark'] .theme-preview {
border-color: var(--td-border-level-2-color);
}
</style>

View File

@@ -9,7 +9,7 @@ const props = withDefaults(defineProps<Props>(), {
showSettings: true,
showBack: false,
title: '',
color: 'black'
color: 'var(--titlebar-btn-text-color)'
})
const Store = LocalUserDetailStore()
const { userInfo } = storeToRefs(Store)
@@ -202,7 +202,7 @@ const handleBack = (): void => {
}
&:hover .iconfont {
color: #111827;
color: v-bind(color) !important;
}
}
@@ -222,12 +222,20 @@ const handleBack = (): void => {
-webkit-app-region: no-drag;
margin-right: 0.5rem;
&:hover {
background-color: #f3f4f6;
background-color: var(--titlebar-btn-hover-bg);
}
}
}
.title-box {
flex: 1;
p {
margin: 0;
font-size: 0.875rem;
font-weight: 500;
color: var(--settings-text-primary, v-bind(color));
line-height: 1.2;
}
}
}
@@ -235,7 +243,7 @@ const handleBack = (): void => {
margin-right: 0.5rem;
&:hover {
background-color: #f3f4f6;
background-color: var(--titlebar-btn-hover-bg);
}
}
@@ -251,23 +259,23 @@ const handleBack = (): void => {
}
&:hover {
background-color: #f3f4f6;
background-color: var(--titlebar-btn-hover-bg);
}
}
.minimize-btn:hover {
background-color: #f3f4f6;
background-color: var(--titlebar-btn-hover-bg);
}
.maximize-btn:hover {
background-color: #f3f4f6;
background-color: var(--titlebar-btn-hover-bg);
}
.close-btn:hover {
background-color: #fee2e2;
background-color: var(--titlebar-close-hover-bg);
.iconfont {
color: #dc2626;
color: v-bind(color) !important;
}
}
}

View File

@@ -11,3 +11,53 @@ const versions = reactive({ ...window.electron.process.versions })
<li class="node-version">Node v{{ versions.node }}</li>
</ul>
</template>
<style lang="scss" scoped>
.versions {
list-style: none;
padding: 0;
margin: 0;
display: flex;
flex-direction: column;
gap: 0.5rem;
li {
display: flex;
justify-content: space-between;
align-items: center;
padding: 0.75rem 1rem;
background: var(--settings-tech-item-bg, #f8fafc);
border-radius: 0.5rem;
border: 1px solid var(--settings-tech-item-border, #e2e8f0);
color: var(--settings-text-primary, #1e293b);
font-size: 0.875rem;
font-weight: 500;
transition: all 0.2s ease;
&:hover {
background: var(--settings-nav-hover-bg, #f1f5f9);
}
}
.electron-version {
&::before {
content: '⚡';
margin-right: 0.5rem;
}
}
.chrome-version {
&::before {
content: '🌐';
margin-right: 0.5rem;
}
}
.node-version {
&::before {
content: '🟢';
margin-right: 0.5rem;
}
}
}
</style>

View File

@@ -164,7 +164,7 @@ const handleKeyDown = () => {
<i class="iconfont icon-music"></i>
</div>
<p class="app-title">
<span style="color: #000; font-weight: 800">Ceru Music</span>
<span style="font-weight: 800">Ceru Music</span>
</p>
</div>
@@ -240,13 +240,13 @@ const handleKeyDown = () => {
style="display: flex; align-items: center; justify-content: center"
@click="handleSearch"
>
<SearchIcon style="font-size: 16px; color: #000" />
<SearchIcon style="font-size: 16px; color: var(--td-text-color-primary)" />
</t-button>
</template>
</t-input>
</div>
<TitleBarControls :color="'#000'"></TitleBarControls>
<TitleBarControls></TitleBarControls>
</div>
</div>
@@ -305,8 +305,12 @@ const handleKeyDown = () => {
.sidebar {
width: 15rem;
background-image: linear-gradient(to bottom, var(--td-brand-color-4) -140vh, #ffffff 30vh);
border-right: 0.0625rem solid #e5e7eb;
background-image: linear-gradient(
to bottom,
var(--td-brand-color-4) -140vh,
var(--td-bg-color-container) 30vh
);
border-right: 0.0625rem solid var(--td-border-level-1-color);
flex-shrink: 0;
.sidebar-content {
@@ -330,18 +334,17 @@ const handleKeyDown = () => {
.iconfont {
font-size: 1.25rem;
color: white;
color: #fff;
}
}
.app-title {
font-weight: 500;
font-size: 1.125rem;
color: #111827;
color: var(--td-text-color-primary);
span {
font-weight: 500;
color: #b8f0cc;
}
}
}
@@ -363,22 +366,30 @@ const handleKeyDown = () => {
margin-right: 0.75rem;
font-size: 1rem;
}
div {
display: none !important;
visibility: hidden;
}
&.active {
background-color: var(--td-brand-color-4);
color: rgb(255, 255, 255);
color: var(--td-text-color-anti);
&:active {
background-color: var(--td-brand-color-5) !important;
}
&:hover {
background-color: var(--td-brand-color-5);
background-color: var(--td-brand-color-5) !important;
}
}
&:not(.active) {
color: #6b7280;
color: var(--hover-nav-text);
// color: var(--td-text-color-secondary);
&:hover {
color: #111827;
background-color: #f3f4f6;
color: var(--hover-nav-text-hover);
background-color: var(--hover-nav-color);
}
}
}
@@ -393,7 +404,11 @@ const handleKeyDown = () => {
.content {
padding: 0;
background-image: linear-gradient(to bottom, var(--td-brand-color-4) -110vh, #ffffff 15vh);
background-image: linear-gradient(
to bottom,
var(--td-brand-color-4) -110vh,
var(--td-bg-color-container) 15vh
);
display: flex;
flex: 1;
@@ -415,11 +430,11 @@ const handleKeyDown = () => {
.iconfont {
font-size: 1rem;
color: #3d4043;
color: var(--home-nav-btn-color);
}
&:hover .iconfont {
color: #111827;
color: var(--home-nav-btn-hover);
}
}
@@ -438,7 +453,7 @@ const handleKeyDown = () => {
width: min(18.75rem, 400px);
margin-right: 0.5rem;
border-radius: 1.25rem !important;
background-color: #fff;
background-color: var(--td-bg-color-container);
overflow: visible;
position: relative;
@@ -458,7 +473,7 @@ const handleKeyDown = () => {
transition: background-color 0.2s;
&:hover {
background-color: #f3f4f6;
background-color: var(--home-source-selector-hover);
}
.source-arrow {
@@ -489,10 +504,10 @@ const handleKeyDown = () => {
top: 100%;
left: 0;
z-index: 10000000;
background: white;
border: 1px solid #e5e7eb;
background: var(--home-source-list-bg);
border: 1px solid var(--home-source-list-border);
border-radius: 0.5rem;
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
box-shadow: var(--home-source-list-shadow);
min-width: 10rem;
overflow-y: hidden;
margin-top: 0.25rem;
@@ -534,7 +549,7 @@ const handleKeyDown = () => {
}
&:hover {
background-color: #f3f4f6;
background-color: var(--home-source-item-hover);
}
&.active {
@@ -568,11 +583,11 @@ const handleKeyDown = () => {
.settings-btn {
.iconfont {
font-size: 1rem;
color: #6b7280;
color: var(--td-text-color-secondary);
}
&:hover .iconfont {
color: #111827;
color: var(--td-text-color-primary);
}
}
}
@@ -591,23 +606,23 @@ const handleKeyDown = () => {
}
&::-webkit-scrollbar-track {
background: #f1f5f9;
background: var(--home-scrollbar-track);
border-radius: 0.1875rem;
}
&::-webkit-scrollbar-thumb {
background: #cbd5e1;
background: var(--home-scrollbar-thumb);
border-radius: 0.1875rem;
transition: background-color 0.2s ease;
&:hover {
background: #94a3b8;
background: var(--home-scrollbar-thumb-hover);
}
}
/* Firefox 滚动条样式 */
scrollbar-width: thin;
scrollbar-color: #cbd5e1 #f1f5f9;
scrollbar-color: var(--home-scrollbar-color);
}
}
</style>

View File

@@ -0,0 +1,368 @@
<!--
主题演示页面 - 展示暗色模式适配效果
-->
<template>
<div class="theme-demo">
<div class="demo-header">
<h1 class="demo-title">主题演示</h1>
<p class="demo-description">测试不同主题和暗色模式的效果</p>
</div>
<div class="demo-content">
<!-- 主题选择器 -->
<div class="demo-section">
<h2 class="section-title">主题选择</h2>
<ThemeSelector />
</div>
<!-- 组件演示 -->
<div class="demo-section">
<h2 class="section-title">组件演示</h2>
<div class="component-grid">
<!-- 按钮演示 -->
<div class="component-item">
<h3 class="component-title">按钮</h3>
<div class="button-group">
<button class="btn btn-primary">主要按钮</button>
<button class="btn btn-secondary">次要按钮</button>
<button class="btn btn-outline">轮廓按钮</button>
</div>
</div>
<!-- 输入框演示 -->
<div class="component-item">
<h3 class="component-title">输入框</h3>
<div class="input-group">
<input type="text" class="input" placeholder="请输入内容" />
<textarea class="textarea" placeholder="多行文本输入"></textarea>
</div>
</div>
<!-- 卡片演示 -->
<div class="component-item">
<h3 class="component-title">卡片</h3>
<div class="card">
<div class="card-header">
<h4 class="card-title">卡片标题</h4>
</div>
<div class="card-body">
<p class="card-text">这是卡片内容用于展示暗色模式下的效果</p>
<div class="card-actions">
<button class="btn btn-small btn-primary">操作</button>
<button class="btn btn-small btn-outline">取消</button>
</div>
</div>
</div>
</div>
<!-- 列表演示 -->
<div class="component-item">
<h3 class="component-title">列表</h3>
<div class="list">
<div class="list-item">
<div class="list-content">
<div class="list-title">列表项 1</div>
<div class="list-description">这是列表项的描述文本</div>
</div>
<div class="list-action">
<button class="btn btn-small btn-outline">编辑</button>
</div>
</div>
<div class="list-item">
<div class="list-content">
<div class="list-title">列表项 2</div>
<div class="list-description">这是另一个列表项的描述</div>
</div>
<div class="list-action">
<button class="btn btn-small btn-outline">编辑</button>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- 颜色演示 -->
<div class="demo-section">
<h2 class="section-title">颜色系统</h2>
<div class="color-grid">
<div class="color-item">
<div class="color-swatch color-primary"></div>
<span class="color-label">主色</span>
</div>
<div class="color-item">
<div class="color-swatch color-success"></div>
<span class="color-label">成功</span>
</div>
<div class="color-item">
<div class="color-swatch color-warning"></div>
<span class="color-label">警告</span>
</div>
<div class="color-item">
<div class="color-swatch color-error"></div>
<span class="color-label">错误</span>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import ThemeSelector from '../components/ThemeSelector.vue'
</script>
<style scoped>
.theme-demo {
min-height: 100vh;
background: var(--td-bg-color-page);
padding: 24px;
}
.demo-header {
text-align: center;
margin-bottom: 32px;
}
.demo-title {
font-size: var(--td-font-size-headline-large);
color: var(--td-text-color-primary);
margin-bottom: 8px;
}
.demo-description {
font-size: var(--td-font-size-body-large);
color: var(--td-text-color-secondary);
}
.demo-content {
max-width: 1200px;
margin: 0 auto;
}
.demo-section {
margin-bottom: 32px;
background: var(--td-bg-color-container);
border-radius: var(--td-radius-large);
padding: 24px;
border: 1px solid var(--td-border-level-1-color);
}
.section-title {
font-size: var(--td-font-size-title-large);
color: var(--td-text-color-primary);
margin-bottom: 16px;
}
.component-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 24px;
}
.component-item {
padding: 16px;
background: var(--td-bg-color-secondarycontainer);
border-radius: var(--td-radius-medium);
border: 1px solid var(--td-border-level-1-color);
}
.component-title {
font-size: var(--td-font-size-title-medium);
color: var(--td-text-color-primary);
margin-bottom: 12px;
}
/* 按钮样式 */
.button-group {
display: flex;
gap: 12px;
flex-wrap: wrap;
}
.btn {
padding: 8px 16px;
border-radius: var(--td-radius-medium);
border: 1px solid transparent;
font-size: var(--td-font-size-body-medium);
cursor: pointer;
transition: all 0.2s ease;
}
.btn-small {
padding: 4px 8px;
font-size: var(--td-font-size-body-small);
}
.btn-primary {
background: var(--td-brand-color);
color: var(--td-text-color-anti);
border-color: var(--td-brand-color);
}
.btn-primary:hover {
background: var(--td-brand-color-hover);
}
.btn-secondary {
background: var(--td-bg-color-component);
color: var(--td-text-color-primary);
border-color: var(--td-component-border);
}
.btn-secondary:hover {
background: var(--td-bg-color-component-hover);
}
.btn-outline {
background: transparent;
color: var(--td-brand-color);
border-color: var(--td-brand-color);
}
.btn-outline:hover {
background: var(--td-brand-color-light);
}
/* 输入框样式 */
.input-group {
display: flex;
flex-direction: column;
gap: 12px;
}
.input,
.textarea {
padding: 8px 12px;
border: 1px solid var(--td-component-border);
border-radius: var(--td-radius-medium);
background: var(--td-bg-color-container);
color: var(--td-text-color-primary);
font-size: var(--td-font-size-body-medium);
}
.input:focus,
.textarea:focus {
outline: none;
border-color: var(--td-brand-color);
box-shadow: 0 0 0 2px var(--td-brand-color-light);
}
.textarea {
min-height: 80px;
resize: vertical;
}
/* 卡片样式 */
.card {
background: var(--td-bg-color-container);
border: 1px solid var(--td-border-level-1-color);
border-radius: var(--td-radius-medium);
overflow: hidden;
}
.card-header {
padding: 16px;
background: var(--td-bg-color-secondarycontainer);
border-bottom: 1px solid var(--td-border-level-1-color);
}
.card-title {
font-size: var(--td-font-size-title-medium);
color: var(--td-text-color-primary);
margin: 0;
}
.card-body {
padding: 16px;
}
.card-text {
color: var(--td-text-color-secondary);
margin-bottom: 16px;
}
.card-actions {
display: flex;
gap: 8px;
}
/* 列表样式 */
.list {
background: var(--td-bg-color-container);
border: 1px solid var(--td-border-level-1-color);
border-radius: var(--td-radius-medium);
overflow: hidden;
}
.list-item {
display: flex;
align-items: center;
justify-content: space-between;
padding: 16px;
border-bottom: 1px solid var(--td-border-level-1-color);
}
.list-item:last-child {
border-bottom: none;
}
.list-item:hover {
background: var(--td-bg-color-container-hover);
}
.list-title {
font-size: var(--td-font-size-body-medium);
color: var(--td-text-color-primary);
font-weight: 500;
margin-bottom: 4px;
}
.list-description {
font-size: var(--td-font-size-body-small);
color: var(--td-text-color-secondary);
}
/* 颜色演示 */
.color-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
gap: 16px;
}
.color-item {
display: flex;
flex-direction: column;
align-items: center;
gap: 8px;
}
.color-swatch {
width: 60px;
height: 60px;
border-radius: var(--td-radius-medium);
border: 1px solid var(--td-border-level-1-color);
}
.color-primary {
background: var(--td-brand-color);
}
.color-success {
background: var(--td-success-color);
}
.color-warning {
background: var(--td-warning-color);
}
.color-error {
background: var(--td-error-color);
}
.color-label {
font-size: var(--td-font-size-body-small);
color: var(--td-text-color-secondary);
}
</style>

View File

@@ -228,14 +228,14 @@ onUnmounted(() => {
margin-bottom: 2rem;
h2 {
color: #111827;
color: var(--td-text-color-primary);
margin-bottom: 0.5rem;
font-size: 1.875rem;
font-weight: 600;
}
p {
color: #6b7280;
color: var(--find-text-secondary);
font-size: 1rem;
}
}
@@ -244,7 +244,7 @@ onUnmounted(() => {
margin-bottom: 3rem;
.section-title {
color: #111827;
color: var(--td-text-color-primary);
font-size: 1.25rem;
font-weight: 600;
margin-bottom: 1.5rem;
@@ -293,12 +293,10 @@ onUnmounted(() => {
.playlist-card {
// 卡片样式
background: #fff;
background: var(--find-card-bg);
border-radius: 1rem;
overflow: hidden;
box-shadow:
0 2px 8px rgba(0, 0, 0, 0.06),
0 1px 4px rgba(0, 0, 0, 0.04);
box-shadow: var(--find-card-shadow);
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
cursor: pointer;
position: relative;
@@ -306,9 +304,7 @@ onUnmounted(() => {
// 现代化悬浮效果
&:hover {
transform: translateY(-4px) scale(1.02);
box-shadow:
0 8px 25px rgba(0, 0, 0, 0.12),
0 4px 10px rgba(0, 0, 0, 0.08);
box-shadow: var(--find-card-shadow-hover);
.playlist-cover::after {
opacity: 1;
@@ -317,7 +313,7 @@ onUnmounted(() => {
.playlist-info {
backdrop-filter: blur(8px);
background-color: var(--hover-bg-color);
color: #111827;
color: var(--find-text-primary);
.playlist-title {
color: var(--hover-text-color);
}
@@ -377,7 +373,7 @@ onUnmounted(() => {
.playlist-info {
padding: 1.25rem 1rem;
position: relative;
background: rgba(255, 255, 255, 0.95);
background: var(--find-card-info-bg);
backdrop-filter: blur(4px);
transition: all 0.3s ease;
@@ -385,7 +381,7 @@ onUnmounted(() => {
.playlist-title {
font-size: 1rem;
font-weight: 600;
color: #1f2937;
color: var(--find-text-primary);
margin-bottom: 0.5rem;
line-height: 1.4;
display: -webkit-box;
@@ -398,7 +394,7 @@ onUnmounted(() => {
.playlist-desc {
font-size: 0.875rem;
color: #6b7280;
color: var(--find-text-secondary);
margin-bottom: 0.75rem;
line-height: 1.5;
display: -webkit-box;
@@ -416,13 +412,13 @@ onUnmounted(() => {
gap: 0.5rem;
margin-top: auto; // 推到底部
padding-top: 0.5rem;
border-top: 1px solid rgba(229, 231, 235, 0.5);
border-top: 1px solid var(--find-meta-border);
transition: color 0.3s ease;
}
.play-count {
font-size: 0.75rem;
color: #9ca3af;
color: var(--find-text-muted);
display: flex;
align-items: center;
gap: 0.25rem;
@@ -437,9 +433,9 @@ onUnmounted(() => {
.song-count {
font-size: 0.75rem;
color: #9ca3af;
color: var(--find-text-muted);
font-weight: 500;
background: rgba(156, 163, 175, 0.1);
background: var(--find-song-count-bg);
padding: 0.125rem 0.5rem;
border-radius: 0.375rem;
transition: color 0.3s ease;
@@ -447,7 +443,7 @@ onUnmounted(() => {
.playlist-author {
font-size: 0.75rem;
color: #6b7280;
color: var(--find-text-secondary);
font-style: italic;
margin-top: 0.25rem;
opacity: 0.8;
@@ -457,17 +453,17 @@ onUnmounted(() => {
}
.song-list {
background: #fff;
background: var(--find-song-bg);
border-radius: 0.75rem;
overflow: hidden;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
box-shadow: var(--td-shadow-1);
}
.song-item {
display: flex;
align-items: center;
padding: 1rem 1.5rem;
border-bottom: 1px solid #f3f4f6;
border-bottom: 1px solid var(--find-border-color);
cursor: pointer;
transition: background-color 0.2s ease;
@@ -476,14 +472,14 @@ onUnmounted(() => {
}
&:hover {
background-color: #f9fafb;
background-color: var(--find-song-hover-bg);
}
.song-index {
width: 2rem;
text-align: center;
font-size: 0.875rem;
color: #6b7280;
color: var(--find-text-secondary);
font-weight: 500;
}
@@ -494,19 +490,19 @@ onUnmounted(() => {
.song-title {
font-size: 0.875rem;
font-weight: 500;
color: #111827;
color: var(--find-text-primary);
margin-bottom: 0.25rem;
}
.song-artist {
font-size: 0.75rem;
color: #6b7280;
color: var(--find-text-secondary);
}
}
.song-duration {
font-size: 0.75rem;
color: #6b7280;
color: var(--find-text-secondary);
margin-right: 1rem;
}

View File

@@ -543,8 +543,7 @@ onUnmounted(() => {
<style lang="scss" scoped>
.list-container {
box-sizing: border-box;
// background: #fafafa;
box-sizing: border-box;
// background: var(--list-bg-primary);
width: 100%;
padding: 20px;
height: 100%;
@@ -557,10 +556,10 @@ onUnmounted(() => {
}
.scrollable-content {
background: #fff;
background: var(--list-content-bg);
border-radius: 8px;
overflow: hidden;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
box-shadow: var(--list-content-shadow);
flex: 1;
min-height: 0;
display: flex;
@@ -580,8 +579,8 @@ onUnmounted(() => {
.loading-spinner {
width: 40px;
height: 40px;
border: 4px solid #f3f3f3;
border-top: 4px solid #507daf;
border: 4px solid var(--list-loading-border);
border-top: 4px solid var(--list-loading-spinner);
border-radius: 50%;
animation: spin 1s linear infinite;
margin: 0 auto 16px;
@@ -589,7 +588,7 @@ onUnmounted(() => {
p {
font-size: 14px;
color: #666;
color: var(--list-loading-text);
margin: 0;
}
}
@@ -609,9 +608,9 @@ onUnmounted(() => {
align-items: center;
gap: 1.5rem;
padding: 1.5rem;
background: #fff;
background: var(--list-header-bg);
border-radius: 0.75rem;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
box-shadow: var(--list-header-shadow);
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
&.compact {
@@ -660,7 +659,7 @@ onUnmounted(() => {
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.7);
background: var(--list-cover-overlay);
display: flex;
flex-direction: column;
align-items: center;
@@ -690,7 +689,7 @@ onUnmounted(() => {
.playlist-title {
font-size: 1.5rem;
font-weight: 600;
color: #111827;
color: var(--list-title-color);
margin: 0 0 0.5rem 0;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
@@ -702,7 +701,7 @@ onUnmounted(() => {
.playlist-author {
font-size: 1rem;
color: #6b7280;
color: var(--list-author-color);
margin: 0 0 0.5rem 0;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
opacity: 1;
@@ -719,7 +718,7 @@ onUnmounted(() => {
.playlist-stats {
font-size: 0.875rem;
color: #9ca3af;
color: var(--list-stats-color);
margin: 0 0 1rem 0;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
opacity: 1;

View File

@@ -225,6 +225,8 @@ const createPlaylist = async () => {
description: '这是我创建的歌单'
}
await loadPlaylists()
// 触发歌单更新事件
window.dispatchEvent(new Event('playlist-updated'))
} else {
MessagePlugin.error(result.error || '创建歌单失败')
}
@@ -264,6 +266,8 @@ const savePlaylistEdit = async () => {
showEditPlaylistDialog.value = false
currentEditingPlaylist.value = null
await loadPlaylists()
// 触发歌单更新事件
window.dispatchEvent(new Event('playlist-updated'))
} else {
MessagePlugin.error(result.error || '更新歌单信息失败')
}
@@ -297,8 +301,8 @@ const deletePlaylist = async (playlist: SongList) => {
if (result.success) {
MessagePlugin.success('歌单删除成功')
await loadPlaylists()
// 歌单删除成功,无需额外处理
// 触发歌单更新事件
window.dispatchEvent(new Event('playlist-updated'))
} else {
MessagePlugin.error(result.error || '删除歌单失败')
}
@@ -1428,6 +1432,8 @@ onMounted(() => {
margin: 0 auto;
width: 100%;
position: relative;
// background: var(--local-bg);
color: var(--local-text-primary);
}
// 编辑歌单对话框样式
@@ -1443,7 +1449,7 @@ onMounted(() => {
display: block;
margin-bottom: 0.5rem;
font-weight: 500;
color: #374151;
color: var(--local-text-primary);
font-size: 14px;
}
}
@@ -1451,20 +1457,20 @@ onMounted(() => {
.form-tips {
margin-top: 1rem;
padding: 0.75rem;
background: #f3f4f6;
background: var(--local-tips-bg);
border-radius: 6px;
border-left: 3px solid #10b981;
border-left: 3px solid var(--td-success-color);
.tip-note {
margin: 0;
color: #6b7280;
color: var(--local-text-secondary);
font-size: 13px;
display: flex;
align-items: center;
gap: 0.5rem;
.iconfont {
color: #10b981;
color: var(--td-success-color);
font-size: 14px;
}
}
@@ -1500,17 +1506,17 @@ onMounted(() => {
margin-bottom: 2rem;
position: sticky;
top: 0;
background: #fff;
background: var(--td-bg-color-container);
z-index: 10;
padding: 0.5rem 0;
margin: -0.5rem 0 1.5rem 0;
border-bottom: 1px solid #f0f0f0;
border-bottom: 1px solid var(--local-border);
.form-label {
display: block;
margin-bottom: 1rem;
font-weight: 600;
color: #374151;
color: var(--local-text-primary);
font-size: 15px;
}
@@ -1550,11 +1556,11 @@ onMounted(() => {
.import-content {
.import-description {
margin-bottom: 1.25rem;
color: #64748b;
color: var(--local-text-secondary);
font-size: 14px;
line-height: 1.6;
padding: 1rem;
background: linear-gradient(135deg, #f8fafc, #f1f5f9);
background: var(--local-tips-bg);
border-radius: 8px;
border-left: 4px solid var(--td-brand-color-4);
}
@@ -1564,10 +1570,10 @@ onMounted(() => {
}
.import-tips {
background: linear-gradient(135deg, #f8fafc, #f1f5f9);
background: var(--local-tips-bg);
border-radius: 12px;
padding: 1.25rem;
border: 1px solid #e2e8f0;
border: 1px solid var(--local-border);
position: relative;
overflow: hidden;
@@ -1584,7 +1590,7 @@ onMounted(() => {
.tip-title {
margin: 0 0 0.75rem 0;
font-weight: 600;
color: #334155;
color: var(--local-text-primary);
font-size: 15px;
display: flex;
align-items: center;
@@ -1601,17 +1607,17 @@ onMounted(() => {
padding-left: 1.5rem;
li {
color: #64748b;
color: var(--local-text-secondary);
font-size: 13px;
margin-bottom: 0.5rem;
font-family: 'SF Mono', 'Monaco', 'Consolas', monospace;
padding: 0.25rem 0.5rem;
background: rgba(255, 255, 255, 0.6);
background: var(--local-code-bg);
border-radius: 4px;
transition: all 0.2s ease;
&:hover {
background: rgba(255, 255, 255, 0.9);
background: var(--local-code-hover-bg);
transform: translateX(4px);
}
}
@@ -1619,14 +1625,14 @@ onMounted(() => {
.tip-note {
margin: 0;
color: #94a3b8;
color: var(--local-text-tertiary);
font-size: 12px;
font-style: italic;
display: flex;
align-items: center;
gap: 0.5rem;
padding: 0.5rem;
background: rgba(255, 255, 255, 0.5);
background: var(--local-note-bg);
border-radius: 6px;
&::before {
@@ -1668,7 +1674,7 @@ onMounted(() => {
.header-left {
h2 {
color: #111827;
color: var(--local-text-primary);
margin-bottom: 0.5rem;
font-size: 1.875rem;
font-weight: 600;
@@ -1678,13 +1684,13 @@ onMounted(() => {
display: flex;
gap: 1rem;
font-size: 0.875rem;
color: #6b7280;
color: var(--local-text-secondary);
span {
&:not(:last-child)::after {
content: '•';
margin-left: 1rem;
color: #d1d5db;
color: var(--local-border);
}
}
}
@@ -1709,7 +1715,7 @@ onMounted(() => {
h3 {
font-size: 1.25rem;
font-weight: 600;
color: #111827;
color: var(--local-text-primary);
}
.section-actions {
@@ -1733,17 +1739,17 @@ onMounted(() => {
}
.playlist-card {
background: #fff;
background: var(--local-card-bg);
border-radius: 0.75rem;
overflow: hidden;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
box-shadow: var(--local-card-shadow);
transition:
transform 0.2s ease,
box-shadow 0.2s ease;
&:hover {
transform: translateY(-4px);
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.15);
box-shadow: var(--local-card-shadow-hover);
.playlist-cover .cover-overlay {
opacity: 1;
@@ -1788,7 +1794,7 @@ onMounted(() => {
.playlist-name {
font-weight: 600;
color: #111827;
color: var(--local-text-primary);
margin-bottom: 0.5rem;
white-space: nowrap;
overflow: hidden;
@@ -1797,13 +1803,13 @@ onMounted(() => {
font-size: 1rem;
&:hover {
color: #4f46e5;
color: var(--td-brand-color);
}
}
.playlist-description {
font-size: 0.875rem;
color: #6b7280;
color: var(--local-text-secondary);
margin-bottom: 0.5rem;
white-space: nowrap;
overflow: hidden;
@@ -1815,13 +1821,13 @@ onMounted(() => {
flex-direction: column;
gap: 0.25rem;
font-size: 0.75rem;
color: #9ca3af;
color: var(--local-text-tertiary);
span {
&:first-child {
text-transform: uppercase;
font-weight: 500;
color: #4f46e5;
color: var(--td-brand-color);
}
}
}
@@ -1844,19 +1850,19 @@ onMounted(() => {
.iconfont {
font-size: 4rem;
color: #d1d5db;
color: var(--local-text-tertiary);
}
}
h4 {
color: #111827;
color: var(--local-text-primary);
margin-bottom: 0.5rem;
font-size: 1.125rem;
font-weight: 600;
}
p {
color: #6b7280;
color: var(--local-text-secondary);
margin-bottom: 2rem;
}
}
@@ -1876,10 +1882,10 @@ onMounted(() => {
.music-list {
width: 100%;
background: #fff;
background: var(--local-card-bg);
border-radius: 0.75rem;
overflow: hidden;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
box-shadow: var(--local-card-shadow);
}
.list-header {
@@ -1888,13 +1894,13 @@ onMounted(() => {
grid-template-columns: 0.5fr 2fr 1fr 2fr 1fr 1fr 1fr 1fr;
gap: 1rem;
padding: 1rem 1.5rem;
background: #f9fafb;
border-bottom: 1px solid #e5e7eb;
background: var(--local-header-bg);
border-bottom: 1px solid var(--local-border);
.header-item {
font-size: 0.75rem;
font-weight: 600;
color: #6b7280;
color: var(--local-text-secondary);
text-transform: uppercase;
letter-spacing: 0.05em;
}
@@ -1906,7 +1912,7 @@ onMounted(() => {
grid-template-columns: 0.5fr 2fr 1fr 2fr 1fr 1fr 1fr 1fr;
gap: 1rem;
padding: 1rem 1.5rem;
border-bottom: 1px solid #f3f4f6;
border-bottom: 1px solid var(--local-border);
cursor: pointer;
transition: background-color 0.2s ease;
@@ -1915,7 +1921,7 @@ onMounted(() => {
}
&:hover {
background-color: #f9fafb;
background-color: var(--local-hover-bg);
.actions {
opacity: 1;
@@ -1929,14 +1935,14 @@ onMounted(() => {
&.index {
justify-content: center;
color: #6b7280;
color: var(--local-text-secondary);
font-weight: 500;
}
&.title {
.song-title {
font-weight: 500;
color: #111827;
color: var(--local-text-primary);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
@@ -1945,7 +1951,7 @@ onMounted(() => {
&.artist,
&.album {
color: #6b7280;
color: var(--local-text-secondary);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
@@ -1953,7 +1959,7 @@ onMounted(() => {
&.duration,
&.size {
color: #6b7280;
color: var(--local-text-secondary);
font-variant-numeric: tabular-nums;
}
@@ -1963,8 +1969,8 @@ onMounted(() => {
gap: 0.125rem;
.format-badge {
background: #f3f4f6;
color: #6b7280;
background: var(--local-badge-bg);
color: var(--local-text-secondary);
padding: 0.125rem 0.375rem;
border-radius: 0.25rem;
font-size: 0.75rem;
@@ -1973,7 +1979,7 @@ onMounted(() => {
.bitrate {
font-size: 0.75rem;
color: #9ca3af;
color: var(--local-text-tertiary);
}
}
@@ -1995,19 +2001,19 @@ onMounted(() => {
.iconfont {
font-size: 4rem;
color: #d1d5db;
color: var(--local-text-tertiary);
}
}
h3 {
color: #111827;
color: var(--local-text-primary);
margin-bottom: 0.5rem;
font-size: 1.25rem;
font-weight: 600;
}
p {
color: #6b7280;
color: var(--local-text-secondary);
margin-bottom: 2rem;
}
}
@@ -2028,14 +2034,15 @@ onMounted(() => {
display: flex;
align-items: center;
padding: 1rem;
border: 1px solid #e5e7eb;
border: 1px solid var(--local-border);
border-radius: 0.5rem;
cursor: pointer;
transition: all 0.2s ease;
background: var(--local-card-bg);
&:hover {
border-color: var(--td-brand-color-4);
background-color: #f8fafc;
background-color: var(--local-hover-bg);
}
.option-icon {
@@ -2053,20 +2060,20 @@ onMounted(() => {
h4 {
font-size: 1rem;
font-weight: 600;
color: #111827;
color: var(--local-text-primary);
margin-bottom: 0.25rem;
}
p {
font-size: 0.875rem;
color: #6b7280;
color: var(--local-text-secondary);
margin: 0;
}
.coming-soon {
display: inline-block;
background: #fef3c7;
color: #d97706;
background: var(--local-warning-bg);
color: var(--local-warning-text);
padding: 0.125rem 0.5rem;
border-radius: 0.25rem;
font-size: 0.75rem;
@@ -2078,7 +2085,7 @@ onMounted(() => {
.option-arrow {
.iconfont {
font-size: 1rem;
color: #9ca3af;
color: var(--local-text-tertiary);
}
}
}

View File

@@ -206,9 +206,11 @@ const formatPlayTime = (timeStr: string): string => {
<style lang="scss" scoped>
.recent-container {
// background: var(--recent-bg);
padding: 2rem;
max-width: 1200px;
margin: 0 auto;
min-height: 100vh;
}
.page-header {
@@ -219,14 +221,14 @@ const formatPlayTime = (timeStr: string): string => {
.header-left {
h2 {
color: #111827;
color: var(--recent-title-color);
margin-bottom: 0.5rem;
font-size: 1.875rem;
font-weight: 600;
}
p {
color: #6b7280;
color: var(--recent-subtitle-color);
font-size: 1rem;
}
}
@@ -236,7 +238,7 @@ const formatPlayTime = (timeStr: string): string => {
margin-bottom: 3rem;
.section-title {
color: #111827;
color: var(--recent-section-title);
font-size: 1.25rem;
font-weight: 600;
margin-bottom: 1.5rem;
@@ -253,15 +255,15 @@ const formatPlayTime = (timeStr: string): string => {
display: flex;
align-items: center;
padding: 1rem;
background: #fff;
background: var(--recent-card-bg);
border-radius: 0.75rem;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
box-shadow: var(--recent-card-shadow);
cursor: pointer;
transition: all 0.3s ease;
&:hover {
transform: translateY(-1px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
box-shadow: var(--recent-card-shadow-hover);
.play-overlay {
opacity: 1;
@@ -308,13 +310,13 @@ const formatPlayTime = (timeStr: string): string => {
.playlist-title {
font-size: 1rem;
font-weight: 600;
color: #111827;
color: var(--recent-playlist-title);
margin-bottom: 0.25rem;
}
.playlist-desc {
font-size: 0.875rem;
color: #6b7280;
color: var(--recent-playlist-desc);
margin-bottom: 0.5rem;
}
@@ -322,7 +324,7 @@ const formatPlayTime = (timeStr: string): string => {
display: flex;
gap: 1rem;
font-size: 0.75rem;
color: #9ca3af;
color: var(--recent-playlist-meta);
span {
&:not(:last-child)::after {
@@ -336,17 +338,17 @@ const formatPlayTime = (timeStr: string): string => {
}
.song-list {
background: #fff;
background: var(--recent-card-bg);
border-radius: 0.75rem;
overflow: hidden;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
box-shadow: var(--recent-card-shadow);
}
.song-item {
display: flex;
align-items: center;
padding: 1rem 1.5rem;
border-bottom: 1px solid #f3f4f6;
border-bottom: 1px solid var(--recent-song-item-border);
cursor: pointer;
transition: background-color 0.2s ease;
@@ -355,7 +357,7 @@ const formatPlayTime = (timeStr: string): string => {
}
&:hover {
background-color: #f9fafb;
background-color: var(--recent-song-item-hover);
.song-actions {
opacity: 1;
@@ -366,7 +368,7 @@ const formatPlayTime = (timeStr: string): string => {
width: 2rem;
text-align: center;
font-size: 0.875rem;
color: #6b7280;
color: var(--recent-song-index);
font-weight: 500;
}
@@ -377,13 +379,13 @@ const formatPlayTime = (timeStr: string): string => {
.song-title {
font-size: 0.875rem;
font-weight: 500;
color: #111827;
color: var(--recent-song-title);
margin-bottom: 0.25rem;
}
.song-artist {
font-size: 0.75rem;
color: #6b7280;
color: var(--recent-song-artist);
}
}
@@ -393,19 +395,19 @@ const formatPlayTime = (timeStr: string): string => {
.play-count {
font-size: 0.75rem;
color: #6b7280;
color: var(--recent-song-stats);
margin-bottom: 0.125rem;
}
.play-time {
font-size: 0.75rem;
color: #9ca3af;
color: var(--recent-playlist-meta);
}
}
.song-duration {
font-size: 0.75rem;
color: #6b7280;
color: var(--recent-song-duration);
margin-right: 1rem;
font-variant-numeric: tabular-nums;
}
@@ -427,19 +429,19 @@ const formatPlayTime = (timeStr: string): string => {
.iconfont {
font-size: 4rem;
color: #d1d5db;
color: var(--recent-empty-icon);
}
}
h3 {
color: #111827;
color: var(--recent-empty-title);
margin-bottom: 0.5rem;
font-size: 1.25rem;
font-weight: 600;
}
p {
color: #6b7280;
color: var(--recent-empty-text);
}
}
</style>

View File

@@ -218,6 +218,7 @@ const handleScroll = (event: Event) => {
<style lang="scss" scoped>
.search-container {
box-sizing: border-box;
// background: var(--search-bg);
width: 100%;
padding: 20px;
height: 100%;
@@ -231,25 +232,25 @@ const handleScroll = (event: Event) => {
.search-title {
font-size: 24px;
font-weight: normal;
color: #333;
color: var(--search-title-color);
margin: 0 0 8px 0;
.keyword {
color: #507daf;
color: var(--search-keyword-color);
}
}
.result-info {
font-size: 12px;
color: #999;
color: var(--search-info-color);
}
}
.song-list-wrapper {
background: #fff;
background: var(--search-content-bg);
border-radius: 8px;
overflow: hidden;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
box-shadow: var(--search-content-shadow);
flex: 1;
min-height: 0;
display: flex;
@@ -273,14 +274,14 @@ const handleScroll = (event: Event) => {
h3 {
font-size: 16px;
color: #333;
color: var(--search-empty-title);
margin: 0 0 8px 0;
font-weight: normal;
}
p {
font-size: 12px;
color: #999;
color: var(--search-empty-text);
margin: 0;
}
}
@@ -291,8 +292,8 @@ const handleScroll = (event: Event) => {
.loading-spinner {
width: 40px;
height: 40px;
border: 4px solid #f3f3f3;
border-top: 4px solid #507daf;
border: 4px solid var(--search-loading-border);
border-top: 4px solid var(--search-loading-spinner);
border-radius: 50%;
animation: spin 1s linear infinite;
margin: 0 auto 16px;
@@ -300,7 +301,7 @@ const handleScroll = (event: Event) => {
p {
font-size: 14px;
color: #666;
color: var(--search-loading-text);
margin: 0;
}
}

View File

@@ -890,22 +890,22 @@ const getTagOptionsStatus = () => {
height: 100vh;
display: flex;
flex-direction: column;
background: #f8fafc;
background: var(--settings-main-bg);
}
.header {
-webkit-app-region: drag;
display: flex;
align-items: center;
background: #ffffff;
background: var(--settings-header-bg);
padding: 1.5rem;
// border-bottom: 1px solid #e2e8f0;
// box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
// border-bottom: 1px solid var(--settings-sidebar-border);
// box-shadow: 0 1px 3px var(--settings-group-shadow);
z-index: 1000;
}
.settings-layout {
margin: 0px 6px;
// margin: 0px 6px;
display: flex;
flex: 1;
@@ -915,22 +915,22 @@ const getTagOptionsStatus = () => {
// 左侧导航栏
.sidebar {
width: 280px;
background: #ffffff;
// border-right: 1px solid #e2e8f0;
background: var(--settings-sidebar-bg);
// border-right: 1px solid var(--settings-sidebar-border);
padding-right: 5px;
display: flex;
flex-direction: column;
overflow-y: auto;
padding-left: 5px;
.sidebar-header {
// padding: 1.5rem;
border-bottom: 1px solid #e2e8f0;
border-bottom: 1px solid var(--settings-sidebar-border);
h3 {
margin: 0;
font-size: 1.125rem;
font-weight: 600;
color: #1e293b;
color: var(--settings-text-primary);
}
}
@@ -950,19 +950,19 @@ const getTagOptionsStatus = () => {
border-left: 3px solid transparent;
&:hover {
background: #f1f5f9;
background: var(--settings-nav-hover-bg);
}
&.active {
background: var(--td-brand-color-1);
border-left-color: var(--td-brand-color-5);
background: var(--settings-nav-active-bg);
border-left-color: var(--settings-nav-active-border);
.nav-icon {
color: var(--td-brand-color-5);
color: var(--settings-nav-icon-active);
}
.nav-label {
color: var(--td-brand-color-6);
color: var(--settings-nav-label-active);
font-weight: 600;
}
}
@@ -970,7 +970,7 @@ const getTagOptionsStatus = () => {
.nav-icon {
width: 20px;
height: 20px;
color: #64748b;
color: var(--settings-nav-icon-color);
display: flex;
justify-content: center;
align-items: center;
@@ -990,14 +990,14 @@ const getTagOptionsStatus = () => {
.nav-label {
font-size: 0.875rem;
font-weight: 500;
color: #334155;
color: var(--settings-nav-label-color);
margin-bottom: 0.125rem;
transition: color 0.2s ease;
}
.nav-description {
font-size: 0.75rem;
color: #64748b;
color: var(--settings-nav-desc-color);
line-height: 1.3;
}
}
@@ -1014,19 +1014,19 @@ const getTagOptionsStatus = () => {
.panel-header {
padding: 2rem 2rem 1rem;
background: #ffffff;
border-bottom: 1px solid #e2e8f0;
background: var(--settings-header-bg);
border-bottom: 1px solid var(--settings-sidebar-border);
h2 {
margin: 0 0 0.5rem;
font-size: 1.5rem;
font-weight: 700;
color: #1e293b;
color: var(--settings-text-primary);
}
p {
margin: 0;
color: #64748b;
color: var(--settings-text-secondary);
font-size: 0.875rem;
}
}
@@ -1035,30 +1035,30 @@ const getTagOptionsStatus = () => {
flex: 1;
overflow-y: auto;
// padding: 2rem;
background: #f8fafc;
background: var(--settings-main-bg);
}
}
// 设置区域
.settings-section {
.setting-group {
background: #ffffff;
background: var(--settings-group-bg);
border-radius: 0.75rem;
padding: 1.5rem;
margin-bottom: 1.5rem;
border: 1px solid #e2e8f0;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
border: 1px solid var(--settings-group-border);
box-shadow: 0 1px 3px var(--settings-group-shadow);
h3 {
margin: 0 0 0.5rem;
font-size: 1.125rem;
font-weight: 600;
color: #1e293b;
color: var(--settings-text-primary);
}
> p {
margin: 0 0 1.5rem;
color: #64748b;
color: var(--settings-text-secondary);
font-size: 0.875rem;
}
}
@@ -1078,16 +1078,16 @@ const getTagOptionsStatus = () => {
gap: 1rem;
.preview-item {
background: #f8fafc;
background: var(--settings-preview-bg);
padding: 1rem;
border-radius: 0.5rem;
border: 1px solid #e2e8f0;
border: 1px solid var(--settings-preview-border);
h4 {
margin: 0 0 0.75rem;
font-size: 0.875rem;
font-weight: 600;
color: #374151;
color: var(--settings-text-primary);
}
}
}
@@ -1097,13 +1097,13 @@ const getTagOptionsStatus = () => {
align-items: center;
justify-content: space-between;
padding: 0.75rem 1rem;
background: #f6f6f6;
background: var(--settings-mock-titlebar-bg);
border-radius: 0.375rem;
border: 1px solid #d1d5db;
border: 1px solid var(--settings-mock-titlebar-border);
.mock-title {
font-weight: 500;
color: #374151;
color: var(--settings-text-primary);
font-size: 0.875rem;
}
}
@@ -1119,9 +1119,9 @@ const getTagOptionsStatus = () => {
align-items: flex-start;
gap: 0.75rem;
padding: 1rem;
background: #f8fafc;
background: var(--settings-feature-bg);
border-radius: 0.5rem;
border: 1px solid #e2e8f0;
border: 1px solid var(--settings-feature-border);
.iconfont {
font-size: 1.125rem;
@@ -1134,13 +1134,13 @@ const getTagOptionsStatus = () => {
strong {
display: block;
color: #1e293b;
color: var(--settings-text-primary);
margin-bottom: 0.25rem;
font-weight: 600;
}
p {
color: #64748b;
color: var(--settings-text-secondary);
font-size: 0.875rem;
margin: 0;
line-height: 1.4;
@@ -1157,7 +1157,7 @@ const getTagOptionsStatus = () => {
label {
display: block;
font-weight: 600;
color: #1e293b;
color: var(--settings-text-primary);
margin-bottom: 0.5rem;
font-size: 0.875rem;
}
@@ -1203,19 +1203,19 @@ const getTagOptionsStatus = () => {
.status-text {
font-size: 0.875rem;
color: #64748b;
color: var(--settings-text-secondary);
}
}
}
.api-key-tips {
background: #f8fafc;
background: var(--settings-api-tips-bg);
padding: 1rem;
border-radius: 0.5rem;
border: 1px solid #e2e8f0;
border: 1px solid var(--settings-api-tips-border);
h4 {
color: #1e293b;
color: var(--settings-text-primary);
margin: 0 0 0.75rem 0;
font-size: 0.875rem;
font-weight: 600;
@@ -1226,7 +1226,7 @@ const getTagOptionsStatus = () => {
padding-left: 1.25rem;
li {
color: #64748b;
color: var(--settings-text-secondary);
font-size: 0.875rem;
margin-bottom: 0.5rem;
@@ -1285,32 +1285,32 @@ const getTagOptionsStatus = () => {
align-items: center;
gap: 1rem;
padding: 1rem;
background: #ffffff;
border: 2px solid #e2e8f0;
background: var(--settings-source-card-bg);
border: 2px solid var(--settings-source-card-border);
border-radius: 0.75rem;
cursor: pointer;
transition: all 0.2s ease;
&:hover {
border-color: var(--td-brand-color-3);
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
border-color: var(--settings-source-card-hover-border);
box-shadow: 0 4px 6px -1px var(--settings-group-shadow);
}
&.active {
border-color: var(--td-brand-color-5);
background: var(--td-brand-color-1);
border-color: var(--settings-source-card-active-border);
background: var(--settings-source-card-active-bg);
box-shadow: 0 0 0 3px var(--td-brand-color-2);
}
.source-icon {
width: 2.5rem;
height: 2.5rem;
background: #f1f5f9;
background: var(--settings-source-icon-bg);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
color: #64748b;
color: var(--settings-text-secondary);
}
.source-info {
@@ -1319,13 +1319,13 @@ const getTagOptionsStatus = () => {
.source-name {
font-weight: 600;
font-size: 0.875rem;
color: #1e293b;
color: var(--settings-text-primary);
margin-bottom: 0.125rem;
}
.source-type {
font-size: 0.75rem;
color: #64748b;
color: var(--settings-text-secondary);
}
}
@@ -1336,10 +1336,10 @@ const getTagOptionsStatus = () => {
}
.quality-slider-container {
background: #f8fafc;
background: var(--settings-quality-container-bg);
padding: 1.5rem;
border-radius: 0.75rem;
border: 1px solid #e2e8f0;
border: 1px solid var(--settings-quality-container-border);
.quality-slider {
margin-bottom: 1rem;
@@ -1356,12 +1356,12 @@ const getTagOptionsStatus = () => {
&:first-child {
font-size: 1rem;
font-weight: 600;
color: #1e293b;
color: var(--settings-text-primary);
}
&.quality-hint {
font-size: 0.875rem;
color: #64748b;
color: var(--settings-text-secondary);
}
}
}
@@ -1376,19 +1376,19 @@ const getTagOptionsStatus = () => {
justify-content: space-between;
align-items: center;
padding: 1rem;
background: #f8fafc;
background: var(--settings-status-item-bg);
border-radius: 0.5rem;
border: 1px solid #e2e8f0;
border: 1px solid var(--settings-status-item-border);
.status-label {
font-weight: 500;
color: #64748b;
color: var(--settings-text-secondary);
font-size: 0.875rem;
}
.status-value {
font-weight: 600;
color: #1e293b;
color: var(--settings-text-primary);
font-size: 0.875rem;
}
}
@@ -1401,9 +1401,9 @@ const getTagOptionsStatus = () => {
align-items: center;
gap: 1.5rem;
padding: 2rem;
background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);
background: var(--settings-plugin-prompt-bg);
border-radius: 1rem;
border: 2px dashed #cbd5e1;
border: 2px dashed var(--settings-plugin-prompt-border);
.prompt-icon {
width: 3rem;
@@ -1422,14 +1422,14 @@ const getTagOptionsStatus = () => {
flex: 1;
h4 {
color: #1e293b;
color: var(--settings-text-primary);
margin: 0 0 0.5rem 0;
font-size: 1.125rem;
font-weight: 600;
}
p {
color: #64748b;
color: var(--settings-text-secondary);
margin: 0 0 1.5rem 0;
line-height: 1.5;
}
@@ -1669,7 +1669,7 @@ const getTagOptionsStatus = () => {
margin: 0;
font-size: 1.5rem;
font-weight: 700;
color: #1e293b;
color: var(--settings-text-primary);
}
.app-version {
@@ -1692,7 +1692,7 @@ const getTagOptionsStatus = () => {
.app-description {
margin: 0;
color: #64748b;
color: var(--settings-text-secondary);
line-height: 1.5;
}
}
@@ -1708,19 +1708,19 @@ const getTagOptionsStatus = () => {
justify-content: space-between;
align-items: center;
padding: 0.75rem;
background: #f8fafc;
background: var(--settings-tech-item-bg);
border-radius: 0.5rem;
border: 1px solid #e2e8f0;
border: 1px solid var(--settings-tech-item-border);
transition: 0.3s;
.tech-name {
font-weight: 600;
color: #1e293b;
color: var(--settings-text-primary);
}
.tech-desc {
font-size: 0.875rem;
color: #64748b;
color: var(--settings-text-secondary);
}
&.link:hover {
@@ -1745,13 +1745,13 @@ const getTagOptionsStatus = () => {
align-items: center;
gap: 1rem;
padding: 1rem;
background: #f8fafc;
background: var(--settings-developer-item-bg);
border-radius: 0.75rem;
border: 1px solid #e2e8f0;
border: 1px solid var(--settings-developer-item-border);
transition: all 0.2s ease;
&:hover {
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
box-shadow: 0 4px 6px -1px var(--settings-group-shadow);
}
.developer-avatar {
@@ -1775,13 +1775,13 @@ const getTagOptionsStatus = () => {
margin: 0 0 0.25rem;
font-size: 1rem;
font-weight: 600;
color: #1e293b;
color: var(--settings-text-primary);
}
p {
margin: 0;
font-size: 0.875rem;
color: #64748b;
color: var(--settings-text-secondary);
}
}
}
@@ -1790,7 +1790,7 @@ const getTagOptionsStatus = () => {
.license-info {
p {
margin: 0 0 1rem;
color: #64748b;
color: var(--settings-text-secondary);
line-height: 1.5;
}
@@ -1812,13 +1812,13 @@ const getTagOptionsStatus = () => {
margin: 0 0 0.5rem;
font-size: 0.875rem;
font-weight: 600;
color: #1e293b;
color: var(--settings-text-primary);
}
p {
margin: 0;
font-size: 0.875rem;
color: #64748b;
color: var(--settings-text-secondary);
line-height: 1.5;
}
}
@@ -1858,24 +1858,24 @@ const getTagOptionsStatus = () => {
.tag-option {
padding: 1rem;
background: #f8fafc;
background: var(--settings-tag-option-bg);
border-radius: 0.5rem;
border: 1px solid #e2e8f0;
border: 1px solid var(--settings-tag-option-border);
.option-desc {
margin: 0.5rem 0 0 1.5rem;
font-size: 0.875rem;
color: #64748b;
color: var(--settings-text-secondary);
line-height: 1.4;
}
}
}
.tag-options-status {
background: #f8fafc;
background: var(--settings-tag-status-bg);
padding: 1rem;
border-radius: 0.5rem;
border: 1px solid #e2e8f0;
border: 1px solid var(--settings-tag-status-border);
.status-summary {
display: flex;
@@ -1884,13 +1884,13 @@ const getTagOptionsStatus = () => {
.status-label {
font-weight: 500;
color: #64748b;
color: var(--settings-text-secondary);
font-size: 0.875rem;
}
.status-value {
font-weight: 600;
color: #1e293b;
color: var(--settings-text-primary);
font-size: 0.875rem;
}
}

View File

@@ -59,7 +59,7 @@ onMounted(async () => {
.welcome-container {
width: 100vw;
height: 100vh;
background: #ffffff;
background: var(--welcome-bg);
display: flex;
align-items: center;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', sans-serif;
@@ -131,7 +131,7 @@ onMounted(async () => {
.brand-subtitle {
font-size: 1.5rem;
color: #666666;
color: var(--welcome-subtitle-color);
margin: 1rem 0 5rem 0;
font-weight: 400;
}
@@ -144,7 +144,7 @@ onMounted(async () => {
.progress-bar {
width: 100%;
height: 4px;
background: #f0f0f0;
background: var(--welcome-progress-bg);
border-radius: 2px;
overflow: hidden;
margin-bottom: 1rem;
@@ -159,7 +159,7 @@ onMounted(async () => {
.loading-text {
font-size: 0.9rem;
color: #888888;
color: var(--welcome-loading-text);
margin: 0;
font-weight: 400;
}
@@ -173,11 +173,11 @@ onMounted(async () => {
.tag {
padding: 0.4rem 0.8rem;
background: #b8f1ce;
border: 1px solid #e9ecef;
background: var(--welcome-tag-bg);
border: 1px solid var(--welcome-tag-border);
border-radius: 20px;
font-size: 0.8rem;
color: #333333;
color: var(--welcome-tag-color);
transition: all 0.3s ease;
opacity: 0.5;
}
@@ -197,7 +197,7 @@ onMounted(async () => {
bottom: 2rem;
right: 2rem;
font-size: 0.8rem;
color: #9e9e9e;
color: var(--welcome-version-color);
font-weight: 300;
}
@@ -273,32 +273,5 @@ onMounted(async () => {
}
} */
/* 暗色主题适配 */
@media (prefers-color-scheme: dark) {
.welcome-container {
background: #1a1a1a;
}
.brand-subtitle {
color: #999999;
}
.loading-text {
color: #aaaaaa;
}
.progress-bar {
background: #333333;
}
.tag {
background: #2d2d2d;
border-color: #404040;
color: #cccccc;
}
.version-info {
color: #666666;
}
}
/* 暗色主题适配已通过 CSS 变量实现 */
</style>

View File

@@ -43,7 +43,7 @@ async function getAllReleases() {
// Filter and sort releases by version
const releases = data
.filter(release => !release.draft && !release.prerelease)
.filter((release) => !release.draft && !release.prerelease)
.sort((a, b) => compareVersions(b.tag_name, a.tag_name))
// Cache the data
@@ -99,15 +99,15 @@ async function downloadApp(platform) {
)
// Use proxy for download if it's a GitHub URL
const finalDownloadUrl = downloadUrl.includes('github.com') ?
`${GITHUB_PROXY}${downloadUrl}` : downloadUrl
const finalDownloadUrl = downloadUrl.includes('github.com')
? `${GITHUB_PROXY}${downloadUrl}`
: downloadUrl
// Start download
window.open(finalDownloadUrl, '_blank')
// Track download
trackDownload(platform, release.tag_name, asset ? asset.name : '')
} catch (error) {
console.error('Download error:', error)
showNotification(`下载失败: ${error.message}`, 'error')
@@ -126,8 +126,6 @@ async function downloadApp(platform) {
}
}
// Get latest release from GitHub API
async function getLatestRelease() {
// Check cache first
@@ -156,8 +154,6 @@ async function getLatestRelease() {
}
}
// Find appropriate download asset based on platform
function findDownloadAsset(assets, platform) {
if (!assets || !Array.isArray(assets)) {
@@ -632,12 +628,10 @@ async function updateVersionInfo() {
}
}
// Find asset for platform (helper function)
function findAssetForPlatform(assets, platform) {
const userArch = detectArchitecture()
// Filter out unwanted files
const filteredAssets = assets.filter((asset) => {
const name = asset.name.toLowerCase()
@@ -919,22 +913,22 @@ function compareVersions(a, b) {
// Remove 'v' prefix if present
const versionA = a.replace(/^v/, '')
const versionB = b.replace(/^v/, '')
// Split version numbers into parts
const partsA = versionA.split('.').map(num => parseInt(num, 10))
const partsB = versionB.split('.').map(num => parseInt(num, 10))
const partsA = versionA.split('.').map((num) => parseInt(num, 10))
const partsB = versionB.split('.').map((num) => parseInt(num, 10))
// Compare each part
const maxLength = Math.max(partsA.length, partsB.length)
for (let i = 0; i < maxLength; i++) {
const partA = partsA[i] || 0
const partB = partsB[i] || 0
if (partA > partB) return 1
if (partA < partB) return -1
}
return 0
}