Redesign the frontend UI on twui

Rebuild every page on a shared set of twui-based primitives with a dense
ops-console look, WireGuard red accent and light/dark/system theming.

- Add design tokens (WireGuard red accent, zinc neutrals, theme-flipping
  semantic colours) and a no-flash theme cookie + toggle
- Add shared components: page header, panel, sub-nav, data table with
  mobile card list, stat tile, status dot, key-value list, copy button,
  inline alert, empty state, form section/actions, confirm dialog and
  toast providers
- New admin shell (sidebar, sticky header, mobile drawer) and a centered
  shell for auth and 404; strip the public template pages
- Unify adding clients at /admin/clients/add with a host picker; tabbed
  client detail (Overview / Rules / Config & QR) with config copy/download
- Re-run client setup after rule changes on the detail page so the
  firewall matches the DB
- Split Setup into status/maintenance/firewall and Settings into
  profile/password subpages
- Replace window.confirm/alert and page reloads with in-app dialogs,
  toasts and in-place list updates
- Fix nested rule form submitting the client form, prefilled signup
  passwords, hidden submit buttons, fields not updating after "next
  free" lookups, and TinyMCE white-on-white in dark mode

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
2026-10-16 06:29:21 +01:00
co-authored by Claude Opus 5.5
parent e50b0405b0
commit cad1d32ae4
291 changed files with 6436 additions and 6612 deletions
@@ -0,0 +1,57 @@
import type { BUN_SQLITE_WGUI_CLIENT_RULES } from "@/db/types/db";
import type { ClientRuleProtocol, ClientRuleType } from "@/src/types";
import { v4 as uuidv4 } from "uuid";
export type ClientRuleDraft = {
local_id: string;
id?: number | "";
rule_type: ClientRuleType;
destination?: string;
ports?: string;
protocol: ClientRuleProtocol;
};
type CreateParams = Partial<ClientRuleDraft>;
export function createClientRuleDraft(params?: CreateParams): ClientRuleDraft {
return {
local_id: uuidv4(),
rule_type: "destination",
destination: "",
ports: "",
protocol: "any",
...params,
};
}
export function clientRuleToDraft({
rule,
}: {
rule: BUN_SQLITE_WGUI_CLIENT_RULES;
}): ClientRuleDraft {
return {
local_id: String(rule.id || uuidv4()),
id: rule.id,
rule_type: rule.rule_type == "all" ? "all" : "destination",
destination: rule.destination || "",
ports: rule.ports || "",
protocol:
rule.protocol == "tcp" || rule.protocol == "udp"
? rule.protocol
: "any",
};
}
export function clientRuleDraftToRecord({
draft,
}: {
draft: ClientRuleDraft;
}): BUN_SQLITE_WGUI_CLIENT_RULES {
return {
...(draft.id ? { id: draft.id } : {}),
rule_type: draft.rule_type,
destination: draft.destination || "",
ports: draft.ports || "",
protocol: draft.protocol,
};
}