feat: 全局主题切换(浅色/深色/跟随系统)
- CSS 变量驱动的主题系统,所有颜色响应 data-theme 属性 - 新增语义化色彩 heading/secondary/tertiary,替换硬编码 text-white/text-gray-* - 右上角三态主题按钮(自动/浅色/深色),全局可用无需登录 - layout.tsx 内联脚本防闪烁 - 修复个人中心页面溢出无法滚动
This commit is contained in:
+14
-14
@@ -266,7 +266,7 @@ export default function ProfilePage() {
|
||||
: `https://www.google.com/maps/search/?api=1&query=${encodeURIComponent(r.name)}`;
|
||||
|
||||
return (
|
||||
<div className="min-h-dvh bg-background pb-16 overflow-y-auto scrollbar-none">
|
||||
<div className="h-dvh bg-background pb-16 overflow-y-auto scrollbar-none">
|
||||
<nav className="sticky top-0 z-10 flex h-14 items-center gap-3 bg-background/80 px-4 backdrop-blur-sm">
|
||||
<button
|
||||
onClick={() => router.push("/")}
|
||||
@@ -324,10 +324,10 @@ export default function ProfilePage() {
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex items-center gap-2">
|
||||
<h2 className="text-lg font-bold text-white">{profile.username}</h2>
|
||||
<h2 className="text-lg font-bold text-heading">{profile.username}</h2>
|
||||
<button
|
||||
onClick={() => { setEditingUsername(true); setNewUsername(profile.username); }}
|
||||
className="text-muted transition-colors active:text-gray-300"
|
||||
className="text-muted transition-colors active:text-secondary"
|
||||
>
|
||||
<Edit3 size={13} />
|
||||
</button>
|
||||
@@ -385,7 +385,7 @@ export default function ProfilePage() {
|
||||
className="flex w-full items-center gap-2"
|
||||
>
|
||||
<Lock size={15} className="text-muted" />
|
||||
<h3 className="text-sm font-semibold text-gray-300">修改密码</h3>
|
||||
<h3 className="text-sm font-semibold text-secondary">修改密码</h3>
|
||||
</button>
|
||||
|
||||
<AnimatePresence>
|
||||
@@ -405,7 +405,7 @@ export default function ProfilePage() {
|
||||
type={showPassword ? "text" : "password"}
|
||||
value={currentPassword}
|
||||
onChange={(e) => { setCurrentPassword(e.target.value); setPasswordMsg(""); }}
|
||||
className="h-9 w-full rounded-lg border-none bg-elevated px-3 pr-9 text-sm text-white outline-none ring-1 ring-border focus:ring-2 focus:ring-accent/50"
|
||||
className="h-9 w-full rounded-lg border-none bg-elevated px-3 pr-9 text-sm text-heading outline-none ring-1 ring-border focus:ring-2 focus:ring-accent/50"
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
@@ -423,7 +423,7 @@ export default function ProfilePage() {
|
||||
value={newPassword}
|
||||
onChange={(e) => { setNewPassword(e.target.value); setPasswordMsg(""); }}
|
||||
placeholder="至少 6 个字符"
|
||||
className="mt-1 h-9 w-full rounded-lg border-none bg-elevated px-3 text-sm text-white outline-none ring-1 ring-border placeholder:text-dim focus:ring-2 focus:ring-accent/50"
|
||||
className="mt-1 h-9 w-full rounded-lg border-none bg-elevated px-3 text-sm text-heading outline-none ring-1 ring-border placeholder:text-dim focus:ring-2 focus:ring-accent/50"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
@@ -433,7 +433,7 @@ export default function ProfilePage() {
|
||||
value={confirmPassword}
|
||||
onChange={(e) => { setConfirmPassword(e.target.value); setPasswordMsg(""); }}
|
||||
placeholder="再次输入新密码"
|
||||
className="mt-1 h-9 w-full rounded-lg border-none bg-elevated px-3 text-sm text-white outline-none ring-1 ring-border placeholder:text-dim focus:ring-2 focus:ring-accent/50"
|
||||
className="mt-1 h-9 w-full rounded-lg border-none bg-elevated px-3 text-sm text-heading outline-none ring-1 ring-border placeholder:text-dim focus:ring-2 focus:ring-accent/50"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -465,7 +465,7 @@ export default function ProfilePage() {
|
||||
>
|
||||
<div className="flex items-center gap-2">
|
||||
<Mail size={15} className="text-muted" />
|
||||
<h3 className="text-sm font-semibold text-gray-300">绑定邮箱</h3>
|
||||
<h3 className="text-sm font-semibold text-secondary">绑定邮箱</h3>
|
||||
<span className="text-[10px] text-dim">(可选)</span>
|
||||
</div>
|
||||
<div className="mt-3 flex gap-2">
|
||||
@@ -477,7 +477,7 @@ export default function ProfilePage() {
|
||||
setEmail(e.target.value);
|
||||
setEmailMsg("");
|
||||
}}
|
||||
className="h-9 flex-1 rounded-lg border-none bg-elevated px-3 text-sm text-white outline-none ring-1 ring-border placeholder:text-dim focus:ring-2 focus:ring-accent/50"
|
||||
className="h-9 flex-1 rounded-lg border-none bg-elevated px-3 text-sm text-heading outline-none ring-1 ring-border placeholder:text-dim focus:ring-2 focus:ring-accent/50"
|
||||
/>
|
||||
<button
|
||||
onClick={handleSaveEmail}
|
||||
@@ -507,7 +507,7 @@ export default function ProfilePage() {
|
||||
>
|
||||
<div className="flex items-center gap-2">
|
||||
<Clock size={15} className="text-muted" />
|
||||
<h3 className="text-sm font-semibold text-gray-300">
|
||||
<h3 className="text-sm font-semibold text-secondary">
|
||||
决策记录 {history.length > 0 && `(${history.length})`}
|
||||
</h3>
|
||||
</div>
|
||||
@@ -556,7 +556,7 @@ export default function ProfilePage() {
|
||||
/>
|
||||
)}
|
||||
<div className="flex min-w-0 flex-1 flex-col justify-center">
|
||||
<p className="truncate text-sm font-semibold text-white">{d.restaurantName}</p>
|
||||
<p className="truncate text-sm font-semibold text-heading">{d.restaurantName}</p>
|
||||
<div className="mt-0.5 flex items-center gap-2 text-[11px] text-muted">
|
||||
<span>{d.matchType === "unanimous" ? "全员一致" : "最佳匹配"}</span>
|
||||
<span>{d.participants} 人参与</span>
|
||||
@@ -585,7 +585,7 @@ export default function ProfilePage() {
|
||||
>
|
||||
<div className="flex items-center gap-2">
|
||||
<Star size={15} className="text-muted" />
|
||||
<h3 className="text-sm font-semibold text-gray-300">
|
||||
<h3 className="text-sm font-semibold text-secondary">
|
||||
收藏餐厅 {favorites.length > 0 && `(${favorites.length})`}
|
||||
</h3>
|
||||
</div>
|
||||
@@ -633,7 +633,7 @@ export default function ProfilePage() {
|
||||
/>
|
||||
)}
|
||||
<div className="flex min-w-0 flex-1 flex-col justify-center">
|
||||
<p className="truncate text-sm font-semibold text-white">{r.name}</p>
|
||||
<p className="truncate text-sm font-semibold text-heading">{r.name}</p>
|
||||
<div className="mt-0.5 flex items-center gap-2 text-[11px] text-muted">
|
||||
<span className="flex items-center gap-0.5">
|
||||
<Star size={10} className="fill-amber-400 text-amber-400" />
|
||||
@@ -684,7 +684,7 @@ export default function ProfilePage() {
|
||||
<AnimatePresence>
|
||||
{toast && (
|
||||
<motion.div
|
||||
className="fixed left-1/2 top-10 z-60 -translate-x-1/2 rounded-xl bg-elevated px-4 py-2.5 text-xs font-medium text-white shadow-lg ring-1 ring-subtle"
|
||||
className="fixed left-1/2 top-10 z-60 -translate-x-1/2 rounded-xl bg-elevated px-4 py-2.5 text-xs font-medium text-heading shadow-lg ring-1 ring-subtle"
|
||||
initial={{ opacity: 0, y: -12, x: "-50%" }}
|
||||
animate={{ opacity: 1, y: 0, x: "-50%" }}
|
||||
exit={{ opacity: 0, y: -12, x: "-50%" }}
|
||||
|
||||
Reference in New Issue
Block a user