<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="/app.css">
<title>Device Setup</title>
<script>
// Theme bootstrap. Runs before paint to avoid a flash of the wrong theme.
(() => {
const SYSTEM_DARK = "afterdark";
const SYSTEM_LIGHT = "her";
const mq = window.matchMedia("(prefers-color-scheme: dark)");
const systemTheme = () => (mq.matches ? SYSTEM_DARK : SYSTEM_LIGHT);
window.portalSetTheme = (theme) => {
if (theme === "system") {
localStorage.removeItem("portal:theme");
document.documentElement.setAttribute("data-theme", systemTheme());
} else {
localStorage.setItem("portal:theme", theme);
document.documentElement.setAttribute("data-theme", theme);
}
};
if (!document.documentElement.hasAttribute("data-theme")) {
window.portalSetTheme(localStorage.getItem("portal:theme") || "system");
}
mq.addEventListener("change", () => {
if (!localStorage.getItem("portal:theme")) window.portalSetTheme("system");
});
})();
</script>
</head>
<body class="min-h-screen bg-base-100 text-base-content">
<header class="navbar bg-base-200 border-b border-base-300 px-4 sm:px-6">
<div class="flex-1">
<span class="font-bold tracking-[0.2em] text-accent"><span id="brand-root"></span>DEVICE SETUP</span>
</div>
<div class="flex-none">
<div class="dropdown dropdown-end">
<div tabindex="0" role="button" class="btn btn-ghost btn-sm gap-2" aria-label="Choose theme">
<svg xmlns="http://www.w3.org/2000/svg" class="size-4" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="13.5" cy="6.5" r=".5" fill="currentColor"/>
<circle cx="17.5" cy="10.5" r=".5" fill="currentColor"/>
<circle cx="8.5" cy="7.5" r=".5" fill="currentColor"/>
<circle cx="6.5" cy="12.5" r=".5" fill="currentColor"/>
<path d="M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10c.926 0 1.648-.746 1.648-1.688 0-.437-.18-.835-.437-1.125-.29-.289-.438-.652-.438-1.125a1.64 1.64 0 0 1 1.668-1.668h1.996c3.051 0 5.555-2.503 5.555-5.554C21.965 6.012 17.461 2 12 2z"/>
</svg>
<span class="hidden sm:inline">Theme</span>
</div>
<ul tabindex="0" class="dropdown-content menu bg-base-200 border border-base-300 rounded-box z-10 mt-1 w-44 p-1 shadow-lg">
<li><button type="button" onclick="portalSetTheme('system')">System</button></li>
<li>
<button type="button" onclick="portalSetTheme('her')" class="flex items-center justify-between">
<span>Her</span>
<span class="size-3 rounded-full border border-base-content/20" data-theme="her" style="background: var(--color-primary)"></span>
</button>
</li>
<li>
<button type="button" onclick="portalSetTheme('afterdark')" class="flex items-center justify-between">
<span>Afterdark</span>
<span class="size-3 rounded-full border border-base-content/20" data-theme="afterdark" style="background: var(--color-primary)"></span>
</button>
</li>
</ul>
</div>
</div>
</header>
<main class="px-4 py-10 sm:px-6">
<div class="mx-auto max-w-md space-y-4">
<div class="card bg-base-200 border border-base-300 shadow-lg">
<div class="card-body gap-4">
<h1 class="card-title text-accent">Network Setup</h1>
<form method="post" action="/save" class="space-y-6">
<section class="space-y-3">
<h2 class="text-xs font-bold uppercase tracking-wider text-secondary">Wi-Fi</h2>
<label class="flex flex-col w-full">
<span class="mb-1 text-sm text-base-content">Network (SSID)</span>
<input type="text" name="wifi_ssid" class="input w-full"
autocapitalize="off" autocorrect="off" required>
</label>
<label class="flex flex-col w-full">
<span class="mb-1 text-sm text-base-content">Password</span>
<input type="password" name="wifi_pass" class="input w-full">
</label>
<p class="text-xs opacity-60">Leave the password blank for an open network.</p>
<details class="rounded-lg border border-base-300 bg-base-100 px-3 py-2">
<summary class="cursor-pointer text-xs font-semibold uppercase tracking-wider text-secondary">
Other networks
</summary>
<p class="mt-2 text-xs opacity-60">
Optional. The device joins whichever of these is in range, strongest first,
so it can be moved without being set up again.
</p>
<div class="mt-3 space-y-3">
<label class="flex flex-col w-full">
<span class="mb-1 text-sm text-base-content">Network 2 (SSID)</span>
<input type="text" name="wifi_ssid_2" class="input input-sm w-full"
autocapitalize="off" autocorrect="off">
</label>
<label class="flex flex-col w-full">
<span class="mb-1 text-sm text-base-content">Password 2</span>
<input type="password" name="wifi_pass_2" class="input input-sm w-full">
</label>
<label class="flex flex-col w-full">
<span class="mb-1 text-sm text-base-content">Network 3 (SSID)</span>
<input type="text" name="wifi_ssid_3" class="input input-sm w-full"
autocapitalize="off" autocorrect="off">
</label>
<label class="flex flex-col w-full">
<span class="mb-1 text-sm text-base-content">Password 3</span>
<input type="password" name="wifi_pass_3" class="input input-sm w-full">
</label>
</div>
</details>
</section>
<section class="space-y-3">
<h2 class="text-xs font-bold uppercase tracking-wider text-secondary">MQTT Broker</h2>
<div class="flex gap-3">
<label class="flex flex-col grow">
<span class="mb-1 text-sm text-base-content">Host</span>
<input type="text" name="mqtt_host" class="input w-full"
placeholder="192.168.1.10" required>
</label>
<label class="flex flex-col w-24">
<span class="mb-1 text-sm text-base-content">Port</span>
<input type="number" name="mqtt_port" value="1883" min="1" max="65535"
class="input w-full">
</label>
</div>
<label class="flex flex-col w-full">
<span class="mb-1 text-sm text-base-content">Username</span>
<input type="text" name="mqtt_username" class="input w-full" autocapitalize="off">
</label>
<label class="flex flex-col w-full">
<span class="mb-1 text-sm text-base-content">Password</span>
<input type="password" name="mqtt_password" class="input w-full">
</label>
<label class="flex cursor-pointer select-none items-center justify-start gap-3 px-1">
<input type="checkbox" name="mqtt_use_tls" class="checkbox checkbox-primary checkbox-sm">
<span class="text-sm text-base-content">Use TLS (mqtts)</span>
</label>
</section>
<section class="space-y-3">
<h2 class="text-xs font-bold uppercase tracking-wider text-secondary">Topic</h2>
<label class="flex flex-col w-full">
<span class="mb-1 text-sm text-base-content">Root prefix</span>
<input type="text" name="topic_root" id="topic_root" value="neiam" class="input w-full">
</label>
<p class="text-xs opacity-60">
Published topics are built under <code><root>/…</code>.
</p>
</section>
<button type="submit" class="btn btn-primary w-full">Save & Reboot</button>
</form>
</div>
</div>
</div>
</main>
<script>
// Prefix the navbar brand with the topic root, e.g. "CBZ DEVICE SETUP",
// and keep it in sync as the field is edited.
(() => {
const input = document.getElementById('topic_root');
const brand = document.getElementById('brand-root');
const sync = () => {
const root = input.value.trim();
brand.textContent = root ? root.toUpperCase() + ' ' : '';
};
input.addEventListener('input', sync);
sync();
})();
</script>
</body>
</html>
neiam
/neiam-portal
public · Issues · Pulls · Labels · Forks · Compare · Actions success · Badges · Packages
⭐
Log in to mark this repository.
8.9 KiB · text
History
65cab78