635 lines
24 KiB
HTML
635 lines
24 KiB
HTML
<!doctype html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="UTF-8" />
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||
<title>Pi-Kit Dashboard</title>
|
||
<link rel="stylesheet" href="assets/style.css" />
|
||
</head>
|
||
<body>
|
||
<header class="topbar">
|
||
<div class="brand">
|
||
<div
|
||
class="dot"
|
||
title="Dashboard status indicator (shows when the UI is loaded)"
|
||
aria-label="Dashboard status indicator"
|
||
></div>
|
||
<span>Pi-Kit</span>
|
||
</div>
|
||
<div class="top-indicators">
|
||
<span class="chip-label">Status</span>
|
||
<span id="updatesFlagTop" class="status-chip quiet">Auto updates</span>
|
||
<span id="updatesNoteTop" class="hint quiet"></span>
|
||
<span id="refreshFlagTop" class="status-chip quiet">Refresh: 10s</span>
|
||
<span id="tempFlagTop" class="status-chip quiet">Temp: OK</span>
|
||
</div>
|
||
<div class="top-actions">
|
||
<button
|
||
id="themeToggle"
|
||
class="ghost icon-btn"
|
||
title="Toggle theme"
|
||
aria-label="Toggle theme"
|
||
>
|
||
<span id="themeToggleIcon" aria-hidden="true">🌙</span>
|
||
</button>
|
||
<button id="aboutBtn" class="ghost" title="About Pi-Kit">About</button>
|
||
<button id="helpBtn" class="ghost" title="Open help">Help</button>
|
||
<button id="advBtn" class="ghost" title="Open settings">
|
||
Settings
|
||
</button>
|
||
</div>
|
||
</header>
|
||
|
||
<main class="layout">
|
||
<section class="hero">
|
||
<div>
|
||
<p class="eyebrow">All-in-one launcher</p>
|
||
<h1>Welcome to your Pi-Kit homebase</h1>
|
||
<p class="lede">
|
||
Launch services, view quick health, and handle essentials without
|
||
cracking open SSH.
|
||
</p>
|
||
</div>
|
||
<div class="hero-stats" id="heroStats"></div>
|
||
</section>
|
||
|
||
<section class="panel">
|
||
<div class="panel-header">
|
||
<div>
|
||
<p class="eyebrow">Configured services</p>
|
||
<h2>Web interfaces</h2>
|
||
<p class="hint">
|
||
Shortcuts to the web UIs running on your Pi. Click a card to open it. Use the + button to add another service; use the ⋮ menu on a card to edit or remove it.
|
||
</p>
|
||
</div>
|
||
<div class="panel-actions">
|
||
<button id="addServiceOpen" class="ghost icon-btn" title="Add a service" aria-label="Add service">
|
||
+
|
||
</button>
|
||
</div>
|
||
</div>
|
||
<div id="servicesGrid" class="grid"></div>
|
||
</section>
|
||
</main>
|
||
|
||
<div id="readyOverlay" class="overlay hidden">
|
||
<div class="overlay-box">
|
||
<h3>Finishing setup</h3>
|
||
<p>
|
||
This only takes a couple of minutes. You'll see the dashboard once
|
||
Pi-Kit setup completes.
|
||
</p>
|
||
<div class="spinner"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="busyOverlay" class="overlay hidden">
|
||
<div class="overlay-box">
|
||
<h3 id="busyTitle">Working…</h3>
|
||
<p id="busyText" class="hint">This may take a few seconds.</p>
|
||
<div class="spinner"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="aboutModal" class="modal hidden">
|
||
<div class="modal-card wide">
|
||
<div class="panel-header sticky">
|
||
<div>
|
||
<p class="eyebrow">About</p>
|
||
<h3>About Pi-Kit</h3>
|
||
</div>
|
||
<button id="aboutClose" class="ghost icon-btn close-btn" title="Close about">
|
||
×
|
||
</button>
|
||
</div>
|
||
<div class="help-body">
|
||
<h4>What is this?</h4>
|
||
<p>
|
||
Pi-Kit is a self-hosted dashboard for managing services, monitoring your Pi,
|
||
and handling unattended updates, all through a single UI.
|
||
</p>
|
||
<h4>Font licensing</h4>
|
||
<p>
|
||
The following fonts are included under the SIL Open Font License 1.1 (no attribution required):
|
||
</p>
|
||
<ul>
|
||
<li>Red Hat Display / Red Hat Text</li>
|
||
<li>Space Grotesk</li>
|
||
<li>Manrope</li>
|
||
<li>DM Sans</li>
|
||
<li>Sora</li>
|
||
<li>Chivo</li>
|
||
<li>Atkinson Hyperlegible</li>
|
||
<li>IBM Plex Sans</li>
|
||
</ul>
|
||
<p class="hint">OFL license text is bundled at assets/fonts/OFL.txt.</p>
|
||
<h4>Other licenses</h4>
|
||
<p>
|
||
Pi-Kit code is MIT licensed. Third-party tooling (Vite, @fontsource) is MIT; Playwright (dev/test) is Apache 2.0.
|
||
See <a href="/THIRD-PARTY-LICENSES.txt" target="_blank">THIRD-PARTY-LICENSES.txt</a> and <a href="/LICENSE.txt" target="_blank">LICENSE.txt</a> for details, and <a href="/assets/fonts/OFL.txt" target="_blank">OFL.txt</a> for font licensing.
|
||
</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="addServiceModal" class="modal hidden">
|
||
<div class="modal-card wide">
|
||
<div class="panel-header sticky">
|
||
<div>
|
||
<p class="eyebrow">Add service</p>
|
||
<h3>Register a web interface</h3>
|
||
<p class="hint">
|
||
Adds a local service by name and port. Choose HTTP or HTTPS to match how it serves traffic.
|
||
</p>
|
||
</div>
|
||
<button id="addSvcClose" class="ghost icon-btn close-btn" title="Close add service">
|
||
×
|
||
</button>
|
||
</div>
|
||
<div class="controls column">
|
||
<div class="control-actions column">
|
||
<input
|
||
type="text"
|
||
id="svcName"
|
||
placeholder="Service name"
|
||
maxlength="32"
|
||
/>
|
||
<p class="hint quiet">Service name: max 32 characters.</p>
|
||
<input
|
||
type="number"
|
||
id="svcPort"
|
||
placeholder="Port (e.g. 8080)"
|
||
min="1"
|
||
max="65535"
|
||
/>
|
||
<input
|
||
type="text"
|
||
id="svcPath"
|
||
placeholder="Optional path (e.g. /admin)"
|
||
/>
|
||
<div class="control-row split">
|
||
<label class="checkbox-row">
|
||
<span>Protocol</span>
|
||
<select id="svcScheme">
|
||
<option value="http">HTTP</option>
|
||
<option value="https">HTTPS</option>
|
||
</select>
|
||
</label>
|
||
<label class="checkbox-row inline tight nowrap">
|
||
<input type="checkbox" id="svcSelfSigned" />
|
||
<span>Self-signed TLS</span>
|
||
</label>
|
||
</div>
|
||
<textarea
|
||
id="svcNotice"
|
||
rows="3"
|
||
placeholder="Optional notice (shown on card)"
|
||
></textarea>
|
||
<input
|
||
type="text"
|
||
id="svcNoticeLink"
|
||
placeholder="Optional link for more info"
|
||
/>
|
||
<div class="control-actions">
|
||
<button id="svcAddBtn" title="Add service and open port on LAN">
|
||
Add
|
||
</button>
|
||
</div>
|
||
<div id="svcMsg" class="hint status-msg"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="advModal" class="modal hidden">
|
||
<div class="modal-card wide">
|
||
<div class="panel-header sticky">
|
||
<div>
|
||
<p class="eyebrow warning">Settings</p>
|
||
<h3>System controls</h3>
|
||
</div>
|
||
<button
|
||
id="advClose"
|
||
class="ghost icon-btn close-btn"
|
||
title="Close settings panel"
|
||
>
|
||
×
|
||
</button>
|
||
</div>
|
||
<div class="controls accordion-list">
|
||
<div class="accordion">
|
||
<button class="accordion-toggle" data-target="acc-updates">
|
||
Automatic updates
|
||
</button>
|
||
<div class="accordion-body" id="acc-updates">
|
||
<p class="hint">
|
||
Daily unattended-upgrades: choose scope, schedule, cleanup, bandwidth, and reboot policy.
|
||
</p>
|
||
<div class="control-actions column" id="updatesSection">
|
||
<div class="control-actions">
|
||
<span id="updatesStatus" class="status-chip">Unknown</span>
|
||
<label class="toggle" title="Toggle unattended updates">
|
||
<input type="checkbox" id="updatesToggle" />
|
||
<span class="slider"></span>
|
||
</label>
|
||
<span class="hint" id="updatesToggleLabel">Enable/disable unattended upgrades</span>
|
||
</div>
|
||
<div id="updatesControls">
|
||
<div class="form-grid">
|
||
<label class="field">
|
||
<span>What to update</span>
|
||
<select id="updatesScope">
|
||
<option value="all">Security + regular updates</option>
|
||
<option value="security">Security only</option>
|
||
</select>
|
||
</label>
|
||
<label class="field">
|
||
<span>Download updates at</span>
|
||
<input type="time" id="updateTimeInput" value="04:00" title="Time of day to download updates" />
|
||
</label>
|
||
<label class="field">
|
||
<span>Install updates at</span>
|
||
<input type="time" id="upgradeTimeInput" value="04:30" title="Time of day to install updates" />
|
||
</label>
|
||
<div class="field checkbox-field">
|
||
<span>Cleanup unused packages</span>
|
||
<label class="checkbox-row inline tight">
|
||
<input type="checkbox" id="updatesCleanup" title="Automatically remove unused dependencies after upgrades" />
|
||
<span>Auto-remove dependencies after upgrades</span>
|
||
</label>
|
||
</div>
|
||
<label class="field">
|
||
<span>Bandwidth limit (KB/s, 0 = unlimited)</span>
|
||
<input
|
||
type="number"
|
||
id="updatesBandwidth"
|
||
min="0"
|
||
placeholder="0"
|
||
/>
|
||
</label>
|
||
<div class="field checkbox-field">
|
||
<span>Reboot options</span>
|
||
<div class="control-actions column tight">
|
||
<label class="checkbox-row inline tight">
|
||
<input type="checkbox" id="updatesRebootToggle" title="Auto-reboot when updates require it" />
|
||
<span>Auto-reboot if required</span>
|
||
</label>
|
||
<label class="checkbox-row inline tight">
|
||
<span>Reboot time</span>
|
||
<input type="time" id="updatesRebootTime" value="04:30" title="Scheduled reboot time when auto-reboot is enabled" />
|
||
</label>
|
||
<label class="checkbox-row inline tight nowrap">
|
||
<input type="checkbox" id="updatesRebootUsers" title="Allow reboot even if users are logged in" />
|
||
<span>Allow reboot with active users</span>
|
||
</label>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="control-actions split-row">
|
||
<button id="updatesSaveBtn" title="Save unattended-upgrades settings" disabled>
|
||
Save settings
|
||
</button>
|
||
<span id="updatesUnsavedNote" class="note-warn hidden">Please save changes or they will not apply.</span>
|
||
</div>
|
||
<div id="updatesMsg" class="hint status-msg"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="accordion">
|
||
<button class="accordion-toggle" data-target="acc-anim">
|
||
Animations
|
||
</button>
|
||
<div class="accordion-body" id="acc-anim">
|
||
<p class="hint">
|
||
Adds smooth hover and click motion cues across the dashboard.
|
||
Default is on.
|
||
</p>
|
||
<div class="control-actions">
|
||
<span class="status-chip">Enable animations</span>
|
||
<label class="toggle" title="Toggle UI animations">
|
||
<input type="checkbox" id="animToggle" checked />
|
||
<span class="slider"></span>
|
||
</label>
|
||
</div>
|
||
<div class="form-grid">
|
||
<label class="field">
|
||
<span>Toast position</span>
|
||
<select id="toastPosSelect" title="Choose where toast notifications appear">
|
||
<option value="bottom-center">Bottom center</option>
|
||
<option value="bottom-right">Bottom right</option>
|
||
<option value="bottom-left">Bottom left</option>
|
||
<option value="top-right">Top right</option>
|
||
<option value="top-left">Top left</option>
|
||
<option value="top-center">Top center</option>
|
||
</select>
|
||
</label>
|
||
<label class="field">
|
||
<span>Toast animation</span>
|
||
<select id="toastAnimSelect" title="Toast entry animation style">
|
||
<option value="slide-in">Slide in</option>
|
||
<option value="fade">Fade</option>
|
||
<option value="pop">Pop</option>
|
||
<option value="bounce">Bounce</option>
|
||
<option value="drop">Drop</option>
|
||
<option value="grow">Grow</option>
|
||
</select>
|
||
</label>
|
||
<label class="field">
|
||
<span>Toast speed (ms)</span>
|
||
<input
|
||
type="number"
|
||
id="toastSpeedInput"
|
||
min="100"
|
||
max="3000"
|
||
step="50"
|
||
value="280"
|
||
title="Animation duration for toasts"
|
||
/>
|
||
</label>
|
||
<label class="field">
|
||
<span>Toast duration (ms)</span>
|
||
<input
|
||
type="number"
|
||
id="toastDurationInput"
|
||
min="1000"
|
||
max="15000"
|
||
step="250"
|
||
value="5000"
|
||
title="How long to keep toasts visible"
|
||
/>
|
||
</label>
|
||
</div>
|
||
<div class="control-actions">
|
||
<button id="toastTestBtn" title="Show a sample toast">Test toast</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="accordion">
|
||
<button class="accordion-toggle" data-target="acc-appearance">
|
||
Appearance
|
||
</button>
|
||
<div class="accordion-body" id="acc-appearance">
|
||
<p class="hint">Choose the dashboard typeface.</p>
|
||
<div class="form-grid">
|
||
<label class="field">
|
||
<span>Dashboard font</span>
|
||
<select id="fontSelect" title="Choose dashboard typeface">
|
||
<option value="redhat">Red Hat (default)</option>
|
||
<option value="space">Space Grotesk</option>
|
||
<option value="manrope">Manrope</option>
|
||
<option value="dmsans">DM Sans</option>
|
||
<option value="sora">Sora</option>
|
||
<option value="chivo">Chivo</option>
|
||
<option value="atkinson">Atkinson Hyperlegible</option>
|
||
<option value="plex">IBM Plex Sans</option>
|
||
</select>
|
||
</label>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="accordion">
|
||
<button class="accordion-toggle" data-target="acc-refresh">
|
||
Refresh interval
|
||
</button>
|
||
<div class="accordion-body" id="acc-refresh">
|
||
<p class="hint">
|
||
Sets how often status and services auto-refresh. Minimum 5
|
||
seconds; default 10.
|
||
</p>
|
||
<div class="control-actions column">
|
||
<label class="checkbox-row">
|
||
<span>Seconds</span>
|
||
<input
|
||
type="number"
|
||
id="refreshIntervalInput"
|
||
min="5"
|
||
max="120"
|
||
value="10"
|
||
/>
|
||
</label>
|
||
<div class="control-actions">
|
||
<button
|
||
id="refreshIntervalSave"
|
||
title="Update auto refresh rate"
|
||
>
|
||
Save
|
||
</button>
|
||
</div>
|
||
<div id="refreshIntervalMsg" class="hint status-msg"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="accordion">
|
||
<button class="accordion-toggle danger-btn" data-target="acc-reset">
|
||
Factory reset
|
||
</button>
|
||
<div class="accordion-body" id="acc-reset">
|
||
<p class="hint">
|
||
Restores Pi-Kit defaults, resets firewall and passwords
|
||
(root/dietpi → pikit), then reboots. Type YES to confirm.
|
||
</p>
|
||
<div class="control-actions column">
|
||
<input
|
||
type="text"
|
||
id="resetConfirm"
|
||
placeholder="Type YES to confirm"
|
||
/>
|
||
<button
|
||
id="resetBtn"
|
||
class="danger-btn"
|
||
disabled
|
||
title="Type YES above to enable"
|
||
>
|
||
Factory reset
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="helpModal" class="modal hidden">
|
||
<div class="modal-card wide">
|
||
<div class="panel-header">
|
||
<div>
|
||
<p class="eyebrow">Help</p>
|
||
<h3>How Pi-Kit dashboard works</h3>
|
||
<p class="hint">Quick, friendly guidance for common tasks.</p>
|
||
</div>
|
||
<button
|
||
id="helpClose"
|
||
class="ghost icon-btn close-btn"
|
||
title="Close help"
|
||
>
|
||
×
|
||
</button>
|
||
</div>
|
||
<div class="help-body">
|
||
<h4>Quick tour</h4>
|
||
<ul>
|
||
<li><strong>Status chips</strong> show uptime, OS, CPU temp, memory/disk, LAN IP, and auto-update/reboot flags.</li>
|
||
<li><strong>Service cards</strong> open your web UIs; the “…” menu lets you rename, change port/protocol/path, or remove.</li>
|
||
<li><strong>Hero stats</strong> up top give you a fast health snapshot.</li>
|
||
</ul>
|
||
|
||
<h4>Adding and editing services</h4>
|
||
<ul>
|
||
<li>Use <strong>Web interfaces → Add service</strong> to register a local UI. Pick HTTP/HTTPS to match the service.</li>
|
||
<li>Mark “Self‑signed TLS” if the cert isn’t trusted to avoid surprise warnings.</li>
|
||
<li>Paths should start with “/” (e.g., <code>/admin</code>); ports must be 1–65535.</li>
|
||
</ul>
|
||
|
||
<h4>Automatic updates</h4>
|
||
<ul>
|
||
<li>Turn unattended upgrades on/off, choose security‑only or all updates.</li>
|
||
<li>Set download/install times, bandwidth limit, cleanup, and reboot policy.</li>
|
||
<li>Save to apply; the top chip shows if a reboot is required/scheduled.</li>
|
||
</ul>
|
||
|
||
<h4>Appearance & toasts</h4>
|
||
<ul>
|
||
<li>Pick a font in <strong>Settings → Appearance</strong> (Red Hat, Space Grotesk, Manrope, etc.).</li>
|
||
<li>Customize toast position, animation, speed, and duration under <strong>Animations</strong>.</li>
|
||
</ul>
|
||
|
||
<h4>Passwords & SSH (friendly defaults)</h4>
|
||
<ul>
|
||
<li>Default password for <strong>root</strong> and <strong>dietpi</strong>: <code>pikit</code>. Please change it ASAP.</li>
|
||
<li>To use keys: <code>ssh-copy-id -i ~/.ssh/yourkey.pub user@pikit</code>, then test with <code>ssh -i ~/.ssh/yourkey user@pikit</code>.</li>
|
||
<li>Once keys work, consider disabling password auth in <code>/etc/ssh/sshd_config</code> for extra safety.</li>
|
||
</ul>
|
||
|
||
<h4>Safety</h4>
|
||
<ul>
|
||
<li>Firewall allows LAN by default; nothing is exposed to the internet by Pi‑Kit.</li>
|
||
<li>Factory reset reverts passwords and firewall rules and reboots. Use only when you need a clean slate.</li>
|
||
</ul>
|
||
|
||
<h4>Troubleshooting</h4>
|
||
<ul>
|
||
<li>Service link fails? Make sure the service runs, port/path are right, and edit via the “…” menu.</li>
|
||
<li>Key login fails? Re-run <code>ssh-copy-id</code> for the correct user and retry.</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="menuModal" class="modal hidden">
|
||
<div class="modal-card wide">
|
||
<div class="panel-header">
|
||
<div>
|
||
<p class="eyebrow">Service actions</p>
|
||
<h3 id="menuTitle"></h3>
|
||
<p id="menuSubtitle" class="hint"></p>
|
||
</div>
|
||
<button class="ghost icon-btn close-btn" id="menuClose" title="Close">
|
||
×
|
||
</button>
|
||
</div>
|
||
<div class="config-list">
|
||
<div class="config-row">
|
||
<div class="config-label">
|
||
<h4>Rename</h4>
|
||
<p class="hint">Update the display name (max 32 characters).</p>
|
||
</div>
|
||
<div class="config-controls">
|
||
<input type="text" id="menuRename" maxlength="32" />
|
||
</div>
|
||
</div>
|
||
|
||
<div class="config-row">
|
||
<div class="config-label">
|
||
<h4>Change port</h4>
|
||
<p class="hint">
|
||
Moves the service to a new port and opens it on LAN.
|
||
</p>
|
||
</div>
|
||
<div class="config-controls">
|
||
<input type="number" id="menuPort" min="1" max="65535" />
|
||
</div>
|
||
</div>
|
||
|
||
<div class="config-row">
|
||
<div class="config-label">
|
||
<h4>Path</h4>
|
||
<p class="hint">Optional subpath (e.g. /admin or /ui/).</p>
|
||
</div>
|
||
<div class="config-controls">
|
||
<input type="text" id="menuPath" placeholder="/admin" />
|
||
</div>
|
||
</div>
|
||
|
||
<div class="config-row">
|
||
<div class="config-label">
|
||
<h4>Protocol</h4>
|
||
<p class="hint">Choose HTTP or HTTPS link.</p>
|
||
</div>
|
||
<div class="config-controls">
|
||
<select id="menuScheme">
|
||
<option value="http">HTTP</option>
|
||
<option value="https">HTTPS</option>
|
||
</select>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="config-row">
|
||
<div class="config-label">
|
||
<h4>Self-signed TLS</h4>
|
||
<p class="hint">Show a self-signed badge.</p>
|
||
</div>
|
||
<div class="config-controls">
|
||
<label class="checkbox-row">
|
||
<input type="checkbox" id="menuSelfSigned" />
|
||
<span>Mark as self-signed</span>
|
||
</label>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="config-row">
|
||
<div class="config-label">
|
||
<h4>Notice</h4>
|
||
<p class="hint">Optional badge + info text on the card.</p>
|
||
</div>
|
||
<div class="config-controls">
|
||
<textarea id="menuNotice" rows="4" placeholder="e.g., Uses a self-signed certificate."></textarea>
|
||
<input
|
||
type="text"
|
||
id="menuNoticeLink"
|
||
placeholder="Optional link for more info"
|
||
/>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="menuMsg" class="hint status-msg"></div>
|
||
</div>
|
||
|
||
<div class="modal-actions">
|
||
<button
|
||
id="menuRemoveBtn"
|
||
class="danger-btn"
|
||
title="Remove this service"
|
||
>
|
||
Remove
|
||
</button>
|
||
<div class="push"></div>
|
||
<button id="menuCancelBtn" class="ghost" title="Cancel changes">
|
||
Cancel
|
||
</button>
|
||
<button id="menuSaveBtn" class="primary" title="Save changes">
|
||
Save
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<script type="module" src="assets/main.js"></script>
|
||
<div id="toastContainer" class="toast-container"></div>
|
||
</body>
|
||
</html>
|