Some checks failed
lotteryfront CI / build (push) Has been cancelled
- 桌面端侧栏 + 全局顶栏(Logo 在侧栏顶、激活态对齐后台红底白字) - 移除各页重复页内顶栏,统一主区与卡片顶部留白 - 视口遮罩/弹层约束到主内容区,移动端保留底栏与顶栏 Logo
118 lines
3.7 KiB
TypeScript
118 lines
3.7 KiB
TypeScript
"use client";
|
|
|
|
import Image from "next/image";
|
|
import Link from "next/link";
|
|
import { usePathname } from "next/navigation";
|
|
|
|
import {
|
|
BarChart3,
|
|
BookOpen,
|
|
ClipboardList,
|
|
Home,
|
|
Wallet,
|
|
} from "lucide-react";
|
|
import { useTranslation } from "react-i18next";
|
|
|
|
import { isCreditFundingPlayer } from "@/lib/player-funding-mode";
|
|
import { cn } from "@/lib/utils";
|
|
import { usePlayerSessionStore } from "@/stores/player-session-store";
|
|
|
|
const navItems = [
|
|
{
|
|
href: "/hall",
|
|
labelKey: "nav.home",
|
|
labelDefault: "首页",
|
|
icon: Home,
|
|
match: (p: string) => p === "/hall",
|
|
},
|
|
{
|
|
href: "/results",
|
|
labelKey: "nav.results",
|
|
labelDefault: "开奖结果",
|
|
icon: BarChart3,
|
|
match: (p: string) => p === "/results" || p.startsWith("/results/"),
|
|
},
|
|
{
|
|
href: "/orders",
|
|
labelKey: "nav.orders",
|
|
labelDefault: "我的注单",
|
|
icon: ClipboardList,
|
|
match: (p: string) => p === "/orders" || p.startsWith("/orders/"),
|
|
},
|
|
{
|
|
href: "/wallet",
|
|
labelKey: "nav.wallet",
|
|
creditLabelKey: "nav.credit",
|
|
labelDefault: "钱包",
|
|
creditLabelDefault: "信用",
|
|
icon: Wallet,
|
|
match: (p: string) => p === "/wallet" || p.startsWith("/wallet/"),
|
|
},
|
|
{
|
|
href: "/rules",
|
|
labelKey: "nav.rules",
|
|
labelDefault: "规则",
|
|
icon: BookOpen,
|
|
match: (p: string) => p === "/rules",
|
|
},
|
|
] as const;
|
|
|
|
/** 与 lotteryadmin `NAV_BTN` / `NAV_ACTIVE` 一致 */
|
|
const playerNavLinkClass =
|
|
"flex h-8 w-full items-center gap-2 rounded-md px-2.5 text-[13px] leading-snug font-normal text-sidebar-foreground/90 transition-colors hover:bg-sidebar-accent hover:text-sidebar-accent-foreground [&_svg]:size-4 [&_svg]:shrink-0";
|
|
|
|
const playerNavLinkActiveClass =
|
|
"bg-sidebar-primary/90 font-medium text-sidebar-primary-foreground shadow-sm hover:bg-sidebar-primary/90 hover:text-sidebar-primary-foreground";
|
|
|
|
/** 桌面端左侧导航(激活态对齐后台侧栏) */
|
|
export function PlayerSidebar() {
|
|
const pathname = usePathname() ?? "";
|
|
const { t } = useTranslation("player");
|
|
const creditMode = isCreditFundingPlayer(usePlayerSessionStore((state) => state.profile));
|
|
|
|
return (
|
|
<aside
|
|
className="player-sidebar hidden h-full w-56 shrink-0 flex-col border-r border-[#e4ebf5] bg-white lg:flex"
|
|
aria-label={t("nav.aria")}
|
|
>
|
|
<div className="shrink-0 border-b border-[#e4ebf5] px-2 py-2">
|
|
<Link href="/hall" className="flex h-10 items-center px-1" aria-label="N lotto">
|
|
<Image
|
|
src="/logo.png"
|
|
alt="N lotto"
|
|
width={243}
|
|
height={84}
|
|
className="h-auto max-h-10 w-full object-contain object-left"
|
|
priority
|
|
/>
|
|
</Link>
|
|
</div>
|
|
|
|
<nav className="flex min-h-0 flex-1 flex-col gap-0.5 overflow-y-auto px-1.5 py-1.5">
|
|
{navItems.map(({ href, labelKey, labelDefault, icon: Icon, match, ...item }) => {
|
|
const active = match(pathname);
|
|
const creditLabelKey = "creditLabelKey" in item ? item.creditLabelKey : undefined;
|
|
const creditLabelDefault =
|
|
"creditLabelDefault" in item ? item.creditLabelDefault : undefined;
|
|
const label =
|
|
creditMode && creditLabelKey
|
|
? t(creditLabelKey, { defaultValue: creditLabelDefault ?? labelDefault })
|
|
: t(labelKey, { defaultValue: labelDefault });
|
|
|
|
return (
|
|
<Link
|
|
key={href}
|
|
href={href}
|
|
prefetch
|
|
aria-current={active ? "page" : undefined}
|
|
className={cn(playerNavLinkClass, active && playerNavLinkActiveClass)}
|
|
>
|
|
<Icon aria-hidden />
|
|
<span className="truncate">{label}</span>
|
|
</Link>
|
|
);
|
|
})}
|
|
</nav>
|
|
</aside>
|
|
);
|
|
} |