Gold is the primary in both themes, Bricolage Grotesque carries the wordmark, titles and the score, and Movie A / Movie B wear the blue and magenta of three-strip Technicolor on their posters instead of colouring whole rows. The loop closes on screen - connectors light, a gold line draws back to Movie A, the row glows, then the result arrives - in place of confetti, on every play mode, scaled to the chain's length. Every page shares one header and hairline lists; copy is sentence case with one verb per flow, and the Home hero shows a real finished loop. Also clamps link counts at zero: an opponent who had not moved yet showed "-1 links".
72 lines
2.3 KiB
TypeScript
72 lines
2.3 KiB
TypeScript
import { useHints } from '@/hooks/use-hints';
|
||
import { useChainValidation } from '@/hooks/use-chain-validation';
|
||
import { profileUrl } from '@/lib/tmdb';
|
||
import { Button } from '@/components/ui/button';
|
||
import { Lightbulb, Loader2 } from 'lucide-react';
|
||
import type { TmdbPersonResult } from '@/types';
|
||
|
||
export default function HintButton() {
|
||
const { hints, isLoading, getHint, clearHints, canHint, hintsUsed, maxHints } =
|
||
useHints();
|
||
const { validateAndAddActor } = useChainValidation();
|
||
|
||
const handleSelectHint = (member: { id: number; name: string; profile_path: string | null; popularity: number; known_for_department: string }) => {
|
||
clearHints();
|
||
// Convert cast member to TmdbPersonResult shape for validation
|
||
const person: TmdbPersonResult = {
|
||
id: member.id,
|
||
name: member.name,
|
||
profile_path: member.profile_path,
|
||
popularity: member.popularity,
|
||
known_for_department: member.known_for_department,
|
||
known_for: [],
|
||
adult: false,
|
||
};
|
||
validateAndAddActor(person);
|
||
};
|
||
|
||
const remaining = maxHints - hintsUsed;
|
||
|
||
return (
|
||
<div className="space-y-2">
|
||
<Button
|
||
variant="outline"
|
||
size="sm"
|
||
onClick={getHint}
|
||
disabled={!canHint}
|
||
>
|
||
{isLoading ? (
|
||
<Loader2 className="mr-1 h-3.5 w-3.5 animate-spin" />
|
||
) : (
|
||
<Lightbulb className="mr-1 h-3.5 w-3.5" />
|
||
)}
|
||
Hint ({remaining} left)
|
||
<span className="ml-1 text-xs text-muted-foreground">−200</span>
|
||
</Button>
|
||
|
||
{hints.length > 0 && (
|
||
<div className="flex flex-wrap gap-2">
|
||
{hints.map((member) => (
|
||
<button
|
||
key={member.id}
|
||
type="button"
|
||
className="flex items-center gap-2 rounded-md bg-card px-2 py-1.5 text-left ring-1 ring-foreground/10 transition-colors hover:bg-accent"
|
||
onClick={() => handleSelectHint(member)}
|
||
>
|
||
<img
|
||
src={
|
||
profileUrl(member.profile_path, 'w45') ||
|
||
'/placeholder-person.svg'
|
||
}
|
||
alt={member.name}
|
||
className="h-8 w-8 shrink-0 rounded-full object-cover"
|
||
/>
|
||
<span className="text-sm font-medium">{member.name}</span>
|
||
</button>
|
||
))}
|
||
</div>
|
||
)}
|
||
</div>
|
||
);
|
||
}
|