[feat] number-ball #1
@@ -69,6 +69,7 @@ export default function Page() {
|
|||||||
number={n}
|
number={n}
|
||||||
state={actions.getBallState(n)}
|
state={actions.getBallState(n)}
|
||||||
colorIndex={actions.getBallColorIndex(n)}
|
colorIndex={actions.getBallColorIndex(n)}
|
||||||
|
dimmed={actions.getBallDimmed(n)}
|
||||||
size="large"
|
size="large"
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
|
|||||||
+15
-4
@@ -88,6 +88,7 @@ export interface RollCallActions {
|
|||||||
clearResult: () => void
|
clearResult: () => void
|
||||||
getBallState: (n: number) => "idle" | "highlighted" | "used"
|
getBallState: (n: number) => "idle" | "highlighted" | "used"
|
||||||
getBallColorIndex: (n: number) => number | undefined
|
getBallColorIndex: (n: number) => number | undefined
|
||||||
|
getBallDimmed: (n: number) => boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export const COLORS = [
|
export const COLORS = [
|
||||||
@@ -112,7 +113,7 @@ export const COLORS = [
|
|||||||
|
|
||||||
export function useRollCallLogic(): [RollCallState, RollCallActions] {
|
export function useRollCallLogic(): [RollCallState, RollCallActions] {
|
||||||
const [mode, setMode] = useState<Mode>("single")
|
const [mode, setMode] = useState<Mode>("single")
|
||||||
const [totalTasks, setTotalTasks] = useState(20)
|
const [totalTasks, setTotalTasks] = useState(35)
|
||||||
const [pickCount, setPickCount] = useState(1)
|
const [pickCount, setPickCount] = useState(1)
|
||||||
const [rounds, setRounds] = useState(1)
|
const [rounds, setRounds] = useState(1)
|
||||||
const [allowRepeat, setAllowRepeat] = useState(false)
|
const [allowRepeat, setAllowRepeat] = useState(false)
|
||||||
@@ -251,14 +252,15 @@ export function useRollCallLogic(): [RollCallState, RollCallActions] {
|
|||||||
|
|
||||||
const getBallState = useCallback((n: number): "idle" | "highlighted" | "used" => {
|
const getBallState = useCallback((n: number): "idle" | "highlighted" | "used" => {
|
||||||
if (mode === "single") {
|
if (mode === "single") {
|
||||||
const isInRecords = selectedRecords.some(r => r.number === n)
|
// Only highlight current round's selections
|
||||||
if (isInRecords) return "highlighted"
|
const isCurrentRound = singleHighlighted.includes(n)
|
||||||
|
if (isCurrentRound) return "highlighted"
|
||||||
return "idle"
|
return "idle"
|
||||||
}
|
}
|
||||||
if (highlighted.has(n)) return "highlighted"
|
if (highlighted.has(n)) return "highlighted"
|
||||||
if (hasResult && usedAll.size > 0 && !usedAll.has(n)) return "used"
|
if (hasResult && usedAll.size > 0 && !usedAll.has(n)) return "used"
|
||||||
return "idle"
|
return "idle"
|
||||||
}, [mode, selectedRecords, highlighted, hasResult, usedAll])
|
}, [mode, singleHighlighted, highlighted, hasResult, usedAll])
|
||||||
|
|
||||||
const getBallColorIndex = useCallback((n: number): number | undefined => {
|
const getBallColorIndex = useCallback((n: number): number | undefined => {
|
||||||
if (mode === "single") {
|
if (mode === "single") {
|
||||||
@@ -275,6 +277,14 @@ export function useRollCallLogic(): [RollCallState, RollCallActions] {
|
|||||||
return undefined
|
return undefined
|
||||||
}, [mode, selectedRecords, groups])
|
}, [mode, selectedRecords, groups])
|
||||||
|
|
||||||
|
const getBallDimmed = useCallback((n: number): boolean => {
|
||||||
|
// Only dim in single mode when there are highlighted numbers
|
||||||
|
if (mode === "single" && singleHighlighted.length > 0) {
|
||||||
|
return !singleHighlighted.includes(n)
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}, [mode, singleHighlighted])
|
||||||
|
|
||||||
const state: RollCallState = {
|
const state: RollCallState = {
|
||||||
mode,
|
mode,
|
||||||
totalTasks,
|
totalTasks,
|
||||||
@@ -308,6 +318,7 @@ export function useRollCallLogic(): [RollCallState, RollCallActions] {
|
|||||||
clearResult,
|
clearResult,
|
||||||
getBallState,
|
getBallState,
|
||||||
getBallColorIndex,
|
getBallColorIndex,
|
||||||
|
getBallDimmed,
|
||||||
}
|
}
|
||||||
|
|
||||||
return [state, actions]
|
return [state, actions]
|
||||||
|
|||||||
@@ -8,19 +8,23 @@ interface NumberBallProps {
|
|||||||
state: "idle" | "highlighted" | "used"
|
state: "idle" | "highlighted" | "used"
|
||||||
colorIndex?: number
|
colorIndex?: number
|
||||||
size?: "normal" | "large"
|
size?: "normal" | "large"
|
||||||
|
dimmed?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export function NumberBall({ number, state, colorIndex, size = "normal" }: NumberBallProps) {
|
export function NumberBall({ number, state, colorIndex, size = "normal", dimmed = false }: NumberBallProps) {
|
||||||
const isHighlighted = state === "highlighted"
|
const isHighlighted = state === "highlighted"
|
||||||
const borderColor = isHighlighted && colorIndex !== undefined
|
const hasColor = colorIndex !== undefined
|
||||||
|
|
||||||
|
const borderColor = hasColor
|
||||||
? COLORS[colorIndex]
|
? COLORS[colorIndex]
|
||||||
: state === "idle" ? "#e2e6ea"
|
: state === "idle" ? "#e2e6ea"
|
||||||
: "#eef0f2"
|
: "#eef0f2"
|
||||||
const bgColor = isHighlighted && colorIndex !== undefined
|
const bgColor = isHighlighted && hasColor
|
||||||
? COLORS[colorIndex]
|
? COLORS[colorIndex]
|
||||||
: "transparent"
|
: "transparent"
|
||||||
const textColor = isHighlighted && colorIndex !== undefined
|
const textColor = isHighlighted && hasColor
|
||||||
? "#ffffff"
|
? "#ffffff"
|
||||||
|
: hasColor ? COLORS[colorIndex]
|
||||||
: state === "idle" ? "#8a95a1"
|
: state === "idle" ? "#8a95a1"
|
||||||
: "#cdd2d8"
|
: "#cdd2d8"
|
||||||
|
|
||||||
@@ -30,6 +34,7 @@ export function NumberBall({ number, state, colorIndex, size = "normal" }: Numbe
|
|||||||
"flex items-center justify-center font-mono select-none transition-all duration-150",
|
"flex items-center justify-center font-mono select-none transition-all duration-150",
|
||||||
size === "normal" && "w-8 h-8 text-sm",
|
size === "normal" && "w-8 h-8 text-sm",
|
||||||
size === "large" && "w-14 h-14 text-lg",
|
size === "large" && "w-14 h-14 text-lg",
|
||||||
|
dimmed && !isHighlighted && "opacity-30",
|
||||||
)}
|
)}
|
||||||
style={{
|
style={{
|
||||||
border: `1px solid ${borderColor}`,
|
border: `1px solid ${borderColor}`,
|
||||||
|
|||||||
@@ -8,13 +8,7 @@ interface SingleModePanelProps {
|
|||||||
|
|
||||||
export function SingleModePanel({ singleBatches }: SingleModePanelProps) {
|
export function SingleModePanel({ singleBatches }: SingleModePanelProps) {
|
||||||
if (singleBatches.length === 0) {
|
if (singleBatches.length === 0) {
|
||||||
return (
|
return null
|
||||||
<div className="flex flex-col items-center justify-center h-12 gap-3">
|
|
||||||
<div className="text-[10px] tracking-[0.2em] text-[#cdd2d8] font-mono uppercase">
|
|
||||||
— AWAITING INPUT —
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reverse to show newest first
|
// Reverse to show newest first
|
||||||
|
|||||||
Reference in New Issue
Block a user