Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 66 additions & 0 deletions src/components/alert/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { FC } from 'react'
import { CircleAlert, CircleCheck, Info, TriangleAlert } from 'lucide-react'
import { cva, type VariantProps } from 'class-variance-authority'
import { cn } from '../../lib/utils'
import { Alert as BaseAlert, AlertDescription, AlertTitle } from '../ui/alert'

const alertVariants = cva('p-2 md:p-4 gap-1 rounded-lg border', {
variants: {
variant: {
info: 'bg-background border-border',
error: 'bg-background border-destructive dark:border-[#7F2424] text-destructive',
warning: 'bg-background border-warning/50 text-warning',
'error-filled': 'bg-destructive/10 border-destructive dark:border-[#7F2424] text-destructive',
'warning-filled':
'bg-yellow-50 border-warning/50 text-warning dark:bg-yellow-900/10 dark:border-yellow-900/50 dark:text-yellow-500',
success: 'bg-background border-success text-success',
'success-filled': 'bg-success/10 border-success text-success',
},
},
defaultVariants: {
variant: 'info',
},
})

type AlertProps = {
className?: string
title?: string
children?: React.ReactNode
sticky?: boolean
} & VariantProps<typeof alertVariants>

export const Alert: FC<AlertProps> = ({ className, title, variant = 'info', sticky = false, children }) => {
const iconMap = {
info: Info,
success: CircleCheck,
'success-filled': CircleCheck,
error: CircleAlert,
'error-filled': CircleAlert,
warning: TriangleAlert,
'warning-filled': TriangleAlert,
}
const Icon = iconMap[variant || 'info']

return (
<BaseAlert
className={cn(
alertVariants({ variant }),
{
'sticky top-0 z-[1000] rounded-none border-0 flex justify-center items-center': sticky,
},
className
)}
>
<Icon
className={cn('w-4 h-4 min-w-4 min-h-4', {
'mt-0.5': title,
'-mt-1': !title && sticky,
})}
/>
<div className="flex flex-col gap-1">
{title && <AlertTitle className="text-inherit text-base font-medium leading-6">{title}</AlertTitle>}
<AlertDescription className="text-inherit text-sm font-normal leading-5">{children}</AlertDescription>
</div>
</BaseAlert>
)
}
35 changes: 22 additions & 13 deletions src/stories/Alert/Alert.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import type { Meta, StoryObj } from '@storybook/react-vite'
import { Alert, AlertDescription, AlertTitle } from '../../components/ui/alert.tsx'
import { InfoIcon } from 'lucide-react'
import { Alert } from '../../components/alert'
import { expect, within } from 'storybook/test'

const meta: Meta<typeof Alert> = {
Expand All @@ -19,23 +18,33 @@ const meta: Meta<typeof Alert> = {
},
},
tags: ['autodocs'],
argTypes: {
variant: {
control: 'select',
options: ['info', 'success', 'success-filled', 'warning', 'warning-filled', 'error', 'error-filled'],
description: 'The variant of the alert',
table: {
defaultValue: { summary: 'info' },
},
},
sticky: {
control: 'boolean',
description: 'Makes the alert stick to the top of its container',
table: {
defaultValue: { summary: 'false' },
},
},
},
}

export default meta
type Story = StoryObj<typeof meta>

export const Default: Story = {
export const Info: Story = {
args: {
children: (
<>
<InfoIcon />
<AlertTitle>Information</AlertTitle>
<AlertDescription>
Alert description provides additional information about the alert.
</AlertDescription>
</>
),
variant: 'default',
children: <>Alert description provides additional information about the alert.</>,
variant: 'info',
title: '',
},
play: async ({ canvasElement }) => {
const canvas = within(canvasElement)
Expand Down