Appearance
Participants Panel Component Documentation
File: src/components/app/call/participants.svelte
Overview
This comprehensive component manages participant interactions in a video conferencing application, combining participant management, chat functionality, and device control in a single panel. It serves as the central hub for all participant-related actions during a call.
Key Features
Participant Management:
- View all call participants with profile information
- Mute/unmute audio and video
- Pin/unpin participants
- Raise/lower hands
- Set host/guest roles
- Remove participants
Integrated Chat System:
- Group chat with all participants
- Private messaging
- Unread message indicators
Device & Participant Addition:
- Add participants by name or email
- Connect Headet device to the call
- Rapid Connect functionality
Detailed Views:
- Participant details modal
- User selection for Headset device authentication
- Collapsible sections for better mobile experience
Component Structure
Module Context (Utility Functions)
typescript
// Participant spotlight controls
export function pin(pexip: PexipClient, participant)
export function unpin(pexip: PexipClient, participant)
export function toggleSpotlight(pexip: PexipClient, participant: IParticipant)
// Hand raising controls
export function lowerHand(pexip: PexipClient, participant)
export function raiseHand(pexip: PexipClient, participant)
export function toggleHand(pexip: PexipClient, participant: IParticipant)
// Audio controls
export function mute(pexip: PexipClient, participant)
export function unmute(pexip: PexipClient, participant)
export function toggleAudio(pexip: PexipClient, participant)
// Video controls
export function muteVideo(pexip: PexipClient, participant)
export function unmuteVideo(pexip: PexipClient, participant)
export function toggleVideo(pexip: PexipClient, participant)
// Participant management
export function remove(pexip: PexipClient, participant: IParticipant)
export function setAsGuest(pexip: PexipClient, participant: IParticipant)
export function setAsHost(pexip: PexipClient, participant: IParticipant)
// Search functions
export async function getContactSearch(filter: string)
export async function getDeviceSearch()
// Call addition functions
export async function summonDevice(eventId, tenantDeviceId, userId?)
export async function addToCall(eventId, contactId?, email?, joinCode?)
export async function addDeviceToCall(eventId, deviceId?, joinCode?, userId?)Props
typescript
export let data = []; // Participant data array
export let contacts = []; // User contacts list
export let event; // Current event data
export let me: IParticipant; // Current user participant data
export let pexip: PexipClient; // Pexip client instance
export let cnt; // Participant count
export let canAddParticipants = true; // Add participants permission
export let rapidUser: any = null; // Rapid user data
export let readonly = false; // Read-only mode flagState Management
typescript
// UI state
let showParticipants = false;
let hideContactDetails = false;
let showChatView = false;
let showSearchBox = false;
let showSubMenu = false;
let showSelectUser = false;
// Data state
let inputValue;
let unreadMessageCount = 0;
let participants = [];
let activeContact;
let chatContactList = [];
let addContactFilter = "";
let addDeviceFilter = "";
let searchContacts = [];
let contactSearchError = "";
let deviceItems = [];
let summondData = {
eventId: null,
userId: null,
tenantDeviceId: null,
deviceName: ""
};
// Computed properties
$: nonStreamingParticipants = participants.filter(x => !x.is_streaming_conference);
$: user = rapidUser ? rapidUser : $userInfo;
$: activeGroup = { id: event?.id, kind: "event" };UI Components
Main Panel Structure
svelte
<div class="h-full flex flex-col bg-white border-l border-gray-200">
<!-- Header section -->
<div class="flex justify-between border-b p-2">
<span class="text-lg">Participants</span>
<div class="flex gap-2 text-gray-600">
<button on:click={() => dispatch("close")}>
<Icon src={Close} size="20" />
</button>
</div>
</div>
<!-- Participants section -->
<div>
<div class="flex justify-between px-2">
<span>Participants ({data.length})</span>
<div class="flex gap-2">
<button on:click={() => (showSearchBox = !showSearchBox)}>
<Icon src={Search} size="15" />
</button>
<button on:click={() => (showParticipants = !showParticipants)}>
<Icon src={showParticipants ? ArrowUpS : ArrowDownS} size="18" />
</button>
</div>
</div>
</div>
<!-- Participant list and controls -->
{#if showParticipants}
<div class="m-2 flex flex-col">
<!-- Add participant/device forms -->
<Form>
<SelectInput name="participants" ... />
<SelectInput name="devices" ... />
</Form>
<!-- Participant list -->
<ul class="max-h-full rounded-md border-t mt-1 divide-y divide-gray-200">
{#each participants as participant}
<!-- Participant item with controls -->
{/each}
</ul>
</div>
{/if}
<!-- Chat section -->
<div class="flex flex-col flex-grow overflow-y-hidden">
<div class="flex justify-between border-b p-2">
<span>Chat {#if unreadMessageCount}({unreadMessageCount}){/if}</span>
<button on:click={toggleChatView}>
<Icon src={showChatView ? ArrowUpS : ArrowDownS} size="17" />
</button>
</div>
{#if showChatView}
<MessageList ... />
{/if}
</div>
</div>Participant Item Controls
Each participant item includes:
- Profile image/initials
- Name and specialty
- Interactive controls:
- Pin/unpin
- Raise/lower hand
- Mute/unmute audio
- Mute/unmute video
- Admin indicators
- Overflow menu with additional actions
Modals
Contact Details Modal:
- Shows detailed participant information
- Triggered by clicking "View Details"
User Selection Modal:
- Appears when device requires user authentication
- Allows selecting a user to authorize device connection
Technical Implementation
Data Flow
Participant Data Processing:
- Filters and maps raw participant data
- Enriches with contact information
- Computes display properties (initials, status)
Search Functionality:
- Debounced contact search
- Device search with online status
- Custom filtering for emails and join codes
Event Handling
Participant Actions:
- Wrapped in
pexechelper for error handling - Dispatched to Pexip client
- Visual feedback via toast notifications
- Wrapped in
Chat Integration:
- Toggle between chat and participant views
- Unread message tracking
- Contact selection for private chats
Responsive Design
- Collapsible sections for mobile
- Fixed panel width
- Scrollable lists with hidden scrollbars
- Conditional rendering of controls based on permissions
Usage Example
svelte
<script>
import Participants from "./participants.svelte";
let participants = [];
let event = {};
let me = {};
let pexip = new PexipClient();
function handleClose() {
// Close panel logic
}
</script>
<Participants
data={participants}
{event}
{me}
{pexip}
on:close={handleClose}
/>Dependencies
@steeze-ui/svelte-iconfor icons@steeze-ui/remix-icons(Pushpin2, Voiceprint, Camera, etc.)@steeze-ui/iconic-free(VideoCamera, MicrophoneMute)@steeze-ui/heroicons(DotsVertical, Search, Hand)- Svelte transitions (
fly,fade,slide,scale) - Custom actions (
clickOutside,tipfor tooltips) - Lodash debounce
- Svelte French Toast for notifications
- Custom form components (
SelectInput,Form) - Pexip client integration
Styling Notes
- White background with gray borders
- Blue accent colors for active elements
- Compact participant items with hover states
- Hidden scrollbars for cleaner appearance
- Responsive spacing and padding
- Consistent icon sizing
Accessibility Features
- Clear visual hierarchy
- Interactive elements have hover/focus states
- Tooltips for icon buttons
- Screen reader text for main action button
- Semantic HTML structure