Skip to content

Commit c7f7f4d

Browse files
committed
搞定深色模式
1 parent 7e3552f commit c7f7f4d

File tree

7 files changed

+120
-64
lines changed

7 files changed

+120
-64
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@ tiny-nav
33
cache/
44
dist/
55
/public/
6+
/data/

front/src/components/AppLayout.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<template>
2-
<div class="min-h-screen flex flex-col">
2+
<div class="min-h-screen flex flex-col bg-white dark:bg-gray-900 text-gray-800 dark:text-gray-100">
33
<!-- 主要内容 -->
44
<main class="flex-grow">
55
<slot></slot>

front/src/components/LinkCard.vue

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<div class="relative group">
33
<!-- 整个卡片作为可点击区域 -->
44
<a :href="link.url" target="_blank" rel="noopener noreferrer"
5-
class="block p-4 bg-white rounded-lg shadow-md hover:shadow-lg transition-all">
5+
class="block p-4 bg-white dark:bg-gray-800 text-gray-800 dark:text-gray-100 rounded-lg shadow-md hover:shadow-lg transition-all">
66
<div class="flex flex-col items-center">
77
<div class="mb-2 w-12 h-12">
88
<!-- SVG 代码 -->
@@ -13,8 +13,9 @@
1313
@error="onImageError" />
1414
</div>
1515

16-
<div class="w-full px-2"> <!-- 添加容器控制宽度 -->
17-
<span class="text-blue-500 text-center mt-2 text-sm block truncate" :title="link.name">
16+
<div class="w-full px-2">
17+
<span class="text-blue-500 dark:text-blue-400 text-center mt-2 text-sm block truncate"
18+
:title="link.name">
1819
{{ link.name }}
1920
</span>
2021
</div>
@@ -26,22 +27,22 @@
2627
class="absolute inset-x-0 top-1/2 -translate-y-1/2 flex justify-between px-2 opacity-50 duration-200">
2728
<!-- 修改按钮 -->
2829
<button @click.prevent="$emit('update', link.globalIndex)"
29-
class="w-8 h-8 flex items-center justify-center text-gray-400 hover:text-yellow-500 bg-white rounded-full shadow-md transition-all hover:scale-110"
30+
class="w-8 h-8 flex items-center justify-center text-gray-400 dark:text-gray-300 hover:text-yellow-500 dark:hover:text-yellow-400 bg-white dark:bg-gray-800 rounded-full shadow-md transition-all hover:scale-110"
3031
title="修改">
3132
<div class="i-mdi-pencil text-xl"></div>
3233
</button>
3334

3435
<!-- 拖动图标 -->
3536
<button
36-
class="w-8 h-8 flex items-center justify-center text-gray-400 hover:text-blue-500 rounded-full shadow-md transition-all hover:scale-110 drag-handle"
37+
class="w-8 h-8 flex items-center justify-center text-gray-400 dark:text-gray-300 hover:text-blue-500 dark:hover:text-blue-400 rounded-full shadow-md transition-all hover:scale-110 drag-handle"
3738
title="拖动">
3839
<div class="i-mdi-drag text-xl"></div>
3940
</button>
4041

4142

4243
<!-- 删除按钮 -->
4344
<button @click.prevent="$emit('delete', link.globalIndex)"
44-
class="w-8 h-8 flex items-center justify-center text-gray-400 hover:text-red-500 bg-white rounded-full shadow-md transition-all hover:scale-110"
45+
class="w-8 h-8 flex items-center justify-center text-gray-400 dark:text-gray-300 hover:text-red-500 dark:hover:text-red-400 bg-white dark:bg-gray-800 rounded-full shadow-md transition-all hover:scale-110"
4546
title="删除">
4647
<div class="i-mdi-delete text-xl"></div>
4748
</button>

