New historyButtonsOpacity setting (10-100 percent, default 50) in the terminal menu (Display & Interaction) and the Web UI. Upgrade now also copies the Web UI app to /opt/kiosk-webui and restarts it, so new Web UI settings appear after an upgrade (it previously kept its old copy). Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013wi3ZQveYdjfcrEsyazq32
312 lines
13 KiB
HTML
312 lines
13 KiB
HTML
<!doctype html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<title>Kiosk Web UI</title>
|
|
<link rel="stylesheet" href="style.css">
|
|
</head>
|
|
<body>
|
|
<div class="shell">
|
|
<nav class="sidebar">
|
|
<div class="brand">
|
|
<div class="brand-mark">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="4" width="18" height="13" rx="2"/><path d="M8 21h8M12 17v4"/></svg>
|
|
</div>
|
|
<div class="brand-text">
|
|
<strong>Kiosk Web UI</strong>
|
|
<span id="brand-sub">this kiosk</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="nav">
|
|
<button class="nav-item active" data-page="sites">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2"/><path d="M3 9h18M9 21V9"/></svg>
|
|
Sites & Timing
|
|
</button>
|
|
<button class="nav-item" data-page="display">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="4" width="20" height="14" rx="2"/><path d="M8 21h8M12 18v3"/></svg>
|
|
Display
|
|
</button>
|
|
<button class="nav-item" data-page="lockout">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="4" y="10" width="16" height="10" rx="2"/><path d="M8 10V7a4 4 0 0 1 8 0v3"/></svg>
|
|
Lockout
|
|
</button>
|
|
<button class="nav-item" data-page="addons">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 2 3 7l9 5 9-5-9-5Z"/><path d="m3 12 9 5 9-5M3 17l9 5 9-5"/></svg>
|
|
Addons
|
|
</button>
|
|
<button class="nav-item" data-page="region">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9"/><path d="M3 12h18M12 3a14 14 0 0 1 0 18M12 3a14 14 0 0 0 0 18"/></svg>
|
|
Region
|
|
</button>
|
|
<button class="nav-item" data-page="update">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 12a9 9 0 1 1-2.6-6.4M21 4v5h-5"/></svg>
|
|
Update
|
|
</button>
|
|
</div>
|
|
|
|
<div class="sidebar-footer">No login of its own - front this with your own reverse proxy + Authelia if it needs to be reachable beyond a trusted LAN.</div>
|
|
</nav>
|
|
|
|
<main class="main">
|
|
<div id="msg" class="banner" hidden></div>
|
|
|
|
<!-- Sites & Page Timing -->
|
|
<section class="page active" id="page-sites">
|
|
<div class="page-header">
|
|
<h1>Sites & Page Timing</h1>
|
|
<p>The pages this kiosk rotates through, and how long each stays on screen.</p>
|
|
</div>
|
|
<div class="card">
|
|
<div id="sites-list"></div>
|
|
<div class="button-row">
|
|
<button type="button" id="add-site" class="secondary">Add a page</button>
|
|
<button type="button" id="save-sites">Save Sites & Page Timing</button>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- Display & Interaction -->
|
|
<section class="page" id="page-display">
|
|
<div class="page-header">
|
|
<h1>Display & Interaction</h1>
|
|
<p>Touch gestures, link navigation, on-screen buttons, and the home page.</p>
|
|
</div>
|
|
<div class="card">
|
|
<form id="display-form">
|
|
<label>
|
|
Touch gesture mode
|
|
<select name="swipeMode">
|
|
<option value="dual">Dual-direction (recommended for touchscreens)</option>
|
|
<option value="standard">Standard</option>
|
|
</select>
|
|
</label>
|
|
|
|
<label>
|
|
Link navigation security
|
|
<select name="allowNavigation">
|
|
<option value="restricted">Restricted - only the loaded URL</option>
|
|
<option value="same-origin">Same-origin - links within the same domain (recommended)</option>
|
|
<option value="open">Open - any link</option>
|
|
</select>
|
|
</label>
|
|
|
|
<label class="checkbox"><input type="checkbox" name="enablePauseButton"> Pause button</label>
|
|
<label class="checkbox"><input type="checkbox" name="enableKeyboardButton"> On-screen keyboard button</label>
|
|
<label class="checkbox"><input type="checkbox" name="enableNavButton"> Navigation/help button</label>
|
|
<label class="checkbox"><input type="checkbox" name="enableHistoryButtons"> On-screen back/forward buttons (top middle)</label>
|
|
|
|
<fieldset>
|
|
<legend>Home page</legend>
|
|
<label>
|
|
Home page
|
|
<select name="homeTabIndex" id="home-tab-select">
|
|
<option value="-1">Disabled</option>
|
|
</select>
|
|
</label>
|
|
<label>
|
|
Back/forward button opacity (10 = faint, 100 = solid)
|
|
<input type="number" name="historyButtonsOpacity" min="10" max="100" step="5">
|
|
</label>
|
|
<label>
|
|
Inactivity timeout (minutes)
|
|
<input type="number" name="inactivityTimeoutMinutes" min="1" max="240" step="1">
|
|
</label>
|
|
</fieldset>
|
|
|
|
<div class="button-row"><button type="submit">Save Display & Interaction</button></div>
|
|
</form>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- Password Protection & Lockout -->
|
|
<section class="page" id="page-lockout">
|
|
<div class="page-header">
|
|
<h1>Password Protection & Lockout</h1>
|
|
<p>Blank the screen after inactivity and require a password or PIN to unlock. These are the kiosk's own codes, not the admin (sudo) password.</p>
|
|
</div>
|
|
<div class="card">
|
|
<form id="lockout-form">
|
|
<label class="checkbox"><input type="checkbox" name="enablePasswordProtection" id="lockout-enabled"> Enable password protection</label>
|
|
|
|
<div id="lockout-fields">
|
|
<label>
|
|
Unlock with
|
|
<select name="lockoutCodeType">
|
|
<option value="password">Password (needs a keyboard)</option>
|
|
<option value="pin">PIN, 4-8 digits (on-screen number pad)</option>
|
|
</select>
|
|
</label>
|
|
<label>
|
|
<span id="password-label">Set lockout password</span>
|
|
<input type="password" name="newLockoutPassword" autocomplete="new-password">
|
|
</label>
|
|
<label>
|
|
Confirm password/PIN
|
|
<input type="password" id="lockout-password-confirm" autocomplete="new-password">
|
|
</label>
|
|
|
|
<label>
|
|
Inactivity lockout timeout (minutes, 0 = boot/wake only)
|
|
<input type="number" name="lockoutTimeoutMinutes" min="0" max="1440" step="1">
|
|
</label>
|
|
|
|
<label class="checkbox"><input type="checkbox" id="daily-lock-enabled"> Lock at a specific time daily</label>
|
|
<label>
|
|
Daily lock time
|
|
<input type="time" name="lockoutAtTime" id="lockout-at-time" disabled>
|
|
</label>
|
|
|
|
<label class="checkbox"><input type="checkbox" name="requirePasswordOnBoot" id="boot-lock-enabled"> Lock the kiosk on system boot</label>
|
|
<div id="boot-code-fields">
|
|
<label>
|
|
Boot code
|
|
<select name="bootCodeMode" id="boot-code-mode">
|
|
<option value="same">Same as the unlock code</option>
|
|
<option value="separate">Its own password/PIN</option>
|
|
</select>
|
|
</label>
|
|
<div id="boot-separate-fields">
|
|
<label>
|
|
Boot code type
|
|
<select name="bootCodeType">
|
|
<option value="password">Password (needs a keyboard)</option>
|
|
<option value="pin">PIN, 4-8 digits (on-screen number pad)</option>
|
|
</select>
|
|
</label>
|
|
<label>
|
|
<span id="boot-password-label">Set boot password/PIN</span>
|
|
<input type="password" name="newBootPassword" autocomplete="new-password">
|
|
</label>
|
|
<label>
|
|
Confirm boot password/PIN
|
|
<input type="password" id="boot-password-confirm" autocomplete="new-password">
|
|
</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="button-row"><button type="submit">Save Password Protection & Lockout</button></div>
|
|
</form>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- Addons -->
|
|
<section class="page" id="page-addons">
|
|
<div class="page-header">
|
|
<h1>Addons</h1>
|
|
<p>Install and configure the same addons the terminal menu offers. Uninstall isn't available here yet.</p>
|
|
</div>
|
|
<div id="addons-list"></div>
|
|
</section>
|
|
|
|
<!-- Region -->
|
|
<section class="page" id="page-region">
|
|
<div class="page-header">
|
|
<h1>Region</h1>
|
|
<p>WiFi country, system language and keyboard layout. The WiFi country decides which channels the adapter may join - without it many 5 GHz networks show up in scans but won't connect.</p>
|
|
</div>
|
|
<div class="card">
|
|
<form id="region-form">
|
|
<label>
|
|
WiFi country (2 letters, e.g. US)
|
|
<input type="text" id="region-country" maxlength="2" autocomplete="off" spellcheck="false" style="text-transform: uppercase">
|
|
</label>
|
|
<label>
|
|
Language / locale
|
|
<select id="region-locale"></select>
|
|
</label>
|
|
<label>
|
|
Keyboard layout
|
|
<select id="region-keyboard"></select>
|
|
</label>
|
|
<div class="button-row">
|
|
<button type="submit">Save region</button>
|
|
<button type="button" id="region-from-locale" class="secondary">Country from locale</button>
|
|
</div>
|
|
<p class="hint">Locale and keyboard apply after a restart; the WiFi country applies immediately.</p>
|
|
</form>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- Update -->
|
|
<section class="page" id="page-update">
|
|
<div class="page-header">
|
|
<h1>Update</h1>
|
|
<p>Pull the latest code from git and re-apply setup (packages, app files, hardware config).</p>
|
|
</div>
|
|
<div class="card">
|
|
<div class="button-row"><button type="button" id="run-upgrade">Check for and apply updates</button></div>
|
|
<div class="job-panel" id="job-panel-upgrade">
|
|
<div class="job-panel-header">
|
|
<span>Update</span>
|
|
<span class="job-status" id="job-status-upgrade"></span>
|
|
</div>
|
|
<pre class="job-log" id="job-log-upgrade"></pre>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
</main>
|
|
</div>
|
|
|
|
<template id="site-row-template">
|
|
<div class="site-row card-inset">
|
|
<div class="site-row-grid">
|
|
<label>
|
|
URL
|
|
<input type="text" class="site-url" placeholder="example.com, https://example.com or /path/to/file.pdf">
|
|
</label>
|
|
<label>
|
|
Name (optional)
|
|
<input type="text" class="site-name" placeholder="Shown instead of the URL">
|
|
</label>
|
|
<label>
|
|
Duration (seconds; -1=hidden, 0=manual, >0=auto-rotate)
|
|
<input type="number" class="site-duration" min="-1" max="86400" step="1" value="180">
|
|
</label>
|
|
</div>
|
|
<details class="site-auth">
|
|
<summary>HTTP Basic Auth <span class="auth-state"></span></summary>
|
|
<label class="checkbox"><input type="checkbox" class="site-auth-enable"> Requires a username/password</label>
|
|
<label>
|
|
Username
|
|
<input type="text" class="site-auth-username">
|
|
</label>
|
|
<label>
|
|
New password <span class="hint">(leave blank to keep the current one)</span>
|
|
<input type="password" class="site-auth-password" autocomplete="new-password">
|
|
</label>
|
|
</details>
|
|
<button type="button" class="remove-site danger">Remove page</button>
|
|
</div>
|
|
</template>
|
|
|
|
<template id="addon-card-template">
|
|
<div class="card addon-card">
|
|
<div class="addon-card-top">
|
|
<div class="addon-title">
|
|
<div class="addon-icon"></div>
|
|
<div>
|
|
<div class="addon-name"></div>
|
|
<div class="addon-desc"></div>
|
|
</div>
|
|
</div>
|
|
<span class="pill unknown">checking…</span>
|
|
</div>
|
|
<div class="button-row addon-actions"></div>
|
|
<form class="addon-form"></form>
|
|
<div class="job-panel">
|
|
<div class="job-panel-header">
|
|
<span>Log</span>
|
|
<span class="job-status"></span>
|
|
</div>
|
|
<pre class="job-log"></pre>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script src="app.js"></script>
|
|
</body>
|
|
</html>
|