+ {/* Left: Room Name Box */}
+
+ {roomName}
+
+
+
+ {/* Center: Control Buttons */}
+
+
+
+ {recording ? (
+
+ radio_button_checked
+
+ ) : (
+
+ radio_button_checked
+
+ )}
+
+
+ call_end
+
+
+
+ {/* Right: Settings Button */}
+
+ {SHOW_SETTINGS_MENU && (
+
+ )}
+
+
+ );
+}
+
diff --git a/package.json b/package.json
index 13413d7..aaf098e 100644
--- a/package.json
+++ b/package.json
@@ -15,6 +15,7 @@
"@livekit/krisp-noise-filter": "^0.2.8",
"livekit-client": "2.8.1",
"livekit-server-sdk": "2.9.7",
+ "material-symbols": "^0.28.2",
"next": "14.2.12",
"react": "18.3.1",
"react-dom": "18.3.1",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 7b2137e..f0f8262 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -13,19 +13,22 @@ importers:
version: 5.26.0
'@livekit/components-react':
specifier: 2.6.0
- version: 2.6.0(@livekit/protocol@1.20.1)(livekit-client@2.5.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(tslib@2.7.0)
+ version: 2.6.0(@livekit/protocol@1.34.0)(livekit-client@2.8.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(tslib@2.8.1)
'@livekit/components-styles':
specifier: 1.1.2
version: 1.1.2
'@livekit/krisp-noise-filter':
specifier: ^0.2.8
- version: 0.2.8(livekit-client@2.5.2)
+ version: 0.2.8(livekit-client@2.8.1)
livekit-client:
- specifier: 2.5.2
- version: 2.5.2
+ specifier: 2.8.1
+ version: 2.8.1
livekit-server-sdk:
- specifier: 2.6.2
- version: 2.6.2
+ specifier: 2.9.7
+ version: 2.9.7
+ material-symbols:
+ specifier: ^0.28.2
+ version: 0.28.2
next:
specifier: 14.2.12
version: 14.2.12(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
@@ -43,8 +46,8 @@ importers:
specifier: 20.16.3
version: 20.16.3
'@types/react':
- specifier: 18.3.5
- version: 18.3.5
+ specifier: 18.3.8
+ version: 18.3.8
'@types/react-dom':
specifier: 18.3.0
version: 18.3.0
@@ -172,8 +175,14 @@ packages:
peerDependencies:
livekit-client: ^2.0.8
- '@livekit/protocol@1.20.1':
- resolution: {integrity: sha512-TgyuwOx+XJn9inEYT9OKfFNs9YIPS4BdLa4pF5FDf9MhWRnahKwPe7jxr/+sVdWxYbZmy9hRrH58jSAFu0ONHw==}
+ '@livekit/mutex@1.1.1':
+ resolution: {integrity: sha512-EsshAucklmpuUAfkABPxJNhzj9v2sG7JuzFDL4ML1oJQSV14sqrpTYnsaOudMAw9yOaW53NU3QQTlUQoRs4czw==}
+
+ '@livekit/protocol@1.30.0':
+ resolution: {integrity: sha512-SDI9ShVKj8N3oOSinr8inaxD3FXgmgoJlqN35uU/Yx1sdoDeQbzAuBFox7bYjM+VhnZ1V22ivIDjAsKr00H+XQ==}
+
+ '@livekit/protocol@1.34.0':
+ resolution: {integrity: sha512-bU7pCLAMRVTVZb1KSxA46q55bhOc4iATrY/gccy2/oX1D57tiZEI+8wGRWHeDwBb0UwnABu6JXzC4tTFkdsaOg==}
'@next/env@14.2.12':
resolution: {integrity: sha512-3fP29GIetdwVIfIRyLKM7KrvJaqepv+6pVodEbx0P5CaMLYBtx+7eEg8JYO5L9sveJO87z9eCReceZLi0hxO1Q==}
@@ -282,8 +291,8 @@ packages:
'@types/react-dom@18.3.0':
resolution: {integrity: sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg==}
- '@types/react@18.3.5':
- resolution: {integrity: sha512-WeqMfGJLGuLCqHGYRGHxnKrXcTitc6L/nBUWfWPcTarG3t9PsquqUMuVeXZeca+mglY4Vo5GZjCi0A3Or2lnxA==}
+ '@types/react@18.3.8':
+ resolution: {integrity: sha512-syBUrW3/XpnW4WJ41Pft+I+aPoDVbrBVQGEnbD7NijDGlVC+8gV/XKRY+7vMDlfPpbwYt0l1vd/Sj8bJGMbs9Q==}
'@typescript-eslint/parser@7.2.0':
resolution: {integrity: sha512-5FKsVcHTk6TafQKQbuIVkXq58Fnbkd2wDL4LB7AURN7RUOu1utVP+G8+6u3ZhEroW3DF6hyo3ZEXxgKgp4KeCg==}
@@ -1101,12 +1110,12 @@ packages:
resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==}
engines: {node: '>= 0.8.0'}
- livekit-client@2.5.2:
- resolution: {integrity: sha512-rzWFH02UznHxpnbj+WEEoHxL1ZSo9BdFK+7ltSZWniTt2llnNckdqeXNsjkBH6k+C9agHTF4XikmxKcpWa4YrQ==}
+ livekit-client@2.8.1:
+ resolution: {integrity: sha512-HPv9iHNrnBANI9ucK7CKZspx0sBZK3hjR2EbwaV08+J3RM9+tNGL2ob2n76nxJLEZG7LzdWlLZdbr4fQBP6Hkg==}
- livekit-server-sdk@2.6.2:
- resolution: {integrity: sha512-3fFzHu7sAynUaUFTCKtRP9lgQCU0Qe/x7XA99GpT1ro7fTy1ZVzaWq34WcXEyUGBBMFxG19LlSIAQBcGZVStWQ==}
- engines: {node: '>=19'}
+ livekit-server-sdk@2.9.7:
+ resolution: {integrity: sha512-uIkFOaqBCJnVgYOidZdanPWQH5G0LMxe0+Qp5zbx7MZCkJ7lGiju//yonfEvFofriJBKACjMq/KQHBex96QpeA==}
+ engines: {node: '>=18'}
loader-runner@4.3.0:
resolution: {integrity: sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==}
@@ -1137,6 +1146,9 @@ packages:
resolution: {integrity: sha512-2L3MIgJynYrZ3TYMriLDLWocz15okFakV6J12HXvMXDHui2x/zgChzg1u9mFFGbbGWE+GsLpQByt4POb9Or+uA==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+ material-symbols@0.28.2:
+ resolution: {integrity: sha512-JLK+Bgtfg5Dn9V2WYk6lSwmxciNNF2zmqc/V8MLmH0K9LttUhPCaauJzrS1Vw3mJPs/Tyfi/tszynNRX6nWQOA==}
+
merge-stream@2.0.0:
resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==}
@@ -1577,6 +1589,9 @@ packages:
tslib@2.7.0:
resolution: {integrity: sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==}
+ tslib@2.8.1:
+ resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
+
type-check@0.4.0:
resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}
engines: {node: '>= 0.8.0'}
@@ -1777,33 +1792,39 @@ snapshots:
'@jridgewell/resolve-uri': 3.1.2
'@jridgewell/sourcemap-codec': 1.5.0
- '@livekit/components-core@0.11.5(@livekit/protocol@1.20.1)(livekit-client@2.5.2)(tslib@2.7.0)':
+ '@livekit/components-core@0.11.5(@livekit/protocol@1.34.0)(livekit-client@2.8.1)(tslib@2.8.1)':
dependencies:
'@floating-ui/dom': 1.6.11
- '@livekit/protocol': 1.20.1
- livekit-client: 2.5.2
+ '@livekit/protocol': 1.34.0
+ livekit-client: 2.8.1
loglevel: 1.9.1
rxjs: 7.8.1
- tslib: 2.7.0
+ tslib: 2.8.1
- '@livekit/components-react@2.6.0(@livekit/protocol@1.20.1)(livekit-client@2.5.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(tslib@2.7.0)':
+ '@livekit/components-react@2.6.0(@livekit/protocol@1.34.0)(livekit-client@2.8.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(tslib@2.8.1)':
dependencies:
- '@livekit/components-core': 0.11.5(@livekit/protocol@1.20.1)(livekit-client@2.5.2)(tslib@2.7.0)
- '@livekit/protocol': 1.20.1
+ '@livekit/components-core': 0.11.5(@livekit/protocol@1.34.0)(livekit-client@2.8.1)(tslib@2.8.1)
+ '@livekit/protocol': 1.34.0
clsx: 2.1.1
- livekit-client: 2.5.2
+ livekit-client: 2.8.1
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
- tslib: 2.7.0
+ tslib: 2.8.1
usehooks-ts: 3.1.0(react@18.3.1)
'@livekit/components-styles@1.1.2': {}
- '@livekit/krisp-noise-filter@0.2.8(livekit-client@2.5.2)':
+ '@livekit/krisp-noise-filter@0.2.8(livekit-client@2.8.1)':
dependencies:
- livekit-client: 2.5.2
+ livekit-client: 2.8.1
- '@livekit/protocol@1.20.1':
+ '@livekit/mutex@1.1.1': {}
+
+ '@livekit/protocol@1.30.0':
+ dependencies:
+ '@bufbuild/protobuf': 1.10.0
+
+ '@livekit/protocol@1.34.0':
dependencies:
'@bufbuild/protobuf': 1.10.0
@@ -1880,9 +1901,9 @@ snapshots:
'@types/react-dom@18.3.0':
dependencies:
- '@types/react': 18.3.5
+ '@types/react': 18.3.8
- '@types/react@18.3.5':
+ '@types/react@18.3.8':
dependencies:
'@types/prop-types': 15.7.12
csstype: 3.1.3
@@ -2403,7 +2424,7 @@ snapshots:
eslint: 9.9.1
eslint-import-resolver-node: 0.3.9
eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@7.2.0(eslint@9.9.1)(typescript@5.5.4))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(eslint@9.9.1))(eslint@9.9.1)
- eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.2.0(eslint@9.9.1)(typescript@5.5.4))(eslint-import-resolver-typescript@3.6.3)(eslint@9.9.1)
+ eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.2.0(eslint@9.9.1)(typescript@5.5.4))(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@7.2.0(eslint@9.9.1)(typescript@5.5.4))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(eslint@9.9.1))(eslint@9.9.1))(eslint@9.9.1)
eslint-plugin-jsx-a11y: 6.9.0(eslint@9.9.1)
eslint-plugin-react: 7.35.0(eslint@9.9.1)
eslint-plugin-react-hooks: 4.6.2(eslint@9.9.1)
@@ -2434,7 +2455,7 @@ snapshots:
is-bun-module: 1.1.0
is-glob: 4.0.3
optionalDependencies:
- eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.2.0(eslint@9.9.1)(typescript@5.5.4))(eslint-import-resolver-typescript@3.6.3)(eslint@9.9.1)
+ eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.2.0(eslint@9.9.1)(typescript@5.5.4))(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@7.2.0(eslint@9.9.1)(typescript@5.5.4))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(eslint@9.9.1))(eslint@9.9.1))(eslint@9.9.1)
transitivePeerDependencies:
- '@typescript-eslint/parser'
- eslint-import-resolver-node
@@ -2452,7 +2473,7 @@ snapshots:
transitivePeerDependencies:
- supports-color
- eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.2.0(eslint@9.9.1)(typescript@5.5.4))(eslint-import-resolver-typescript@3.6.3)(eslint@9.9.1):
+ eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.2.0(eslint@9.9.1)(typescript@5.5.4))(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@7.2.0(eslint@9.9.1)(typescript@5.5.4))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(eslint@9.9.1))(eslint@9.9.1))(eslint@9.9.1):
dependencies:
array-includes: 3.1.8
array.prototype.findlastindex: 1.2.5
@@ -2924,20 +2945,22 @@ snapshots:
prelude-ls: 1.2.1
type-check: 0.4.0
- livekit-client@2.5.2:
+ livekit-client@2.8.1:
dependencies:
- '@livekit/protocol': 1.20.1
+ '@livekit/mutex': 1.1.1
+ '@livekit/protocol': 1.30.0
events: 3.3.0
loglevel: 1.9.1
sdp-transform: 2.14.2
ts-debounce: 4.0.0
- tslib: 2.7.0
+ tslib: 2.8.1
typed-emitter: 2.1.0
webrtc-adapter: 9.0.1
- livekit-server-sdk@2.6.2:
+ livekit-server-sdk@2.9.7:
dependencies:
- '@livekit/protocol': 1.20.1
+ '@bufbuild/protobuf': 1.10.0
+ '@livekit/protocol': 1.34.0
camelcase-keys: 9.1.3
jose: 5.8.0
@@ -2961,6 +2984,8 @@ snapshots:
map-obj@5.0.0: {}
+ material-symbols@0.28.2: {}
+
merge-stream@2.0.0: {}
merge2@1.4.1: {}
@@ -3408,6 +3433,8 @@ snapshots:
tslib@2.7.0: {}
+ tslib@2.8.1: {}
+
type-check@0.4.0:
dependencies:
prelude-ls: 1.2.1
diff --git a/styles/CustomControlBar.css b/styles/CustomControlBar.css
new file mode 100644
index 0000000..bc719a9
--- /dev/null
+++ b/styles/CustomControlBar.css
@@ -0,0 +1,186 @@
+@import url('https://fonts.googleapis.com/icon?family=Material+Symbols+Outlined');
+@import url('https://fonts.googleapis.com/css2?family=Roboto&display=swap');
+
+.custom-control-bar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 10px;
+ position: fixed;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ background: rgba(0, 0, 0, 0.8);
+ z-index: 1000;
+ backdrop-filter: blur(5px);
+}
+
+.room-name-box {
+ background: rgba(144, 155, 170, 0.1);
+ border-radius: 8px;
+ padding: 5px 10px;
+ display: flex;
+ align-items: center;
+ gap: 5px;
+}
+
+.room-name {
+ font-family: 'Roboto', sans-serif;
+ font-size: 14px;
+ color: #909baa;
+}
+
+.copy-link-button {
+ background: none;
+ border: none;
+ cursor: pointer;
+ margin-left: 5px;
+ padding: 0;
+}
+
+.copy-link-button .material-symbols-outlined {
+ font-size: 20px;
+ color: #909baa;
+}
+
+.control-buttons {
+ display: flex;
+ gap: 10px;
+ justify-content: center;
+ flex-grow: 1;
+}
+
+.control-button {
+ width: 40px;
+ height: 40px;
+ background: rgba(144, 155, 170, 0.1);
+ border-radius: 8px;
+ border: none;
+ cursor: pointer;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-size: 24px;
+}
+
+.mic-button[data-lk-audio-enabled="false"] {
+ background: #ff5252;
+ opacity: 0.8;
+}
+
+.mic-button[data-lk-audio-enabled="true"] .material-symbols-outlined {
+ content: 'mic';
+ color: #ffffff;
+}
+
+.mic-button[data-lk-audio-enabled="false"] .material-symbols-outlined {
+ content: 'mic_off';
+ color: #ffffff;
+}
+
+.camera-button[data-lk-video-enabled="false"] {
+ background: #ff5252;
+ opacity: 0.8;
+}
+
+.camera-button[data-lk-video-enabled="true"] .material-symbols-outlined {
+ content: 'videocam';
+ color: #ffffff;
+}
+
+.camera-button[data-lk-video-enabled="false"] .material-symbols-outlined {
+ content: 'videocam_off';
+ color: #ffffff;
+}
+
+.screen-share-button[data-lk-screen-share-enabled="true"] .material-symbols-outlined {
+ content: 'screen_share';
+ color: #49c998;
+}
+
+.screen-share-button[data-lk-screen-share-enabled="false"] .material-symbols-outlined {
+ content: 'screen_share';
+ color: #ffffff;
+}
+
+.record-sign {
+ background: rgba(144, 155, 170, 0.1);
+}
+
+.record-sign.disabled {
+ background: rgba(144, 155, 170, 0.1);
+}
+
+.record-sign .material-symbols-outlined,
+.record-sign.disabled .material-symbols-outlined {
+ font-size: 24px;
+}
+
+.record-sign .material-symbols-outlined {
+ color: #ff6f6f;
+ animation: pulse 1s infinite;
+}
+
+.record-sign.disabled .material-symbols-outlined {
+ color: #ffffff;
+}
+
+@keyframes pulse {
+ 0% { opacity: 1; }
+ 50% { opacity: 0.5; }
+ 100% { opacity: 1; }
+}
+
+.end-call-button {
+ width: 64px;
+ height: 40px;
+ background: #ff5252;
+ border-radius: 8px;
+ border: none;
+ cursor: pointer;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+.end-call-button .material-symbols-outlined {
+ font-size: 24px;
+ color: #ffffff;
+}
+
+.settings-section {
+ position: relative;
+}
+
+.settings-button {
+ width: 40px;
+ height: 40px;
+ background: rgba(144, 155, 170, 0.1);
+ border-radius: 8px;
+ border: none;
+ cursor: pointer;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+.settings-button .material-symbols-outlined {
+ font-size: 24px;
+ color: #ffffff;
+}
+
+
+.lk-grid-layout {
+ height: calc(100vh - 60px) !important;
+ width: 100% !important;
+}
+
+.lk-grid-layout > div {
+ position: relative !important;
+ overflow: hidden !important;
+}
+
+.lk-video {
+ object-fit: cover !important;
+ background-color: #000 !important;
+}
\ No newline at end of file
From e6f9cf9a433666cd13cec5d88bdb7ffb479029d4 Mon Sep 17 00:00:00 2001
From: anujsb <141896390+anujsb@users.noreply.github.com>
Date: Tue, 25 Feb 2025 23:08:30 +0530
Subject: [PATCH 2/2] fix : added settings and Participants button
---
app/custom/CustomControlBar.tsx | 210 +++++++++++-----------
app/custom/VideoTrack.tsx | 27 +++
app/rooms/[roomName]/PageClientImpl.tsx | 225 ++++++++----------------
styles/CustomControlBar.css | 114 ++++++------
styles/PageClientImpl.css | 25 +++
styles/VideoTrack.css | 5 +
6 files changed, 285 insertions(+), 321 deletions(-)
create mode 100644 app/custom/VideoTrack.tsx
create mode 100644 styles/PageClientImpl.css
create mode 100644 styles/VideoTrack.css
diff --git a/app/custom/CustomControlBar.tsx b/app/custom/CustomControlBar.tsx
index 4269dba..9b3d4fe 100644
--- a/app/custom/CustomControlBar.tsx
+++ b/app/custom/CustomControlBar.tsx
@@ -1,123 +1,111 @@
-// // import React from 'react';
-// // import { TrackToggle, DisconnectButton } from '@livekit/components-react';
-// // import SettingsMenu from '@/lib/SettingsMenu';
-// // import { MaterialSymbol } from 'material-symbols';
-// // import '../../styles/CustomControlBar.css';
+'use client';
+
+import React, { useState, useEffect } from 'react';
+import {
+ TrackToggle,
+ DisconnectButton
+} from '@livekit/components-react';
+import {
+ Room,
+ RoomEvent,
+ Track
+} from 'livekit-client';
+import '../../styles/CustomControlBar.css';
-// // const CustomControlBar = ({ roomName, room }) => {
-// // const [recording, setRecording] = React.useState(false);
-// // const [showSettings, setShowSettings] = React.useState(false);
+interface CustomControlBarProps {
+ room: Room;
+ roomName: string;
+}
-// // React.useEffect(() => {
-// // if (room) {
-// // room.on('recordedStatusChanged', () => {
-// // setRecording(room.isRecording);
-// // });
-// // return () => {
-// // room.off('recordedStatusChanged');
-// // };
-// // }
-// // }, [room]);
+export function CustomControlBar({ room, roomName }: CustomControlBarProps) {
+ const [recording, setRecording] = useState(false);
+ const [participantCount, setParticipantCount] = useState(1);
-// // const handleCopyLink = () => {
-// // navigator.clipboard.writeText(window.location.href);
-// // };
+ useEffect(() => {
+ if (room) {
-// // return (
-// //
-// //
-// //
-// // {roomName}
-// //
-// //
-// //
-// //
-// //
-// //
-// // {recording && (
-// //
-// // {/* */}
-// //
-// // )}
-// //
-// //
-// //
-// //
-// //
-// // {showSettings && setShowSettings(false)} />}
-// //
-// //
-// // );
-// // };
+ const updateRecordingStatus = () => setRecording(room.isRecording);
+
-// // export default CustomControlBar;
+ const updateParticipantCount = () => {
+ if (room && room.participants) {
+ setParticipantCount(room.participants.size + 1);
+ }
+ };
+
+ if (room.state === 'connected') {
+ updateParticipantCount();
+ }
+
+ room.on(RoomEvent.Connected, updateParticipantCount);
+ room.on(RoomEvent.ParticipantConnected, updateParticipantCount);
+ room.on(RoomEvent.ParticipantDisconnected, updateParticipantCount);
+ room.on(RoomEvent.RecordingStatusChanged, updateRecordingStatus);
+
+ return () => {
+ room.off(RoomEvent.Connected, updateParticipantCount);
+ room.off(RoomEvent.ParticipantConnected, updateParticipantCount);
+ room.off(RoomEvent.ParticipantDisconnected, updateParticipantCount);
+ room.off(RoomEvent.RecordingStatusChanged, updateRecordingStatus);
+ };
+ }
+ }, [room]);
-// import { TrackToggle, DisconnectButton, RoomAudioRenderer, GridLayout } from '@livekit/components-react';
-// import { useState, useEffect } from 'react';
+ const handleCopyLink = () => {
+ navigator.clipboard.writeText(window.location.href)
+ .then(() => alert('Link copied to clipboard!'))
+ .catch((err) => console.error('Failed to copy link:', err));
+ };
-// function CustomControlBar({ room, roomName }) {
-// const [recording, setRecording] = useState(false);
+ return (
+
-// // Update recording status
-// useEffect(() => {
-// if (room) {
-// const updateRecordingStatus = () => setRecording(room.isRecording);
-// room.on(RoomEvent.RecordingStarted, updateRecordingStatus);
-// room.on(RoomEvent.RecordingStopped, updateRecordingStatus);
-// return () => {
-// room.off(RoomEvent.RecordingStarted, updateRecordingStatus);
-// room.off(RoomEvent.RecordingStopped, updateRecordingStatus);
-// };
-// }
-// }, [room]);
+
+ {roomName}
+
+
-// // Copy room link to clipboard
-// const handleCopyLink = () => {
-// navigator.clipboard.writeText(window.location.href)
-// .then(() => alert('Link copied to clipboard!'))
-// .catch((err) => console.error('Failed to copy link:', err));
-// };
+ {/* Center: Control Buttons */}
+
+
+ {/* mic
+ mic_off */}
+
+
+
+ {/* videocam
+ videocam_off */}
+
+
+
+ radio_button_checked
+
+
+
+ {/* screen_share
+ screen_share */}
+
+
+
+ call_end
+
+
-// return (
-//
-// {/* Left: Room Name Box */}
-//
-// {roomName}
-//
-//
-
-// {/* Center: Control Buttons */}
-//
-//
-//
-// {recording && (
-//
-// radio_button_checked
-//
-// )}
-//
-//
-// call_end
-//
-//
-
-// {/* Right: Settings Button */}
-//
-// {SHOW_SETTINGS_MENU && (
-//
-// )}
-//
-//
-// );
-// }
\ No newline at end of file
+ {/* Participants, Settings btn */}
+
+
+ people
+ {participantCount}
+
+
+
+ settings
+
+
+
+ );
+}
\ No newline at end of file
diff --git a/app/custom/VideoTrack.tsx b/app/custom/VideoTrack.tsx
new file mode 100644
index 0000000..9fc9fb6
--- /dev/null
+++ b/app/custom/VideoTrack.tsx
@@ -0,0 +1,27 @@
+'use client';
+
+import React, { useRef, useEffect } from 'react';
+import { TrackReferenceOrPlaceholder } from '@livekit/components-react';
+import '../../styles/VideoTrack.css';
+
+interface VideoTrackProps {
+ ref: TrackReferenceOrPlaceholder;
+}
+
+export function VideoTrack({ ref: trackRef }: VideoTrackProps) {
+ const videoRef = useRef