front/src/components/LinkDialog.vue

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,39 @@
11
<template>
22
<div v-if="show" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center p-4">
3-
<div class="bg-white rounded-lg p-6 max-w-lg w-full">
3+
<div class="bg-white dark:bg-gray-800 text-gray-800 dark:text-gray-100 rounded-lg p-6 max-w-lg w-full">
44
<h3 class="text-lg font-medium mb-4">
55
{{ mode === 'add' ? '添加链接' : '编辑链接' }}
66
</h3>
77

88
<form @submit.prevent="handleSubmit" class="space-y-4">
99
<!-- 名称输入 -->
1010
<div>
11-
<label class="block text-sm font-medium text-gray-700 mb-1">
11+
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
1212
名称
1313
</label>
1414
<input v-model="formData.name" type="text" required
15-
class="w-full border border-gray-300 rounded-md px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500" />
15+
class="w-full border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-800 dark:text-gray-100 rounded-md px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500 dark:focus:ring-blue-400" />
1616
</div>
1717

1818
<!-- URL输入 -->
1919
<div>
20-
<label class="block text-sm font-medium text-gray-700 mb-1">
20+
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
2121
URL
2222
</label>
2323
<input v-model="formData.url" type="url" required
24-
class="w-full border border-gray-300 rounded-md px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500" />
24+
class="w-full border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-800 dark:text-gray-100 rounded-md px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500 dark:focus:ring-blue-400" />
2525
</div>
2626

2727
<!-- 图标相关输入 -->
2828
<div class="w-full max-w-full overflow-hidden">
29-
<label class="block text-sm font-medium text-gray-700 mb-1">
29+
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
3030
图标
3131
</label>
3232
<div class="flex space-x-2">
3333
<input v-model="formData.icon" type="text" placeholder="图标URL"
34-
class="flex-1 max-w-[calc(100%-3.5rem)] border border-gray-300 rounded-md px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500" />
34+
class="flex-1 max-w-[calc(100%-3.5rem)] border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-800 dark:text-gray-100 rounded-md px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500 dark:focus:ring-blue-400" />
3535
<button type="button" @click="fetchIcon" :disabled="isLoading"
36-
class="shrink-0 px-4 py-2 bg-gray-100 text-gray-700 rounded-md hover:bg-gray-200 focus:outline-none focus:ring-2 focus:ring-blue-500 disabled:opacity-50 disabled:cursor-not-allowed">
36+
class="shrink-0 px-4 py-2 bg-gray-100 dark:bg-gray-800 text-gray-700 dark:text-gray-300 rounded-md hover:bg-gray-200 dark:hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-blue-500 dark:focus:ring-blue-400 disabled:opacity-50 disabled:cursor-not-allowed">
3737
<div class="i-mdi-image-sync-outline"></div>
3838
</button>
3939
</div>
@@ -43,27 +43,29 @@
4343
<div>
4444
<Combobox v-model="formData.category">
4545
<div class="relative">
46-
<label class="block text-sm font-medium text-gray-700 mb-1">
46+
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
4747
分类
4848
</label>
4949
<div
50-
class="relative w-full cursor-default overflow-hidden rounded-md bg-white text-left border border-gray-300 focus:outline-none focus-visible:ring-2 focus-visible:ring-blue-500">
51-
<ComboboxInput class="w-full border-none px-3 py-2 text-gray-900 focus:outline-none"
50+
class="relative w-full cursor-default overflow-hidden rounded-md bg-white dark:bg-gray-700 text-left border border-gray-300 dark:border-gray-600 focus:outline-none focus-visible:ring-2 focus-visible:ring-blue-500 dark:focus-visible:ring-blue-400">
51+
<ComboboxInput
52+
class="w-full border-none px-3 py-2 text-gray-900 dark:text-gray-100 bg-white dark:bg-gray-700 focus:outline-none"
5253
:displayValue="(category: unknown) => category as string"
5354
@change="handleCategoryInput" />
5455
<ComboboxButton class="absolute inset-y-0 right-0 flex items-center pr-2">
55-
<div class="i-mdi-chevron-up-down h-5 w-5 text-gray-400" aria-hidden="true" />
56+
<div class="i-mdi-chevron-up-down h-5 w-5 text-gray-400 dark:text-gray-300"
57+
aria-hidden="true" />
5658
</ComboboxButton>
5759
</div>
5860
<TransitionRoot leave="transition ease-in duration-100" leaveFrom="opacity-100"
5961
leaveTo="opacity-0" @after-leave="query = ''">
6062
<ComboboxOptions
61-
class="absolute mt-1 max-h-60 w-full overflow-auto rounded-md bg-white py-1 text-base shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none sm:text-sm">
63+
class="absolute mt-1 max-h-60 w-full overflow-auto rounded-md bg-white dark:bg-gray-700 py-1 text-base shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none sm:text-sm">
6264
<ComboboxOption v-if="filteredCategories.length === 0 && query !== ''"
6365
:value="query" v-slot="{ active }">
6466
<li class="relative cursor-default select-none py-2 px-4" :class="{
6567
'bg-blue-500 text-white': active,
66-
'text-gray-900': !active
68+
'text-gray-900 dark:text-gray-100': !active
6769
}">
6870
创建新分类 "{{ query }}"
6971
</li>
@@ -73,7 +75,7 @@
7375
:value="category" as="template" v-slot="{ selected, active }">
7476
<li class="relative cursor-default select-none py-2 px-4" :class="{
7577
'bg-blue-500 text-white': active,
76-
'text-gray-900': !active
78+
'text-gray-900 dark:text-gray-100': !active
7779
}">
7880
<span class="block truncate"
7981
:class="{ 'font-medium': selected, 'font-normal': !selected }">
@@ -90,11 +92,11 @@
9092
<!-- 按钮组 -->
9193
<div class="flex justify-end space-x-4 mt-6">
9294
<button type="button" @click="$emit('update:show', false)"
93-
class="px-4 py-2 text-gray-600 hover:text-gray-800 focus:outline-none">
95+
class="px-4 py-2 text-gray-600 dark:text-gray-300 rounded-md hover:text-gray-800 dark:hover:text-gray-100 focus:outline-none">
9496
取消
9597
</button>
9698
<button type="submit"
97-
class="px-4 py-2 bg-blue-500 text-white rounded-md hover:bg-blue-600 focus:outline-none focus:ring-2 focus:ring-blue-500">
99+
class="px-4 py-2 bg-blue-500 text-white rounded-md hover:bg-blue-600 dark:hover:bg-blue-400 focus:outline-none focus:ring-2 focus:ring-blue-500 dark:focus:ring-blue-400">
98100
确定
99101
</button>
100102
</div>

