Initial commit: Kalendartool (Next.js, Prisma, Docker)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
120
components/ui/ui.tsx
Normal file
120
components/ui/ui.tsx
Normal file
@@ -0,0 +1,120 @@
|
||||
/** Gemeinsame UI-Bausteine (Forms, Buttons, Badges) im einheitlichen Look. */
|
||||
|
||||
/**
|
||||
* Einheitliches Badge fuer Status/Rollen-Labels.
|
||||
* variant: neutral (Standard), success (aktiv), warning (Hinweis),
|
||||
* danger (Fehler), accent (hervorgehoben, z. B. eigene Rolle).
|
||||
*/
|
||||
export function Badge({
|
||||
children,
|
||||
variant = 'neutral',
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
variant?: 'neutral' | 'success' | 'warning' | 'danger' | 'accent';
|
||||
}) {
|
||||
const styles = {
|
||||
neutral:
|
||||
'bg-slate-200 text-slate-700 dark:bg-slate-700 dark:text-slate-200',
|
||||
success:
|
||||
'bg-slate-200 text-slate-800 ring-1 ring-slate-400 dark:bg-slate-600 dark:text-slate-100 dark:ring-slate-500',
|
||||
warning:
|
||||
'bg-slate-100 text-slate-700 ring-1 ring-slate-300 dark:bg-slate-800 dark:text-slate-300 dark:ring-slate-600',
|
||||
danger:
|
||||
'bg-slate-800 text-slate-100 dark:bg-slate-100 dark:text-slate-900',
|
||||
accent:
|
||||
'bg-slate-700 text-slate-50 dark:bg-slate-300 dark:text-slate-900',
|
||||
}[variant];
|
||||
|
||||
return (
|
||||
<span
|
||||
className={`inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium ${styles}`}
|
||||
>
|
||||
{children}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
export function Card({
|
||||
children,
|
||||
className = '',
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
className?: string;
|
||||
}) {
|
||||
return (
|
||||
<div
|
||||
className={`rounded-lg border border-slate-200 bg-white p-6 shadow-sm dark:border-slate-700 dark:bg-slate-900 ${className}`}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function Button({
|
||||
children,
|
||||
type = 'submit',
|
||||
variant = 'primary',
|
||||
disabled,
|
||||
onClick,
|
||||
...rest
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
type?: 'submit' | 'button';
|
||||
variant?: 'primary' | 'secondary' | 'danger';
|
||||
disabled?: boolean;
|
||||
onClick?: () => void;
|
||||
} & Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, 'type' | 'onClick' | 'disabled'>) {
|
||||
const styles = {
|
||||
primary: 'bg-slate-800 text-white hover:bg-slate-700 dark:bg-slate-100 dark:text-slate-900 dark:hover:bg-slate-200',
|
||||
secondary:
|
||||
'bg-slate-200 text-slate-900 hover:bg-slate-300 dark:bg-slate-700 dark:text-slate-100 dark:hover:bg-slate-600',
|
||||
danger: 'bg-red-600 text-white hover:bg-red-700',
|
||||
}[variant];
|
||||
|
||||
return (
|
||||
<button
|
||||
type={type}
|
||||
disabled={disabled}
|
||||
onClick={onClick}
|
||||
{...rest}
|
||||
className={`rounded-md px-4 py-2 text-sm font-medium transition-colors disabled:cursor-not-allowed disabled:opacity-50 ${styles}`}
|
||||
>
|
||||
{children}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
export function Input(props: React.InputHTMLAttributes<HTMLInputElement>) {
|
||||
const { className = '', ...rest } = props;
|
||||
return (
|
||||
<input
|
||||
{...rest}
|
||||
className={`w-full rounded-md border border-slate-300 bg-white px-3 py-2 text-sm text-slate-900 placeholder:text-slate-400 focus:border-slate-500 focus:outline-none focus:ring-1 focus:ring-slate-500 dark:border-slate-600 dark:bg-slate-800 dark:text-slate-100 dark:placeholder:text-slate-500 ${className}`}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export function Label({ children, htmlFor }: { children: React.ReactNode; htmlFor?: string }) {
|
||||
return (
|
||||
<label
|
||||
htmlFor={htmlFor}
|
||||
className="mb-1 block text-sm font-medium text-slate-700 dark:text-slate-300"
|
||||
>
|
||||
{children}
|
||||
</label>
|
||||
);
|
||||
}
|
||||
|
||||
export function ErrorMessage({ message }: { message: string | null }) {
|
||||
if (!message) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<p
|
||||
role="alert"
|
||||
className="rounded-md bg-red-50 px-3 py-2 text-sm text-red-700 dark:bg-red-900/40 dark:text-red-300"
|
||||
>
|
||||
{message}
|
||||
</p>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user