feat: add translate

This commit is contained in:
liuyuanchuang
2026-01-24 13:53:50 +08:00
parent 6747205bd0
commit 42850c4460
12 changed files with 572 additions and 66 deletions

View File

@@ -1,11 +1,15 @@
import { useState, useRef, useEffect } from 'react';
import { Mail, Users, MessageCircle, ChevronDown, Check, Heart, X } from 'lucide-react';
import { Mail, Users, MessageCircle, ChevronDown, Check, Heart, X, Languages, HelpCircle } from 'lucide-react';
import { useLanguage } from '../contexts/LanguageContext';
export default function Navbar() {
const { language, setLanguage, t } = useLanguage();
const [showContact, setShowContact] = useState(false);
const [showReward, setShowReward] = useState(false);
const [showLangMenu, setShowLangMenu] = useState(false);
const [copied, setCopied] = useState(false);
const dropdownRef = useRef<HTMLDivElement>(null);
const langMenuRef = useRef<HTMLDivElement>(null);
const handleCopyQQ = async () => {
await navigator.clipboard.writeText('1018282100');
@@ -19,6 +23,9 @@ export default function Navbar() {
if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) {
setShowContact(false);
}
if (langMenuRef.current && !langMenuRef.current.contains(event.target as Node)) {
setShowLangMenu(false);
}
};
document.addEventListener('mousedown', handleClickOutside);
@@ -37,8 +44,59 @@ export default function Navbar() {
</span>
</div>
{/* Right: Reward & Contact Buttons */}
{/* Right: Actions */}
<div className="flex items-center gap-3">
{/* Language Switcher */}
<div className="relative" ref={langMenuRef}>
<button
onClick={() => setShowLangMenu(!showLangMenu)}
className="flex items-center gap-2 px-3 py-2 hover:bg-gray-100 rounded-lg text-gray-700 text-sm font-medium transition-colors"
title="Switch Language"
>
<Languages size={18} />
<span className="hidden sm:inline">{language === 'en' ? 'English' : '简体中文'}</span>
<ChevronDown size={14} className={`transition-transform duration-200 ${showLangMenu ? 'rotate-180' : ''}`} />
</button>
{showLangMenu && (
<div className="absolute right-0 top-full mt-2 w-32 bg-white rounded-xl shadow-lg border border-gray-200 py-1 z-50 animate-in fade-in slide-in-from-top-2 duration-200">
<button
onClick={() => {
setLanguage('en');
setShowLangMenu(false);
}}
className={`w-full flex items-center justify-between px-4 py-2 text-sm transition-colors hover:bg-gray-50 ${language === 'en' ? 'text-blue-600 font-medium' : 'text-gray-700'}`}
>
English
{language === 'en' && <Check size={14} />}
</button>
<button
onClick={() => {
setLanguage('zh');
setShowLangMenu(false);
}}
className={`w-full flex items-center justify-between px-4 py-2 text-sm transition-colors hover:bg-gray-50 ${language === 'zh' ? 'text-blue-600 font-medium' : 'text-gray-700'}`}
>
{language === 'zh' && <Check size={14} />}
</button>
</div>
)}
</div>
{/* User Guide Button */}
<button
id="guide-button"
className="flex items-center gap-2 px-3 py-2 hover:bg-gray-100 rounded-lg text-gray-700 text-sm font-medium transition-colors"
onClick={() => {
// This will be handled in App.tsx via a custom event or shared state
window.dispatchEvent(new CustomEvent('start-user-guide'));
}}
>
<HelpCircle size={18} />
<span className="hidden sm:inline">{t.common.guide}</span>
</button>
{/* Reward Button */}
<div className="relative">
<button
@@ -46,7 +104,7 @@ export default function Navbar() {
className="flex items-center gap-2 px-4 py-2 bg-gradient-to-r from-rose-500 to-pink-500 hover:from-rose-600 hover:to-pink-600 rounded-lg text-white text-sm font-medium transition-all shadow-sm hover:shadow-md"
>
<Heart size={14} className="fill-white" />
<span></span>
<span>{t.common.reward}</span>
</button>
{/* Reward Modal */}
@@ -60,7 +118,7 @@ export default function Navbar() {
onClick={e => e.stopPropagation()}
>
<div className="flex items-center justify-between mb-4">
<span className="text-lg font-bold text-gray-900"></span>
<span className="text-lg font-bold text-gray-900">{t.navbar.rewardTitle}</span>
<button
onClick={() => setShowReward(false)}
className="p-2 hover:bg-gray-100 rounded-lg transition-colors"
@@ -71,12 +129,12 @@ export default function Navbar() {
<div className="flex flex-col items-center">
<img
src="https://cdn.texpixel.com/public/rewardcode.png"
alt="微信赞赏码"
alt={t.navbar.rewardTitle}
className="w-64 h-64 object-contain rounded-lg shadow-sm"
/>
<p className="text-sm text-gray-500 text-center mt-4">
<br />
<span className="text-xs text-gray-400 mt-1 block"></span>
{t.navbar.rewardThanks}<br />
<span className="text-xs text-gray-400 mt-1 block">{t.navbar.rewardSubtitle}</span>
</p>
</div>
</div>
@@ -91,7 +149,7 @@ export default function Navbar() {
className="flex items-center gap-2 px-4 py-2 bg-gray-100 hover:bg-gray-200 rounded-lg text-gray-700 text-sm font-medium transition-colors"
>
<MessageCircle size={14} />
<span>Contact Us</span>
<span>{t.common.contactUs}</span>
<ChevronDown
size={14}
className={`transition-transform duration-200 ${showContact ? 'rotate-180' : ''}`}
@@ -109,7 +167,7 @@ export default function Navbar() {
<Mail size={16} className="text-blue-600" />
</div>
<div>
<div className="text-xs text-gray-500">Email</div>
<div className="text-xs text-gray-500">{t.common.email}</div>
<div className="text-sm font-medium text-gray-900">yogecoder@gmail.com</div>
</div>
</a>
@@ -126,7 +184,7 @@ export default function Navbar() {
</div>
<div>
<div className={`text-xs transition-colors ${copied ? 'text-green-600 font-medium' : 'text-gray-500'}`}>
{copied ? 'Copied!' : 'QQ Group (Click to Copy)'}
{copied ? t.common.copied : t.common.qqGroup}
</div>
<div className="text-sm font-medium text-gray-900">1018282100</div>
</div>