mirror of
https://github.com/Since-3/since3-portal.git
synced 2026-10-12 19:51:17 +00:00
58 lines
2.6 KiB
TypeScript
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>
|
|
)
|
|
}
|