Files
roll-call/app/page.tsx
T
2026-06-16 19:15:56 +08:00

143 lines
5.7 KiB
TypeScript

"use client"
import { Matrix } from "@/components/matrix"
import { SettingsPanel } from "@/components/settings"
import { ResultPanel } from "@/components/group-result"
import { SingleModePanel } from "@/components/single-panel"
import { TitleBar } from "@/components/title-bar"
import { useRollCallLogic } from "@/components/logic"
import { useEffect } from "react"
export default function Page() {
const [state, actions] = useRollCallLogic()
const isSingleMode = state.mode === "single"
// 禁用右键菜单
useEffect(() => {
const handleContextMenu = (e: MouseEvent) => {
e.preventDefault()
}
document.addEventListener('contextmenu', handleContextMenu)
return () => {
document.removeEventListener('contextmenu', handleContextMenu)
}
}, [])
return (
<div className="h-screen w-full bg-[#0f141a] text-[#16191f] font-mono flex flex-col overflow-hidden">
{/* Custom title bar */}
<TitleBar />
{/* Main content */}
<div className="flex-1 bg-[#ffffff] flex flex-col lg:flex-row overflow-hidden">
{/* Left sidebar — config (fixed width, full height) */}
<aside className="w-full lg:w-72 flex-shrink-0 border-b lg:border-b-0 lg:border-r border-[#e2e6ea] bg-[#f7f8fa] overflow-y-auto scrollbar-thin">
<div className="p-5">
<SettingsPanel
mode={state.mode}
totalTasks={state.totalTasks}
pickCount={state.pickCount}
rounds={state.rounds}
allowRepeat={state.allowRepeat}
singleAllowRepeat={state.singleAllowRepeat}
selectedRecords={state.selectedRecords}
onModeChange={actions.setMode}
onTotalTasksChange={actions.setTotalTasks}
onPickCountChange={actions.setPickCount}
onRoundsChange={actions.setRounds}
onAllowRepeatChange={actions.setAllowRepeat}
onSingleAllowRepeatChange={actions.setSingleAllowRepeat}
onRoll={isSingleMode ? actions.handleSingleRoll : actions.handleRoll}
onReset={actions.resetSingle}
isRolling={state.isRolling}
errorMsg={state.errorMsg}
/>
</div>
</aside>
{/* Right content — fills remaining space */}
<main className="flex-1 flex flex-col min-w-0 min-h-0">
{/* Single mode: Full height matrix with records */}
{isSingleMode ? (
<>
{/* Matrix area - full width, dynamic centering */}
<section className="flex flex-col flex-1 min-h-0">
<div className="flex items-center gap-3 px-5 py-2.5 border-b border-[#e2e6ea] flex-shrink-0">
<span className="text-[10px] tracking-[0.2em] uppercase text-[#8a95a1]">MATRIX</span>
<span className="flex-1 h-px bg-[#e2e6ea]" />
{state.selectedRecords.length > 0 && (
<span className="text-[10px] text-[#0f141a]">
{state.selectedRecords.length} SELECTED
</span>
)}
</div>
<div className="flex-1 flex items-center justify-center overflow-auto scrollbar-thin p-3">
<Matrix
total={state.totalTasks}
getBallState={actions.getBallState}
getBallColorIndex={actions.getBallColorIndex}
getBallDimmed={actions.getBallDimmed}
size="xlarge"
/>
</div>
</section>
{/* Single mode records panel */}
<section className="flex flex-col border-t border-[#e2e6ea] max-h-[35vh]">
<SingleModePanel singleBatches={state.singleBatches} />
</section>
</>
) : (
<>
{/* Group mode: Matrix grid */}
<section className="flex flex-col flex-shrink-0 border-b border-[#e2e6ea]">
<div className="flex items-center gap-3 px-5 py-2.5 border-b border-[#e2e6ea]">
<span className="text-[10px] tracking-[0.2em] uppercase text-[#8a95a1]">MATRIX</span>
<span className="flex-1 h-px bg-[#e2e6ea]" />
{state.hasResult && (
<span className="text-[10px] text-[#0f141a]">
{state.highlighted.size} SELECTED
</span>
)}
</div>
<div className="p-3 max-h-[40vh] overflow-y-auto scrollbar-thin">
<Matrix
total={state.totalTasks}
getBallState={actions.getBallState}
getBallColorIndex={actions.getBallColorIndex}
getBallDimmed={actions.getBallDimmed}
size="large"
/>
</div>
</section>
{/* Group mode result panel */}
<section className="flex flex-col flex-1 min-h-0">
<div className="flex items-center gap-3 px-4 py-2.5 border-b border-[#e2e6ea] flex-shrink-0">
<span className="text-[10px] tracking-[0.2em] uppercase text-[#8a95a1]">OUTPUT</span>
<span className="flex-1 h-px bg-[#e2e6ea]" />
{state.hasResult && state.groups.length > 0 && (
<button
onClick={actions.clearResult}
className="text-[10px] text-[#8a95a1] hover:text-[#16191f] transition-colors tracking-widest uppercase"
>
CLEAR
</button>
)}
</div>
<div className="flex-1 overflow-y-auto scrollbar-thin px-4 py-3">
<ResultPanel groups={state.groups} hasResult={state.hasResult} />
</div>
</section>
</>
)}
</main>
</div>
</div>
)
}