update
This commit is contained in:
parent
0c0ea54d18
commit
280f6ec6e3
@ -5,7 +5,7 @@ services:
|
|||||||
build:
|
build:
|
||||||
context: .
|
context: .
|
||||||
dockerfile: Dockerfile
|
dockerfile: Dockerfile
|
||||||
image: tradus-web:1.3.9
|
image: tradus-web:1.3.10
|
||||||
container_name: tradus-web
|
container_name: tradus-web
|
||||||
ports:
|
ports:
|
||||||
- '6000:80'
|
- '6000:80'
|
||||||
|
|||||||
@ -17,35 +17,69 @@
|
|||||||
--vt-c-text-light-2: var(--vt-c-white-soft);
|
--vt-c-text-light-2: var(--vt-c-white-soft);
|
||||||
--vt-c-text-dark-1: var(--vt-c-white);
|
--vt-c-text-dark-1: var(--vt-c-white);
|
||||||
--vt-c-text-dark-2: var(--vt-c-white-soft);
|
--vt-c-text-dark-2: var(--vt-c-white-soft);
|
||||||
|
|
||||||
|
/* 通用颜色 */
|
||||||
|
--color-accent: #3355ff;
|
||||||
|
--color-accent-hover: #2244ee;
|
||||||
|
--color-accent-light: rgba(51, 85, 255, 0.08);
|
||||||
|
--color-accent-rgb: 51, 85, 255;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* semantic color variables for this project */
|
/* 深色主题变量 - 默认 */
|
||||||
:root {
|
:root,
|
||||||
--color-background: var(--vt-c-black);
|
html[data-theme='dark'] {
|
||||||
--color-background-soft: var(--vt-c-black-soft);
|
--color-bg-primary: #050505;
|
||||||
--color-background-mute: var(--vt-c-black-mute);
|
--color-bg-secondary: rgba(255, 255, 255, 0.05);
|
||||||
|
--color-text-primary: rgba(255, 255, 255, 0.9);
|
||||||
|
--color-text-secondary: rgba(255, 255, 255, 0.6);
|
||||||
|
--color-border: rgba(255, 255, 255, 0.1);
|
||||||
|
--color-border-hover: rgba(255, 255, 255, 0.2);
|
||||||
|
--color-shadow: rgba(0, 0, 0, 0.3);
|
||||||
|
|
||||||
--color-border: var(--vt-c-divider-dark-2);
|
--color-background: var(--color-bg-primary);
|
||||||
--color-border-hover: var(--vt-c-divider-dark-1);
|
--color-background-soft: var(--color-bg-secondary);
|
||||||
|
--color-background-mute: #111111;
|
||||||
|
|
||||||
--color-heading: var(--vt-c-text-dark-1);
|
--color-heading: var(--color-text-primary);
|
||||||
--color-text: var(--vt-c-text-dark-1);
|
--color-text: var(--color-text-primary);
|
||||||
|
|
||||||
--section-gap: 160px;
|
--section-gap: 160px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (prefers-color-scheme: dark) {
|
/* 浅色主题变量 */
|
||||||
:root {
|
html[data-theme='light'] {
|
||||||
--color-background: var(--vt-c-black);
|
--color-bg-primary: #ffffff;
|
||||||
--color-background-soft: var(--vt-c-black-soft);
|
--color-bg-secondary: rgba(0, 0, 0, 0.03);
|
||||||
--color-background-mute: var(--vt-c-black-mute);
|
--color-text-primary: rgba(0, 0, 0, 0.9);
|
||||||
|
--color-text-secondary: rgba(0, 0, 0, 0.6);
|
||||||
|
--color-border: rgba(0, 0, 0, 0.1);
|
||||||
|
--color-border-hover: rgba(0, 0, 0, 0.2);
|
||||||
|
--color-shadow: rgba(0, 0, 0, 0.1);
|
||||||
|
|
||||||
--color-border: var(--vt-c-divider-dark-2);
|
--color-background: var(--color-bg-primary);
|
||||||
--color-border-hover: var(--vt-c-divider-dark-1);
|
--color-background-soft: var(--color-bg-secondary);
|
||||||
|
--color-background-mute: #f5f5f5;
|
||||||
|
|
||||||
--color-heading: var(--vt-c-text-dark-1);
|
--color-heading: var(--color-text-primary);
|
||||||
--color-text: var(--vt-c-text-dark-2);
|
--color-text: var(--color-text-primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 深色主题变量 - 通过data-theme属性设置 */
|
||||||
|
html[data-theme='dark'] {
|
||||||
|
--color-bg-primary: #050505;
|
||||||
|
--color-bg-secondary: rgba(255, 255, 255, 0.05);
|
||||||
|
--color-text-primary: rgba(255, 255, 255, 0.9);
|
||||||
|
--color-text-secondary: rgba(255, 255, 255, 0.6);
|
||||||
|
--color-border: rgba(255, 255, 255, 0.1);
|
||||||
|
--color-border-hover: rgba(255, 255, 255, 0.2);
|
||||||
|
--color-shadow: rgba(0, 0, 0, 0.3);
|
||||||
|
|
||||||
|
--color-background: var(--color-bg-primary);
|
||||||
|
--color-background-soft: var(--color-bg-secondary);
|
||||||
|
--color-background-mute: #111111;
|
||||||
|
|
||||||
|
--color-heading: var(--color-text-primary);
|
||||||
|
--color-text: var(--color-text-primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
*,
|
*,
|
||||||
@ -73,8 +107,8 @@ body {
|
|||||||
color: var(--color-text);
|
color: var(--color-text);
|
||||||
background: var(--color-background);
|
background: var(--color-background);
|
||||||
transition:
|
transition:
|
||||||
color 0.5s,
|
color 0.3s ease,
|
||||||
background-color 0.5s;
|
background-color 0.3s ease;
|
||||||
line-height: 1.6;
|
line-height: 1.6;
|
||||||
font-family:
|
font-family:
|
||||||
Inter,
|
Inter,
|
||||||
|
|||||||
23
src/main.ts
23
src/main.ts
@ -5,10 +5,29 @@ import { createPinia } from 'pinia'
|
|||||||
|
|
||||||
import App from './App.vue'
|
import App from './App.vue'
|
||||||
import router from './router'
|
import router from './router'
|
||||||
|
import { useThemeStore } from './stores/theme'
|
||||||
|
|
||||||
|
// 设置默认主题attribute以防止闪烁
|
||||||
|
const applyInitialTheme = () => {
|
||||||
|
const savedTheme = localStorage.getItem('theme') || 'dark'
|
||||||
|
document.documentElement.setAttribute('data-theme', savedTheme)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 在应用挂载前应用初始主题,避免闪烁
|
||||||
|
applyInitialTheme()
|
||||||
|
|
||||||
const app = createApp(App)
|
const app = createApp(App)
|
||||||
|
const pinia = createPinia()
|
||||||
app.use(createPinia())
|
app.use(pinia)
|
||||||
app.use(router)
|
app.use(router)
|
||||||
|
|
||||||
|
// 在pinia初始化后,确保theme store被创建并应用主题设置
|
||||||
|
app.config.globalProperties.$initTheme = () => {
|
||||||
|
useThemeStore() // 只需创建实例,watch会自动处理主题设置
|
||||||
|
}
|
||||||
|
|
||||||
|
// 挂载应用
|
||||||
app.mount('#app')
|
app.mount('#app')
|
||||||
|
|
||||||
|
// 确保主题store被初始化
|
||||||
|
app.config.globalProperties.$initTheme()
|
||||||
|
|||||||
54
src/stores/theme.ts
Normal file
54
src/stores/theme.ts
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
import { defineStore } from 'pinia'
|
||||||
|
import { ref, watch } from 'vue'
|
||||||
|
|
||||||
|
type ThemeMode = 'dark' | 'light'
|
||||||
|
|
||||||
|
// 设置主题到DOM
|
||||||
|
const applyThemeToDOM = (theme: ThemeMode) => {
|
||||||
|
document.documentElement.setAttribute('data-theme', theme)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useThemeStore = defineStore('theme', () => {
|
||||||
|
// 获取存储的主题或默认为深色
|
||||||
|
const storedTheme = localStorage.getItem('theme') as ThemeMode | null
|
||||||
|
const currentTheme = ref<ThemeMode>(storedTheme || 'dark')
|
||||||
|
|
||||||
|
// 立即应用当前主题到DOM
|
||||||
|
applyThemeToDOM(currentTheme.value)
|
||||||
|
|
||||||
|
// 监听主题变化并应用
|
||||||
|
watch(
|
||||||
|
currentTheme,
|
||||||
|
(newTheme) => {
|
||||||
|
// 保存到本地存储
|
||||||
|
localStorage.setItem('theme', newTheme)
|
||||||
|
// 设置文档根元素的主题属性
|
||||||
|
applyThemeToDOM(newTheme)
|
||||||
|
},
|
||||||
|
{ immediate: true },
|
||||||
|
)
|
||||||
|
|
||||||
|
// 切换主题
|
||||||
|
function toggleTheme() {
|
||||||
|
currentTheme.value = currentTheme.value === 'dark' ? 'light' : 'dark'
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置特定主题
|
||||||
|
function setTheme(theme: ThemeMode) {
|
||||||
|
currentTheme.value = theme
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断是否为深色主题
|
||||||
|
const isDarkTheme = ref(currentTheme.value === 'dark')
|
||||||
|
|
||||||
|
watch(currentTheme, (newTheme) => {
|
||||||
|
isDarkTheme.value = newTheme === 'dark'
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
currentTheme,
|
||||||
|
isDarkTheme,
|
||||||
|
toggleTheme,
|
||||||
|
setTheme,
|
||||||
|
}
|
||||||
|
})
|
||||||
@ -1,9 +1,12 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed, ref, onMounted } from 'vue'
|
import { computed, ref, onMounted, watch } from 'vue'
|
||||||
import { useUserStore } from '../stores/user'
|
import { useUserStore } from '../stores/user'
|
||||||
|
import { useThemeStore } from '../stores/theme'
|
||||||
|
|
||||||
const userStore = useUserStore()
|
const userStore = useUserStore()
|
||||||
|
const themeStore = useThemeStore()
|
||||||
const isAuthenticated = computed(() => userStore.isAuthenticated)
|
const isAuthenticated = computed(() => userStore.isAuthenticated)
|
||||||
|
const isDarkTheme = computed(() => themeStore.isDarkTheme)
|
||||||
|
|
||||||
const emit = defineEmits(['openAuth'])
|
const emit = defineEmits(['openAuth'])
|
||||||
|
|
||||||
@ -11,6 +14,24 @@ const openAuthModal = (mode: 'login' | 'register') => {
|
|||||||
emit('openAuth', mode)
|
emit('openAuth', mode)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 切换主题并添加动画效果
|
||||||
|
const toggleTheme = () => {
|
||||||
|
themeStore.toggleTheme()
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
// 确保组件挂载时主题已被正确应用
|
||||||
|
document.documentElement.setAttribute('data-theme', themeStore.currentTheme)
|
||||||
|
})
|
||||||
|
|
||||||
|
// 监听主题变化更新UI
|
||||||
|
watch(
|
||||||
|
() => themeStore.currentTheme,
|
||||||
|
(newTheme) => {
|
||||||
|
document.documentElement.setAttribute('data-theme', newTheme)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
// 平台信息相关
|
// 平台信息相关
|
||||||
const apiBaseUrl =
|
const apiBaseUrl =
|
||||||
import.meta.env.MODE === 'development' ? 'http://127.0.0.1:8000' : 'https://api.ibtc.work'
|
import.meta.env.MODE === 'development' ? 'http://127.0.0.1:8000' : 'https://api.ibtc.work'
|
||||||
@ -97,6 +118,46 @@ onMounted(() => {
|
|||||||
<template>
|
<template>
|
||||||
<div class="home-view">
|
<div class="home-view">
|
||||||
<section class="hero-section">
|
<section class="hero-section">
|
||||||
|
<!-- 主题切换按钮 -->
|
||||||
|
<div class="theme-toggle">
|
||||||
|
<button
|
||||||
|
class="theme-toggle-button"
|
||||||
|
@click="toggleTheme"
|
||||||
|
:title="isDarkTheme ? '切换到浅色模式' : '切换到深色模式'"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
v-if="isDarkTheme"
|
||||||
|
class="theme-icon"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width="2"
|
||||||
|
>
|
||||||
|
<!-- 太阳图标 -->
|
||||||
|
<circle cx="12" cy="12" r="5"></circle>
|
||||||
|
<line x1="12" y1="1" x2="12" y2="3"></line>
|
||||||
|
<line x1="12" y1="21" x2="12" y2="23"></line>
|
||||||
|
<line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line>
|
||||||
|
<line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line>
|
||||||
|
<line x1="1" y1="12" x2="3" y2="12"></line>
|
||||||
|
<line x1="21" y1="12" x2="23" y2="12"></line>
|
||||||
|
<line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line>
|
||||||
|
<line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line>
|
||||||
|
</svg>
|
||||||
|
<svg
|
||||||
|
v-else
|
||||||
|
class="theme-icon"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width="2"
|
||||||
|
>
|
||||||
|
<!-- 月亮图标 -->
|
||||||
|
<path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"></path>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="hero-content">
|
<div class="hero-content">
|
||||||
<h1 class="hero-title">
|
<h1 class="hero-title">
|
||||||
<span class="accent">tradus</span>
|
<span class="accent">tradus</span>
|
||||||
@ -517,6 +578,22 @@ onMounted(() => {
|
|||||||
.deepseek-name {
|
.deepseek-name {
|
||||||
font-size: 0.8rem;
|
font-size: 0.8rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.theme-toggle {
|
||||||
|
top: 16px;
|
||||||
|
right: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-toggle-button {
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
padding: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-icon {
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 删除底部悬浮的模型支持信息样式 */
|
/* 删除底部悬浮的模型支持信息样式 */
|
||||||
@ -570,4 +647,38 @@ onMounted(() => {
|
|||||||
background-clip: text;
|
background-clip: text;
|
||||||
text-fill-color: transparent;
|
text-fill-color: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 主题切换按钮样式 */
|
||||||
|
.theme-toggle {
|
||||||
|
position: absolute;
|
||||||
|
top: 20px;
|
||||||
|
right: 20px;
|
||||||
|
z-index: 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-toggle-button {
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 6px;
|
||||||
|
border-radius: 50%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
background-color: var(--color-bg-secondary);
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
width: 38px;
|
||||||
|
height: 38px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-toggle-button:hover {
|
||||||
|
background-color: var(--color-accent-light);
|
||||||
|
color: var(--color-accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-icon {
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user