diff --git a/app/components/Album/Wrapper.tsx b/app/components/Album/Wrapper.tsx index 8f76cfa..d262aeb 100644 --- a/app/components/Album/Wrapper.tsx +++ b/app/components/Album/Wrapper.tsx @@ -73,7 +73,7 @@ const AlbumWrapper: React.FC = ({ keyFunction={(genre, i) => `${genre}-${i}`} toFunction={(genre) => `/genre/${genre}`} childFunction={(genre) => genre} - className={clsx('btn-xs')} + className={clsx('!btn-xs')} wrapperClassName={clsx( 'stat-actions', 'sm:flex-col', diff --git a/app/components/Base/index.tsx b/app/components/Base/index.tsx index f4d6551..b4ae014 100644 --- a/app/components/Base/index.tsx +++ b/app/components/Base/index.tsx @@ -1,41 +1,63 @@ +import { Slot } from '@radix-ui/react-slot' import { LinkProps, Link as RemixLink } from '@remix-run/react' -import clsx from 'clsx' +import { type VariantProps, cva } from 'class-variance-authority' import React from 'react' +import { cn } from '~/lib/util' + export { default as Layout } from './Layout' export { default as EmojiText } from './EmojiText' +const headingVariants = cva('', { + variants: { + level: { + h1: 'text-4xl md:text-5xl', + h2: 'text-3xl md:text-4xl', + h3: 'text-2xl md:text-3xl', + h4: 'text-xl md:text-2xl', + h5: 'uppercase font-bold text-xs', + h6: 'uppercase text-xs font-bold', + }, + noSpacing: { + false: 'my-4', + }, + noStyles: { + true: '', + }, + }, +}) + export interface HeadingProps extends React.HTMLAttributes { level: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' + asChild?: boolean noSpacing?: boolean noStyles?: boolean } export const Heading = React.forwardRef( ( - { level, className, noSpacing = false, noStyles = false, ...props }, + { + level, + asChild, + className, + noSpacing = false, + noStyles = false, + ...props + }, ref, ) => { - const Component = level as unknown as React.FC< - JSX.IntrinsicElements[typeof level] - > + const Component = asChild ? Slot : level return ( @@ -43,66 +65,84 @@ export const Heading = React.forwardRef( }, ) -export interface ButtonProps - extends React.HTMLAttributes { - color?: 'primary' | 'info' | 'warning' | 'danger' | 'reset' - size?: 'lg' | 'md' | 'sm' | 'xs' | null - ghost?: boolean - disabled?: boolean - loading?: boolean - type?: 'button' | 'reset' | 'submit' -} - -function buttonStyles({ - color = 'primary', - className, - size, - ghost, - disabled, - loading, -}: ButtonProps) { - return clsx( - 'btn', - { - 'btn-primary': color === 'primary', - 'btn-secondary': color === 'info', - 'btn-warning': color === 'warning', - 'btn-accent': color === 'danger', +const buttonVariants = cva('btn', { + variants: { + color: { + primary: 'btn-primary', + secondary: 'btn-info', + success: 'btn-success', + info: 'btn-secondary', + warning: 'btn-warning', + danger: 'btn-accent', + reset: '', }, - { - 'btn-lg': size === 'lg', - 'btn-md': size === 'md', - 'btn-sm': size === 'sm', - 'btn-xs': size === 'xs', + size: { + lg: 'btn-lg', + md: 'btn-md', + sm: 'btn-sm', + xs: 'btn-xs', }, - ghost && 'btn-ghost', - disabled && 'btn-disabled', - loading && 'loading', - className, - ) + ghost: { + true: 'btn-ghost', + }, + disabled: { + true: 'btn-disabled', + }, + loading: { + true: 'loading', + }, + }, + defaultVariants: { + color: 'primary', + size: 'md', + }, +}) + +export type BaseButtonProps = VariantProps & { + asChild?: boolean + disabled?: boolean } -export const Button = React.forwardRef< - HTMLButtonElement, - ButtonProps ->(({ className, color = 'primary', size = 'md', loading, ...props }, ref) => ( - + ) +}) export type ButtonLinkProps = ( | LinkProps @@ -111,36 +151,69 @@ export type ButtonLinkProps = ( target?: string }) ) & - ButtonProps + BaseButtonProps -export const ButtonLink: React.FC = ({ - className, - ...props -}) => { - if ('href' in props) { - /* eslint-disable-next-line jsx-a11y/anchor-has-content */ - return - } +export const ButtonLink = React.forwardRef( + ({ className, color, size, loading, ...props }, ref) => { + if ('href' in props) { + return ( + + ) + } - return ( - - ) -} + return ( + + ) + }, +) -export const Link: React.FC< - LinkProps & { - color?: boolean - colorHover?: boolean - } -> = ({ className, color = true, colorHover = false, ...props }) => ( +const linkVariants = cva('link link-hover', { + variants: { + color: { + true: '', + }, + colorHover: { + true: 'hover:text-primary hover:no-underline', + }, + }, + compoundVariants: [ + { + color: true, + colorHover: false, + className: 'link-primary', + }, + ], + defaultVariants: { + color: true, + colorHover: false, + }, +}) + +export const Link: React.FC> = ({ + className, + color = true, + colorHover = false, + ...props +}) => ( ) @@ -148,29 +221,41 @@ export const Link: React.FC< export const ButtonGroup: React.FC> = ({ className, ...props -}) =>
+}) =>
-export interface TypographyProps - extends React.HTMLAttributes { - variant?: 'base' | 'italics' | 'bold' | 'hint' -} +const typographyVariants = cva('text-base', { + variants: { + variant: { + base: '', + hint: 'italic text-gray-400', + italics: 'italic', + bold: 'font-bold', + }, + }, + defaultVariants: { + variant: 'base', + }, +}) + +export type TypographyProps = React.HTMLAttributes & + VariantProps & { + asChild?: boolean + } export const Typography = React.forwardRef< HTMLParagraphElement, TypographyProps ->(({ variant = 'base', className, ...props }, ref) => ( -

-)) +>(({ variant = 'base', asChild, className, ...props }, ref) => { + const Component = asChild ? Slot : 'p' + + return ( + + ) +}) export interface InputProps extends React.HTMLAttributes { width?: 'full' | 'half' @@ -183,7 +268,7 @@ export const Input = React.forwardRef( ({ className, width = 'full', ...props }, ref) => ( ( ), ) -export interface ContainerProps extends React.HTMLAttributes { - center?: boolean -} +const containerVariants = cva('container mx-auto', { + variants: { + center: { + true: 'text-center flex justify-items-center align-items-center flex-col', + }, + }, +}) + +export type ContainerProps = React.HTMLAttributes & + VariantProps & { + asChild?: boolean + } export const Container = React.forwardRef( - ({ className, center, ...props }, ref) => ( -

- ), + ({ className, center, asChild, ...props }, ref) => { + const Component = asChild ? Slot : 'div' + return ( + + ) + }, ) type AProps = React.HTMLAttributes & { @@ -231,7 +317,7 @@ export const A = React.forwardRef( /* eslint-disable-next-line jsx-a11y/anchor-has-content */ ), @@ -246,7 +332,7 @@ export const Fieldset = React.forwardRef( ({ className, flexDirection, ...props }, ref) => (
(({ className, ...props }, ref) => ( )) @@ -286,9 +372,9 @@ export const Checkbox: React.FC> = ({ ...props }) => (
-