crestron-v4 / index.html
ReadyMedia's picture
Functional and Design Specification – NTNU Crestron 10” Touchpanel (HTML5)
aa0cf42 verified
Raw
History Blame Contribute Delete
49 kB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>NTNU Crestron Control Panel</title>
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://unpkg.com/feather-icons"></script>
<script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script>
<link href="https://fonts.googleapis.com/css2?family=Open+Sans:wght@300;400;600;700&display=swap" rel="stylesheet">
<style>
:root {
--ntnu-blue: #00509e;
--ntnu-blue-light: #e6f0fa;
--active-green: #4CAF50;
--muted-red: #F44336;
--neutral-gray: #607D8B;
}
body {
font-family: 'Open Sans', Arial, sans-serif;
touch-action: manipulation;
-webkit-tap-highlight-color: transparent;
}
.touch-target {
min-width: 44px;
min-height: 44px;
}
.drag-source {
touch-action: none;
user-select: none;
}
.drop-zone {
transition: all 0.2s ease;
}
.drop-zone.active {
background-color: var(--ntnu-blue-light);
border: 2px dashed var(--ntnu-blue);
}
.volume-fader::-webkit-slider-thumb {
-webkit-appearance: none;
width: 24px;
height: 24px;
border-radius: 50%;
background: var(--ntnu-blue);
cursor: pointer;
}
.volume-fader::-moz-range-thumb {
width: 24px;
height: 24px;
border-radius: 50%;
background: var(--ntnu-blue);
cursor: pointer;
}
</style>
</head>
<body class="bg-white h-screen w-screen overflow-hidden flex flex-col">
<!-- Top Bar -->
<div class="bg-[#00509e] text-white p-2 flex items-center justify-between">
<!-- Language Toggle -->
<div class="flex items-center space-x-2">
<button id="langToggle" class="bg-white text-[#00509e] px-3 py-1 rounded-full font-semibold text-sm">
EN
</button>
</div>
<!-- NTNU Logo (Placeholder) -->
<div class="flex-1 text-center">
<div class="font-bold text-xl">NTNU</div>
</div>
<!-- Help and Recording -->
<div class="flex items-center space-x-4">
<button id="helpBtn" class="bg-white text-[#00509e] rounded-full w-8 h-8 flex items-center justify-center">
<i data-feather="help-circle"></i>
</button>
<div id="recordingIndicator" class="w-6 h-6 rounded-full bg-[#4CAF50]"></div>
</div>
</div>
<!-- Main Content Area -->
<div class="flex flex-1 overflow-hidden">
<!-- Side Menu -->
<div class="w-24 bg-gray-100 flex flex-col items-center py-4 space-y-4 border-r border-gray-300">
<button class="menu-btn active bg-[#00509e] text-white" data-menu="home">
<i data-feather="home" class="w-6 h-6"></i>
<span class="text-xs mt-1">Home</span>
</button>
<button class="menu-btn" data-menu="image">
<i data-feather="monitor" class="w-6 h-6"></i>
<span class="text-xs mt-1">Image</span>
</button>
<button class="menu-btn" data-menu="audio">
<i data-feather="volume-2" class="w-6 h-6"></i>
<span class="text-xs mt-1">Audio</span>
</button>
<button class="menu-btn" data-menu="lighting">
<i data-feather="sun" class="w-6 h-6"></i>
<span class="text-xs mt-1">Lighting</span>
</button>
<button class="menu-btn" data-menu="blinds">
<i data-feather="layers" class="w-6 h-6"></i>
<span class="text-xs mt-1">Blinds</span>
</button>
<button class="menu-btn" data-menu="camera">
<i data-feather="camera" class="w-6 h-6"></i>
<span class="text-xs mt-1">Camera</span>
</button>
<button class="menu-btn hidden" id="techBtn" data-menu="technician">
<i data-feather="settings" class="w-6 h-6"></i>
<span class="text-xs mt-1">Technician</span>
</button>
<button class="menu-btn" data-menu="shutdown">
<i data-feather="power" class="w-6 h-6"></i>
<span class="text-xs mt-1">Exit</span>
</button>
</div>
<!-- Content Panels -->
<div class="flex-1 overflow-auto p-4">
<!-- Home Panel -->
<div id="homePanel" class="menu-panel">
<div class="flex flex-col items-center justify-center h-full">
<h2 class="text-2xl font-bold text-[#00509e] mb-8">NTNU Classroom Control</h2>
<button id="startRoomBtn" class="bg-[#00509e] hover:bg-[#003d7a] text-white font-bold py-4 px-8 rounded-lg text-xl transition-colors">
Start Room
</button>
</div>
</div>
<!-- Image Panel -->
<div id="imagePanel" class="menu-panel hidden">
<h2 class="text-xl font-bold text-[#00509e] mb-4">Image Routing</h2>
<div class="mb-8">
<h3 class="text-lg font-semibold mb-2">Sources</h3>
<div class="grid grid-cols-4 gap-4">
<div class="drag-source bg-[#00509e] text-white p-3 rounded-lg text-center cursor-move touch-target" draggable="true" data-source="ntnu-pc">
<i data-feather="cpu" class="w-8 h-8 mx-auto"></i>
<div class="font-semibold mt-1">NTNU PC</div>
</div>
<div class="drag-source bg-[#00509e] text-white p-3 rounded-lg text-center cursor-move touch-target" draggable="true" data-source="laptop-hdmi">
<i data-feather="laptop" class="w-8 h-8 mx-auto"></i>
<div class="font-semibold mt-1">Laptop HDMI</div>
</div>
<div class="drag-source bg-[#00509e] text-white p-3 rounded-lg text-center cursor-move touch-target" draggable="true" data-source="doc-cam">
<i data-feather="image" class="w-8 h-8 mx-auto"></i>
<div class="font-semibold mt-1">Document Camera</div>
</div>
<div class="drag-source bg-gray-500 text-white p-3 rounded-lg text-center cursor-move touch-target" draggable="true" data-source="off">
<i data-feather="x" class="w-8 h-8 mx-auto"></i>
<div class="font-semibold mt-1">Image Off</div>
</div>
</div>
</div>
<div>
<h3 class="text-lg font-semibold mb-2">Destinations</h3>
<div class="grid grid-cols-3 gap-4">
<div class="drop-zone bg-gray-100 p-4 rounded-lg min-h-32 flex flex-col items-center justify-center touch-target" data-destination="projector1">
<div class="destination-content text-center">
<i data-feather="monitor" class="w-8 h-8 mx-auto text-gray-500"></i>
<div class="font-semibold mt-1">Projector 1</div>
<div class="text-xs text-gray-500">Drag source here</div>
</div>
<div class="audio-indicator mt-2 w-4 h-4 rounded-full bg-gray-300"></div>
</div>
<div class="drop-zone bg-gray-100 p-4 rounded-lg min-h-32 flex flex-col items-center justify-center touch-target" data-destination="projector2">
<div class="destination-content text-center">
<i data-feather="monitor" class="w-8 h-8 mx-auto text-gray-500"></i>
<div class="font-semibold mt-1">Projector 2</div>
<div class="text-xs text-gray-500">Drag source here</div>
</div>
<div class="audio-indicator mt-2 w-4 h-4 rounded-full bg-gray-300"></div>
</div>
<div class="drop-zone bg-gray-100 p-4 rounded-lg min-h-32 flex flex-col items-center justify-center touch-target hidden" id="projector3Zone" data-destination="projector3">
<div class="destination-content text-center">
<i data-feather="monitor" class="w-8 h-8 mx-auto text-gray-500"></i>
<div class="font-semibold mt-1">Projector 3</div>
<div class="text-xs text-gray-500">Drag source here</div>
</div>
<div class="audio-indicator mt-2 w-4 h-4 rounded-full bg-gray-300"></div>
</div>
</div>
</div>
</div>
<!-- Audio Panel -->
<div id="audioPanel" class="menu-panel hidden">
<h2 class="text-xl font-bold text-[#00509e] mb-4">Audio Controls</h2>
<div class="grid grid-cols-4 gap-6 mb-8">
<div class="mic-control">
<h3 class="text-lg font-semibold mb-2">Mic 1</h3>
<input type="range" min="0" max="100" value="50" class="volume-fader w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer">
<div class="flex justify-between text-xs text-gray-600 mt-1">
<span>0%</span>
<span>100%</span>
</div>
<button class="mic-mute-btn mt-2 bg-[#4CAF50] text-white px-4 py-2 rounded-lg w-full touch-target">
<i data-feather="mic" class="w-4 h-4 inline mr-1"></i>
<span>Mute</span>
</button>
</div>
<div class="mic-control">
<h3 class="text-lg font-semibold mb-2">Mic 2</h3>
<input type="range" min="0" max="100" value="50" class="volume-fader w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer">
<div class="flex justify-between text-xs text-gray-600 mt-1">
<span>0%</span>
<span>100%</span>
</div>
<button class="mic-mute-btn mt-2 bg-[#4CAF50] text-white px-4 py-2 rounded-lg w-full touch-target">
<i data-feather="mic" class="w-4 h-4 inline mr-1"></i>
<span>Mute</span>
</button>
</div>
<div class="mic-control">
<h3 class="text-lg font-semibold mb-2">Mic 3</h3>
<input type="range" min="0" max="100" value="50" class="volume-fader w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer">
<div class="flex justify-between text-xs text-gray-600 mt-1">
<span>0%</span>
<span>100%</span>
</div>
<button class="mic-mute-btn mt-2 bg-[#4CAF50] text-white px-4 py-2 rounded-lg w-full touch-target">
<i data-feather="mic" class="w-4 h-4 inline mr-1"></i>
<span>Mute</span>
</button>
</div>
<div class="mic-control">
<h3 class="text-lg font-semibold mb-2">Mic 4</h3>
<input type="range" min="0" max="100" value="50" class="volume-fader w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer">
<div class="flex justify-between text-xs text-gray-600 mt-1">
<span>0%</span>
<span>100%</span>
</div>
<button class="mic-mute-btn mt-2 bg-[#4CAF50] text-white px-4 py-2 rounded-lg w-full touch-target">
<i data-feather="mic" class="w-4 h-4 inline mr-1"></i>
<span>Mute</span>
</button>
</div>
</div>
<div class="bg-gray-100 p-4 rounded-lg">
<h3 class="text-lg font-semibold mb-2">Program Audio</h3>
<div class="flex items-center space-x-4">
<div class="flex-1">
<input type="range" min="0" max="100" value="70" class="volume-fader w-full h-2 bg-gray-300 rounded-lg appearance-none cursor-pointer">
<div class="flex justify-between text-xs text-gray-600 mt-1">
<span>0%</span>
<span>100%</span>
</div>
</div>
<button class="program-mute-btn bg-[#4CAF50] text-white px-4 py-2 rounded-lg touch-target">
<i data-feather="volume-2" class="w-4 h-4 inline mr-1"></i>
<span>Mute</span>
</button>
</div>
<div class="mt-4">
<h4 class="font-semibold mb-2">Audio Source Override</h4>
<div class="grid grid-cols-4 gap-2">
<button class="audio-source-btn bg-gray-200 hover:bg-gray-300 px-3 py-2 rounded-lg text-sm touch-target">NTNU PC</button>
<button class="audio-source-btn bg-gray-200 hover:bg-gray-300 px-3 py-2 rounded-lg text-sm touch-target">Laptop HDMI</button>
<button class="audio-source-btn bg-gray-200 hover:bg-gray-300 px-3 py-2 rounded-lg text-sm touch-target">Doc Camera</button>
<button class="audio-source-btn bg-gray-200 hover:bg-gray-300 px-3 py-2 rounded-lg text-sm touch-target">None</button>
</div>
</div>
</div>
</div>
<!-- Lighting Panel -->
<div id="lightingPanel" class="menu-panel hidden">
<h2 class="text-xl font-bold text-[#00509e] mb-4">Lighting Controls</h2>
<div class="mb-6">
<h3 class="text-lg font-semibold mb-2">Presets</h3>
<div class="grid grid-cols-4 gap-4">
<button class="light-preset-btn bg-gray-200 hover:bg-gray-300 p-3 rounded-lg text-center touch-target">
<i data-feather="sun" class="w-6 h-6 mx-auto"></i>
<div class="font-semibold mt-1">All Lights</div>
</button>
<button class="light-preset-btn bg-gray-200 hover:bg-gray-300 p-3 rounded-lg text-center touch-target">
<i data-feather="user" class="w-6 h-6 mx-auto"></i>
<div class="font-semibold mt-1">Podium</div>
</button>
<button class="light-preset-btn bg-gray-200 hover:bg-gray-300 p-3 rounded-lg text-center touch-target">
<i data-feather="edit-3" class="w-6 h-6 mx-auto"></i>
<div class="font-semibold mt-1">Whiteboard</div>
</button>
<button class="light-preset-btn bg-gray-200 hover:bg-gray-300 p-3 rounded-lg text-center touch-target">
<i data-feather="video" class="w-6 h-6 mx-auto"></i>
<div class="font-semibold mt-1">Video</div>
</button>
</div>
</div>
<div>
<h3 class="text-lg font-semibold mb-2">Adjustable Lights</h3>
<div class="grid grid-cols-2 gap-6">
<div class="light-control">
<h4 class="font-semibold mb-2">Room Lights</h4>
<input type="range" min="0" max="100" value="70" class="volume-fader w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer" orient="vertical" style="height: 120px;">
<div class="flex justify-between text-xs text-gray-600 mt-1">
<span>0%</span>
<span>100%</span>
</div>
</div>
<div class="light-control">
<h4 class="font-semibold mb-2">Podium Lights</h4>
<input type="range" min="0" max="100" value="70" class="volume-fader w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer" orient="vertical" style="height: 120px;">
<div class="flex justify-between text-xs text-gray-600 mt-1">
<span>0%</span>
<span>100%</span>
</div>
</div>
</div>
</div>
</div>
<!-- Blinds Panel -->
<div id="blindsPanel" class="menu-panel hidden">
<h2 class="text-xl font-bold text-[#00509e] mb-4">Blinds & Screens</h2>
<div class="grid grid-cols-2 gap-6">
<div class="screen-control">
<h3 class="text-lg font-semibold mb-2">Projection Screen</h3>
<div class="grid grid-cols-3 gap-2">
<button class="screen-btn bg-[#00509e] text-white p-3 rounded-lg text-center touch-target">
<i data-feather="chevron-up" class="w-6 h-6 mx-auto"></i>
<div class="font-semibold mt-1">Up</div>
</button>
<button class="screen-btn bg-gray-500 text-white p-3 rounded-lg text-center touch-target">
<i data-feather="square" class="w-6 h-6 mx-auto"></i>
<div class="font-semibold mt-1">Stop</div>
</button>
<button class="screen-btn bg-[#00509e] text-white p-3 rounded-lg text-center touch-target">
<i data-feather="chevron-down" class="w-6 h-6 mx-auto"></i>
<div class="font-semibold mt-1">Down</div>
</button>
</div>
</div>
<div class="blinds-control">
<h3 class="text-lg font-semibold mb-2">Window Blinds</h3>
<div class="grid grid-cols-3 gap-2">
<button class="blinds-btn bg-[#00509e] text-white p-3 rounded-lg text-center touch-target">
<i data-feather="chevron-up" class="w-6 h-6 mx-auto"></i>
<div class="font-semibold mt-1">Up</div>
</button>
<button class="blinds-btn bg-gray-500 text-white p-3 rounded-lg text-center touch-target">
<i data-feather="square" class="w-6 h-6 mx-auto"></i>
<div class="font-semibold mt-1">Stop</div>
</button>
<button class="blinds-btn bg-[#00509e] text-white p-3 rounded-lg text-center touch-target">
<i data-feather="chevron-down" class="w-6 h-6 mx-auto"></i>
<div class="font-semibold mt-1">Down</div>
</button>
</div>
</div>
</div>
</div>
<!-- Camera Panel -->
<div id="cameraPanel" class="menu-panel hidden">
<h2 class="text-xl font-bold text-[#00509e] mb-4">Teaching Camera</h2>
<div class="mb-6">
<h3 class="text-lg font-semibold mb-2">Presets</h3>
<div class="grid grid-cols-3 gap-4">
<button class="camera-preset-btn bg-[#00509e] text-white p-3 rounded-lg text-center touch-target">
<i data-feather="edit-3" class="w-6 h-6 mx-auto"></i>
<div class="font-semibold mt-1">Whiteboard</div>
</button>
<button class="camera-preset-btn bg-[#00509e] text-white p-3 rounded-lg text-center touch-target">
<i data-feather="user" class="w-6 h-6 mx-auto"></i>
<div class="font-semibold mt-1">Lecturer Desk</div>
</button>
<button class="camera-preset-btn bg-[#00509e] text-white p-3 rounded-lg text-center touch-target">
<i data-feather="mic" class="w-6 h-6 mx-auto"></i>
<div class="font-semibold mt-1">Podium</div>
</button>
<button class="camera-preset-btn bg-[#00509e] text-white p-3 rounded-lg text-center touch-target">
<i data-feather="arrow-left" class="w-6 h-6 mx-auto"></i>
<div class="font-semibold mt-1">WB Left</div>
</button>
<button class="camera-preset-btn bg-[#00509e] text-white p-3 rounded-lg text-center touch-target">
<i data-feather="align-center" class="w-6 h-6 mx-auto"></i>
<div class="font-semibold mt-1">WB Center</div>
</button>
<button class="camera-preset-btn bg-[#00509e] text-white p-3 rounded-lg text-center touch-target">
<i data-feather="arrow-right" class="w-6 h-6 mx-auto"></i>
<div class="font-semibold mt-1">WB Right</div>
</button>
</div>
</div>
<div class="bg-gray-100 p-4 rounded-lg">
<h3 class="text-lg font-semibold mb-2">Tracking Control</h3>
<button id="trackingToggle" class="bg-[#4CAF50] hover:bg-[#3e8e41] text-white font-bold py-3 px-6 rounded-lg text-lg transition-colors w-full touch-target">
<i data-feather="user-check" class="w-5 h-5 inline mr-2"></i>
<span>Tracking: ON</span>
</button>
</div>
</div>
<!-- Shutdown Panel -->
<div id="shutdownPanel" class="menu-panel hidden">
<h2 class="text-xl font-bold text-[#00509e] mb-4">System Shutdown</h2>
<div class="bg-gray-100 p-6 rounded-lg max-w-md mx-auto">
<p class="text-lg mb-6">Are you sure you want to shut down the system?</p>
<div class="grid grid-cols-2 gap-4 mb-6">
<button id="shutdownConfirm" class="bg-[#00509e] hover:bg-[#003d7a] text-white font-bold py-3 px-4 rounded-lg transition-colors touch-target">
Shut Down
</button>
<button id="shutdownCancel" class="bg-gray-500 hover:bg-gray-600 text-white font-bold py-3 px-4 rounded-lg transition-colors touch-target">
Cancel
</button>
</div>
<div class="border-t border-gray-300 pt-4">
<p class="text-sm font-semibold mb-2">How did the room work today?</p>
<div class="flex justify-around">
<button class="feedback-btn text-[#4CAF50] hover:text-[#3e8e41] text-4xl touch-target" data-rating="good">
😊
</button>
<button class="feedback-btn text-[#FFC107] hover:text-[#FFA000] text-4xl touch-target" data-rating="neutral">
😐
</button>
<button class="feedback-btn text-[#F44336] hover:text-[#D32F2F] text-4xl touch-target" data-rating="poor">
😞
</button>
</div>
</div>
</div>
</div>
<!-- Technician Panel -->
<div id="technicianPanel" class="menu-panel hidden">
<div class="flex items-center justify-between mb-6">
<h2 class="text-xl font-bold text-[#00509e]">Technician Menu</h2>
<button id="logoutTechBtn" class="bg-gray-500 hover:bg-gray-600 text-white font-bold py-2 px-4 rounded-lg text-sm transition-colors touch-target">
Logout
</button>
</div>
<div class="bg-gray-100 rounded-lg overflow-hidden">
<div class="flex border-b border-gray-300">
<button class="tech-tab-btn active py-3 px-6 font-semibold text-[#00509e] border-b-2 border-[#00509e] touch-target">System</button>
<button class="tech-tab-btn py-3 px-6 font-semibold text-gray-600 hover:text-[#00509e] touch-target">Audio Mixer</button>
<button class="tech-tab-btn py-3 px-6 font-semibold text-gray-600 hover:text-[#00509e] touch-target">Video Mixer</button>
<button class="tech-tab-btn py-3 px-6 font-semibold text-gray-600 hover:text-[#00509e] touch-target">Microphones</button>
<button class="tech-tab-btn py-3 px-6 font-semibold text-gray-600 hover:text-[#00509e] touch-target">Camera</button>
<button class="tech-tab-btn py-3 px-6 font-semibold text-gray-600 hover:text-[#00509e] touch-target">Feedback</button>
<button class="tech-tab-btn py-3 px-6 font-semibold text-gray-600 hover:text-[#00509e] touch-target">Diagnostics</button>
</div>
<div class="p-6">
<!-- System Tab Content -->
<div id="systemTab" class="tech-tab-content">
<h3 class="text-lg font-semibold mb-4">System Information</h3>
<div class="grid grid-cols-2 gap-4 mb-6">
<div>
<p class="text-sm text-gray-600">Crestron Version:</p>
<p class="font-semibold">3.12.456.0</p>
</div>
<div>
<p class="text-sm text-gray-600">Last Updated:</p>
<p class="font-semibold">2023-11-15</p>
</div>
<div>
<p class="text-sm text-gray-600">Programmer:</p>
<p class="font-semibold">NTNU AV Services</p>
</div>
<div>
<p class="text-sm text-gray-600">Vendor:</p>
<p class="font-semibold">Crestron Electronics</p>
</div>
</div>
<div class="border-t border-gray-300 pt-4">
<h3 class="text-lg font-semibold mb-2">Change Technician PIN</h3>
<div class="flex items-center space-x-4">
<input type="password" class="border border-gray-300 rounded-lg px-3 py-2 w-32" placeholder="New PIN" maxlength="5">
<button class="bg-[#00509e] hover:bg-[#003d7a] text-white font-bold py-2 px-4 rounded-lg transition-colors touch-target">
Update
</button>
</div>
</div>
</div>
<!-- Other tabs would be implemented similarly -->
<div id="audioMixerTab" class="tech-tab-content hidden">
<!-- Audio mixer controls would go here -->
</div>
<div id="videoMixerTab" class="tech-tab-content hidden">
<!-- Video mixer controls would go here -->
</div>
<div id="microphonesTab" class="tech-tab-content hidden">
<!-- Microphone pairing controls would go here -->
</div>
<div id="cameraTab" class="tech-tab-content hidden">
<!-- Camera PTZ controls would go here -->
</div>
<div id="feedbackTab" class="tech-tab-content hidden">
<!-- Feedback statistics would go here -->
</div>
<div id="diagnosticsTab" class="tech-tab-content hidden">
<!-- Diagnostics information would go here -->
</div>
</div>
</div>
</div>
<!-- PIN Entry Modal -->
<div id="pinModal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center hidden z-50">
<div class="bg-white p-6 rounded-lg max-w-sm w-full">
<h3 class="text-xl font-bold text-[#00509e] mb-4">Enter Technician PIN</h3>
<div class="mb-4">
<input type="password" id="pinInput" class="border border-gray-300 rounded-lg px-4 py-3 w-full text-center text-xl tracking-widest" placeholder="00000" maxlength="5">
</div>
<div class="grid grid-cols-3 gap-2 mb-4">
<button class="pin-btn bg-gray-200 hover:bg-gray-300 py-3 rounded-lg font-semibold touch-target">1</button>
<button class="pin-btn bg-gray-200 hover:bg-gray-300 py-3 rounded-lg font-semibold touch-target">2</button>
<button class="pin-btn bg-gray-200 hover:bg-gray-300 py-3 rounded-lg font-semibold touch-target">3</button>
<button class="pin-btn bg-gray-200 hover:bg-gray-300 py-3 rounded-lg font-semibold touch-target">4</button>
<button class="pin-btn bg-gray-200 hover:bg-gray-300 py-3 rounded-lg font-semibold touch-target">5</button>
<button class="pin-btn bg-gray-200 hover:bg-gray-300 py-3 rounded-lg font-semibold touch-target">6</button>
<button class="pin-btn bg-gray-200 hover:bg-gray-300 py-3 rounded-lg font-semibold touch-target">7</button>
<button class="pin-btn bg-gray-200 hover:bg-gray-300 py-3 rounded-lg font-semibold touch-target">8</button>
<button class="pin-btn bg-gray-200 hover:bg-gray-300 py-3 rounded-lg font-semibold touch-target">9</button>
<button class="pin-btn bg-gray-200 hover:bg-gray-300 py-3 rounded-lg font-semibold touch-target">0</button>
<button class="pin-btn bg-gray-200 hover:bg-gray-300 py-3 rounded-lg font-semibold touch-target">
<i data-feather="delete" class="w-5 h-5 mx-auto"></i>
</button>
</div>
<div class="flex space-x-4">
<button id="pinSubmit" class="flex-1 bg-[#00509e] hover:bg-[#003d7a] text-white font-bold py-2 px-4 rounded-lg transition-colors touch-target">
Submit
</button>
<button id="pinCancel" class="flex-1 bg-gray-500 hover:bg-gray-600 text-white font-bold py-2 px-4 rounded-lg transition-colors touch-target">
Cancel
</button>
</div>
</div>
</div>
<!-- Help Modal -->
<div id="helpModal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center hidden z-50">
<div class="bg-white p-6 rounded-lg max-w-md w-full">
<div class="flex justify-between items-center mb-4">
<h3 class="text-xl font-bold text-[#00509e]">Help</h3>
<button id="helpClose" class="text-gray-500 hover:text-gray-700">
<i data-feather="x" class="w-6 h-6"></i>
</button>
</div>
<div class="prose">
<p>For assistance with the classroom AV system:</p>
<ul class="list-disc pl-5">
<li>Press the "Start Room" button to power on all equipment</li>
<li>Drag video sources to projectors to route content</li>
<li>Adjust microphone and audio levels as needed</li>
<li>Use presets for quick lighting adjustments</li>
</ul>
<p class="mt-4">For technical support, contact NTNU AV Services:</p>
<p class="font-semibold">Phone: 123 456 78</p>
<p class="font-semibold">Email: av-support@ntnu.no</p>
</div>
<div class="mt-6 text-center">
<img src="http://static.photos/technology/320x240/1" alt="Support QR Code" class="w-32 h-32 mx-auto">
<p class="text-sm mt-2">Scan for more help resources</p>
</div>
</div>
</div>
</div>
</div>
<script>
// Initialize Feather Icons
feather.replace();
// Current state variables
let currentLanguage = 'en';
let isRecording = false;
let isTrackingOn = true;
let isRoomStarted = false;
let isTechMode = false;
// DOM Elements
const langToggle = document.getElementById('langToggle');
const helpBtn = document.getElementById('helpBtn');
const helpModal = document.getElementById('helpModal');
const helpClose = document.getElementById('helpClose');
const recordingIndicator = document.getElementById('recordingIndicator');
const startRoomBtn = document.getElementById('startRoomBtn');
const techBtn = document.getElementById('techBtn');
const pinModal = document.getElementById('pinModal');
const pinInput = document.getElementById('pinInput');
const pinSubmit = document.getElementById('pinSubmit');
const pinCancel = document.getElementById('pinCancel');
const logoutTechBtn = document.getElementById('logoutTechBtn');
const trackingToggle = document.getElementById('trackingToggle');
const shutdownConfirm = document.getElementById('shutdownConfirm');
const shutdownCancel = document.getElementById('shutdownCancel');
// Menu buttons and panels
const menuButtons = document.querySelectorAll('.menu-btn');
const menuPanels = document.querySelectorAll('.menu-panel');
// Technician tab buttons and content
const techTabButtons = document.querySelectorAll('.tech-tab-btn');
const techTabContents = document.querySelectorAll('.tech-tab-content');
// PIN buttons
const pinButtons = document.querySelectorAll('.pin-btn');
// Feedback buttons
const feedbackButtons = document.querySelectorAll('.feedback-btn');
// Drag and drop elements
const dragSources = document.querySelectorAll('.drag-source');
const dropZones = document.querySelectorAll('.drop-zone');
// Mute buttons
const muteButtons = document.querySelectorAll('.mic-mute-btn, .program-mute-btn');
// Event Listeners
langToggle.addEventListener('click', toggleLanguage);
helpBtn.addEventListener('click', () => helpModal.classList.remove('hidden'));
helpClose.addEventListener('click', () => helpModal.classList.add('hidden'));
startRoomBtn.addEventListener('click', startRoom);
techBtn.addEventListener('click', () => pinModal.classList.remove('hidden'));
pinSubmit.addEventListener('click', checkPin);
pinCancel.addEventListener('click', () => pinModal.classList.add('hidden'));
logoutTechBtn.addEventListener('click', logoutTechnician);
trackingToggle.addEventListener('click', toggleTracking);
shutdownConfirm.addEventListener('click', shutdownSystem);
shutdownCancel.addEventListener('click', () => showPanel('home'));
// Menu navigation
menuButtons.forEach(button => {
button.addEventListener('click', () => {
const menu = button.dataset.menu;
showPanel(menu);
// Update active state
menuButtons.forEach(btn => btn.classList.remove('active', 'bg-[#00509e]', 'text-white'));
button.classList.add('active', 'bg-[#00509e]', 'text-white');
});
});
// Technician tabs
techTabButtons.forEach((button, index) => {
button.addEventListener('click', () => {
techTabButtons.forEach(btn => {
btn.classList.remove('active', 'text-[#00509e]', 'border-[#00509e]');
btn.classList.add('text-gray-600');
});
button.classList.add('active', 'text-[#00509e]', 'border-[#00509e]');
button.classList.remove('text-gray-600');
techTabContents.forEach(content => content.classList.add('hidden'));
techTabContents[index].classList.remove('hidden');
});
});
// PIN pad
pinButtons.forEach(button => {
button.addEventListener('click', () => {
if (button.querySelector('i')) {
// Delete button
pinInput.value = pinInput.value.slice(0, -1);
} else {
// Number button
if (pinInput.value.length < 5) {
pinInput.value += button.textContent.trim();
}
}
});
});
// Feedback buttons
feedbackButtons.forEach(button => {
button.addEventListener('click', () => {
const rating = button.dataset.rating;
// In a real implementation, this would send the feedback to a server
alert(`Thank you for your feedback (${rating}). The system will now shut down.`);
shutdownSystem();
});
});
// Drag and drop functionality
dragSources.forEach(source => {
source.addEventListener('dragstart', dragStart);
});
dropZones.forEach(zone => {
zone.addEventListener('dragover', dragOver);
zone.addEventListener('dragenter', dragEnter);
zone.addEventListener('dragleave', dragLeave);
zone.addEventListener('drop', drop);
zone.addEventListener('click', dropZoneClick);
});
// Mute buttons
muteButtons.forEach(button => {
button.addEventListener('click', toggleMute);
});
// Functions
function toggleLanguage() {
currentLanguage = currentLanguage === 'en' ? 'no' : 'en';
langToggle.textContent = currentLanguage.toUpperCase();
// In a real implementation, this would switch all text in the UI
}
function startRoom() {
isRoomStarted = true;
startRoomBtn.textContent = 'Room Started';
startRoomBtn.classList.remove('bg-[#00509e]', 'hover:bg-[#003d7a]');
startRoomBtn.classList.add('bg-gray-500', 'hover:bg-gray-600');
startRoomBtn.disabled = true;
// Show projector 3 if it exists in this room
document.getElementById('projector3Zone').classList.remove('hidden');
// Auto-switch to Image panel
showPanel('image');
}
function showPanel(panelName) {
menuPanels.forEach(panel => panel.classList.add('hidden'));
document.getElementById(`${panelName}Panel`).classList.remove('hidden');
}
function checkPin() {
if (pinInput.value === '00000') {
isTechMode = true;
techBtn.classList.remove('hidden');
pinModal.classList.add('hidden');
showPanel('technician');
} else {
alert('Incorrect PIN');
pinInput.value = '';
}
}
function logoutTechnician() {
isTechMode = false;
techBtn.classList.add('hidden');
showPanel('home');
}
function toggleTracking() {
isTrackingOn = !isTrackingOn;
trackingToggle.innerHTML = `
<i data-feather="${isTrackingOn ? 'user-check' : 'user-x'}" class="w-5 h-5 inline mr-2"></i>
<span>Tracking: ${isTrackingOn ? 'ON' : 'OFF'}</span>
`;
trackingToggle.classList.toggle('bg-[#4CAF50]', isTrackingOn);
trackingToggle.classList.toggle('bg-[#F44336]', !isTrackingOn);
trackingToggle.classList.toggle('hover:bg-[#3e8e41]', isTrackingOn);
trackingToggle.classList.toggle('hover:bg-[#D32F2F]', !isTrackingOn);
feather.replace();
}
function shutdownSystem() {
// In a real implementation, this would send a shutdown command to the Crestron system
alert('System is shutting down...');
isRoomStarted = false;
showPanel('home');
// Reset start button
startRoomBtn.textContent = 'Start Room';
startRoomBtn.classList.add('bg-[#00509e]', 'hover:bg-[#003d7a]');
startRoomBtn.classList.remove('bg-gray-500', 'hover:bg-gray-600');
startRoomBtn.disabled = false;
}
function toggleMute(e) {
const button = e.currentTarget;
const isMuted = button.classList.contains('bg-[#F44336]');
button.classList.toggle('bg-[#4CAF50]', isMuted);
button.classList.toggle('bg-[#F44336]', !isMuted);
button.classList.toggle('hover:bg-[#3e8e41]', isMuted);
button.classList.toggle('hover:bg-[#D32F2F]', !isMuted);
const icon = button.querySelector('i');
const text = button.querySelector('span');
if (isMuted) {
icon.setAttribute('data-feather', 'mic');
text.textContent = 'Mute';
} else {
icon.setAttribute('data-feather', 'mic-off');
text.textContent = 'Unmute';
}
feather.replace();
}
// Drag and drop functions
let draggedSource = null;
function dragStart(e) {
draggedSource = e.target;
e.dataTransfer.setData('text/plain', e.target.dataset.source);
setTimeout(() => {
e.target.classList.add('opacity-50');
}, 0);
}
function dragOver(e) {
e.preventDefault();
}
function dragEnter(e) {
e.preventDefault();
e.currentTarget.classList.add('active');
}
function dragLeave(e) {
e.currentTarget.classList.remove('active');
}
function drop(e) {
e.preventDefault();
e.currentTarget.classList.remove('active');
const sourceType = e.dataTransfer.getData('text/plain');
const dropZone = e.currentTarget;
updateDropZone(dropZone, sourceType);
if (draggedSource) {
draggedSource.classList.remove('opacity-50');
draggedSource = null;
}
}
function dropZoneClick(e) {
const dropZone = e.currentTarget.closest('.drop-zone');
if (!dropZone) return;
// Create a simple source selector for touch devices
const currentSource = dropZone.dataset.currentSource;
const sources = ['ntnu-pc', 'laptop-hdmi', 'doc-cam', 'off'];
const currentIndex = sources.indexOf(currentSource);
const nextIndex = (currentIndex + 1) % sources.length;
updateDropZone(dropZone, sources[nextIndex]);
}
function updateDropZone(dropZone, sourceType) {
const content = dropZone.querySelector('.destination-content');
const audioIndicator = dropZone.querySelector('.audio-indicator');
dropZone.dataset.currentSource = sourceType;
if (sourceType === 'off') {
content.innerHTML = `
<i data-feather="monitor" class="w-8 h-8 mx-auto text-gray-500"></i>
<div class="font-semibold mt-1">${dropZone.dataset.destination.replace('projector', 'Projector ')}</div>
<div class="text-xs text-gray-500">Drag source here</div>
`;
audioIndicator.classList.remove('bg-[#4CAF50]');
audioIndicator.classList.add('bg-gray-300');
} else {
let icon, label;
switch(sourceType) {
case 'ntnu-pc':
icon = 'cpu';
label = 'NTNU PC';
break;
case 'laptop-hdmi':
icon = 'laptop';
label = 'Laptop HDMI';
break;
case 'doc-cam':
icon = 'image';
label = 'Document Camera';
break;
}
content.innerHTML = `
<i data-feather="${icon}" class="w-8 h-8 mx-auto text-[#00509e]"></i>
<div class="font-semibold mt-1">${label}</div>
`;
// Set audio indicator to active (green) if this is the audio source
const isAudioSource = true; // In a real app, this would check the actual state
audioIndicator.classList.toggle('bg-[#4CAF50]', isAudioSource);
audioIndicator.classList.toggle('bg-gray-300', !isAudioSource);
}
feather.replace();
}
</script>
</body>
</html>