since3-portal/modules/templates/catalog/shared/fields.tsx
2026-10-05 08:23:02 +02:00

58 lines
2.6 KiB
TypeScript

import type { InputHTMLAttributes, ReactNode, SelectHTMLAttributes, TextareaHTMLAttributes } from "react"
import { cn } from "@/lib/utils"
// Formularfelder der Vorlagen in vier Grundstilen; Farben kommen aus der Umgebung (currentColor, t-accent)
export type FieldVariant = "line" | "box" | "soft" | "glass"
const labelStyle: Record<FieldVariant, string> = {
line: "text-[11px] uppercase tracking-[0.22em] opacity-60",
box: "text-xs font-medium opacity-70",
soft: "px-1 text-xs font-medium opacity-70",
glass: "text-xs font-medium opacity-70",
}
const controlStyle: Record<FieldVariant, string> = {
line: "mt-2 w-full border-b border-current/20 bg-transparent py-2.5 outline-none transition-colors focus:border-t-accent",
box: "mt-1.5 w-full rounded-xl border border-current/15 bg-transparent px-4 py-3 outline-none transition-colors focus:border-t-accent",
soft: "mt-1.5 w-full rounded-2xl bg-t-surface px-4 py-3.5 outline-none ring-2 ring-transparent transition focus:ring-t-accent/50",
glass: "mt-1.5 w-full rounded-xl border border-white/10 bg-white/5 px-4 py-3 outline-none transition-colors focus:border-t-accent",
}
type Shared = { label: string; variant?: FieldVariant; className?: string }
function Wrap({ label, variant, className, children }: Shared & { variant: FieldVariant; children: ReactNode }) {
return (
<label className={cn("block", className)}>
<span className={labelStyle[variant]}>{label}</span>
{children}
</label>
)
}
export function TField({ label, variant = "box", className, ...props }: Shared & InputHTMLAttributes<HTMLInputElement>) {
return (
<Wrap label={label} variant={variant} className={className}>
<input {...props} className={controlStyle[variant]} />
</Wrap>
)
}
export function TArea({ label, variant = "box", className, rows = 4, ...props }: Shared & TextareaHTMLAttributes<HTMLTextAreaElement>) {
return (
<Wrap label={label} variant={variant} className={className}>
<textarea {...props} rows={rows} className={cn(controlStyle[variant], "resize-none")} />
</Wrap>
)
}
export function TSelect({ label, variant = "box", className, options, ...props }: Shared & SelectHTMLAttributes<HTMLSelectElement> & { options: string[] }) {
return (
<Wrap label={label} variant={variant} className={className}>
<select {...props} className={cn(controlStyle[variant], "[&>option]:text-zinc-900")}>
{options.map((option) => (
<option key={option}>{option}</option>
))}
</select>
</Wrap>
)
}