feat(player): 优化桌面投注布局与账号功能
This commit is contained in:
184
src/features/hall/hall-desktop-workspace.tsx
Normal file
184
src/features/hall/hall-desktop-workspace.tsx
Normal file
@@ -0,0 +1,184 @@
|
||||
import type { ReactNode } from "react";
|
||||
import { AlertTriangle, CheckCircle2, Lock, Ticket } from "lucide-react";
|
||||
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
type HallDesktopWorkflowBarProps = {
|
||||
gameControls: ReactNode;
|
||||
fillControls: ReactNode;
|
||||
reviewControls: ReactNode;
|
||||
stepGame: string;
|
||||
stepFill: string;
|
||||
stepReview: string;
|
||||
};
|
||||
|
||||
export function HallDesktopWorkflowBar({
|
||||
gameControls,
|
||||
fillControls,
|
||||
reviewControls,
|
||||
stepGame,
|
||||
stepFill,
|
||||
stepReview,
|
||||
}: HallDesktopWorkflowBarProps) {
|
||||
const steps = [
|
||||
{ label: stepGame, content: gameControls },
|
||||
{ label: stepFill, content: fillControls },
|
||||
{ label: stepReview, content: reviewControls },
|
||||
];
|
||||
|
||||
return (
|
||||
<div className="hidden overflow-hidden rounded-xl border border-[#dfe8f5] bg-white shadow-[0_8px_24px_rgba(15,23,42,0.04)] lg:grid lg:grid-cols-[minmax(10rem,0.8fr)_minmax(16rem,1.5fr)_minmax(10rem,0.65fr)] xl:grid-cols-[minmax(15rem,0.8fr)_minmax(24rem,1.5fr)_minmax(13rem,0.65fr)]">
|
||||
{steps.map((step, index) => (
|
||||
<section
|
||||
key={step.label}
|
||||
className={cn(
|
||||
"min-w-0 px-4 py-3",
|
||||
index > 0 && "border-l border-[#e7edf6]",
|
||||
)}
|
||||
>
|
||||
<div className="mb-2 flex items-center gap-2">
|
||||
<span className="inline-flex size-6 shrink-0 items-center justify-center rounded-full bg-[#eaf2ff] text-xs font-black text-[#1658c4]">
|
||||
{index + 1}
|
||||
</span>
|
||||
<h2 className="text-sm font-black text-[#23395f]">{step.label}</h2>
|
||||
</div>
|
||||
{step.content}
|
||||
</section>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export type HallDesktopReviewModel = {
|
||||
lineCount: number;
|
||||
providerCount: number;
|
||||
actualAmount: string;
|
||||
availableCredit: string;
|
||||
remainingCredit: string;
|
||||
warningCount: number;
|
||||
creditSufficient: boolean;
|
||||
};
|
||||
|
||||
type HallDesktopReviewPanelProps = {
|
||||
model: HallDesktopReviewModel;
|
||||
labels: {
|
||||
title: string;
|
||||
lineCount: string;
|
||||
providerCount: string;
|
||||
actualTotal: string;
|
||||
availableCredit: string;
|
||||
remainingCredit: string;
|
||||
noWarnings: string;
|
||||
warningCount: string;
|
||||
creditEnough: string;
|
||||
creditInsufficient: string;
|
||||
submit: string;
|
||||
};
|
||||
disabled: boolean;
|
||||
loading: boolean;
|
||||
isBettable: boolean;
|
||||
onSubmit: () => void;
|
||||
};
|
||||
|
||||
export function HallDesktopReviewPanel({
|
||||
model,
|
||||
labels,
|
||||
disabled,
|
||||
loading,
|
||||
isBettable,
|
||||
onSubmit,
|
||||
}: HallDesktopReviewPanelProps) {
|
||||
return (
|
||||
<aside className="w-full shrink-0 self-start overflow-hidden rounded-xl border border-[#dfe8f5] bg-white text-[#304f86] shadow-[0_8px_24px_rgba(15,23,42,0.05)] min-[1500px]:sticky min-[1500px]:top-3 min-[1500px]:w-80">
|
||||
<div className="border-b border-[#e7edf6] bg-[#f7faff] px-4 py-3.5">
|
||||
<p className="text-[15px] font-black text-[#20385f]">{labels.title}</p>
|
||||
</div>
|
||||
|
||||
<div className="grid gap-3 p-4 lg:grid-cols-[repeat(4,minmax(0,1fr))_auto] lg:items-center min-[1500px]:block min-[1500px]:space-y-4">
|
||||
<dl className="grid grid-cols-2 gap-x-5 gap-y-3 lg:contents min-[1500px]:grid">
|
||||
<div>
|
||||
<dt className="text-xs font-semibold text-slate-500">{labels.lineCount}</dt>
|
||||
<dd className="mt-1 font-mono text-lg font-black tabular-nums text-[#143f86]">
|
||||
{model.lineCount}
|
||||
</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt className="text-xs font-semibold text-slate-500">{labels.providerCount}</dt>
|
||||
<dd className="mt-1 font-mono text-lg font-black tabular-nums text-[#143f86]">
|
||||
{model.providerCount}
|
||||
</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt className="text-xs font-semibold text-slate-500">{labels.availableCredit}</dt>
|
||||
<dd className="mt-1 text-sm font-black tabular-nums text-[#143f86]">
|
||||
{model.availableCredit}
|
||||
</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt className="text-xs font-semibold text-slate-500">{labels.remainingCredit}</dt>
|
||||
<dd className="mt-1 text-sm font-black tabular-nums text-[#143f86]">
|
||||
{model.remainingCredit}
|
||||
</dd>
|
||||
</div>
|
||||
</dl>
|
||||
|
||||
<div className="rounded-lg border border-[#d8e5f7] bg-[#f7fbff] px-3 py-2.5 lg:min-w-36 min-[1500px]:px-4 min-[1500px]:py-3.5">
|
||||
<p className="text-xs font-semibold text-slate-500">{labels.actualTotal}</p>
|
||||
<p className="mt-1 text-lg font-black tabular-nums text-[#0b3f96] min-[1500px]:text-2xl">
|
||||
{model.actualAmount}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2 lg:min-w-48 min-[1500px]:border-t min-[1500px]:border-[#e7edf6] min-[1500px]:pt-4">
|
||||
<div
|
||||
className={cn(
|
||||
"flex items-center gap-2 text-xs font-bold",
|
||||
model.creditSufficient ? "text-emerald-700" : "text-red-600",
|
||||
)}
|
||||
>
|
||||
{model.creditSufficient ? (
|
||||
<CheckCircle2 className="size-4 shrink-0" aria-hidden />
|
||||
) : (
|
||||
<AlertTriangle className="size-4 shrink-0" aria-hidden />
|
||||
)}
|
||||
<span>{model.creditSufficient ? labels.creditEnough : labels.creditInsufficient}</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-2 text-xs font-semibold text-slate-500">
|
||||
{model.warningCount > 0 ? (
|
||||
<AlertTriangle className="size-4 shrink-0 text-amber-600" aria-hidden />
|
||||
) : (
|
||||
<CheckCircle2 className="size-4 shrink-0 text-slate-400" aria-hidden />
|
||||
)}
|
||||
<span>
|
||||
{model.warningCount > 0
|
||||
? labels.warningCount
|
||||
: labels.noWarnings}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="lg:min-w-52 min-[1500px]:border-t min-[1500px]:border-[#e7edf6] min-[1500px]:pt-4">
|
||||
<Button
|
||||
type="button"
|
||||
disabled={disabled || loading}
|
||||
onClick={onSubmit}
|
||||
className={cn(
|
||||
"h-11 w-full gap-2 rounded-lg border-0 text-sm font-black text-white",
|
||||
!isBettable
|
||||
? "bg-slate-500 shadow-none hover:bg-slate-500 disabled:opacity-100"
|
||||
: "bg-[#e5002c] shadow-[0_8px_20px_rgba(229,0,44,0.24)] hover:bg-[#d10028]",
|
||||
)}
|
||||
>
|
||||
{!isBettable ? (
|
||||
<Lock className="size-4 shrink-0" aria-hidden />
|
||||
) : (
|
||||
<Ticket className="size-4 shrink-0" aria-hidden />
|
||||
)}
|
||||
{labels.submit}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user