639 lines
28 KiB
HTML
639 lines
28 KiB
HTML
<!doctype html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||
<title>Bilateral Stimulation Simulator - Admin</title>
|
||
<link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Ccircle cx='8' cy='8' r='6' fill='%231f6feb'/%3E%3C/svg%3E">
|
||
<link rel="stylesheet" href="css/admin.css">
|
||
</head>
|
||
<body>
|
||
<header>
|
||
<div class="header-content">
|
||
<h1>Bilateral Stimulation Simulator</h1>
|
||
<div class="simple-toggle" style="margin:0 auto; display:flex; align-items:center; gap:8px;">
|
||
<label class="control-label" style="color:inherit;">Simple View</label>
|
||
<label class="toggle">
|
||
<input type="checkbox" id="simpleViewEnable">
|
||
<span class="toggle-track"><span class="toggle-thumb"></span></span>
|
||
</label>
|
||
</div>
|
||
<div class="header-actions">
|
||
<button id="openPatient" class="btn-secondary">
|
||
<span class="btn-icon">👁️</span>
|
||
Open Patient View
|
||
</button>
|
||
|
||
</div>
|
||
</div>
|
||
</header>
|
||
|
||
<div id="lockBanner" class="lock-banner">
|
||
<span class="lock-icon">🔒</span>
|
||
LOCKED • Hold U to unlock
|
||
</div>
|
||
|
||
<main>
|
||
<!-- Left Column: Controls -->
|
||
<aside class="sidebar">
|
||
<section class="panel collapsible" id="visualPanel">
|
||
<h2 role="button" tabindex="0">
|
||
<span class="panel-icon">🎨</span>
|
||
Visual Settings
|
||
<span class="panel-actions">
|
||
<label class="toggle" title="Toggle Dark/Light">
|
||
<input type="checkbox" id="themeToggle">
|
||
<span class="toggle-track"><span class="toggle-thumb"></span></span>
|
||
</label>
|
||
</span>
|
||
</h2>
|
||
|
||
<div class="control-group">
|
||
<label class="control-label">Shape</label>
|
||
<div class="button-group" id="shapeControls">
|
||
<button data-shape="circle" class="active">⚪ Circle</button>
|
||
<button data-shape="square">⬛ Square</button>
|
||
<button data-shape="triangle">🔺 Triangle</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="control-group">
|
||
<label class="control-label">Shape Color</label>
|
||
<div class="color-swatches" id="shapeSwatches">
|
||
<button class="swatch swatch-green" data-color="#00ff00" title="Green"></button>
|
||
<button class="swatch swatch-blue" data-color="#0066ff" title="Blue"></button>
|
||
<button class="swatch swatch-yellow" data-color="#ffd400" title="Yellow"></button>
|
||
<button class="swatch swatch-red" data-color="#ff2a2a" title="Red"></button>
|
||
<button class="swatch swatch-white" data-color="#ffffff" title="White"></button>
|
||
<button class="swatch swatch-custom" id="shapeCustom" title="Custom Color"></button>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="control-group">
|
||
<label class="control-label">Background</label>
|
||
<div class="color-swatches" id="bgSwatches">
|
||
<button class="swatch swatch-black" data-color="#000000" title="Black"></button>
|
||
<button class="swatch swatch-blue" data-color="#0066ff" title="Blue"></button>
|
||
<button class="swatch swatch-yellow" data-color="#ffd400" title="Yellow"></button>
|
||
<button class="swatch swatch-red" data-color="#ff2a2a" title="Red"></button>
|
||
<button class="swatch swatch-white" data-color="#ffffff" title="White"></button>
|
||
<button class="swatch swatch-custom" id="bgCustom" title="Custom Color"></button>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="control-group">
|
||
<label class="control-label">Movement Direction</label>
|
||
<div class="button-group" id="directionControls">
|
||
<button data-direction="lr" class="active">HORIZ ↔️</button>
|
||
<button data-direction="ud">VERT ↕️</button>
|
||
<button data-direction="diag_down">DIAG L ↘️</button>
|
||
<button data-direction="diag_up">DIAG R ↗️</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="control-group">
|
||
<label class="control-label">Display Width</label>
|
||
<div class="button-group" id="widthControls">
|
||
<button data-width="full" class="active">Full</button>
|
||
<button data-width="reduced">Reduced</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="control-group">
|
||
<label class="control-label">Size: <span id="sizeLabel">28 px</span></label>
|
||
<input type="range" id="size" min="10" max="100" step="0.5" value="28" class="slider">
|
||
</div>
|
||
|
||
<div class="control-group">
|
||
<label class="control-label">Vertical Position: <span id="yPercentLabel">50%</span></label>
|
||
<div class="slider-with-reset">
|
||
<input type="range" id="yPercent" min="0" max="100" step="1" value="50" class="slider">
|
||
<button id="yReset" class="btn-small">Reset</button>
|
||
</div>
|
||
<div class="control-row" style="margin-top:8px;">
|
||
<div class="control-group">
|
||
<label class="control-label" style="margin:0;">Vertical Oscillation</label>
|
||
<label class="toggle">
|
||
<input type="checkbox" id="yOscillateEnable">
|
||
<span class="toggle-track"><span class="toggle-thumb"></span></span>
|
||
</label>
|
||
</div>
|
||
<div class="control-group">
|
||
<label class="control-label">Gradual Speed Ramp</label>
|
||
<label class="toggle">
|
||
<input type="checkbox" id="rampEnable">
|
||
<span class="toggle-track"><span class="toggle-thumb"></span></span>
|
||
</label>
|
||
</div>
|
||
</div>
|
||
<div class="control-group">
|
||
<label class="control-label">Ramp Duration: <span id="rampLabel">10 s</span></label>
|
||
<input type="range" id="rampSeconds" min="1" max="60" step="1" value="10" class="slider">
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<section class="panel collapsible" id="networkPanel">
|
||
<h2 role="button" tabindex="0">
|
||
<span class="panel-icon">✨</span>
|
||
Effects
|
||
</h2>
|
||
|
||
<div class="control-group">
|
||
<label class="control-label">Glow Pulse Effect</label>
|
||
<label class="toggle">
|
||
<input type="checkbox" id="glowEnable">
|
||
<span class="toggle-track"><span class="toggle-thumb"></span></span>
|
||
</label>
|
||
</div>
|
||
|
||
<div class="control-group control-indent">
|
||
<label class="control-label">Intensity: <span id="glowIntensityLabel">100%</span></label>
|
||
<input type="range" id="glowIntensity" min="0" max="200" step="5" value="100" class="slider">
|
||
</div>
|
||
|
||
<div class="control-group control-indent">
|
||
<label class="control-label">Rate: <span id="glowRateLabel">0.5 Hz</span></label>
|
||
<input type="range" id="glowRate" min="0.1" max="3" step="0.1" value="0.5" class="slider">
|
||
</div>
|
||
|
||
<div class="control-group">
|
||
<label class="control-label">Wiggle Effect</label>
|
||
<label class="toggle">
|
||
<input type="checkbox" id="wiggleEnable">
|
||
<span class="toggle-track"><span class="toggle-thumb"></span></span>
|
||
</label>
|
||
</div>
|
||
|
||
<div class="control-group control-indent">
|
||
<label class="control-label">Amount: <span id="wiggleLabel">0 px</span></label>
|
||
<input type="range" id="wiggleAmplitude" min="0" max="10" step="1" value="0" class="slider">
|
||
</div>
|
||
|
||
<div class="control-group">
|
||
<label class="control-label">Movement Style</label>
|
||
<div class="button-group" id="easingControls">
|
||
<button data-easing="linear" class="active">Linear</button>
|
||
<button data-easing="ease">Smooth</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="control-group">
|
||
<label class="control-label">Edge Pause: <span id="edgePauseLabel">0 ms</span></label>
|
||
<input type="range" id="edgePause" min="0" max="150" step="10" value="0" class="slider">
|
||
</div>
|
||
</section>
|
||
|
||
<section class="panel panel-recording collapsible" id="recordingPanel">
|
||
<h2 role="button" tabindex="0">
|
||
<span class="panel-icon">🔊</span>
|
||
Audio Settings
|
||
</h2>
|
||
|
||
<div class="control-group">
|
||
<div class="button-group" id="audioModeButtons">
|
||
<button data-mode="programmatic" class="active">Program</button>
|
||
<button id="loadAudioBtn">Load Audio</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="control-group" style="display:flex; align-items:center; justify-content:space-between; gap:8px;">
|
||
<div>
|
||
<label class="control-label">Enable Audio</label>
|
||
<label class="toggle">
|
||
<input type="checkbox" id="audioEnable">
|
||
<span class="toggle-track"><span class="toggle-thumb"></span></span>
|
||
</label>
|
||
</div>
|
||
<button id="testSound" class="btn-small">Test Sound</button>
|
||
</div>
|
||
|
||
<div id="programmaticControls" class="audio-controls">
|
||
<div class="control-group">
|
||
<div class="button-group" id="soundToneToggle">
|
||
<button data-mode="sound" class="active">Sound</button>
|
||
<button data-mode="tone">Tone</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="soundPresetControls" class="control-group">
|
||
<label class="control-label">Sound Type</label>
|
||
<select id="soundPreset" class="select-input">
|
||
<option value="pink">Pink Noise</option>
|
||
<option value="hybrid">Hybrid (noise + edge cues)</option>
|
||
<option value="click">Click</option>
|
||
<option value="ping">Ping</option>
|
||
<option value="woodblock">Woodblock</option>
|
||
<option value="bell">Bell</option>
|
||
<option value="bass">Bass</option>
|
||
<option value="kick">Kick</option>
|
||
<option value="snare">Snare</option>
|
||
<option value="hihat">Hi-Hat</option>
|
||
<option value="sweep">Sweep</option>
|
||
<option value="zap">Zap</option>
|
||
<option value="bubble">Bubble</option>
|
||
</select>
|
||
</div>
|
||
|
||
<div id="tonePresetControls" class="control-group">
|
||
<label class="control-label">Tone Preset</label>
|
||
<select id="tonePreset" class="select-input">
|
||
<option value="warm_low">Warm Low — 180 Hz @ 100 ms</option>
|
||
<option value="soft_pulse">Soft Pulse — 220 Hz @ 90 ms</option>
|
||
<option value="neutral_pulse">Neutral Pulse — 280 Hz @ 90 ms</option>
|
||
<option value="bright_pulse">Bright Pulse — 330 Hz @ 80 ms</option>
|
||
<option value="soft_tick">Soft Tick — 440 Hz @ 70 ms</option>
|
||
<option value="medium_tick">Medium Tick — 520 Hz @ 60 ms</option>
|
||
<option value="clear_click">Clear Click — 660 Hz @ 40 ms</option>
|
||
<option value="bright_ping">Bright Ping — 880 Hz @ 50 ms</option>
|
||
<option value="light_ping">Light Ping — 1000 Hz @ 50 ms</option>
|
||
<option value="sharp_cue">Sharp Cue — 1200 Hz @ 30 ms</option>
|
||
<option value="accent">Accent — 1500 Hz @ 30 ms</option>
|
||
<option value="spark">Spark — 1800 Hz @ 30 ms</option>
|
||
<option value="crisp">Crisp — 2000 Hz @ 30 ms</option>
|
||
</select>
|
||
</div>
|
||
|
||
<div id="toneFreqRow" class="control-group">
|
||
<label class="control-label">Frequency (Hz)</label>
|
||
<input type="number" id="toneFreq" min="100" max="2000" step="10" value="440" class="number-input">
|
||
</div>
|
||
|
||
<div id="toneDurRow" class="control-group">
|
||
<label class="control-label">Duration: <span id="toneDurationLabel">70 ms</span></label>
|
||
<input type="range" id="toneDuration" min="30" max="150" step="5" value="70" class="slider">
|
||
</div>
|
||
|
||
<div id="adsrField" class="adsr-controls">
|
||
<details class="adsr-details">
|
||
<summary>Advanced: ADSR Envelope</summary>
|
||
<div class="adsr-grid">
|
||
<div class="adsr-control">
|
||
<label>Attack: <span id="adsrAttackLabel">8 ms</span></label>
|
||
<input type="range" id="adsrAttack" min="5" max="20" step="1" value="8" class="slider">
|
||
</div>
|
||
<div class="adsr-control">
|
||
<label>Decay: <span id="adsrDecayLabel">80 ms</span></label>
|
||
<input type="range" id="adsrDecay" min="40" max="120" step="5" value="80" class="slider">
|
||
</div>
|
||
<div class="adsr-control">
|
||
<label>Sustain: <span id="adsrSustainLabel">0.30</span></label>
|
||
<input type="range" id="adsrSustain" min="0" max="1" step="0.05" value="0.3" class="slider">
|
||
</div>
|
||
<div class="adsr-control">
|
||
<label>Release: <span id="adsrReleaseLabel">10 ms</span></label>
|
||
<input type="range" id="adsrRelease" min="5" max="50" step="1" value="10" class="slider">
|
||
</div>
|
||
</div>
|
||
</details>
|
||
</div>
|
||
|
||
<div class="control-group">
|
||
<label class="control-label">Pan synced to movement</label>
|
||
<label class="toggle">
|
||
<input type="checkbox" id="syncPan" checked>
|
||
<span class="toggle-track"><span class="toggle-thumb"></span></span>
|
||
</label>
|
||
</div>
|
||
|
||
<div class="control-group">
|
||
<label class="control-label">Pan Rate: <span id="panRateLabel">0.5 Hz</span></label>
|
||
<input type="range" id="panRate" min="0.1" max="2" step="0.1" value="0.5" class="slider">
|
||
</div>
|
||
|
||
<div class="control-group">
|
||
<label class="control-label">Cue Rate: <span id="cueRateLabel">1.2 Hz</span></label>
|
||
<input type="range" id="cueRate" min="0.1" max="3" step="0.1" value="1.2" class="slider">
|
||
</div>
|
||
|
||
<div class="control-group">
|
||
<label class="control-label">Volume: <span id="volumeLabel">60%</span></label>
|
||
<input type="range" id="volume" min="0" max="100" step="5" value="60" class="slider">
|
||
</div>
|
||
</div>
|
||
|
||
|
||
</section>
|
||
<section class="panel collapsible" id="presetsPanel">
|
||
<h2 role="button" tabindex="0">PRESETS</h2>
|
||
|
||
<div class="preset-controls">
|
||
<div class="control-row">
|
||
<input type="text" id="presetName" placeholder="Preset name..." class="text-input flex-1">
|
||
<button id="savePreset" class="btn-secondary">Save</button>
|
||
</div>
|
||
|
||
<div class="control-row">
|
||
<select id="presetList" class="select-input flex-1"></select>
|
||
<button id="applyPreset" class="btn-secondary">Apply</button>
|
||
<button id="deletePreset" class="btn-danger-outline">Delete</button>
|
||
</div>
|
||
|
||
<div class="control-row">
|
||
<button id="exportPresets" class="btn-secondary">Export JSON</button>
|
||
<button id="importPresets" class="btn-secondary">Import JSON</button>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
<section id="controllersPanel" class="panel collapsible">
|
||
<h2 role="button" tabindex="0">CONTROL</h2>
|
||
<div class="controller-content">
|
||
<div class="status-display">
|
||
<span id="ctlStatusDot" class="status-dot"></span>
|
||
<span id="ctlStatusText" class="status-value">No device</span>
|
||
</div>
|
||
|
||
<div class="control-group">
|
||
<label class="control-label">MIDI Input</label>
|
||
<select id="midiSelect" class="select-input"></select>
|
||
</div>
|
||
|
||
<div class="mapping-section">
|
||
<h3>Map Actions</h3>
|
||
<div class="mapping-buttons">
|
||
<button data-map-action="start" class="btn-map">Start Session</button>
|
||
<button data-map-action="stop" class="btn-map">End Session</button>
|
||
<button data-map-action="speed_up" class="btn-map">Speed +</button>
|
||
<button data-map-action="speed_down" class="btn-map">Speed −</button>
|
||
<button data-map-action="volume_up" class="btn-map">Volume +</button>
|
||
<button data-map-action="volume_down" class="btn-map">Volume −</button>
|
||
<button data-map-action="audio_toggle" class="btn-map">Audio Toggle</button>
|
||
<button data-map-action="glow_toggle" class="btn-map">Glow Toggle</button>
|
||
<button data-map-action="wiggle_toggle" class="btn-map">Wiggle Toggle</button>
|
||
<button data-map-action="lock_toggle" class="btn-map">Lock Toggle</button>
|
||
<button data-map-action="record_start" class="btn-map">Record Start</button>
|
||
<button data-map-action="record_stop" class="btn-map">Record Stop</button>
|
||
<button data-map-action="replay" class="btn-map">Replay</button>
|
||
<button data-map-action="shape_next" class="btn-map">Cycle Shape</button>
|
||
<button data-map-action="direction_next" class="btn-map">Cycle Direction</button>
|
||
<button data-map-action="easing_next" class="btn-map">Cycle Smoothness</button>
|
||
<button data-map-action="program_next" class="btn-map">Cycle Audio Preset</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="mapping-section">
|
||
<h3>Current Mappings</h3>
|
||
<div id="ctlMappings" class="mappings-list"></div>
|
||
</div>
|
||
|
||
<div class="mapping-section">
|
||
<h3>Hardware Controller</h3>
|
||
<div class="control-row">
|
||
<button id="connectHID" class="btn-secondary">Connect HID Device</button>
|
||
<span id="deviceStatus" class="status-value">Not connected</span>
|
||
</div>
|
||
<div class="control-group">
|
||
<label class="control-label">Sensitivity: <span id="knobSensLabel">x5</span></label>
|
||
<input type="range" id="knobSens" min="1" max="50" step="1" value="5" class="slider">
|
||
</div>
|
||
<div class="control-group" style="display:flex; align-items:center; justify-content:space-between; gap:8px;">
|
||
<div>
|
||
<label class="control-label">Enable Lock Hotkey (L to lock, U to unlock)</label>
|
||
<label class="toggle">
|
||
<input type="checkbox" id="lockHotkeyEnable" checked>
|
||
<span class="toggle-track"><span class="toggle-thumb"></span></span>
|
||
</label>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
</aside>
|
||
|
||
<!-- Right Column: Session & Preview -->
|
||
<div class="main-content">
|
||
<section class="panel panel-session collapsible">
|
||
<h2 role="button" tabindex="0">
|
||
<span class="panel-icon">⚡</span>
|
||
Session Control
|
||
</h2>
|
||
|
||
<div class="preview-container">
|
||
<canvas id="previewCanvas" class="preview-canvas" width="640" height="360"></canvas>
|
||
</div>
|
||
|
||
<div class="session-actions" style="margin-top:10px;">
|
||
<button id="startSession" class="btn-primary btn-large">
|
||
<span class="btn-icon">▶️</span>
|
||
Start Session
|
||
</button>
|
||
<button id="endSession" class="btn-danger btn-large">
|
||
<span class="btn-icon">⏹️</span>
|
||
End Session
|
||
</button>
|
||
</div>
|
||
|
||
<div class="session-controls">
|
||
<div class="control-row">
|
||
<div class="control-group">
|
||
<label class="control-label">Speed: <span id="speedLabel">250 px/s</span></label>
|
||
<div class="speed-control">
|
||
<button id="speedDown" class="btn-adjust">−</button>
|
||
<input type="range" id="speed" min="50" max="1800" step="1" value="250" class="slider slider-wide">
|
||
<button id="speedUp" class="btn-adjust">+</button>
|
||
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
|
||
|
||
|
||
<div class="timer-section">
|
||
<div id="patientViewportShort" class="status-value" style="margin-bottom:8px; font-size:12px; opacity:0.8;">—</div>
|
||
<div class="timer-display">
|
||
<div class="timer-box">
|
||
<label>Duration (minutes)</label>
|
||
<input type="number" id="timerMinutes" min="0" value="10" class="timer-input">
|
||
</div>
|
||
<div class="timer-box">
|
||
<label>Remaining</label>
|
||
<div id="timerDisplay" class="timer-value">10:00</div>
|
||
</div>
|
||
<div class="timer-box">
|
||
<label>Elapsed</label>
|
||
<div id="elapsedText" class="timer-value">00:00</div>
|
||
</div>
|
||
|
||
</div>
|
||
|
||
|
||
|
||
<div class="status-bar">
|
||
<span class="status-label">Status:</span>
|
||
<span id="statusText" class="status-value">Idle</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<section class="panel panel-recording collapsible">
|
||
<h2 role="button" tabindex="0">
|
||
<span class="panel-icon"><EFBFBD></span>
|
||
Recording & Playback
|
||
</h2>
|
||
|
||
<div class="recording-controls">
|
||
<div class="control-row">
|
||
<button id="recStart" class="btn-record">
|
||
<span class="record-dot">●</span>
|
||
Record
|
||
</button>
|
||
<button id="recStop" class="btn-secondary">Stop & Save</button>
|
||
|
||
</div>
|
||
|
||
<div class="control-row">
|
||
<select id="recList" class="select-input flex-1"></select>
|
||
<button id="recPlay" class="btn-secondary">Replay</button>
|
||
<button id="recExport" class="btn-secondary">Export</button>
|
||
<button id="recImport" class="btn-secondary">Import</button>
|
||
</div>
|
||
|
||
<div class="control-row">
|
||
<button id="recDelete" class="btn-danger-outline">Delete</button>
|
||
<button id="recClear" class="btn-danger-outline">Clear All</button>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
|
||
<section class="panel collapsible">
|
||
<h2 role="button" tabindex="0">
|
||
<span class="panel-icon">👤</span>
|
||
Patient Management
|
||
</h2>
|
||
|
||
<div class="patient-controls">
|
||
<div class="control-row">
|
||
<input type="text" id="patientName" placeholder="Patient name..." class="text-input flex-1">
|
||
<button id="savePatient" class="btn-secondary">Save</button>
|
||
</div>
|
||
|
||
<div class="control-row">
|
||
<select id="patientList" class="select-input flex-1"></select>
|
||
<button id="loadPatient" class="btn-secondary">Load</button>
|
||
<button id="deletePatient" class="btn-danger-outline">Delete</button>
|
||
</div>
|
||
|
||
<div class="patient-stats">
|
||
<div class="stat-item">
|
||
<span class="stat-label">Total Sessions:</span>
|
||
<span id="sessionCount" class="stat-value">0</span>
|
||
</div>
|
||
<div class="stat-item">
|
||
<span class="stat-label">Last Session:</span>
|
||
<span id="lastSessionInfo" class="stat-value">—</span>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="control-group">
|
||
<label class="control-label">Session History</label>
|
||
<div id="sessionHistory" class="session-history"></div>
|
||
<button id="clearSessions" class="btn-danger-outline btn-small">Clear All Sessions</button>
|
||
</div>
|
||
|
||
<div class="control-group">
|
||
<label class="control-label">Session Notes</label>
|
||
<div class="control-row">
|
||
<select id="sessionSelect" class="select-input flex-1"></select>
|
||
<button id="loadSession" class="btn-secondary btn-small">Load</button>
|
||
<button id="saveSessionNotes" class="btn-secondary btn-small">Save Notes</button>
|
||
<button id="deleteSession" class="btn-danger-outline btn-small">Delete Session</button>
|
||
</div>
|
||
<textarea id="sessionNotes" class="textarea-input" placeholder="Enter session notes..."></textarea>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<section class="panel collapsible" id="networkPanelSection">
|
||
<h2 id="networkHeading" role="button" tabindex="0">
|
||
<span class="panel-icon">🌐</span>
|
||
Network Connection
|
||
</h2>
|
||
|
||
<div class="network-controls">
|
||
<div class="control-group">
|
||
<label class="control-label">Connection Mode</label>
|
||
<select id="netMode" class="select-input">
|
||
<option value="relay">Relay (WebSocket)</option>
|
||
<option value="webrtc">WebRTC (P2P)</option>
|
||
</select>
|
||
</div>
|
||
|
||
<div id="webrtcControls" class="webrtc-section">
|
||
<div class="control-group">
|
||
<button id="rtcCreateOffer" class="btn-secondary">Create Offer</button>
|
||
<input type="text" id="rtcOffer" placeholder="Offer (base64)" class="text-input flex-1">
|
||
</div>
|
||
<div class="qr-container">
|
||
<img id="rtcOfferQR" alt="Offer QR Code" class="qr-code">
|
||
</div>
|
||
<div class="control-group">
|
||
<button id="rtcAcceptAnswer" class="btn-secondary">Accept Answer</button>
|
||
<input type="text" id="rtcAnswer" placeholder="Answer (base64)" class="text-input flex-1">
|
||
</div>
|
||
<div class="status-display">
|
||
<span class="status-label">WebRTC Status:</span>
|
||
<span id="rtcStatus" class="status-value">Idle</span>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="relay-section">
|
||
<div class="status-display">
|
||
<span id="relayStatusDot" class="status-dot"></span>
|
||
<span id="relayStatusText" class="status-value">Not running</span>
|
||
</div>
|
||
|
||
<div class="control-row">
|
||
<button id="startRelayBtn" class="btn-secondary">Copy Start Command</button>
|
||
<button id="stopRelayBtn" class="btn-danger-outline">Stop Server</button>
|
||
</div>
|
||
|
||
<div class="control-group">
|
||
<label class="control-label">Connection Details</label>
|
||
<div class="connection-inputs">
|
||
<input type="text" id="wsUrl" placeholder="ws://192.168.x.x:8787" class="text-input">
|
||
<input type="text" id="wsSession" placeholder="room-1" class="text-input">
|
||
</div>
|
||
</div>
|
||
|
||
<div class="control-row">
|
||
<button id="detectIP" class="btn-secondary">Detect Local IP</button>
|
||
<button id="wsConnect" class="btn-secondary">Connect</button>
|
||
<button id="wsDisconnect" class="btn-danger-outline">Disconnect</button>
|
||
</div>
|
||
|
||
<div class="status-display">
|
||
<span class="status-label">Status:</span>
|
||
<span id="wsStatus" class="status-value">Disconnected</span>
|
||
</div>
|
||
|
||
<div class="control-group">
|
||
<label class="control-label">Patient Join Link</label>
|
||
<div class="control-row">
|
||
<input type="text" id="joinLink" readonly class="text-input flex-1">
|
||
<button id="copyJoinLink" class="btn-secondary">Copy</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="osHelp" class="help-text"></div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
|
||
</div>
|
||
</main>
|
||
|
||
|
||
<script src="js/bls.js"></script>
|
||
<script src="js/audio.js"></script>
|
||
<script src="js/webrtc.js"></script>
|
||
<script src="js/recorder.js"></script>
|
||
<script src="js/recording-store.js"></script>
|
||
<script src="js/controllers.js"></script>
|
||
<script src="js/admin.js"></script>
|
||
</body>
|
||
</html>
|