[mirotalksfu] - add SHOW_ACTIVE_ROOMS
هذا الالتزام موجود في:
195
public/css/ActiveRooms.css
Normal file
195
public/css/ActiveRooms.css
Normal file
@@ -0,0 +1,195 @@
|
||||
@import url('https://fonts.googleapis.com/css2?family=Montserrat:wght@500&display=swap');
|
||||
|
||||
:root {
|
||||
--primary-bg: #1e2229;
|
||||
--card-bg: #15181d;
|
||||
--accent: #1870d7;
|
||||
--accent2: #2186ff;
|
||||
--text: #f6f8fa;
|
||||
--card-shadow: 0 2px 8px #15181d;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'Montserrat';
|
||||
background: var(--primary-bg);
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 1200px;
|
||||
margin: 40px auto;
|
||||
background: var(--card-bg);
|
||||
border-radius: 12px;
|
||||
box-shadow: var(--card-shadow);
|
||||
padding: 32px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
text-align: center;
|
||||
color: var(--accent2);
|
||||
margin-bottom: 32px;
|
||||
letter-spacing: 1px;
|
||||
}
|
||||
|
||||
.search-bar {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-bottom: 28px;
|
||||
}
|
||||
|
||||
.search-input {
|
||||
padding: 10px 16px;
|
||||
border-radius: 6px 0 0 6px;
|
||||
border: none;
|
||||
font-size: 1.1em;
|
||||
background: #23262e;
|
||||
color: var(--text);
|
||||
outline: none;
|
||||
width: 220px;
|
||||
}
|
||||
|
||||
.search-btn {
|
||||
padding: 10px 20px;
|
||||
border-radius: 0 6px 6px 0;
|
||||
border: none;
|
||||
background: var(--accent);
|
||||
color: #fff;
|
||||
font-size: 1.1em;
|
||||
cursor: pointer;
|
||||
font-weight: bold;
|
||||
transition: background 0.2s;
|
||||
}
|
||||
|
||||
.search-btn:hover {
|
||||
background: var(--accent2);
|
||||
}
|
||||
|
||||
.rooms {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
|
||||
gap: 28px;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.room-card {
|
||||
background: var(--accent);
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 1px 6px #15181d;
|
||||
padding: 32px 24px;
|
||||
min-height: 220px;
|
||||
text-align: center;
|
||||
transition:
|
||||
box-shadow 0.2s,
|
||||
transform 0.2s;
|
||||
color: var(--text);
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.room-card:hover {
|
||||
cursor: pointer;
|
||||
transform: translateY(-4px) scale(1.03);
|
||||
}
|
||||
|
||||
.room-title {
|
||||
font-size: 1.15em;
|
||||
color: #f6f8fa;
|
||||
margin-bottom: 14px;
|
||||
font-weight: bold;
|
||||
letter-spacing: 0.5px;
|
||||
word-break: break-all;
|
||||
overflow-wrap: anywhere;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.peer-count {
|
||||
font-size: 2.3em;
|
||||
color: #ffd700;
|
||||
font-weight: bold;
|
||||
margin-bottom: 8px;
|
||||
margin-top: auto;
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
.peer-label {
|
||||
font-size: 0.9em;
|
||||
color: #f6f8fa;
|
||||
opacity: 0.7;
|
||||
margin-bottom: 60px;
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
.empty {
|
||||
text-align: center;
|
||||
color: #b3c6e0;
|
||||
margin-top: 40px;
|
||||
font-size: 1.2em;
|
||||
}
|
||||
|
||||
.refresh-btn {
|
||||
display: block;
|
||||
margin: 0 auto 32px auto;
|
||||
padding: 10px 28px;
|
||||
background: var(--accent2);
|
||||
color: #fff;
|
||||
border: none;
|
||||
border-radius: 7px;
|
||||
cursor: pointer;
|
||||
font-size: 1.1em;
|
||||
font-weight: bold;
|
||||
letter-spacing: 0.5px;
|
||||
box-shadow: 0 1px 4px #15181d;
|
||||
transition: background 0.2s;
|
||||
}
|
||||
|
||||
.refresh-btn:hover {
|
||||
background: var(--accent);
|
||||
}
|
||||
|
||||
.join-btn {
|
||||
display: block;
|
||||
margin: 0 auto 0 auto;
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
bottom: 18px;
|
||||
transform: translateX(-50%);
|
||||
padding: 10px 24px;
|
||||
background: var(--accent2);
|
||||
color: #fff;
|
||||
border-radius: 6px;
|
||||
font-size: 1em;
|
||||
font-weight: bold;
|
||||
text-decoration: none;
|
||||
transition: background 0.2s;
|
||||
box-shadow: 0 1px 4px #15181d;
|
||||
}
|
||||
|
||||
.join-btn:hover {
|
||||
background: var(--accent);
|
||||
}
|
||||
|
||||
@media (max-width: 900px) {
|
||||
.container {
|
||||
max-width: 98vw;
|
||||
padding: 16px;
|
||||
}
|
||||
.rooms {
|
||||
gap: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 600px) {
|
||||
.rooms {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
.room-card {
|
||||
padding: 20px 10px;
|
||||
}
|
||||
.peer-label {
|
||||
margin-bottom: 70px;
|
||||
}
|
||||
}
|
||||
@@ -2077,6 +2077,10 @@ main {
|
||||
# Common
|
||||
--------------------------------------------------------------*/
|
||||
|
||||
.blue {
|
||||
color: #00bfff;
|
||||
}
|
||||
|
||||
.tac {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
89
public/js/ActiveRooms.js
Normal file
89
public/js/ActiveRooms.js
Normal file
@@ -0,0 +1,89 @@
|
||||
'use strict';
|
||||
|
||||
console.log(window.location);
|
||||
|
||||
const isTest = false; // Set to true for testing with mock data
|
||||
|
||||
const roomsDiv = document.getElementById('rooms');
|
||||
const searchInput = document.getElementById('searchInput');
|
||||
const searchBtn = document.getElementById('search-btn');
|
||||
const refreshBtn = document.getElementById('refresh-btn');
|
||||
|
||||
let allRooms = [];
|
||||
|
||||
searchBtn.addEventListener('click', handleSearch);
|
||||
refreshBtn.addEventListener('click', fetchRooms);
|
||||
|
||||
function setRoomsContent(html) {
|
||||
roomsDiv.innerHTML = html;
|
||||
}
|
||||
|
||||
function getRoomsData(res) {
|
||||
return !isTest ? res.data.activeRooms || [] : mockRooms();
|
||||
}
|
||||
|
||||
function mockRooms(roomCount = 1000) {
|
||||
return Array.from({ length: roomCount }, () => {
|
||||
const id = getUUID();
|
||||
return {
|
||||
id,
|
||||
peers: Math.floor(Math.random() * 10) + 1,
|
||||
join: `${window.location.origin}/${id}`,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
function getUUID() {
|
||||
return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, (c) =>
|
||||
(c ^ (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (c / 4)))).toString(16)
|
||||
);
|
||||
}
|
||||
|
||||
async function fetchRooms() {
|
||||
setRoomsContent('<div class="empty">Loading...</div>');
|
||||
try {
|
||||
const res = await axios.get('/api/v1/activeRooms');
|
||||
if (res.status !== 200) throw new Error('Failed to fetch active rooms');
|
||||
allRooms = getRoomsData(res);
|
||||
renderRooms(allRooms);
|
||||
} catch (err) {
|
||||
const errorMsg = err.response?.data?.error || err.message;
|
||||
setRoomsContent(`<div class="empty">${errorMsg}</div>`);
|
||||
}
|
||||
}
|
||||
|
||||
function renderRooms(rooms) {
|
||||
if (!rooms.length) {
|
||||
setRoomsContent('<div class="empty">No active rooms found.</div>');
|
||||
return;
|
||||
}
|
||||
setRoomsContent(
|
||||
rooms
|
||||
.map(
|
||||
(room) => `
|
||||
<div class="room-card">
|
||||
<div class="room-title">
|
||||
<i class="fa-solid fa-door-open"></i>
|
||||
${room.id}
|
||||
</div>
|
||||
<div class="peer-count">
|
||||
<i class="fa-solid fa-users"></i>
|
||||
${room.peers}
|
||||
</div>
|
||||
<div class="peer-label">${room.peers === 1 ? 'peer' : 'peers'}</div>
|
||||
<a href="${room.join}" class="join-btn" target="_blank">
|
||||
<i class="fa-solid fa-sign-in-alt"></i> Join
|
||||
</a>
|
||||
</div>
|
||||
`
|
||||
)
|
||||
.join('')
|
||||
);
|
||||
}
|
||||
|
||||
function handleSearch() {
|
||||
const value = searchInput.value.trim().toLowerCase();
|
||||
renderRooms(!value ? allRooms : allRooms.filter((room) => room.id.toLowerCase().includes(value)));
|
||||
}
|
||||
|
||||
fetchRooms();
|
||||
@@ -76,7 +76,7 @@ let BRAND = {
|
||||
},
|
||||
about: {
|
||||
imageUrl: '../images/mirotalk-logo.gif',
|
||||
title: '<strong>WebRTC SFU v1.9.18</strong>',
|
||||
title: '<strong>WebRTC SFU v1.9.20</strong>',
|
||||
html: `
|
||||
<button
|
||||
id="support-button"
|
||||
|
||||
@@ -11,7 +11,7 @@ if (location.href.substr(0, 5) !== 'https') location.href = 'https' + location.h
|
||||
* @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon
|
||||
* @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970
|
||||
* @author Miroslav Pejic - miroslav.pejic.85@gmail.com
|
||||
* @version 1.9.18
|
||||
* @version 1.9.20
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -5529,7 +5529,7 @@ function showAbout() {
|
||||
position: 'center',
|
||||
imageUrl: BRAND.about?.imageUrl && BRAND.about.imageUrl.trim() !== '' ? BRAND.about.imageUrl : image.about,
|
||||
customClass: { image: 'img-about' },
|
||||
title: BRAND.about?.title && BRAND.about.title.trim() !== '' ? BRAND.about.title : 'WebRTC SFU v1.9.18',
|
||||
title: BRAND.about?.title && BRAND.about.title.trim() !== '' ? BRAND.about.title : 'WebRTC SFU v1.9.20',
|
||||
html: `
|
||||
<br />
|
||||
<div id="about">
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
* @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon
|
||||
* @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970
|
||||
* @author Miroslav Pejic - miroslav.pejic.85@gmail.com
|
||||
* @version 1.9.18
|
||||
* @version 1.9.20
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
28
public/views/activeRooms.html
Normal file
28
public/views/activeRooms.html
Normal file
@@ -0,0 +1,28 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title id="title">MiroTalk SFU - Active Rooms.</title>
|
||||
<link id="icon" rel="shortcut icon" href="../images/logo.svg" />
|
||||
<link id="appleTouchIcon" rel="apple-touch-icon" href="../images/logo.svg" />
|
||||
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.2/css/all.min.css" />
|
||||
<link rel="stylesheet" type="text/css" href="../css/activeRooms.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>Active Rooms</h1>
|
||||
<div class="search-bar">
|
||||
<input class="search-input" id="searchInput" type="text" placeholder="Search by Room ID..." />
|
||||
<button id="search-btn" class="search-btn">Search</button>
|
||||
</div>
|
||||
<button id="refresh-btn" class="refresh-btn">Refresh</button>
|
||||
<div class="rooms" id="rooms"></div>
|
||||
</div>
|
||||
<script defer src="../js/ActiveRooms.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
المرجع في مشكلة جديدة
حظر مستخدم