更新登录页面和帮助教程

This commit is contained in:
Eamon
2026-08-07 16:54:21 +08:00
parent 038e66d0cc
commit 4c9953ab57
22 changed files with 1278 additions and 133 deletions

View File

@@ -1,8 +1,72 @@
import { useRef, useState, useSyncExternalStore } from "react"
import { useEffect, useRef, useState, useSyncExternalStore } from "react"
import { NavLink, useNavigate } from "react-router-dom"
import { logout } from "@/api/auth"
import Wrap from "@/components/wrap"
import { cn } from "@/lib/utils"
function ProfileOrLogin() {
const [authed, setAuthed] = useState(
() => !!localStorage.getItem("auth_token"),
)
const navigate = useNavigate()
useEffect(() => {
const onFocus = () => setAuthed(!!localStorage.getItem("auth_token"))
window.addEventListener("focus", onFocus)
return () => window.removeEventListener("focus", onFocus)
}, [])
const handleLogout = async () => {
await logout()
}
if (authed) {
return (
<div className="flex items-center gap-2">
<button
onClick={() => navigate("/admin")}
className="w-24 h-12 flex items-center justify-center lg:text-lg text-slate-700 hover:text-blue-500 transition-colors"
>
<span></span>
</button>
<button
onClick={handleLogout}
className={[
"w-20 lg:w-24 h-10 lg:h-12 bg-linear-to-r rounded-full flex items-center justify-center lg:text-lg text-white",
"transition-colors duration-200 ease-in-out",
"from-blue-500 to-cyan-400 hover:from-blue-500 hover:to-cyan-300",
].join(" ")}
>
<span>退</span>
</button>
</div>
)
}
return (
<div className="flex items-center">
<NavLink
to="/login"
state={{ tab: "login" }}
className="w-24 h-12 flex items-center justify-center lg:text-lg"
>
<span></span>
</NavLink>
<NavLink
to="/login"
state={{ tab: "register" }}
className={[
"w-20 lg:w-24 h-10 lg:h-12 bg-linear-to-r rounded-full flex items-center justify-center lg:text-lg text-white",
"transition-colors duration-200 ease-in-out",
"from-blue-500 to-cyan-400 hover:from-blue-500 hover:to-cyan-300",
].join(" ")}
>
<span></span>
</NavLink>
</div>
)
}
export default function Header() {
const scroll = useSyncExternalStore(
callback => {
@@ -47,7 +111,7 @@ export default function Header() {
<ProductDropdown onNavigate={() => setOpenMenu(false)} />
</MenuItem>
<NavItem to="/ipline">IP线路表</NavItem>
<NavItem to="/softDownload"></NavItem>
<NavItem to="/softdownload"></NavItem>
<NavItem to="/help">/</NavItem>
</ul>
</nav>
@@ -79,31 +143,6 @@ const NavItem = ({
</NavLink>
)
function ProfileOrLogin() {
return (
<div className="flex items-center">
<NavLink
to="/login"
state={{ tab: "login" }}
className="w-24 h-12 flex items-center justify-center lg:text-lg"
>
<span></span>
</NavLink>
<NavLink
to="/login"
state={{ tab: "register" }}
className={[
`w-20 lg:w-24 h-10 lg:h-12 bg-linear-to-r rounded-full flex items-center justify-center lg:text-lg text-white`,
`transition-colors duration-200 ease-in-out`,
`from-blue-500 to-cyan-400 hover:from-blue-500 hover:to-cyan-300`,
].join(" ")}
>
<span></span>
</NavLink>
</div>
)
}
const MenuItem = ({
text,
children,
@@ -206,60 +245,60 @@ const ProductDropdown = ({ onNavigate }: { onNavigate: () => void }) => {
title="动静态IP"
desc="千万级动态短效IP自动去重高并发采集"
tag="热门"
onClick={() => handleClick("/product/short")}
onClick={() => handleClick("/product?tab=short")}
/>
<ProductCard
title="新HTTP/S5"
desc="IP可用时长从数小时到365天全覆盖"
tag="稳定"
onClick={() => handleClick("/product/long")}
onClick={() => handleClick("/product?tab=long")}
/>
<ProductCard
title="HTTP/S5"
desc="海量全球住宅优质IP4G/5G真实手机IP"
tag="全球"
onClick={() => handleClick("/product/global")}
onClick={() => handleClick("/product?tab=global")}
/>
<ProductCard
title="软路由成本价"
desc="云端自动切换IP更易于调用与开发"
onClick={() => handleClick("/product/tunnel")}
onClick={() => handleClick("/product?tab=tunnel")}
/>
<ProductCard
title="动态Vps"
desc="IP独享高带宽灵活控制存活周期"
onClick={() => handleClick("/product/exclusive")}
onClick={() => handleClick("/product?tab=exclusive")}
/>
<ProductCard
title="静态独享IP"
desc="纯净IP更符合跨境卖家需求的云主机"
onClick={() => handleClick("/product/static")}
onClick={() => handleClick("/product?tab=static")}
/>
</div>
<div className="flex items-center flex-wrap gap-3 pt-3 border-t border-gray-100">
<span className="text-xs font-medium text-gray-400">:</span>
<button
onClick={() => handleClick("/product/short")}
onClick={() => handleClick("/product?tab=short")}
className="text-sm text-blue-600 hover:underline whitespace-nowrap"
>
</button>
<button
onClick={() => handleClick("/product/global")}
onClick={() => handleClick("/product?tab=global")}
className="text-sm text-blue-600 hover:underline whitespace-nowrap"
>
</button>
<button
onClick={() => handleClick("/product/tunnel")}
onClick={() => handleClick("/product?tab=tunnel")}
className="text-sm text-blue-600 hover:underline whitespace-nowrap"
>
</button>
<span className="text-xs text-gray-300">|</span>
<button
onClick={() => handleClick("/custom")}
onClick={() => handleClick("/product")}
className="text-sm text-orange-500 hover:underline font-medium whitespace-nowrap"
>