mobile nav, locale-preserving navigation, accent button contrast
All checks were successful
Build and Push / build (push) Successful in 2m25s
All checks were successful
Build and Push / build (push) Successful in 2m25s
This commit is contained in:
58
src/components/ui/button.tsx
Normal file
58
src/components/ui/button.tsx
Normal file
@@ -0,0 +1,58 @@
|
||||
import { forwardRef } from "react";
|
||||
|
||||
/**
|
||||
* Shared button primitive.
|
||||
*
|
||||
* Why this exists
|
||||
* ---------------
|
||||
* The accent fill (#00d4aa) is bright; white text on it measures ~1.9:1,
|
||||
* which fails WCAG even for large/UI text. Dark text (surface-0) on the
|
||||
* same accent is ~10:1. The codebase had ~40 hand-rolled accent buttons,
|
||||
* most using `text-white`. This component centralises the correct token
|
||||
* (`text-surface-0` on accent) so the contrast can't drift again — reach
|
||||
* for `<Button>` instead of re-deriving the class string.
|
||||
*/
|
||||
|
||||
type Variant = "primary" | "secondary" | "ghost" | "danger";
|
||||
type Size = "sm" | "md";
|
||||
|
||||
const BASE =
|
||||
"inline-flex items-center justify-center gap-1.5 font-medium rounded-lg " +
|
||||
"transition-colors cursor-pointer focus:outline-none focus-visible:ring-2 " +
|
||||
"focus-visible:ring-accent/50 disabled:opacity-50 disabled:cursor-not-allowed";
|
||||
|
||||
const VARIANTS: Record<Variant, string> = {
|
||||
// surface-0 (dark) text — the contrast-correct pairing for the accent.
|
||||
primary: "bg-accent text-surface-0 hover:bg-accent-dim shadow-sm shadow-accent/20",
|
||||
secondary:
|
||||
"bg-surface-2 text-text-primary border border-border hover:bg-surface-3 hover:border-border-active",
|
||||
ghost: "text-text-secondary hover:text-text-primary hover:bg-surface-2",
|
||||
danger: "bg-error text-surface-0 hover:opacity-90",
|
||||
};
|
||||
|
||||
const SIZES: Record<Size, string> = {
|
||||
sm: "text-xs px-3 py-1.5",
|
||||
md: "text-sm px-4 py-2",
|
||||
};
|
||||
|
||||
export interface ButtonProps
|
||||
extends React.ButtonHTMLAttributes<HTMLButtonElement> {
|
||||
variant?: Variant;
|
||||
size?: Size;
|
||||
}
|
||||
|
||||
export const Button = forwardRef<HTMLButtonElement, ButtonProps>(
|
||||
function Button(
|
||||
{ variant = "primary", size = "md", className = "", type = "button", ...rest },
|
||||
ref
|
||||
) {
|
||||
return (
|
||||
<button
|
||||
ref={ref}
|
||||
type={type}
|
||||
className={`${BASE} ${VARIANTS[variant]} ${SIZES[size]} ${className}`}
|
||||
{...rest}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
Reference in New Issue
Block a user