diff --git a/package.json b/package.json index 4766b64..25d6093 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,8 @@ "smoke:compose": "bash scripts/compose-smoke.sh", "seed:bootstrap": "pnpm --filter @notelett/backend run bootstrap:seed", "audit:release-guards": "bash scripts/release-guard-audit.sh", + "audit:ui": "bash scripts/ui-drift-audit.sh", + "audit:ui:strict": "bash scripts/ui-drift-audit.sh --strict", "dependency:health": "bash scripts/dependency-health.sh", "verify": "pnpm run typecheck && pnpm run test && pnpm run build", "prepare": "husky" diff --git a/scripts/ui-drift-audit.sh b/scripts/ui-drift-audit.sh new file mode 100644 index 0000000..04cc518 --- /dev/null +++ b/scripts/ui-drift-audit.sh @@ -0,0 +1,42 @@ +#!/usr/bin/env bash +set -euo pipefail + +STRICT=0 +if [[ "${1:-}" == "--strict" ]]; then + STRICT=1 +fi + +ROOT="$(git rev-parse --show-toplevel)" +cd "$ROOT" + +report() { + local title="$1" + local pattern="$2" + shift 2 + local matches + matches="$(rg -n "$pattern" "$@" --glob '!**/*.test.*' || true)" + + echo "=== $title ===" + if [[ -z "$matches" ]]; then + echo "ok: no matches" + return 0 + fi + + echo "$matches" + echo + return 1 +} + +failures=0 + +report "Raw interactive controls" '&2 + exit 1 +fi + +echo "UI drift audit completed with $failures non-empty category/categories." diff --git a/web/src/components/ui/Primitives.tsx b/web/src/components/ui/Primitives.tsx index b6b4b71..a247f9e 100644 --- a/web/src/components/ui/Primitives.tsx +++ b/web/src/components/ui/Primitives.tsx @@ -2,9 +2,37 @@ import { Badge as BytelystBadge, Button as BytelystButton, Card as BytelystCard, + DiffCard as BytelystDiffCard, + IconButton as BytelystIconButton, + Input as BytelystInput, + Label as BytelystLabel, + ListItemButton as BytelystListItemButton, + Panel as BytelystPanel, + PanelBody as BytelystPanelBody, + PanelDescription as BytelystPanelDescription, + PanelHeader as BytelystPanelHeader, + PanelTitle as BytelystPanelTitle, + Select as BytelystSelect, + StatusBadge as BytelystStatusBadge, + Textarea as BytelystTextarea, + Timeline as BytelystTimeline, type BadgeProps, type ButtonProps, type CardProps, + type DiffCardProps, + type IconButtonProps, + type InputProps, + type LabelProps, + type ListItemButtonProps, + type PanelBodyProps, + type PanelDescriptionProps, + type PanelHeaderProps, + type PanelProps, + type PanelTitleProps, + type SelectProps, + type StatusBadgeProps, + type TextareaProps, + type TimelineProps, } from "@bytelyst/ui"; function mergeClassNames(...classes: Array) { @@ -46,3 +74,112 @@ export function Card({ className, ...props }: CardProps) { /> ); } + +export function Panel({ className, ...props }: PanelProps) { + return ( + + ); +} + +export function PanelHeader({ className, ...props }: PanelHeaderProps) { + return ; +} + +export function PanelBody({ className, ...props }: PanelBodyProps) { + return ; +} + +export function PanelTitle({ className, ...props }: PanelTitleProps) { + return ; +} + +export function PanelDescription({ className, ...props }: PanelDescriptionProps) { + return ; +} + +export function IconButton({ className, ...props }: IconButtonProps) { + return ( + + ); +} + +export function ListItemButton({ className, ...props }: ListItemButtonProps) { + return ( + + ); +} + +export function StatusBadge({ className, ...props }: StatusBadgeProps) { + return ( + + ); +} + +export function Input({ className, ...props }: InputProps) { + return ( + + ); +} + +export function Textarea({ className, ...props }: TextareaProps) { + return ( + + ); +} + +export function Select({ className, ...props }: SelectProps) { + return ( + + ); +} + +export function Label({ className, ...props }: LabelProps) { + return ; +} + +export function Timeline({ className, ...props }: TimelineProps) { + return ; +} + +export function DiffCard({ className, ...props }: DiffCardProps) { + return ; +}