Files
Strix/webui/web/index.html
T
eduard256 779ae33bac Redesign stream discovery UI with vertical list layout
- Replace carousel navigation with scrollable vertical list
- Remove statistics counters (Tested/Found/Remaining)
- Add collapsible stream details with expand/collapse toggle
- Show stream URL preview in header, full URL in details
- Position URL below stream type badge for better readability
- Add new StreamList component replacing StreamCarousel
- Update CSS with improved layout and hover effects

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-21 23:25:30 +03:00

334 lines
16 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<meta name="theme-color" content="#0a0a0f">
<title>Strix - Camera Stream Discovery</title>
<link rel="stylesheet" href="css/main.css">
</head>
<body>
<!-- Mock Mode Indicator -->
<div id="mock-mode-badge" class="mock-badge hidden">
<svg width="16" height="16" viewBox="0 0 16 16" fill="none">
<path d="M8 1v6l4 2" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
<circle cx="8" cy="8" r="7" stroke="currentColor" stroke-width="2" fill="none"/>
</svg>
MOCK MODE
</div>
<div id="app">
<!-- Screen 1: Initial Address Input -->
<div id="screen-address" class="screen active">
<div class="container">
<div class="hero">
<svg class="logo" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" height="800px" width="800px" version="1.1" id="Layer_1" viewBox="0 0 512.001 512.001" xml:space="preserve">
<g>
<path style="fill:#7E57C2;" d="M124.477,378.183L9.347,495.779c21.628,21.628,56.695,21.628,78.324,0L119,464.45 c21.628,21.628,56.696,21.628,78.324,0l28.375-28.375C187.373,426.203,151.825,405.106,124.477,378.183z"/>
<path style="fill:#7E57C2;" d="M447.27,55.383h-55.383V177.22c0.002-40.997,22.277-76.788,55.383-95.939 c16.293-9.425,35.207-14.822,55.383-14.822c0-6.982,0-11.077,0-11.077V0C472.065,0,447.27,24.796,447.27,55.383z"/>
</g>
<path style="fill:#9575CD;" d="M336.504,55.383C336.504,24.796,311.708,0,281.121,0v66.46c20.176,0,39.091,5.397,55.383,14.822 c33.107,19.153,55.383,54.946,55.383,95.945V55.383H336.504z"/>
<path style="fill:#E8E0F5;" d="M391.887,209.772v-27.116c0-3.312,0-5.432,0-5.432c0-40.997-22.276-76.791-55.383-95.942 c-16.293-9.425-35.207-14.822-55.383-14.822v155.073C311.213,191.443,357.554,187.532,391.887,209.772z M314.351,143.996 c0-12.234,9.918-22.153,22.153-22.153s22.153,9.919,22.153,22.153c0,12.235-9.918,22.153-22.153,22.153 S314.351,156.231,314.351,143.996z"/>
<path style="fill:#D1C4E9;" d="M391.887,177.221v32.551c5.151,3.336,10.037,7.246,14.55,11.76h96.216V66.46 c-20.176,0-39.091,5.397-55.383,14.822C414.164,100.434,391.888,136.225,391.887,177.221z M469.423,143.996 c0,12.235-9.918,22.153-22.153,22.153s-22.153-9.918-22.153-22.153c0-12.234,9.918-22.153,22.153-22.153 C459.504,121.843,469.423,131.762,469.423,143.996z"/>
<path style="fill:#9575CD;" d="M281.121,221.532l-10.2,10.2L281.121,221.532z"/>
<path style="fill:#B39DDB;" d="M406.438,221.533c34.606,34.606,34.606,90.712,0,125.319c-69.21,69.21-181.422,69.21-250.633,0.002 l-31.329,31.33c27.348,26.923,62.896,48.02,101.221,57.892c17.714,4.562,36.285,6.989,55.423,6.989 c122.349,0,221.532-99.182,221.532-221.531C502.653,221.533,406.437,221.532,406.438,221.533z"/>
<path style="fill:#9575CD;" d="M281.121,221.532l125.318,125.319c34.606-34.606,34.606-90.713,0-125.319 c-4.515-4.514-9.401-8.425-14.551-11.761C357.554,187.532,311.213,191.443,281.121,221.532z"/>
<path style="fill:#7E57C2;" d="M406.438,346.851L281.12,221.533l-10.199,10.2L155.802,346.851 C225.017,416.062,337.228,416.061,406.438,346.851z"/>
<circle style="fill:#9575CD;" cx="336.507" cy="143.996" r="22.153"/>
<circle style="fill:#7E57C2;" cx="447.274" cy="143.996" r="22.153"/>
</svg>
<h1 class="title">STRIX</h1>
<p class="subtitle">Camera Stream Discovery</p>
</div>
<div class="form-group">
<label for="network-address" class="label">Network Address</label>
<input
type="text"
id="network-address"
class="input input-large"
placeholder="192.168.1.100"
autocomplete="off"
spellcheck="false"
>
<p class="hint">IP, hostname or full stream URL</p>
</div>
<button id="btn-check-address" class="btn btn-primary btn-large">
Check Address
</button>
<div class="examples">
<p class="examples-title">Examples</p>
<ul class="examples-list">
<li>192.168.1.100</li>
<li>camera.local</li>
<li>rtsp://user:pass@192.168.1.100/stream</li>
</ul>
</div>
</div>
</div>
<!-- Screen 2: Configuration Form -->
<div id="screen-config" class="screen">
<div class="container">
<button id="btn-back-to-address" class="btn-back">
<svg width="20" height="20" viewBox="0 0 20 20" fill="none">
<path d="M12 4L6 10l6 6" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
</svg>
Back
</button>
<h2 class="screen-title">Camera Configuration</h2>
<div class="form-group">
<label for="address-validated" class="label">Network Address</label>
<div class="input-validated">
<input
type="text"
id="address-validated"
class="input"
readonly
>
<svg class="icon-check" width="20" height="20" viewBox="0 0 20 20" fill="none">
<path d="M4 10l4 4 8-8" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
</svg>
</div>
</div>
<div class="form-group">
<label for="camera-model" class="label">Camera Model <span class="optional">(optional)</span></label>
<div class="autocomplete-wrapper">
<input
type="text"
id="camera-model"
class="input"
placeholder="Start typing..."
autocomplete="off"
spellcheck="false"
>
<div id="autocomplete-dropdown" class="autocomplete-dropdown hidden"></div>
</div>
<p id="model-disabled-hint" class="hint hidden">Detected from URL, continue below</p>
</div>
<div class="form-group">
<label for="username" class="label">Username</label>
<input
type="text"
id="username"
class="input"
placeholder="admin"
autocomplete="off"
>
</div>
<div class="form-group">
<label for="password" class="label">Password</label>
<div class="input-password-wrapper">
<input
type="password"
id="password"
class="input"
placeholder="••••••••"
autocomplete="off"
>
<button type="button" class="btn-toggle-password" aria-label="Toggle password visibility">
<svg class="icon-eye" width="20" height="20" viewBox="0 0 20 20" fill="none">
<circle cx="10" cy="10" r="3" stroke="currentColor" stroke-width="1.5"/>
<path d="M2 10c1.5-4 4-6.5 8-6.5s6.5 2.5 8 6.5c-1.5 4-4 6.5-8 6.5S3.5 14 2 10z" stroke="currentColor" stroke-width="1.5"/>
<circle cx="10" cy="10" r="1.5" fill="currentColor"/>
</svg>
</button>
</div>
</div>
<details class="advanced-section">
<summary class="advanced-toggle">Advanced</summary>
<div class="advanced-content">
<div class="form-group">
<label for="channel" class="label">Channel</label>
<input
type="number"
id="channel"
class="input"
value="0"
min="0"
max="255"
>
</div>
<div class="form-group">
<label class="label">Resolution <span class="optional">(optional)</span></label>
<div class="input-row">
<input
type="number"
id="width"
class="input"
placeholder="Width"
>
<span class="input-separator">×</span>
<input
type="number"
id="height"
class="input"
placeholder="Height"
>
</div>
</div>
<div class="form-group">
<label for="max-streams" class="label">Max Streams</label>
<input
type="number"
id="max-streams"
class="input"
value="10"
min="1"
max="50"
>
</div>
</div>
</details>
<button id="btn-discover" class="btn btn-primary btn-large">
Discover Streams
</button>
</div>
</div>
<!-- Screen 3: Stream Discovery -->
<div id="screen-discovery" class="screen">
<div class="container">
<button id="btn-back-to-config" class="btn-back">
<svg width="20" height="20" viewBox="0 0 20 20" fill="none">
<path d="M12 4L6 10l6 6" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
</svg>
Back to Configuration
</button>
<h2 class="screen-title">Discovering Streams</h2>
<div class="progress-container">
<div class="progress-bar">
<div id="progress-fill" class="progress-fill"></div>
</div>
<p id="progress-text" class="progress-text">Starting scan...</p>
</div>
<div id="streams-section" class="streams-section hidden">
<h3 class="section-title">Found Connections</h3>
<div id="streams-list" class="streams-list"></div>
</div>
</div>
</div>
<!-- Screen 4: Configuration Output -->
<div id="screen-output" class="screen">
<div class="container">
<button id="btn-back-to-streams" class="btn-back">
<svg width="20" height="20" viewBox="0 0 20 20" fill="none">
<path d="M12 4L6 10l6 6" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
</svg>
Back to Streams
</button>
<h2 class="screen-title">Stream Configuration</h2>
<div class="stream-selection-container">
<div class="selected-stream-info">
<p class="stream-label">Main Stream</p>
<p id="selected-main-type" class="selected-type"></p>
<p id="selected-main-url" class="selected-url"></p>
</div>
<div id="sub-stream-info" class="selected-stream-info sub-stream hidden">
<p class="stream-label">Sub Stream</p>
<p id="selected-sub-type" class="selected-type"></p>
<p id="selected-sub-url" class="selected-url"></p>
<button id="btn-remove-sub" class="btn-remove-sub">Remove Sub Stream</button>
</div>
</div>
<div class="tabs">
<div class="tabs-scroll">
<button class="tab active" data-tab="url">URL</button>
<button class="tab" data-tab="go2rtc">Go2RTC</button>
<button class="tab" data-tab="frigate">Frigate</button>
</div>
</div>
<div class="tab-content">
<div class="tab-pane active" data-pane="url">
<pre id="config-url" class="config-code"></pre>
</div>
<div class="tab-pane" data-pane="go2rtc">
<pre id="config-go2rtc" class="config-code"></pre>
</div>
<div class="tab-pane" data-pane="frigate">
<!-- Input section for existing config -->
<div class="frigate-input-section">
<label class="frigate-label">
Your Current Frigate Config
<span class="hint">Paste your existing config.yml or leave the example below</span>
</label>
<textarea
id="existing-frigate-config"
class="textarea frigate-config-input"
rows="12"
placeholder="Paste your existing Frigate config here..."></textarea>
</div>
<!-- Generate button -->
<button id="btn-generate-frigate" class="btn btn-primary btn-generate">
Generate Config
</button>
<!-- Output section (hidden by default) -->
<div id="frigate-output-section" class="frigate-output-section hidden">
<label class="frigate-label">Updated Config (Camera Added)</label>
<pre id="config-frigate" class="config-code"></pre>
</div>
</div>
</div>
<div class="actions">
<button id="btn-copy-config" class="btn btn-secondary">
<svg width="20" height="20" viewBox="0 0 20 20" fill="none">
<rect x="6" y="6" width="10" height="10" rx="1" stroke="currentColor" stroke-width="1.5"/>
<path d="M4 4h10v2H5v9H4V4z" fill="currentColor"/>
</svg>
Copy
</button>
<button id="btn-download-config" class="btn btn-secondary">
<svg width="20" height="20" viewBox="0 0 20 20" fill="none">
<path d="M10 3v10m0 0l-4-4m4 4l4-4M4 17h12" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>
</svg>
Download
</button>
</div>
<div class="secondary-actions">
<button id="btn-add-sub-stream" class="btn btn-primary">
<svg width="20" height="20" viewBox="0 0 20 20" fill="none">
<path d="M10 4v12M4 10h12" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
</svg>
Add Sub Stream
</button>
<button id="btn-new-search" class="btn btn-outline">
Add Another Camera
</button>
</div>
</div>
</div>
</div>
<!-- Toast Notification -->
<div id="toast" class="toast hidden"></div>
<script type="module" src="js/main.js"></script>
</body>
</html>