Skip to content

Commit 27776b2

Browse files
add all components from catalyst
1 parent ca5bb98 commit 27776b2

25 files changed

+2834
-0
lines changed

components/Catalyst/alert.tsx

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
import * as Headless from '@headlessui/react'
2+
import clsx from 'clsx'
3+
import type React from 'react'
4+
import { Text } from './text'
5+
6+
const sizes = {
7+
xs: 'sm:max-w-xs',
8+
sm: 'sm:max-w-sm',
9+
md: 'sm:max-w-md',
10+
lg: 'sm:max-w-lg',
11+
xl: 'sm:max-w-xl',
12+
'2xl': 'sm:max-w-2xl',
13+
'3xl': 'sm:max-w-3xl',
14+
'4xl': 'sm:max-w-4xl',
15+
'5xl': 'sm:max-w-5xl',
16+
}
17+
18+
export function Alert({
19+
size = 'md',
20+
className,
21+
children,
22+
...props
23+
}: { size?: keyof typeof sizes; className?: string; children: React.ReactNode } & Omit<
24+
Headless.DialogProps,
25+
'as' | 'className'
26+
>) {
27+
return (
28+
<Headless.Dialog {...props}>
29+
<Headless.DialogBackdrop
30+
transition
31+
className="fixed inset-0 flex w-screen justify-center overflow-y-auto bg-zinc-950/15 px-2 py-2 transition duration-100 focus:outline-0 data-[closed]:opacity-0 data-[enter]:ease-out data-[leave]:ease-in sm:px-6 sm:py-8 lg:px-8 lg:py-16 dark:bg-zinc-950/50"
32+
/>
33+
34+
<div className="fixed inset-0 w-screen overflow-y-auto pt-6 sm:pt-0">
35+
<div className="grid min-h-full grid-rows-[1fr_auto_1fr] justify-items-center p-8 sm:grid-rows-[1fr_auto_3fr] sm:p-4">
36+
<Headless.DialogPanel
37+
transition
38+
className={clsx(
39+
className,
40+
sizes[size],
41+
'row-start-2 w-full rounded-2xl bg-white p-8 shadow-lg ring-1 ring-zinc-950/10 sm:rounded-2xl sm:p-6 dark:bg-zinc-900 dark:ring-white/10 forced-colors:outline',
42+
'transition duration-100 will-change-transform data-[closed]:data-[enter]:scale-95 data-[closed]:opacity-0 data-[enter]:ease-out data-[leave]:ease-in'
43+
)}
44+
>
45+
{children}
46+
</Headless.DialogPanel>
47+
</div>
48+
</div>
49+
</Headless.Dialog>
50+
)
51+
}
52+
53+
export function AlertTitle({
54+
className,
55+
...props
56+
}: { className?: string } & Omit<Headless.DialogTitleProps, 'as' | 'className'>) {
57+
return (
58+
<Headless.DialogTitle
59+
{...props}
60+
className={clsx(
61+
className,
62+
'text-balance text-center text-base/6 font-semibold text-zinc-950 sm:text-wrap sm:text-left sm:text-sm/6 dark:text-white'
63+
)}
64+
/>
65+
)
66+
}
67+
68+
export function AlertDescription({
69+
className,
70+
...props
71+
}: { className?: string } & Omit<Headless.DescriptionProps<typeof Text>, 'as' | 'className'>) {
72+
return (
73+
<Headless.Description
74+
as={Text}
75+
{...props}
76+
className={clsx(className, 'mt-2 text-pretty text-center sm:text-left')}
77+
/>
78+
)
79+
}
80+
81+
export function AlertBody({ className, ...props }: React.ComponentPropsWithoutRef<'div'>) {
82+
return <div {...props} className={clsx(className, 'mt-4')} />
83+
}
84+
85+
export function AlertActions({ className, ...props }: React.ComponentPropsWithoutRef<'div'>) {
86+
return (
87+
<div
88+
{...props}
89+
className={clsx(
90+
className,
91+
'mt-6 flex flex-col-reverse items-center justify-end gap-3 *:w-full sm:mt-4 sm:flex-row sm:*:w-auto'
92+
)}
93+
/>
94+
)
95+
}