front/src/components/NavHeader.vue

Lines changed: 56 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,80 @@
11
<template>
2-
<div class="bg-white shadow">
2+
<div class="bg-white dark:bg-gray-800 shadow dark:shadow-gray-900">
33
<div class="max-w-7xl mx-auto px-4 py-3 flex justify-between items-center">
4-
<!-- 左侧菜单按钮 -->
4+
<!-- 左侧图标和标题 -->
55
<div class="flex items-center gap-2">
6-
<button @click="toggleMobileMenu" class="md:hidden p-2 rounded-md hover:bg-gray-100">
7-
<div class="i-mdi-menu text-2xl text-gray-500"></div>
8-
</button>
96
<img src="/icon.svg" alt="网站图标" class="w-8 h-8" />
10-
<h1 class="text-xl font-bold text-gray-800">我的导航</h1>
7+
<h1 class="text-xl font-bold text-gray-800 dark:text-gray-100">我的导航</h1>
8+
</div>
9+
10+
<!-- 右侧菜单按钮 -->
11+
<div class="flex items-center gap-2">
12+
<button @click="toggleMobileMenu"
13+
class="md:hidden p-2 rounded-md bg-gray-100 dark:bg-gray-800 hover:bg-gray-200 dark:hover:bg-gray-700">
14+
<div :class="[isMobileMenuOpen ? 'i-mdi-close text-red-500' : 'i-mdi-menu text-gray-500 dark:text-gray-300']"
15+
class="text-2xl"></div>
16+
</button>
1117
</div>
1218

