feature/quiz-mode #4
4 changed files with 31 additions and 3 deletions
12
apps/web/src/components/avatar.tsx
Normal file
12
apps/web/src/components/avatar.tsx
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
/** Avatar DiceBear (style lorelei), seedé par le pseudo → stable et reconnaissable. */
|
||||
export function Avatar({ seed, className }: { seed: string; className?: string }) {
|
||||
const url = `https://api.dicebear.com/9.x/lorelei/svg?seed=${encodeURIComponent(seed)}`
|
||||
return (
|
||||
<img
|
||||
src={url}
|
||||
alt={`Avatar de ${seed}`}
|
||||
loading="lazy"
|
||||
className={`bg-muted shrink-0 rounded-full ${className ?? ""}`}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
|
@ -4,6 +4,7 @@ import { Crown } from "lucide-react"
|
|||
import type { PlayerScore, RoomSnapshot } from "@nerdware/shared"
|
||||
import { Button } from "@workspace/ui/components/button"
|
||||
import { useRoomStore } from "@/store/room"
|
||||
import { Avatar } from "@/components/avatar"
|
||||
|
||||
export function GameEndView({ snapshot }: { snapshot: RoomSnapshot }) {
|
||||
const playerId = useRoomStore((s) => s.playerId)
|
||||
|
|
@ -53,12 +54,17 @@ export function GameEndView({ snapshot }: { snapshot: RoomSnapshot }) {
|
|||
initial={{ y: -28, rotate: -25, opacity: 0 }}
|
||||
animate={{ y: 0, rotate: 0, opacity: 1 }}
|
||||
transition={{ type: "spring", stiffness: 500, damping: 14, delay: 0.2 }}
|
||||
className="absolute -top-5"
|
||||
className="absolute -top-5 z-10"
|
||||
>
|
||||
<Crown className="size-9 fill-amber-400 text-amber-400 drop-shadow" />
|
||||
</motion.span>
|
||||
|
||||
<span className="font-heading mt-2 text-xl font-bold text-balance">
|
||||
<Avatar
|
||||
seed={nameOf(winner.playerId)}
|
||||
className="size-20 ring-2 ring-amber-400"
|
||||
/>
|
||||
|
||||
<span className="font-heading mt-1 text-xl font-bold text-balance">
|
||||
{nameOf(winner.playerId)}
|
||||
{isMe(winner.playerId) && (
|
||||
<span className="text-muted-foreground text-sm"> (toi)</span>
|
||||
|
|
@ -86,6 +92,7 @@ export function GameEndView({ snapshot }: { snapshot: RoomSnapshot }) {
|
|||
<span className="text-muted-foreground w-5 text-right tabular-nums">
|
||||
{i + 2}
|
||||
</span>
|
||||
<Avatar seed={nameOf(s.playerId)} className="size-7" />
|
||||
<span>
|
||||
{nameOf(s.playerId)}
|
||||
{isMe(s.playerId) && (
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import { useState } from "react"
|
|||
import type { RoomSnapshot } from "@nerdware/shared"
|
||||
import { Button } from "@workspace/ui/components/button"
|
||||
import { useRoomStore } from "@/store/room"
|
||||
import { Avatar } from "@/components/avatar"
|
||||
|
||||
const QUESTION_OPTIONS = [3, 5, 10]
|
||||
|
||||
|
|
@ -38,7 +39,10 @@ export function LobbyView({ snapshot }: { snapshot: RoomSnapshot }) {
|
|||
key={p.id}
|
||||
className="bg-muted/40 flex items-center justify-between rounded-md px-3 py-2 text-sm"
|
||||
>
|
||||
<span className={p.connected ? "" : "opacity-40"}>
|
||||
<span
|
||||
className={`flex items-center gap-2 ${p.connected ? "" : "opacity-40"}`}
|
||||
>
|
||||
<Avatar seed={p.name} className="size-7" />
|
||||
{p.name}
|
||||
{p.id === playerId && (
|
||||
<span className="text-muted-foreground"> (toi)</span>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import { AnimatePresence, motion } from "framer-motion"
|
||||
import { Check, Crown } from "lucide-react"
|
||||
import type { RoomSnapshot } from "@nerdware/shared"
|
||||
import { Avatar } from "@/components/avatar"
|
||||
|
||||
interface PlayerCardsProps {
|
||||
snapshot: RoomSnapshot
|
||||
|
|
@ -58,6 +59,10 @@ export function PlayerCards({
|
|||
<Crown className="size-4 fill-amber-400" />
|
||||
</motion.span>
|
||||
)}
|
||||
<Avatar
|
||||
seed={p.name}
|
||||
className={`size-9 ${isLeader ? "ring-2 ring-amber-400" : ""}`}
|
||||
/>
|
||||
<span className="max-w-24 truncate text-xs font-medium">
|
||||
{p.name}
|
||||
{isMe && <span className="text-muted-foreground"> (toi)</span>}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue