feat(ui): /settings page + nav link on every page
Slice 5 of the on-box UI uplevel. Adds a third page at /settings/
served by Caddy from /srv/furtka/www/settings/index.html. Three
groups of content:
- About this box (read-only): hostname, IP, Furtka version,
kernel, RAM, Docker, uptime — all consumed from status.json
via the same 30s refresh loop the landing uses.
- Appearance: theme follows prefers-color-scheme, language is
English for v1. Shown read-only.
- Coming next: linked roadmap chips (Reboot / Shut down / Change
hostname / Backup / User accounts / Remote access), each
jumping to the planned section on furtka.org. Implementing any
of these graduates it in-place.
Nav link to Settings also added to the landing page and /apps so
the three pages share one persistent navigation (Jakob's Law).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
c7ca6bfbb1
commit
4e4dc1001f
2 changed files with 93 additions and 0 deletions
|
|
@ -76,6 +76,7 @@ _HTML = """<!DOCTYPE html>
|
|||
<div class="nav-links">
|
||||
<a href="/">Home</a>
|
||||
<a href="/apps" aria-current="page">Apps</a>
|
||||
<a href="/settings/">Settings</a>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
|
|
|
|||
|
|
@ -188,6 +188,7 @@ _INDEX_HTML = """\
|
|||
<div class="nav-links">
|
||||
<a href="/" aria-current="page">Home</a>
|
||||
<a href="/apps">Apps</a>
|
||||
<a href="/settings/">Settings</a>
|
||||
</div>
|
||||
</nav>
|
||||
<header>
|
||||
|
|
@ -719,6 +720,96 @@ details.log-details[open] > summary { color: var(--fg); }
|
|||
.app-icon svg { width: 36px; height: 36px; }
|
||||
"""
|
||||
|
||||
_SETTINGS_HTML = """\
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Settings · Furtka</title>
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
<link rel="stylesheet" href="/style.css">
|
||||
</head>
|
||||
<body>
|
||||
<main class="wrap">
|
||||
<nav class="nav">
|
||||
<a class="brand" href="/">Furtka</a>
|
||||
<div class="nav-links">
|
||||
<a href="/">Home</a>
|
||||
<a href="/apps">Apps</a>
|
||||
<a href="/settings/" aria-current="page">Settings</a>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<h1>Settings</h1>
|
||||
<p class="lede">What this box knows about itself.</p>
|
||||
|
||||
<section>
|
||||
<h2>About this box</h2>
|
||||
<div class="card">
|
||||
<dl class="kv">
|
||||
<dt>Hostname</dt><dd id="set-hostname">—</dd>
|
||||
<dt>IP address</dt><dd id="set-ip">—</dd>
|
||||
<dt>Furtka version</dt><dd id="set-version">—</dd>
|
||||
<dt>Kernel</dt><dd id="set-kernel">—</dd>
|
||||
<dt>RAM</dt><dd id="set-ram">—</dd>
|
||||
<dt>Docker</dt><dd id="set-docker">—</dd>
|
||||
<dt>Uptime</dt><dd id="set-uptime">—</dd>
|
||||
</dl>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h2>Appearance</h2>
|
||||
<div class="card">
|
||||
<dl class="kv">
|
||||
<dt>Theme</dt><dd>Follows your system setting</dd>
|
||||
<dt>Language</dt><dd>English</dd>
|
||||
</dl>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h2>Coming next</h2>
|
||||
<div class="coming">
|
||||
<p class="hint">Controls we're building — follow progress on <a href="https://furtka.org">furtka.org</a>.</p>
|
||||
<a href="https://furtka.org/#planned">Reboot</a>
|
||||
<a href="https://furtka.org/#planned">Shut down</a>
|
||||
<a href="https://furtka.org/#planned">Change hostname</a>
|
||||
<a href="https://furtka.org/#planned">Backup</a>
|
||||
<a href="https://furtka.org/#planned">User accounts</a>
|
||||
<a href="https://furtka.org/#planned">Remote access</a>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<footer>
|
||||
<p>Furtka · <a href="https://furtka.org">furtka.org</a></p>
|
||||
</footer>
|
||||
</main>
|
||||
|
||||
<script>
|
||||
async function refresh() {
|
||||
try {
|
||||
const r = await fetch('/status.json', { cache: 'no-store' });
|
||||
if (!r.ok) return;
|
||||
const s = await r.json();
|
||||
document.getElementById('set-hostname').textContent = s.hostname || '—';
|
||||
document.getElementById('set-ip').textContent = s.ip_primary || '—';
|
||||
document.getElementById('set-version').textContent = s.furtka_version || '—';
|
||||
document.getElementById('set-kernel').textContent = s.kernel || '—';
|
||||
document.getElementById('set-ram').textContent = s.ram_total || '—';
|
||||
document.getElementById('set-docker').textContent = s.docker_version || '—';
|
||||
document.getElementById('set-uptime').textContent = s.uptime || '—';
|
||||
} catch (e) {
|
||||
/* next tick will retry */
|
||||
}
|
||||
}
|
||||
refresh();
|
||||
setInterval(refresh, 15000);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
"""
|
||||
|
||||
_STATUS_JSON_PLACEHOLDER = """\
|
||||
{
|
||||
"hostname": "",
|
||||
|
|
@ -945,6 +1036,7 @@ def _post_install_commands(hostname):
|
|||
return [
|
||||
_write_file_cmd("/etc/caddy/Caddyfile", _CADDYFILE),
|
||||
_write_file_cmd("/srv/furtka/www/index.html", _INDEX_HTML),
|
||||
_write_file_cmd("/srv/furtka/www/settings/index.html", _SETTINGS_HTML),
|
||||
_write_file_cmd("/srv/furtka/www/style.css", _STYLE_CSS),
|
||||
_write_file_cmd("/srv/furtka/www/status.json", _STATUS_JSON_PLACEHOLDER),
|
||||
_write_file_cmd("/usr/local/bin/furtka-status", _FURTKA_STATUS_SH, mode="755"),
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue