feat(player): PC 侧栏布局、顶栏与页内间距优化
Some checks failed
lotteryfront CI / build (push) Has been cancelled
Some checks failed
lotteryfront CI / build (push) Has been cancelled
- 桌面端侧栏 + 全局顶栏(Logo 在侧栏顶、激活态对齐后台红底白字) - 移除各页重复页内顶栏,统一主区与卡片顶部留白 - 视口遮罩/弹层约束到主内容区,移动端保留底栏与顶栏 Logo
This commit is contained in:
@@ -1,21 +1,16 @@
|
||||
"use client";
|
||||
|
||||
import { BookOpen } from "lucide-react";
|
||||
import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import { LanguageSwitcher } from "@/components/language-switcher";
|
||||
import { HallBettingGrid } from "@/features/hall/hall-betting-grid";
|
||||
import { usePlayerStickyTopStyle } from "@/hooks/use-player-sticky-top-style";
|
||||
import { useActivePlayerCurrency } from "@/hooks/use-active-player-currency";
|
||||
import { HallDrawPanel } from "@/features/hall/hall-draw-panel";
|
||||
import { HallWalletStrip } from "@/features/hall/hall-wallet-strip";
|
||||
import { JackpotBurstOverlay } from "@/features/hall/jackpot-burst-overlay";
|
||||
import { useHallDrawLive } from "@/features/hall/use-hall-draw-live";
|
||||
import { useJackpotBurstLive } from "@/features/hall/use-jackpot-burst-live";
|
||||
import { playerHeaderControl, playerPageHeader, playerPageInset } from "@/lib/player-spacing";
|
||||
import { playerViewportColumnClass } from "@/lib/player-viewport";
|
||||
import { playerPageInset } from "@/lib/player-spacing";
|
||||
import { playerContentColumnClass } from "@/lib/player-viewport";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
/**
|
||||
@@ -26,52 +21,15 @@ export function HallScreen() {
|
||||
const drawLive = useHallDrawLive();
|
||||
const { activeCurrency } = useActivePlayerCurrency();
|
||||
const { burstEvent, clearBurstEvent } = useJackpotBurstLive(tp);
|
||||
const stickyTopStyle = usePlayerStickyTopStyle();
|
||||
|
||||
return (
|
||||
<div className={playerViewportColumnClass}>
|
||||
<section className={cn("bg-white text-slate-900", playerPageInset)}>
|
||||
<header
|
||||
className={cn(
|
||||
playerPageHeader,
|
||||
"sticky z-20 mb-2 flex min-h-9 items-center gap-2 overflow-visible bg-white pt-2 pb-2 -mx-3 px-3",
|
||||
)}
|
||||
style={stickyTopStyle}
|
||||
>
|
||||
<div className="flex min-w-0 flex-1 items-center">
|
||||
<Image
|
||||
src="/logo.png"
|
||||
alt="Nlotto"
|
||||
width={243}
|
||||
height={84}
|
||||
className="h-7 w-auto max-w-[min(100%,160px)] object-contain object-left"
|
||||
priority
|
||||
/>
|
||||
</div>
|
||||
<div className="flex shrink-0 items-center gap-1">
|
||||
<LanguageSwitcher
|
||||
variant="minimal"
|
||||
menuAlign="end"
|
||||
showFlag={false}
|
||||
className={cn(
|
||||
playerHeaderControl,
|
||||
"rounded-full border border-[#e4eaf4] bg-[#f8fafc] [&_button]:h-8 [&_button]:gap-1 [&_button]:px-2 [&_button]:py-0 [&_button]:text-xs",
|
||||
)}
|
||||
/>
|
||||
<Link
|
||||
href="/rules"
|
||||
className={cn(
|
||||
playerHeaderControl,
|
||||
"rounded-full border border-[#e4eaf4] bg-[#f8fafc] px-2.5 text-xs font-bold text-[#0b3f96] hover:bg-[#f1f6ff]",
|
||||
)}
|
||||
aria-label={tp("nav.rules")}
|
||||
>
|
||||
<BookOpen className="size-3.5 shrink-0" aria-hidden />
|
||||
<span>{tp("nav.rules")}</span>
|
||||
</Link>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div className={playerContentColumnClass}>
|
||||
<section
|
||||
className={cn(
|
||||
"bg-white text-slate-900 lg:rounded-2xl lg:border lg:border-[#e4ebf5] lg:shadow-sm",
|
||||
playerPageInset,
|
||||
)}
|
||||
>
|
||||
<HallDrawPanel drawLive={drawLive} />
|
||||
|
||||
<HallWalletStrip />
|
||||
@@ -81,4 +39,4 @@ export function HallScreen() {
|
||||
<JackpotBurstOverlay event={burstEvent} onClose={clearBurstEvent} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import { useTranslation } from "react-i18next";
|
||||
import { getDrawResultByNo } from "@/api/draw";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { formatMinorAsCurrency } from "@/lib/money";
|
||||
import { playerViewportOverlayClass } from "@/lib/player-viewport";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
export type JackpotBurstEvent = {
|
||||
@@ -214,7 +215,10 @@ function JackpotBurstOverlayContent({
|
||||
|
||||
return (
|
||||
<div
|
||||
className="fixed inset-0 z-[90] flex items-center justify-center bg-white/88 px-4 py-6 text-slate-900 backdrop-blur-[2px] animate-[jackpot-backdrop-in_0.35s_ease-out]"
|
||||
className={cn(
|
||||
playerViewportOverlayClass,
|
||||
"z-[90] flex items-center justify-center bg-white/88 px-4 py-6 text-slate-900 backdrop-blur-[2px] animate-[jackpot-backdrop-in_0.35s_ease-out]",
|
||||
)}
|
||||
style={{
|
||||
backgroundImage:
|
||||
"radial-gradient(ellipse 75% 55% at 50% 38%, rgba(245,197,66,0.14) 0%, transparent 60%)",
|
||||
|
||||
@@ -450,7 +450,7 @@ export function EntryGate() {
|
||||
|
||||
<div className="flex flex-1 flex-col px-3 py-5">
|
||||
{phase === "loading" || waitingForEmbeddedToken ? (
|
||||
<div className="mx-auto w-full max-w-md">
|
||||
<div className="mx-auto w-full max-w-md lg:max-w-lg">
|
||||
<div className="mb-6 flex items-center gap-2">
|
||||
<div className="flex size-8 items-center justify-center rounded bg-red-600 text-white">
|
||||
<Globe className="size-5" aria-hidden />
|
||||
@@ -525,7 +525,7 @@ export function EntryGate() {
|
||||
) : null}
|
||||
|
||||
{phase === "failed" ? (
|
||||
<div className="mx-auto w-full max-w-md">
|
||||
<div className="mx-auto w-full max-w-md lg:max-w-lg">
|
||||
<div className="mb-6 text-center">
|
||||
<div className="mx-auto mb-4 flex size-16 items-center justify-center rounded-full bg-red-100 text-red-600">
|
||||
<AlertTriangle className="size-8" aria-hidden />
|
||||
@@ -601,7 +601,7 @@ export function EntryGate() {
|
||||
) : null}
|
||||
|
||||
{phase === "success" ? (
|
||||
<div className="mx-auto w-full max-w-md text-center">
|
||||
<div className="mx-auto w-full max-w-md text-center lg:max-w-lg">
|
||||
<div className="mb-6">
|
||||
<div className="mx-auto mb-4 flex size-16 items-center justify-center rounded-full bg-green-100 text-green-600">
|
||||
<CheckCircle2 className="size-8" aria-hidden />
|
||||
|
||||
@@ -160,7 +160,7 @@ export function PlayerLoginScreen(): React.ReactElement {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mx-auto w-full max-w-md flex-1 px-4 py-8">
|
||||
<div className="mx-auto w-full max-w-md flex-1 px-4 py-8 lg:max-w-lg lg:px-8">
|
||||
<h1 className="text-xl font-bold text-gray-900">
|
||||
{t("login.title")}
|
||||
</h1>
|
||||
|
||||
@@ -117,7 +117,8 @@ export function DrawResultsListScreen() {
|
||||
<p className="mb-2 text-xs font-bold text-[#32518d]">
|
||||
{t("results.businessDate")}
|
||||
</p>
|
||||
<div className="flex gap-2">
|
||||
<div className="flex min-w-0 gap-2">
|
||||
<div className="min-w-0 flex-1">
|
||||
<Popover open={datePickerOpen} onOpenChange={setDatePickerOpen}>
|
||||
<PopoverTrigger
|
||||
render={
|
||||
@@ -186,6 +187,7 @@ export function DrawResultsListScreen() {
|
||||
/>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
</div>
|
||||
{date ? (
|
||||
<Button
|
||||
type="button"
|
||||
@@ -201,7 +203,7 @@ export function DrawResultsListScreen() {
|
||||
<Button
|
||||
type="button"
|
||||
size="sm"
|
||||
className="h-10 rounded-lg bg-[#07459f] px-4 text-white hover:bg-[#063b88]"
|
||||
className="h-10 shrink-0 rounded-lg bg-[#07459f] px-4 text-white hover:bg-[#063b88]"
|
||||
onClick={() => void fetchList(1, false)}
|
||||
>
|
||||
{t("actions.apply")}
|
||||
|
||||
Reference in New Issue
Block a user