- /login sends a Supabase magic link (admin emails only); /auth/confirm completes sign-in; proxy.ts guards /admin and every server action re-checks with requireAdmin(), since actions are plain POST endpoints. - /admin lists, creates, duplicates and deletes events. - /admin/events/[eventId] edits teams (colour, order) and games with criteria, presets and notes. All input goes through zod schemas that mirror the database constraints so errors read as plain sentences. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
29 lines
1.0 KiB
TypeScript
29 lines
1.0 KiB
TypeScript
import type { ButtonHTMLAttributes } from "react";
|
|
|
|
const variants = {
|
|
primary: "bg-ink text-white hover:bg-ink/90",
|
|
secondary: "border border-ink/25 bg-white text-ink hover:bg-ink/5",
|
|
danger: "border border-alert/50 bg-white text-alert hover:bg-alert/10",
|
|
} as const;
|
|
|
|
const sizes = {
|
|
// min-h-11 = 44px tap target
|
|
md: "min-h-11 px-4 text-base",
|
|
sm: "min-h-11 min-w-11 px-3 text-sm",
|
|
} as const;
|
|
|
|
export type ButtonVariant = keyof typeof variants;
|
|
|
|
export function buttonClass(variant: ButtonVariant = "primary", size: keyof typeof sizes = "md") {
|
|
return `inline-flex items-center justify-center gap-2 rounded-md font-bold transition-colors disabled:cursor-not-allowed disabled:opacity-50 ${variants[variant]} ${sizes[size]}`;
|
|
}
|
|
|
|
type ButtonProps = ButtonHTMLAttributes<HTMLButtonElement> & {
|
|
variant?: ButtonVariant;
|
|
size?: keyof typeof sizes;
|
|
};
|
|
|
|
export function Button({ variant, size, className = "", type = "button", ...props }: ButtonProps) {
|
|
return <button type={type} className={`${buttonClass(variant, size)} ${className}`} {...props} />;
|
|
}
|