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:
@@ -0,0 +1,50 @@
|
||||
import Row from "@/src/components/twui/layout/Row";
|
||||
import Span from "@/src/components/twui/layout/Span";
|
||||
import { CircleCheck, Info, TriangleAlert, type LucideIcon } from "lucide-react";
|
||||
import type { ReactNode } from "react";
|
||||
import { twMerge } from "tailwind-merge";
|
||||
|
||||
type Tone = "error" | "success" | "warning" | "info";
|
||||
|
||||
type Props = {
|
||||
tone: Tone;
|
||||
msg: ReactNode;
|
||||
className?: string;
|
||||
};
|
||||
|
||||
const ToneStyles: Record<Tone, { className: string; Icon: LucideIcon }> = {
|
||||
error: {
|
||||
className: "border-error/30 bg-error/5 text-error dark:text-error-dark",
|
||||
Icon: TriangleAlert,
|
||||
},
|
||||
success: {
|
||||
className: "border-success/30 bg-success/5 text-success dark:text-success-dark",
|
||||
Icon: CircleCheck,
|
||||
},
|
||||
warning: {
|
||||
className: "border-warning/30 bg-warning/5 text-warning dark:text-warning-dark",
|
||||
Icon: TriangleAlert,
|
||||
},
|
||||
info: {
|
||||
className: "border-line bg-surface-2 text-muted",
|
||||
Icon: Info,
|
||||
},
|
||||
};
|
||||
|
||||
export default function InlineAlert({ tone, msg, className }: Props) {
|
||||
const { className: toneClassName, Icon } = ToneStyles[tone];
|
||||
|
||||
return (
|
||||
<Row
|
||||
role={tone == "error" ? "alert" : "status"}
|
||||
className={twMerge(
|
||||
"w-full gap-2 flex-nowrap items-start px-3 py-2 rounded-default border",
|
||||
toneClassName,
|
||||
className,
|
||||
)}
|
||||
>
|
||||
<Icon size={15} className="shrink-0 mt-0.5" />
|
||||
<Span className="text-[15px] leading-snug">{msg}</Span>
|
||||
</Row>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user