refactor(web): kit consistency — focusRing, PageTitle, Badge, size-4, icon buttons (#66)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-08 23:49:35 +02:00
parent 900f85f8ac
commit 74cde67a54
8 changed files with 18 additions and 13 deletions
+2 -1
View File
@@ -7,6 +7,7 @@ import { useConfig } from "../config/config-context";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { PageTitle } from "@/components/ui/page-title";
/** Accept only a single-leading-slash local path; reject protocol-relative
* ("//host") and absolute URLs to avoid an open redirect. */
@@ -46,7 +47,7 @@ export function LoginPage() {
return (
<div className="flex min-h-screen items-center justify-center p-4">
<form onSubmit={onSubmit} className="w-full max-w-sm space-y-4">
<h1 className="text-2xl font-semibold">{app_name}</h1>
<PageTitle>{app_name}</PageTitle>
{sessionExpired && (
<p className="text-sm text-muted-foreground">{t("auth.sessionExpired")}</p>
)}
+2 -2
View File
@@ -96,9 +96,9 @@ export function FieldList({
>
<span className="font-medium">{labelText(def.labels, lang)}</span>
<span className="text-xs text-muted-foreground">{def.key}</span>
<span className="rounded-md bg-muted px-1.5 py-0.5 text-xs text-muted-foreground">
<Badge variant="secondary">
{t(`fields.types.${def.data_type}`)}
</span>
</Badge>
{def.required && (
<span
className="text-xs text-destructive"
+2 -1
View File
@@ -3,6 +3,7 @@ import { useTranslation } from "react-i18next";
import { X } from "lucide-react";
import { Drawer, DrawerClose, DrawerContent } from "@/components/ui/drawer";
import { Button } from "@/components/ui/button";
/**
* Narrow-viewport object detail: the nested <Outlet/> inside a Base UI Drawer that
@@ -30,7 +31,7 @@ export function ObjectDetailDrawer({
<div className="flex justify-end border-b p-2">
<DrawerClose
aria-label={t("actions.closeDetail")}
className="rounded-md p-1 text-muted-foreground hover:bg-muted hover:text-foreground"
render={<Button variant="ghost" size="icon-sm" />}
>
<X className="size-4" aria-hidden="true" />
</DrawerClose>
+5 -4
View File
@@ -7,6 +7,7 @@ import { ObjectsTable } from "./objects-table";
import { useMediaQuery } from "../lib/use-media-query";
import { useDocumentTitle } from "../lib/use-document-title";
import { useBreadcrumb } from "../shell/use-breadcrumb";
import { Button } from "@/components/ui/button";
import { PageTitle } from "@/components/ui/page-title";
const ObjectDetailDrawer = lazy(() =>
@@ -47,14 +48,14 @@ export function ObjectsPage() {
{open && (
<div className="flex h-full flex-col overflow-hidden border-l">
<div className="flex justify-end border-b p-2">
<button
type="button"
<Button
variant="ghost"
size="icon-sm"
onClick={closeDetail}
aria-label={t("actions.closeDetail")}
className="rounded-md p-1 text-muted-foreground hover:bg-muted hover:text-foreground"
>
<X className="size-4" aria-hidden="true" />
</button>
</Button>
</div>
<div className="flex-1 overflow-auto">
<Outlet />
+1 -1
View File
@@ -20,7 +20,7 @@ export function HeaderSearch() {
<form onSubmit={onSubmit} className="hidden sm:block">
<div className="relative">
<Search
className="pointer-events-none absolute top-1/2 left-2 h-4 w-4 -translate-y-1/2 text-muted-foreground"
className="pointer-events-none absolute top-1/2 left-2 size-4 -translate-y-1/2 text-muted-foreground"
aria-hidden
/>
<Input
+4 -2
View File
@@ -13,6 +13,7 @@ import {
import type { LucideIcon } from "lucide-react";
import { cn } from "@/lib/utils";
import { focusRing } from "../lib/focus-ring";
import { Tooltip } from "@/components/ui/tooltip";
import { useMediaQuery } from "@/lib/use-media-query";
import { useConfig } from "../config/config-context";
@@ -43,7 +44,7 @@ function navLinkClass(collapsed: boolean) {
return ({ isActive }: { isActive: boolean }) =>
cn(
"flex items-center gap-2 rounded-md px-2 py-1 outline-none",
"focus-visible:ring-3 focus-visible:ring-ring/50",
focusRing,
collapsed && "justify-center",
isActive && "bg-accent font-medium",
);
@@ -85,7 +86,8 @@ export function Sidebar() {
title={t(collapsed ? "nav.expandSidebar" : "nav.collapseSidebar")}
className={cn(
"flex items-center justify-center rounded-md p-1 outline-none",
"hover:bg-accent focus-visible:ring-3 focus-visible:ring-ring/50",
"hover:bg-accent",
focusRing,
"disabled:pointer-events-none disabled:opacity-50",
)}
>
+1 -1
View File
@@ -36,7 +36,7 @@ export function ThemeSwitch() {
: "text-muted-foreground hover:text-foreground",
)}
>
<Icon className="h-4 w-4" aria-hidden />
<Icon className="size-4" aria-hidden />
</button>
);
})}
+1 -1
View File
@@ -24,7 +24,7 @@ export function UserMenu() {
<MenuTrigger
render={
<Button variant="ghost" size="sm" className="max-w-44">
<CircleUser className="h-4 w-4" aria-hidden />
<CircleUser className="size-4" aria-hidden />
<span className="truncate">{me.email}</span>
</Button>
}