components/Catalyst/avatar.tsx

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
import * as Headless from '@headlessui/react'
2+
import clsx from 'clsx'
3+
import React, { forwardRef } from 'react'
4+
import { TouchTarget } from './button'
5+
import { Link } from './link'
6+
7+
type AvatarProps = {
8+
src?: string | null
9+
square?: boolean
10+
initials?: string
11+
alt?: string
12+
className?: string
13+
}
14+
15+
export function Avatar({
16+
src = null,
17+
square = false,
18+
initials,
19+
alt = '',
20+
className,
21+
...props
22+
}: AvatarProps & React.ComponentPropsWithoutRef<'span'>) {
23+
return (
24+
<span
25+
data-slot="avatar"
26+
{...props}
27+
className={clsx(
28+
className,
29+
// Basic layout
30+
'inline-grid shrink-0 align-middle [--avatar-radius:20%] [--ring-opacity:20%] *:col-start-1 *:row-start-1',
31+
'outline outline-1 -outline-offset-1 outline-black/[--ring-opacity] dark:outline-white/[--ring-opacity]',
32+
// Add the correct border radius
33+
square ? 'rounded-[--avatar-radius] *:rounded-[--avatar-radius]' : 'rounded-full *:rounded-full'
34+
)}
35+
>
36+
{initials && (
37+
<svg
38+
className="size-full select-none fill-current p-[5%] text-[48px] font-medium uppercase"
39+
viewBox="0 0 100 100"
40+
aria-hidden={alt ? undefined : 'true'}
41+
>
42+
{alt && <title>{alt}</title>}
43+
<text x="50%" y="50%" alignmentBaseline="middle" dominantBaseline="middle" textAnchor="middle" dy=".125em">
44+
{initials}
45+
</text>
46+
</svg>
47+
)}
48+
{src && <img className="size-full" src={src} alt={alt} />}
49+
</span>
50+
)
51+
}
52+
53+
export const AvatarButton = forwardRef(function AvatarButton(
54+
{
55+
src,
56+
square = false,
57+
initials,
58+
alt,
59+
className,
60+
...props
61+
}: AvatarProps &
62+
(Omit<Headless.ButtonProps, 'as' | 'className'> | Omit<React.ComponentPropsWithoutRef<typeof Link>, 'className'>),
63+
ref: React.ForwardedRef<HTMLElement>
64+
) {
65+
let classes = clsx(
66+
className,
67+
square ? 'rounded-[20%]' : 'rounded-full',
68+
'relative inline-grid focus:outline-none data-[focus]:outline data-[focus]:outline-2 data-[focus]:outline-offset-2 data-[focus]:outline-blue-500'
69+
)
70+
71+
return 'href' in props ? (
72+
<Link {...props} className={classes} ref={ref as React.ForwardedRef<HTMLAnchorElement>}>
73+
<TouchTarget>
74+
<Avatar src={src} square={square} initials={initials} alt={alt} />
75+
</TouchTarget>
76+
</Link>
77+
) : (
78+
<Headless.Button {...props} className={classes} ref={ref}>
79+
<TouchTarget>
80+
<Avatar src={src} square={square} initials={initials} alt={alt} />
81+
</TouchTarget>
82+
</Headless.Button>
83+
)
84+
})