1319
<!-- PC端按钮组 -->
1420
<div class="hidden md:flex items-center gap-4">
15-
<button @click="toggleEditMode" class="flex items-center gap-2 px-3 py-2 rounded-md hover:bg-gray-100"
21+
<button @click="toggleEditMode"
22+
class="flex items-center gap-2 px-3 py-2 rounded-md bg-gray-100 dark:bg-gray-800 hover:bg-gray-200 dark:hover:bg-gray-700"
1623
:title="editMode ? '浏览模式' : '编辑模式'">
17-
<div :class="[editMode ? 'i-mdi-eye text-blue-500' : 'i-mdi-pencil text-gray-400']"></div>
24+
<div
25+
:class="[editMode ? 'i-mdi-eye text-blue-500 dark:text-blue-300' : 'i-mdi-pencil text-gray-400 dark:text-gray-300']">
26+
</div>
1827
</button>
19-
<button @click="$emit('add')" class="flex items-center gap-2 px-3 py-2 rounded-md hover:bg-gray-100"
28+
<button @click="$emit('add')"
29+
class="flex items-center gap-2 px-3 py-2 rounded-md bg-gray-100 dark:bg-gray-800 hover:bg-gray-200 dark:hover:bg-gray-700"
2030
title="添加网站">
21-
<div class="i-mdi-plus-circle text-gray-400"></div>
31+
<div class="i-mdi-plus-circle text-gray-400 dark:text-gray-300">
32+
</div>
2233
</button>
23-
<button @click="toggleTheme" class="flex items-center gap-2 px-3 py-2 rounded-md hover:bg-gray-100"
24-
:title="isDarkTheme ? '浅色模式' : '深色模式'">
25-
<div class="i-mdi-theme-light-dark text-gray-400"></div>
34+
<button @click="themeStore.toggleTheme"
35+
class="flex items-center gap-2 px-3 py-2 rounded-md bg-gray-100 dark:bg-gray-800 hover:bg-gray-200 dark:hover:bg-gray-700"
36+
:title="themeStore.isDarkTheme ? '浅色模式' : '深色模式'">
37+
<div
38+
:class="themeStore.isDarkTheme ? 'i-mdi-white-balance-sunny text-blue-500 dark:text-blue-300' : 'i-mdi-moon-waxing-crescent text-gray-400 dark:text-gray-300'">
39+
</div>
2640
</button>
41+
2742
<button v-if="!isNoAuthMode" @click="$emit('logout')"
28-
class="flex items-center gap-2 px-3 py-2 rounded-md hover:bg-gray-100" title="退出登录">
29-
<div class="i-mdi-logout text-gray-400"></div>
43+
class="flex items-center gap-2 px-3 py-2 rounded-md bg-gray-100 dark:bg-gray-800 hover:bg-gray-200 dark:hover:bg-gray-700"
44+
title="退出登录">
45+
<div class="i-mdi-logout text-gray-400 dark:text-gray-300">
46+
</div>
3047
</button>
3148
</div>
3249
</div>
3350

