293 lines
6.3 KiB
Plaintext
293 lines
6.3 KiB
Plaintext
<!DOCTYPE html>
|
|
<html lang="en">
|
|
|
|
<head>
|
|
<meta charset="UTF-8" />
|
|
<title>Live Screen Feed</title>
|
|
|
|
<style>
|
|
* {
|
|
box-sizing: border-box;
|
|
margin: 0;
|
|
padding: 0;
|
|
}
|
|
|
|
body {
|
|
height: 100vh;
|
|
display: flex;
|
|
background: #0f0f0f;
|
|
color: white;
|
|
font-family: "Inter", sans-serif;
|
|
overflow: hidden;
|
|
}
|
|
|
|
/* SIDEBAR */
|
|
.sidebar {
|
|
width: 280px;
|
|
background: #181818;
|
|
border-right: 1px solid #2b2b2b;
|
|
padding: 15px;
|
|
overflow-y: auto;
|
|
transition: transform 0.35s ease;
|
|
z-index: 50;
|
|
}
|
|
|
|
.sidebar h3 {
|
|
margin-bottom: 15px;
|
|
font-size: 18px;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.app {
|
|
background: #252525;
|
|
border: 1px solid #333;
|
|
padding: 12px;
|
|
margin-bottom: 10px;
|
|
border-radius: 8px;
|
|
cursor: pointer;
|
|
transition: 0.3s ease;
|
|
}
|
|
|
|
.app:hover {
|
|
background: #333;
|
|
transform: translateX(3px);
|
|
}
|
|
|
|
.app.active {
|
|
background: #6c63ff;
|
|
border-color: #6c63ff;
|
|
color: white;
|
|
box-shadow: 0 0 10px rgba(108, 99, 255, 0.5);
|
|
}
|
|
|
|
/* MAIN CONTENT */
|
|
.content {
|
|
flex: 1;
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
justify-content: center;
|
|
position: relative;
|
|
padding: 20px;
|
|
overflow: hidden;
|
|
}
|
|
|
|
#selectedAppTitle {
|
|
font-size: 20px;
|
|
margin-bottom: 15px;
|
|
font-weight: 500;
|
|
text-align: center;
|
|
}
|
|
|
|
#liveImage {
|
|
width: 90%;
|
|
max-width: 900px;
|
|
border-radius: 10px;
|
|
border: 2px solid #444;
|
|
object-fit: contain;
|
|
background: black;
|
|
display: none;
|
|
}
|
|
|
|
.placeholder {
|
|
font-size: 16px;
|
|
opacity: 0.8;
|
|
color: #bbb;
|
|
margin-top: 20px;
|
|
}
|
|
|
|
/* MOBILE RESPONSIVE */
|
|
.mobile-toggle {
|
|
display: none;
|
|
position: fixed;
|
|
top: 15px;
|
|
left: 15px;
|
|
background: #6C63FF;
|
|
padding: 14px;
|
|
border-radius: 8px;
|
|
z-index: 9999;
|
|
/* VERY HIGH: always visible */
|
|
cursor: pointer;
|
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.4);
|
|
}
|
|
|
|
.mobile-toggle span {
|
|
display: block;
|
|
width: 26px;
|
|
height: 3px;
|
|
background: #fff;
|
|
margin: 5px 0;
|
|
border-radius: 2px;
|
|
}
|
|
|
|
/* Sidebar Hidden on Mobile */
|
|
@media (max-width: 780px) {
|
|
body {
|
|
flex-direction: column;
|
|
}
|
|
|
|
.sidebar {
|
|
position: fixed;
|
|
left: 0;
|
|
top: 0;
|
|
height: 100%;
|
|
transform: translateX(-100%);
|
|
}
|
|
|
|
.sidebar.open {
|
|
transform: translateX(0%);
|
|
}
|
|
|
|
.mobile-toggle {
|
|
display: block !important;
|
|
}
|
|
|
|
.content {
|
|
padding-top: 60px;
|
|
}
|
|
|
|
/* Dark overlay when sidebar opens */
|
|
#overlay {
|
|
position: fixed;
|
|
inset: 0;
|
|
background: rgba(0, 0, 0, 0.45);
|
|
display: none;
|
|
z-index: 40;
|
|
}
|
|
|
|
#overlay.show {
|
|
display: block;
|
|
}
|
|
}
|
|
</style>
|
|
</head>
|
|
|
|
<body>
|
|
<!-- Mobile Toggle Button -->
|
|
<div class="mobile-toggle" id="toggleBtn">
|
|
<span></span>
|
|
<span></span>
|
|
<span></span>
|
|
</div>
|
|
|
|
<!-- Mobile Overlay -->
|
|
<div id="overlay"></div>
|
|
|
|
<div class="sidebar" id="sidebar">
|
|
<h3>Visible Apps</h3>
|
|
<div id="appsList"></div>
|
|
</div>
|
|
|
|
<div class="content">
|
|
<h2 id="selectedAppTitle">Select an app to view</h2>
|
|
<img id="liveImage" alt="Live Feed" />
|
|
<div id="placeholder" class="placeholder">No app selected</div>
|
|
</div>
|
|
|
|
<script src="/socket.io/socket.io.js"></script>
|
|
<script>
|
|
const vaId = "<%= vaId %>";
|
|
const clientId = "<%= clientId %>";
|
|
const projectId = "<%= projectId %>";
|
|
const token = localStorage.getItem("knoptpq");
|
|
|
|
const socket = io({
|
|
auth: {
|
|
token: token,
|
|
userType: "client",
|
|
projectId: projectId,
|
|
vaId: vaId
|
|
},
|
|
});
|
|
|
|
socket.emit("register", {
|
|
role: "client",
|
|
id: vaId,
|
|
projectId: "<%= projectId %>",
|
|
clientId: clientId
|
|
});
|
|
|
|
|
|
|
|
const sidebar = document.getElementById("sidebar");
|
|
const toggleBtn = document.getElementById("toggleBtn");
|
|
const overlay = document.getElementById("overlay");
|
|
|
|
const appsList = document.getElementById("appsList");
|
|
const liveImage = document.getElementById("liveImage");
|
|
const selectedAppTitle = document.getElementById("selectedAppTitle");
|
|
const placeholder = document.getElementById("placeholder");
|
|
|
|
let currentApp = null;
|
|
|
|
/* MOBILE SIDEBAR TOGGLE */
|
|
toggleBtn.onclick = () => {
|
|
sidebar.classList.add("open");
|
|
overlay.classList.add("show");
|
|
};
|
|
|
|
overlay.onclick = () => {
|
|
sidebar.classList.remove("open");
|
|
overlay.classList.remove("show");
|
|
};
|
|
|
|
socket.on("connected", () => {
|
|
socket.emit("requestVisibleApps", { token });
|
|
});
|
|
|
|
/* Receive visible apps */
|
|
socket.on("receiveVisibleApps", ({ apps, vaId: senderVaId }) => {
|
|
if (vaId !== senderVaId) return;
|
|
|
|
appsList.innerHTML = "";
|
|
|
|
if (!apps?.length) {
|
|
appsList.innerHTML = "<p style='color:#777;'>No visible apps</p>";
|
|
return;
|
|
}
|
|
|
|
apps.forEach(app => {
|
|
const div = document.createElement("div");
|
|
div.classList.add("app");
|
|
div.textContent = app.name || "Unnamed App";
|
|
|
|
div.onclick = () => {
|
|
document.querySelectorAll(".app").forEach(el => el.classList.remove("active"));
|
|
div.classList.add("active");
|
|
|
|
currentApp = app.name;
|
|
selectedAppTitle.textContent = app.name;
|
|
|
|
placeholder.style.display = "none";
|
|
liveImage.style.display = "none";
|
|
|
|
socket.emit("selectApp", { appTitle: app.name, clientId, vaId, projectId });
|
|
|
|
// Close sidebar on mobile
|
|
sidebar.classList.remove("open");
|
|
overlay.classList.remove("show");
|
|
};
|
|
|
|
appsList.appendChild(div);
|
|
});
|
|
});
|
|
|
|
socket.on("authError", () => {
|
|
socket.disconnect();
|
|
localStorage.removeItem("knoptpq");
|
|
window.location.href = "/client/login";
|
|
});
|
|
|
|
/* Receive images */
|
|
socket.on("receiveImage", (base64, title) => {
|
|
if (currentApp && title === currentApp) {
|
|
liveImage.src = base64;
|
|
liveImage.style.display = "block";
|
|
placeholder.style.display = "none";
|
|
}
|
|
});
|
|
</script>
|
|
|
|
</body>
|
|
|
|
</html> |