Files
movieloop-frontend/src/components/game/HintButton.tsx
T
TehRiehlDeal 8d0b7f39ee feat(ui): give the app one visual identity as Movie Loop
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".
2026-09-12 22:42:55 -07:00

72 lines
2.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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>
);
}