({ value, options, onChange, label }: { value: T; options: { value: T; label: ReactNode }[]; onChange: (v: T) => void; label?: string }) {
return (
{options.map((o) => (
))}
);
}
export function Stepper({ value, min, max, onChange, decLabel = '−', incLabel = '+' }: { value: number; min: number; max: number; onChange: (v: number) => void; decLabel?: string; incLabel?: string }) {
return (
);
}
export function Field({ label, error, children, htmlFor }: { label?: ReactNode; error?: ReactNode; children: ReactNode; htmlFor?: string }) {
return (
{label && (
)}
{children}
{error &&
{error}
}
);
}
export function Spinner({ label }: { label?: string }) {
return ;
}
export function Center({ children }: { children: ReactNode }) {
return {children}
;
}
/** «Цветок» из макета: круг + 10 лепестков */
export function Flower({ size = 72, color = '#B8235A', rotate = -10, children, textColor = '#fff', fontSize }: { size?: number; color?: string; rotate?: number; children?: ReactNode; textColor?: string; fontSize?: number }) {
return (
{children !== undefined && {children}}
);
}
export function Sheet({ open, onClose, children, label }: { open: boolean; onClose: () => void; children: ReactNode; label?: string }) {
if (!open) return null;
return (
e.stopPropagation()}>
{children}
);
}
export function Steps({ items }: { items: { label: ReactNode; state: 'done' | 'current' | 'todo'; meta?: ReactNode }[] }) {
return (
{items.map((s, i) => (
-
{s.state === 'done' && }
{s.label}
{s.meta &&
{s.meta}
}
))}
);
}
// ───── иконки из макета (stroke 2, round) ─────
const ICONS = {
home: 'M4 11l8-7 8 7v9H4z',
docs: 'M7 3h7l5 5v13H7zM14 3v5h5M10 13h6M10 17h6',
learn: 'M4 5h6a2 2 0 0 1 2 2v13a2 2 0 0 0-2-2H4zM20 5h-6a2 2 0 0 0-2 2v13a2 2 0 0 1 2-2h6z',
gift: 'M4 8h16v4H4zM5 12h14v8H5zM12 8v12M12 8c-2-3-6-3-6 0M12 8c2-3 6-3 6 0',
check: 'M5 12l4 4 10-10',
arrow: 'M5 12h14M13 6l6 6-6 6',
back: 'M19 12H5M11 18l-6-6 6-6',
plus: 'M12 5v14M5 12h14',
grid: 'M4 4h7v7H4zM13 4h7v7h-7zM4 13h7v7H4zM13 13h7v7h-7z',
user: 'M12 12a4 4 0 1 0 0-8 4 4 0 0 0 0 8zM4 21a8 8 0 0 1 16 0',
clock: 'M12 21a9 9 0 1 0 0-18 9 9 0 0 0 0 18zM12 7v5l3 2',
pin: 'M12 21s-7-6.2-7-11a7 7 0 0 1 14 0c0 4.8-7 11-7 11zM12 12.5a2.5 2.5 0 1 0 0-5 2.5 2.5 0 0 0 0 5z',
camera: 'M4 8h3l2-3h6l2 3h3v11H4zM12 17a4 4 0 1 0 0-8 4 4 0 0 0 0 8z',
chat: 'M4 5h16v11H8l-4 4z',
star: 'M12 3l2.7 5.6 6.1.9-4.4 4.3 1 6.1L12 17l-5.4 2.9 1-6.1L3.2 9.5l6.1-.9z',
logo: 'M12 21.5a9.5 9.5 0 1 0 0-19 9.5 9.5 0 0 0 0 19zM8 12.5l2.6 2.6L16 9.5',
close: 'M6 6l12 12M18 6L6 18',
repeat: 'M4 12a8 8 0 0 1 14-5.3L20 9M20 4v5h-5M20 12a8 8 0 0 1-14 5.3L4 15M4 20v-5h5',
globe: 'M12 21a9 9 0 1 0 0-18 9 9 0 0 0 0 18zM3 12h18M12 3c2.5 2.7 3.8 5.7 3.8 9s-1.3 6.3-3.8 9c-2.5-2.7-3.8-5.7-3.8-9S9.5 5.7 12 3z',
} as const;
export type IconName = keyof typeof ICONS;
export const CATEGORY_ICON: Record = { HOME: 'home', DOCS: 'docs', LEARNING: 'learn', PERKS: 'gift' };
export function Icon({ name, size = 22, strokeWidth = 2, style, label }: { name: IconName; size?: number; strokeWidth?: number; style?: CSSProperties; label?: string }) {
return (
);
}
export function Logo({ size = 24, color = '#4A1028', text = 'Barev Club' }: { size?: number; color?: string; text?: string }) {
return (
);
}
export function Toast({ message, kind = 'info' }: { message: ReactNode; kind?: 'info' | 'error' }) {
return (
{message}
);
}