diff --git a/web/usercenter/components/shared.tsx b/web/usercenter/components/shared.tsx index 73b6e71..ef97b24 100644 --- a/web/usercenter/components/shared.tsx +++ b/web/usercenter/components/shared.tsx @@ -1,5 +1,6 @@ // shared.tsx — 公共样式常量与原子(承袭 ucapp.jsx 的 ucCard / ucInput / UCLang) -import React from 'react'; +'use client'; +import React, { useEffect, useRef, useState } from 'react'; import type { Lang } from '../lib/i18n'; export const card: React.CSSProperties = { @@ -22,34 +23,110 @@ export const input: React.CSSProperties = { boxSizing: 'border-box', }; +const LANGS: [Lang, string][] = [ + ['en', 'English'], ['zh', '中文'], ['ja', '日本語'], + ['ko', '한국어'], ['ru', 'Русский'], ['es', 'Español'], +]; + +// 自定义下拉:原生 setLang(e.target.value as Lang)} - aria-label="Language" - style={{ - // 圆角矩形 + 柔和边框(原纯 --border 太生硬)。 - border: '1px solid color-mix(in oklab, var(--border), transparent 55%)', - cursor: 'pointer', - borderRadius: 10, - padding: '5px 10px', - fontFamily: 'var(--font-sans)', - fontSize: 12.5, - fontWeight: 700, - background: 'var(--bg-subtle)', - color: 'var(--fg2)', - boxShadow: '0 1px 2px rgba(45, 30, 20, 0.05)', - }} - > - {langs.map(([v, l]) => ( - - ))} - +
+ + {open && ( +
+ {LANGS.map(([v, l]) => { + const on = v === lang; + return ( + + ); + })} +
+ )} +
); } diff --git a/web/website/src/components/Header.jsx b/web/website/src/components/Header.jsx index 4123095..3848d52 100644 --- a/web/website/src/components/Header.jsx +++ b/web/website/src/components/Header.jsx @@ -3,7 +3,7 @@ * 迁自 design/ui_kits/website/index.html 的
+ site.js 的菜单/滚动毛玻璃逻辑。 * 语言切换由原型的 JS 文本替换改为「路由跳转」(zh=/, en=/en/),单显不并排(铁律 6)。 */ -import { useEffect, useState } from 'react'; +import { useEffect, useRef, useState } from 'react'; import { Download, Menu } from 'lucide-react'; import { SITE } from '../config/site'; @@ -29,6 +29,17 @@ function Mark() { export default function Header({ lang = 'zh', t = {} }) { const [open, setOpen] = useState(false); const [scrolled, setScrolled] = useState(false); + const [langOpen, setLangOpen] = useState(false); + const langRef = useRef(null); + + useEffect(() => { + if (!langOpen) return; + const onDoc = (e) => { if (langRef.current && !langRef.current.contains(e.target)) setLangOpen(false); }; + const onKey = (e) => { if (e.key === 'Escape') setLangOpen(false); }; + document.addEventListener('mousedown', onDoc); + document.addEventListener('keydown', onKey); + return () => { document.removeEventListener('mousedown', onDoc); document.removeEventListener('keydown', onKey); }; + }, [langOpen]); useEffect(() => { const onScroll = () => setScrolled(window.scrollY > 8); @@ -64,16 +75,36 @@ export default function Header({ lang = 'zh', t = {} }) { ))}
- +
+ + {langOpen && ( +
+ {langs.map(([code, label]) => { + const on = code === lang; + return ( + + {label} + + ); + })} +
+ )} +
{t.login}