196 lines
9.3 KiB
HTML
196 lines
9.3 KiB
HTML
<!doctype html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="utf-8" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
<title>gibbz voice — POC</title>
|
|
<link rel="stylesheet" href="style.css" />
|
|
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200" />
|
|
<link rel="manifest" href="/manifest.webmanifest" />
|
|
<link rel="icon" type="image/png" sizes="192x192" href="/icons/icon-192.png" />
|
|
<link rel="apple-touch-icon" sizes="180x180" href="/icons/apple-touch-icon.png" />
|
|
<meta name="theme-color" content="#1e1f22" />
|
|
<meta name="mobile-web-app-capable" content="yes" />
|
|
<meta name="apple-mobile-web-app-capable" content="yes" />
|
|
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
|
|
<meta name="apple-mobile-web-app-title" content="gibbz" />
|
|
<script src="https://otel.k6n.net/static/otel-rum.js"></script>
|
|
<script>
|
|
window.rum = window.OtelRUM ? OtelRUM.init({
|
|
serviceName: "gibbz",
|
|
baseUrl: "https://otel.k6n.net",
|
|
release: window.__APP_RELEASE__ || "dev",
|
|
environment: "production",
|
|
traceHeaderOrigins: [window.location.origin]
|
|
}) : null;
|
|
</script>
|
|
</head>
|
|
<body>
|
|
<!-- mobile top bar: hamburger opens the channel drawer, shows live status -->
|
|
<header id="mobile-topbar">
|
|
<button id="btn-menu" title="Channels"><span class="material-symbols-outlined">menu</span></button>
|
|
<img id="mobile-logo" src="/icons/icon-192.png" alt="" width="24" height="24" />
|
|
<span id="mobile-title">gibbz voice</span>
|
|
<span class="status-row" id="mobile-status-row">
|
|
<span class="status-indicator" id="mobile-status-dot"></span>
|
|
<span id="mobile-status-text">Disconnected</span>
|
|
</span>
|
|
</header>
|
|
<div id="sidebar-backdrop"></div>
|
|
|
|
<div id="app">
|
|
<!-- channel sidebar -->
|
|
<aside id="sidebar">
|
|
<header id="server-name">
|
|
<img id="server-logo" src="/icons/icon-192.png" alt="" width="22" height="22" />
|
|
<span class="server-name-text">gibbz voice <span class="poc-tag">POC</span></span>
|
|
<button id="btn-sidebar-collapse" class="icon-btn" title="Hide sidebar"><span class="material-symbols-outlined">left_panel_close</span></button>
|
|
</header>
|
|
<div class="channel-group-label">Text channels</div>
|
|
<div class="channel text" data-mx-room="gibbz-general"><span class="material-symbols-outlined channel-icon">tag</span>
|
|
general <span class="hint">matrix</span></div>
|
|
<div class="channel-group-label">Voice channels</div>
|
|
<div class="channel voice" data-room="general"><span class="material-symbols-outlined channel-icon">volume_up</span> General <span class="count" data-room-count="general"></span></div>
|
|
<div class="channel voice" data-room="gaming"><span class="material-symbols-outlined channel-icon">volume_up</span> Gaming <span class="count" data-room-count="gaming"></span></div>
|
|
<div class="channel voice" data-room="lounge"><span class="material-symbols-outlined channel-icon">volume_up</span> Lounge <span class="count" data-room-count="lounge"></span></div>
|
|
|
|
<footer id="user-panel">
|
|
<div class="user-buttons">
|
|
<button id="btn-mic" class="ctl" title="Toggle mic (M)"><span class="material-symbols-outlined">mic</span></button>
|
|
<button id="btn-deafen" class="ctl" title="Toggle deafen (D)"><span class="material-symbols-outlined">headphones</span></button>
|
|
<button id="btn-share" class="ctl" title="Share your screen (S)"><span class="material-symbols-outlined">present_to_all</span></button>
|
|
<button id="btn-settings" class="ctl" title="Voice & ICE settings"><span class="material-symbols-outlined">settings</span></button>
|
|
</div>
|
|
<div class="me">
|
|
<div class="avatar" id="me-avatar">?</div>
|
|
<div class="me-meta">
|
|
<input id="nick" maxlength="24" spellcheck="false" title="Click to edit nickname" />
|
|
<div class="status-row" id="status-row" title="Not connected">
|
|
<span class="status-indicator" id="status-dot"></span>
|
|
<span id="voice-status">Disconnected</span>
|
|
</div>
|
|
</div>
|
|
<button id="btn-help" class="ctl help-ctl" title="How to use gibbz voice"><span class="material-symbols-outlined">help</span></button>
|
|
</div>
|
|
</footer>
|
|
<div id="sidebar-resizer" title="Drag to resize"></div>
|
|
</aside>
|
|
|
|
<!-- main content area -->
|
|
<main id="main">
|
|
<button id="btn-sidebar-expand" title="Show sidebar"><span class="material-symbols-outlined">left_panel_open</span></button>
|
|
<!-- voice stage and spatial audio view -->
|
|
<div id="voice-view">
|
|
<div id="stage">
|
|
<div id="screens"></div>
|
|
<div id="stage-empty">
|
|
<div class="big-icon"><span class="material-symbols-outlined">present_to_all</span></div>
|
|
<h2>No active screen shares</h2>
|
|
<p>When someone shares their screen, it will appear here. Click the screen button below or press <b>S</b> to share.</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div id="spatial-resizer" title="Drag to resize"></div>
|
|
<div id="spatial-wrap">
|
|
<div class="spatial-label">
|
|
<span>SPATIAL AUDIO</span>
|
|
<span class="hint">drag your avatar to move; drag peers for local positioning • scroll to zoom</span>
|
|
<button id="btn-spatial-fit" class="spatial-action-btn" title="Fit all users in view"><span class="material-symbols-outlined">fit_screen</span> Fit View</button>
|
|
</div>
|
|
<div id="spatial"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- matrix text chat view -->
|
|
<div id="mx-panel" class="hidden">
|
|
<div class="mx-header">
|
|
<div class="mx-header-info">
|
|
<span class="material-symbols-outlined channel-icon">tag</span>
|
|
<span class="mx-header-title">general</span>
|
|
<span class="poc-tag">matrix · experimental</span>
|
|
</div>
|
|
<button id="mx-close" class="ghost" title="Back to Voice Stage"><span class="material-symbols-outlined">close</span></button>
|
|
</div>
|
|
<div id="mx-messages"></div>
|
|
<div class="mx-composer">
|
|
<textarea id="mx-input" rows="1" placeholder="Message #general (Enter to send)"></textarea>
|
|
<button id="mx-send">Send</button>
|
|
</div>
|
|
</div>
|
|
</main>
|
|
</div>
|
|
|
|
<!-- mobile bottom bar: always-reachable call controls, mirror the sidebar's -->
|
|
<div id="mobile-controls">
|
|
<button class="ctl mirror-mic" title="Toggle mic (M)"><span class="material-symbols-outlined">mic</span></button>
|
|
<button class="ctl mirror-deafen" title="Toggle deafen (D)"><span class="material-symbols-outlined">headphones</span></button>
|
|
<button class="ctl mirror-share" title="Share your screen (S)"><span class="material-symbols-outlined">present_to_all</span></button>
|
|
</div>
|
|
|
|
<!-- settings modal -->
|
|
<div id="modal-backdrop" class="hidden">
|
|
<div id="settings-modal" role="dialog" aria-modal="true">
|
|
<h2>Voice & ICE settings</h2>
|
|
<p class="hint">Overrides the server-provided ICE configuration (stored in <code>localStorage</code>, applied on next join).</p>
|
|
<label class="toggle-row">
|
|
<input type="checkbox" id="override-enabled" />
|
|
<span>Use custom STUN/TURN (JSON below)</span>
|
|
</label>
|
|
<textarea id="ice-json" rows="12" spellcheck="false"></textarea>
|
|
<div class="modal-actions">
|
|
<button id="ice-reset" class="ghost">Reset to server defaults</button>
|
|
<span class="spacer"></span>
|
|
<button id="ice-cancel" class="ghost">Cancel</button>
|
|
<button id="ice-save">Save</button>
|
|
</div>
|
|
<h3>Server defaults</h3>
|
|
<pre id="ice-server-default" class="hint"></pre>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- welcome / nickname / how-to-use modal -->
|
|
<div id="welcome-backdrop" class="hidden">
|
|
<div id="welcome-modal" role="dialog" aria-modal="true">
|
|
<h2>Welcome to gibbz voice</h2>
|
|
<p class="hint">Pick a name so others can recognize you.</p>
|
|
<label class="field-label" for="welcome-nick">Nickname</label>
|
|
<input id="welcome-nick" maxlength="24" spellcheck="false" autocomplete="off" placeholder="e.g. alex" />
|
|
<div id="welcome-nick-error" class="field-error hidden">Enter a nickname to continue.</div>
|
|
|
|
<h3>Quick start</h3>
|
|
<ul class="howto-list">
|
|
<li>Click a <b>voice channel</b> in the sidebar to join it — click another to switch.</li>
|
|
<li><b>Mic</b>, <b>Deafen</b> and <b>Share screen</b> are the buttons bottom-left, or press <b>M</b> / <b>D</b> / <b>S</b>.</li>
|
|
<li>On the <b>spatial audio</b> map, drag your dot around — you hear people relative to where they stand.</li>
|
|
<li>Screen shares show up at the top of the main area; pop one into its own window with <span class="material-symbols-outlined inline-icon">open_in_new</span>.</li>
|
|
</ul>
|
|
|
|
<div class="modal-actions">
|
|
<span class="spacer"></span>
|
|
<button id="welcome-continue">Continue</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div id="reconnect-banner" class="hidden" role="alert">
|
|
<div class="reconnect-spinner"></div>
|
|
<span id="reconnect-text">Connection lost</span>
|
|
<div class="reconnect-actions">
|
|
<button id="reconnect-retry">Retry now</button>
|
|
<button id="reconnect-dismiss" class="ghost">Dismiss</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div id="toasts"></div>
|
|
|
|
<script type="module" src="/app.js"></script>
|
|
<script>
|
|
if ('serviceWorker' in navigator) {
|
|
window.addEventListener('load', () => {
|
|
navigator.serviceWorker.register('/sw.js').catch((err) => console.warn('sw registration failed', err));
|
|
});
|
|
}
|
|
</script>
|
|
</body>
|
|
</html>
|