components/Catalyst/badge.tsx

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import * as Headless from '@headlessui/react'
2+
import clsx from 'clsx'
3+
import React, { forwardRef } from 'react'
4+
import { TouchTarget } from './button'
5+
import { Link } from './link'
6+
7+
const colors = {
8+
red: 'bg-red-500/15 text-red-700 group-data-[hover]:bg-red-500/25 dark:bg-red-500/10 dark:text-red-400 dark:group-data-[hover]:bg-red-500/20',
9+
orange:
10+
'bg-orange-500/15 text-orange-700 group-data-[hover]:bg-orange-500/25 dark:bg-orange-500/10 dark:text-orange-400 dark:group-data-[hover]:bg-orange-500/20',
11+
amber:
12+
'bg-amber-400/20 text-amber-700 group-data-[hover]:bg-amber-400/30 dark:bg-amber-400/10 dark:text-amber-400 dark:group-data-[hover]:bg-amber-400/15',
13+
yellow:
14+
'bg-yellow-400/20 text-yellow-700 group-data-[hover]:bg-yellow-400/30 dark:bg-yellow-400/10 dark:text-yellow-300 dark:group-data-[hover]:bg-yellow-400/15',
15+
lime: 'bg-lime-400/20 text-lime-700 group-data-[hover]:bg-lime-400/30 dark:bg-lime-400/10 dark:text-lime-300 dark:group-data-[hover]:bg-lime-400/15',
16+
green:
17+
'bg-green-500/15 text-green-700 group-data-[hover]:bg-green-500/25 dark:bg-green-500/10 dark:text-green-400 dark:group-data-[hover]:bg-green-500/20',
18+
emerald:
19+
'bg-emerald-500/15 text-emerald-700 group-data-[hover]:bg-emerald-500/25 dark:bg-emerald-500/10 dark:text-emerald-400 dark:group-data-[hover]:bg-emerald-500/20',
20+
teal: 'bg-teal-500/15 text-teal-700 group-data-[hover]:bg-teal-500/25 dark:bg-teal-500/10 dark:text-teal-300 dark:group-data-[hover]:bg-teal-500/20',
21+
cyan: 'bg-cyan-400/20 text-cyan-700 group-data-[hover]:bg-cyan-400/30 dark:bg-cyan-400/10 dark:text-cyan-300 dark:group-data-[hover]:bg-cyan-400/15',
22+
sky: 'bg-sky-500/15 text-sky-700 group-data-[hover]:bg-sky-500/25 dark:bg-sky-500/10 dark:text-sky-300 dark:group-data-[hover]:bg-sky-500/20',
23+
blue: 'bg-blue-500/15 text-blue-700 group-data-[hover]:bg-blue-500/25 dark:text-blue-400 dark:group-data-[hover]:bg-blue-500/25',
24+
indigo:
25+
'bg-indigo-500/15 text-indigo-700 group-data-[hover]:bg-indigo-500/25 dark:text-indigo-400 dark:group-data-[hover]:bg-indigo-500/20',
26+
violet:
27+
'bg-violet-500/15 text-violet-700 group-data-[hover]:bg-violet-500/25 dark:text-violet-400 dark:group-data-[hover]:bg-violet-500/20',
28+
purple:
29+
'bg-purple-500/15 text-purple-700 group-data-[hover]:bg-purple-500/25 dark:text-purple-400 dark:group-data-[hover]:bg-purple-500/20',
30+
fuchsia:
31+
'bg-fuchsia-400/15 text-fuchsia-700 group-data-[hover]:bg-fuchsia-400/25 dark:bg-fuchsia-400/10 dark:text-fuchsia-400 dark:group-data-[hover]:bg-fuchsia-400/20',
32+
pink: 'bg-pink-400/15 text-pink-700 group-data-[hover]:bg-pink-400/25 dark:bg-pink-400/10 dark:text-pink-400 dark:group-data-[hover]:bg-pink-400/20',
33+
rose: 'bg-rose-400/15 text-rose-700 group-data-[hover]:bg-rose-400/25 dark:bg-rose-400/10 dark:text-rose-400 dark:group-data-[hover]:bg-rose-400/20',
34+
zinc: 'bg-zinc-600/10 text-zinc-700 group-data-[hover]:bg-zinc-600/20 dark:bg-white/5 dark:text-zinc-400 dark:group-data-[hover]:bg-white/10',
35+
}
36+
37+
type BadgeProps = { color?: keyof typeof colors }
38+
39+
export function Badge({ color = 'zinc', className, ...props }: BadgeProps & React.ComponentPropsWithoutRef<'span'>) {
40+
return (
41+
<span
42+
{...props}
43+
className={clsx(
44+
className,
45+
'inline-flex items-center gap-x-1.5 rounded-md px-1.5 py-0.5 text-sm/5 font-medium sm:text-xs/5 forced-colors:outline',
46+
colors[color]
47+
)}
48+
/>
49+
)
50+
}
51+
52+
export const BadgeButton = forwardRef(function BadgeButton(
53+
{
54+
color = 'zinc',
55+
className,
56+
children,
57+
...props
58+
}: BadgeProps & { className?: string; children: React.ReactNode } & (
59+
| Omit<Headless.ButtonProps, 'as' | 'className'>
60+
| Omit<React.ComponentPropsWithoutRef<typeof Link>, 'className'>
61+
),
62+
ref: React.ForwardedRef<HTMLElement>
63+
) {
64+
let classes = clsx(
65+
className,
66+
'group relative inline-flex rounded-md focus:outline-none data-[focus]:outline data-[focus]:outline-2 data-[focus]:outline-offset-2 data-[focus]:outline-blue-500'
67+
)
68+
69+
return 'href' in props ? (
70+
<Link {...props} className={classes} ref={ref as React.ForwardedRef<HTMLAnchorElement>}>
71+
<TouchTarget>
72+
<Badge color={color}>{children}</Badge>
73+
</TouchTarget>
74+
</Link>
75+
) : (
76+
<Headless.Button {...props} className={classes} ref={ref}>
77+
<TouchTarget>
78+
<Badge color={color}>{children}</Badge>
79+
</TouchTarget>
80+
</Headless.Button>
81+
)
82+
})

0 commit comments

Comments
 (0)