refactor(ui): minimalistic utilitarian redesign across all views
New design language:
- dark background, system sans for UI, monospace for data
- single green accent, amber/red for warn/critical
- square-bordered panels + tables, no rounded cards or shadows
- status conveyed via left-border on overview cards + badges
Changes:
- new app.css defines CSS vars + component classes (.panel, .tbl,
.card, .btn, .input, .badge with [data-status=*])
- new ServerWeb.DashboardNav function component for a shared top nav
with active-link highlighting; replaces per-view navigation clutter
- strip the Phoenix welcome scaffold (logo, version badge, twitter/GH
links) from layouts/app.html.heex; leaves only flash + content
- root.html.heex title suffix switched to 'Proxmox Monitor', body
loses the Tailwind-white background
- rewrite render/1 in all four LiveViews + login template to use the
new classes; admin form now uses <.form for={@form}> and properly
clears on success
- login page redesigned to a single tight panel matching the rest
All 58 tests still pass; 'mix compile --warnings-as-errors' is clean.
This commit is contained in:
parent
1b031ecdc3
commit
50676a7cb8
9 changed files with 649 additions and 364 deletions
|
|
@ -6,7 +6,7 @@ defmodule ServerWeb.VmSearchLive do
|
|||
@impl true
|
||||
def mount(_params, _session, socket) do
|
||||
if connected?(socket), do: Phoenix.PubSub.subscribe(Server.PubSub, "metrics")
|
||||
{:ok, socket |> assign(:q, "") |> assign(:vms, load_vms())}
|
||||
{:ok, socket |> assign(q: "", vms: load_vms(), page_title: "VM Search")}
|
||||
end
|
||||
|
||||
@impl true
|
||||
|
|
@ -54,51 +54,57 @@ defmodule ServerWeb.VmSearchLive do
|
|||
@impl true
|
||||
def render(assigns) do
|
||||
~H"""
|
||||
<div class="p-6 max-w-6xl mx-auto space-y-4">
|
||||
<.link navigate={~p"/"} class="text-sm text-zinc-500 hover:text-zinc-900">← Back</.link>
|
||||
<h1 class="text-2xl font-bold">VM Search</h1>
|
||||
<ServerWeb.DashboardNav.nav active={:vms} />
|
||||
|
||||
<div class="page">
|
||||
<div class="pagehead">
|
||||
<h1>VM Search</h1>
|
||||
<span class="sub">{length(filter(@vms, @q))} / {length(@vms)} shown</span>
|
||||
</div>
|
||||
|
||||
<form phx-change="search">
|
||||
<input
|
||||
name="q"
|
||||
value={@q}
|
||||
placeholder="Search by name or IP…"
|
||||
placeholder="name or ip…"
|
||||
autocomplete="off"
|
||||
autofocus
|
||||
class="w-full rounded-md border-zinc-300 focus:border-zinc-400 focus:ring-0"
|
||||
class="input"
|
||||
/>
|
||||
</form>
|
||||
|
||||
<table class="w-full text-sm bg-white border rounded-lg">
|
||||
<thead>
|
||||
<tr class="text-left text-zinc-500 border-b">
|
||||
<th class="py-2 px-3">Name</th>
|
||||
<th class="py-2 px-3">Host</th>
|
||||
<th class="py-2 px-3">Type</th>
|
||||
<th class="py-2 px-3">Status</th>
|
||||
<th class="py-2 px-3">IPs</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr :for={vm <- filter(@vms, @q)} class="border-b last:border-b-0">
|
||||
<td class="py-2 px-3 font-mono">{vm.name}</td>
|
||||
<td class="py-2 px-3">
|
||||
<.link
|
||||
navigate={~p"/hosts/#{vm.host_name}"}
|
||||
class="text-zinc-700 hover:text-zinc-900 underline"
|
||||
>
|
||||
{vm.host_name}
|
||||
</.link>
|
||||
</td>
|
||||
<td class="py-2 px-3">{vm.type}</td>
|
||||
<td class="py-2 px-3">{vm.status}</td>
|
||||
<td class="py-2 px-3 font-mono text-xs">{Enum.join(vm.ips, ", ")}</td>
|
||||
</tr>
|
||||
<tr :if={filter(@vms, @q) == []}>
|
||||
<td colspan="5" class="py-4 px-3 text-center text-zinc-500">No matches.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="panel">
|
||||
<div class="body tight">
|
||||
<table class="tbl" :if={filter(@vms, @q) != []}>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>VMID</th>
|
||||
<th>Name</th>
|
||||
<th>Host</th>
|
||||
<th>Type</th>
|
||||
<th>Status</th>
|
||||
<th>IPs</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr :for={vm <- filter(@vms, @q)}>
|
||||
<td class="num">{vm.vmid}</td>
|
||||
<td class="mono">{vm.name}</td>
|
||||
<td><.link navigate={~p"/hosts/#{vm.host_name}"}>{vm.host_name}</.link></td>
|
||||
<td>{vm.type}</td>
|
||||
<td><span class="badge" data-status={vm_status(vm)}>{vm.status}</span></td>
|
||||
<td class="mono" style="font-size: 0.75rem;">{Enum.join(vm.ips, ", ")}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div :if={filter(@vms, @q) == []} class="empty">No matches.</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
"""
|
||||
end
|
||||
|
||||
defp vm_status(%{status: "running"}), do: "ok"
|
||||
defp vm_status(%{status: "stopped"}), do: "offline"
|
||||
defp vm_status(_), do: "warning"
|
||||
end
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue