// Call UI components — Discord-style, matched to Clean-Rail aesthetic const CALL_PARTICIPANTS = [ { id: 'dennis', name: 'dennis', initial: 'D', color: 'teal', speaking: false, muted: false, video: false, me: true, e2ee: true }, { id: 'max', name: 'Max', initial: 'M', color: 'teal', speaking: true, muted: false, video: true, sharing: true, e2ee: true }, { id: 'lena', name: 'Lena', initial: 'L', color: 'amber', speaking: false, muted: true, video: false, e2ee: true }, { id: 'tom', name: 'Tom', initial: 'T', color: 'violet', speaking: false, muted: false, video: false, e2ee: true }, { id: 'nico', name: 'nico', initial: 'N', color: 'teal', speaking: true, muted: false, video: false, e2ee: true }, ]; const ParticipantTile = ({ p, focused, onClick, small }) => (
{p.video || p.sharing ? (
{p.sharing ? (
{p.name} teilt Bildschirm
) : (
)}
) : (
)}
{p.me && } {p.name}{p.me ? ' (du)' : ''} {p.e2ee && }
{p.muted && } {p.sharing && }
); const CallControls = ({ muted, onToggleMute, sharing, onToggleShare, video, onToggleVideo, onHangup, compact }) => (
); const IncomingCallScreen = ({ chat, onAccept, onDecline }) => (
Eingehender Anruf
{chat.name}
E2E verschlüsselt · Voice Call
); const ActiveCallScreen = ({ participants, mode, setMode, focused, setFocused, onHangup, callState, setCallState }) => { const speaker = participants.find(p => p.id === focused) || participants.find(p => p.sharing) || participants[0]; const others = participants.filter(p => p.id !== speaker.id); const sharingParticipant = participants.find(p => p.sharing); return (
Die Squad · {callState.duration}
E2E verschlüsselt
{mode === 'grid' && (
{participants.map(p => ( { setFocused(p.id); setMode('focus'); }} /> ))}
)} {mode === 'focus' && (
{others.map(p => ( setFocused(p.id)} /> ))}
)} {mode === 'fullscreen' && (
{others.slice(0,4).map(p => ( setFocused(p.id)} /> ))}
Esc zum Verlassen
)}
setCallState(s => ({...s, muted: !s.muted}))} sharing={callState.sharing} onToggleShare={() => setCallState(s => ({...s, sharing: !s.sharing}))} video={callState.video} onToggleVideo={() => setCallState(s => ({...s, video: !s.video}))} onHangup={onHangup} />
); }; const PipCall = ({ onExpand, onHangup, participants }) => { const speaker = participants.find(p => p.sharing) || participants.find(p => p.speaking) || participants[0]; return (
{speaker.sharing ? (
) : ( )}
Die Squad · {participants.length}
Live · tippe zum Öffnen
); }; Object.assign(window, { CALL_PARTICIPANTS, ParticipantTile, CallControls, IncomingCallScreen, ActiveCallScreen, PipCall });