feat: improve UI contrast, dark mode, dialog sizing, color coherence, and add table sorting

- Fix dialog scrollability (flex layout + max-h-[90dvh]) and increase L4 dialog to lg width
- Add styled enable card to L4 dialog matching proxy host pattern
- Unify section colors across proxy host and L4 dialogs (cyan=LB, emerald=DNS, violet=upstream DNS, rose=geo, amber=mTLS)
- Improve light mode contrast: muted-foreground oklch 0.552→0.502, remove opacity modifiers on secondary text
- Improve dark mode: boost muted-foreground to 0.85, increase border opacity 10%→16%, input 15%→20%
- Add bg-card to DataTable wrapper and bg-muted/40 to table headers for surface hierarchy
- Add semantic badge variants (success, warning, info, muted) and StatusChip dark mode fix
- Add server-side sortable columns to Proxy Hosts and L4 Proxy Hosts (name, upstream, status, protocol, listen)
- Add sortKey to DataTable Column type with clickable sort headers (ArrowUp/Down indicators, URL param driven)
- Fix E2E test selectors for shadcn UI (label associations, combobox roles, dropdown menus, mobile drawer)
- Add htmlFor/id to proxy host form fields and aria-labels to select triggers for accessibility
- Add sorting E2E tests for both proxy host pages

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
fuomag9
2026-03-22 22:17:56 +01:00
parent 65753f6a8d
commit 9c60d11c2c
45 changed files with 1616 additions and 1052 deletions

View File

@@ -58,7 +58,7 @@ export function CreateHostDialog({
open={open}
onClose={onClose}
title={initialData ? "Duplicate Proxy Host" : "Create Proxy Host"}
maxWidth="md"
maxWidth="lg"
submitLabel="Create"
onSubmit={() => {
(document.getElementById("create-host-form") as HTMLFormElement)?.requestSubmit();
@@ -76,8 +76,9 @@ export function CreateHostDialog({
enabled={true}
/>
<div>
<label className="text-sm font-medium mb-1 block">Name</label>
<label htmlFor="name" className="text-sm font-medium mb-1 block">Name</label>
<Input
id="name"
name="name"
placeholder="My Service"
defaultValue={initialData ? `${initialData.name} (Copy)` : ""}
@@ -85,8 +86,9 @@ export function CreateHostDialog({
/>
</div>
<div>
<label className="text-sm font-medium mb-1 block">Domains</label>
<label htmlFor="domains" className="text-sm font-medium mb-1 block">Domains</label>
<Textarea
id="domains"
name="domains"
placeholder="app.example.com"
defaultValue={initialData?.domains.join("\n") ?? ""}
@@ -101,7 +103,7 @@ export function CreateHostDialog({
<div>
<label className="text-sm font-medium mb-1 block">Certificate</label>
<Select name="certificate_id" defaultValue={String(initialData?.certificate_id ?? "__none__")}>
<SelectTrigger>
<SelectTrigger aria-label="Certificate">
<SelectValue placeholder="Managed by Caddy (Auto)" />
</SelectTrigger>
<SelectContent>
@@ -117,7 +119,7 @@ export function CreateHostDialog({
<div>
<label className="text-sm font-medium mb-1 block">Access List</label>
<Select name="access_list_id" defaultValue={String(initialData?.access_list_id ?? "__none__")}>
<SelectTrigger>
<SelectTrigger aria-label="Access List">
<SelectValue placeholder="None" />
</SelectTrigger>
<SelectContent>
@@ -194,7 +196,7 @@ export function EditHostDialog({
open={open}
onClose={onClose}
title="Edit Proxy Host"
maxWidth="md"
maxWidth="lg"
submitLabel="Save Changes"
onSubmit={() => {
(document.getElementById("edit-host-form") as HTMLFormElement)?.requestSubmit();
@@ -212,12 +214,13 @@ export function EditHostDialog({
enabled={host.enabled}
/>
<div>
<label className="text-sm font-medium mb-1 block">Name</label>
<Input name="name" defaultValue={host.name} required />
<label htmlFor="name" className="text-sm font-medium mb-1 block">Name</label>
<Input id="name" name="name" defaultValue={host.name} required />
</div>
<div>
<label className="text-sm font-medium mb-1 block">Domains</label>
<label htmlFor="domains" className="text-sm font-medium mb-1 block">Domains</label>
<Textarea
id="domains"
name="domains"
defaultValue={host.domains.join("\n")}
rows={2}
@@ -230,7 +233,7 @@ export function EditHostDialog({
<div>
<label className="text-sm font-medium mb-1 block">Certificate</label>
<Select name="certificate_id" defaultValue={String(host.certificate_id ?? "__none__")}>
<SelectTrigger>
<SelectTrigger aria-label="Certificate">
<SelectValue placeholder="Managed by Caddy (Auto)" />
</SelectTrigger>
<SelectContent>
@@ -246,7 +249,7 @@ export function EditHostDialog({
<div>
<label className="text-sm font-medium mb-1 block">Access List</label>
<Select name="access_list_id" defaultValue={String(host.access_list_id ?? "__none__")}>
<SelectTrigger>
<SelectTrigger aria-label="Access List">
<SelectValue placeholder="None" />
</SelectTrigger>
<SelectContent>