personal-website/components/Card.tsx
Filipe Medeiros 9a9638237f
feat: initial commit
Signed-off-by: Filipe Medeiros <hello@filipesm.eu>
2023-12-03 12:25:52 +01:00

117 lines
2.8 KiB
TypeScript

import clsx from 'clsx'
import {
type ComponentProps,
type ElementType,
type PropsWithChildren,
} from 'react'
import HybridLink, { type Props as HybridLinkProps } from './HybridLink'
import { IconProps } from './icons'
const ChevronRightIcon = (props: IconProps) => {
return (
<svg viewBox="0 0 16 16" fill="none" aria-hidden="true" {...props}>
<path
d="M6.75 5.75 9.25 8l-2.5 2.25"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
)
}
export const CardLink = ({ children, ...props }: HybridLinkProps) => {
return (
<>
<div className="absolute -inset-y-6 -inset-x-4 z-0 scale-95 bg-zinc-50 opacity-0 transition group-hover:scale-100 group-hover:opacity-100 dark:bg-zinc-800/50 sm:-inset-x-6 sm:rounded-2xl" />
<HybridLink {...props}>
<span className="absolute -inset-y-6 -inset-x-4 z-20 sm:-inset-x-6 sm:rounded-2xl" />
<span className="relative z-10">{children}</span>
</HybridLink>
</>
)
}
export const CardTitle = ({
as: Component = 'h2',
href,
children,
}: PropsWithChildren<{
href: string
as?: ElementType
}>) => {
return (
<Component className="text-base font-semibold tracking-tight text-zinc-800 dark:text-zinc-100">
{href ? <CardLink href={href}>{children}</CardLink> : children}
</Component>
)
}
export const CardDescription = ({ children }: PropsWithChildren) => {
return (
<p className="relative z-10 mt-2 text-sm text-zinc-600 dark:text-zinc-400">
{children}
</p>
)
}
export const CardCta = ({ children }: PropsWithChildren) => {
return (
<div
aria-hidden="true"
className="relative z-10 mt-4 flex items-center text-sm font-medium text-teal-500"
>
{children}
<ChevronRightIcon className="ml-1 h-4 w-4 stroke-current" />
</div>
)
}
export function CardEyebrow<C extends ElementType>({
as: Component = 'p',
decorate = false,
children,
...props
}: ComponentProps<C> & {
as: C
decorate?: boolean
}) {
return (
<Component
className={clsx(
'className' in props ? props.className : '',
'relative z-10 order-first mb-3 flex items-center text-sm text-zinc-400 dark:text-zinc-500',
decorate && 'pl-3.5',
)}
{...props}
>
{decorate && (
<span
className="absolute inset-y-0 left-0 flex items-center"
aria-hidden="true"
>
<span className="h-4 w-0.5 rounded-full bg-zinc-200 dark:bg-zinc-500" />
</span>
)}
{children}
</Component>
)
}
const Card = ({
as: Component = 'div',
className,
children,
}: PropsWithChildren<{ className?: string; as?: ElementType }>) => {
return (
<Component
className={clsx(className, 'group relative flex flex-col items-start')}
>
{children}
</Component>
)
}
export default Card