3451
<!-- 移动端菜单 -->
35-
<div v-if="isMobileMenuOpen" class="md:hidden bg-white shadow-lg">
52+
<div v-if="isMobileMenuOpen" class="md:hidden bg-white dark:bg-gray-800 shadow-lg dark:shadow-gray-900">
3653
<div class="flex flex-col gap-2 p-4">
37-
<button @click="toggleEditMode" class="flex items-center px-3 py-2 rounded-md hover:bg-gray-100">
38-
<div :class="[editMode ? 'i-mdi-eye text-blue-500' : 'i-mdi-pencil text-gray-400']"></div>
54+
<button @click="toggleEditMode"
55+
class="flex items-center gap-3 px-2 py-2 rounded-md bg-gray-100 dark:bg-gray-800 hover:bg-gray-200 dark:hover:bg-gray-700">
56+
<div
57+
:class="[editMode ? 'i-mdi-eye text-blue-500 dark:text-blue-300' : 'i-mdi-pencil text-gray-400 dark:text-gray-300']">
58+
</div>
3959
{{ editMode ? '浏览模式' : '编辑模式' }}
4060
</button>
41-
<button @click="$emit('add')" class="flex items-center px-3 py-2 rounded-md hover:bg-gray-100">
42-
<div class="i-mdi-plus-circle text-gray-400"></div>
61+
<button @click="$emit('add')"
62+
class="flex items-center gap-3 px-3 py-2 rounded-md bg-gray-100 dark:bg-gray-800 hover:bg-gray-200 dark:hover:bg-gray-700">
63+
<div class="i-mdi-plus-circle text-gray-400 dark:text-gray-300">
64+
</div>
4365
添加网站
4466
</button>
45-
<button @click="toggleTheme" class="flex items-center px-3 py-2 rounded-md hover:bg-gray-100">
46-
<div class="i-mdi-theme-light-dark text-gray-400"></div>
47-
切换到{{ isDarkTheme ? '浅色模式' : '深色模式' }}
67+
<button @click="themeStore.toggleTheme"
68+
class="flex items-center gap-3 px-3 py-2 rounded-md bg-gray-100 dark:bg-gray-800 hover:bg-gray-200 dark:hover:bg-gray-700">
69+
<div
70+
:class="themeStore.isDarkTheme ? 'i-mdi-white-balance-sunny text-blue-500 dark:text-blue-300' : 'i-mdi-moon-waxing-crescent text-gray-400 dark:text-gray-300'">
71+
</div>
72+
{{ themeStore.isDarkTheme ? '浅色模式' : '深色模式' }}
4873
</button>
4974
<button v-if="!isNoAuthMode" @click="$emit('logout')"
50-
class="flex items-center px-3 py-2 rounded-md hover:bg-gray-100">
51-
<div class="i-mdi-logout text-gray-400"></div>
75+
class="flex items-center gap-3 px-3 py-2 rounded-md bg-gray-100 dark:bg-gray-800 hover:bg-gray-200 dark:hover:bg-gray-700">
76+
<div class="i-mdi-logout text-gray-400 dark:text-gray-300">
77+
</div>
5278
退出登录
5379
</button>
5480
</div>
@@ -58,10 +84,13 @@
5884

5985
<script setup lang="ts">
6086
import { ref } from 'vue'
87+
import { useThemeStore } from '@/stores/themeStore'
88+
89+
const themeStore = useThemeStore()
6190
6291
const props = defineProps<{
6392
editMode: boolean
64-
isNoAuthMode: boolean // 新增属性,表示是否启用无用户密码模式
93+
isNoAuthMode: boolean
6594
}>()
6695
6796
const emit = defineEmits<{
@@ -74,16 +103,10 @@ const toggleEditMode = () => {
74103
emit('update:editMode', !props.editMode)
75104
}
76105
77-
// 主题切换
78-
const isDarkTheme = ref(false)
79-
const toggleTheme = () => {
80-
isDarkTheme.value = !isDarkTheme.value
81-
document.documentElement.classList.toggle('dark', isDarkTheme.value)
82-
}
83-
84106
// 移动端菜单状态
85107
const isMobileMenuOpen = ref(false)
86108
const toggleMobileMenu = () => {
87109
isMobileMenuOpen.value = !isMobileMenuOpen.value
88110
}
111+
89112
</script>

front/src/stores/themeStore.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { defineStore } from 'pinia'
2+
import { ref } from 'vue'
3+
4+
export const useThemeStore = defineStore('theme', () => {
5+
const isDarkTheme = ref(false)
6+
7+
const toggleTheme = () => {
8+
isDarkTheme.value = !isDarkTheme.value
9+
document.documentElement.classList.toggle('dark', isDarkTheme.value)
10+
}
11+
12+
return {
13+
isDarkTheme,
14+
toggleTheme,
15+
}
16+
})

0 commit comments

Comments
 (0)