// Raw User Pile Panel // Purpose: Defines the Raw User Pile Panel module and the local helpers/components used in this file. // Scope: Keeps behavior unchanged while isolating this concern into a clear, single-responsibility unit. import { useMemo } from 'react'; import { useSessionSelector } from '../../context/SessionContext.jsx'; import NicknameForm from '../NicknameForm/index.jsx'; import SocialButtonsGrid from '../SocialButtonsGrid/index.jsx'; import CardFrame from '../CardFrame/index.jsx'; function roleColors(role) { switch (role) { case 'admin': case 'lockdown': return 'text-amber-300'; case 'spectator': return 'text-slate-400'; default: return 'text-sky-300'; } } function formatLabel(user, selfId) { if (!user) return ''; const base = user.nickname || user.socketId?.slice(0, 6) || 'unknown'; if (user.socketId && user.socketId === selfId) { return `${base} (you)`; } return base; } export default function RawUserPilePanel({ hideNicknameForm = false, hideHeader = false, className = '', fillHeight = false, compact = false, }) { const users = useSessionSelector((state) => state.session?.users ?? []); const selfId = useSessionSelector((state) => state.session?.socketId || null); const sorted = useMemo( () => [...users].sort((a, b) => { if (a.socketId === selfId) return -1; if (b.socketId === selfId) return 1; return (a.nickname || '').localeCompare(b.nickname || ''); }), [selfId, users], ); const baseListClass = fillHeight ? 'flex-1 min-h-0 overflow-y-auto' : compact ? 'h-28 overflow-y-auto' : 'h-48 overflow-y-auto'; return ( {!hideNicknameForm && (
{/* Keep identity and social controls stacked until this card itself is wide enough; the viewport says nothing about a sidebar's width. */}
)}
{sorted.length === 0 ? (

Waiting for users…

) : ( sorted.map((user) => ( {formatLabel(user, selfId)} )) )}
); }