-
Notifications
You must be signed in to change notification settings - Fork 2
Alert Banner / Note #716
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Alert Banner / Note #716
Changes from all commits
Commits
Show all changes
13 commits
Select commit
Hold shift + click to select a range
f89ef47
feat: US-001 - Create AlertBanner component with all three variant st…
scazan 53cfc70
feat: US-002 - Create Storybook stories for AlertBanner
scazan 6746d3f
feat: US-001 - Refactor AlertBanner to use Intent UI Note as base
scazan 797ec09
feat: US-002 - Verify Storybook stories work with refactored component
scazan 1b932c2
format
scazan 5d2cf33
feat: US-001 - Install Intent UI Note component into @op/ui
scazan dd96182
feat: US-002 - Refactor AlertBanner to use Intent UI Note as base
scazan 464e8fb
fix: replace twMerge/twJoin with cn() in Note component
scazan 34a2db1
Add in colors on AlertBanner
scazan ac63076
Use Note from Intent
scazan 1752970
Use AlertBanner naming
scazan a8e55b4
Move component
scazan 8120995
Use black on all banners
scazan File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,140 @@ | ||
| import { ReactNode } from 'react'; | ||
| import { LuCircleAlert, LuCircleCheck, LuInfo } from 'react-icons/lu'; | ||
| import { tv } from 'tailwind-variants'; | ||
|
|
||
| import { cn } from '../lib/utils'; | ||
|
|
||
| const alertBannerStyles = tv({ | ||
| slots: { | ||
| root: 'w-full overflow-hidden rounded-lg border p-4 *:[a]:hover:underline **:[strong]:font-medium', | ||
| indicatorOuter: | ||
| 'me-3 grid size-8 place-content-center rounded-full border-2', | ||
| indicatorInner: 'grid size-6 place-content-center rounded-full border-2', | ||
| content: 'text-pretty', | ||
| }, | ||
| variants: { | ||
| intent: { | ||
| default: { | ||
| root: 'bg-muted/50 text-secondary-fg', | ||
| }, | ||
| info: { | ||
| root: 'bg-info-subtle text-info-subtle-fg **:[.text-muted-fg]:text-info-subtle-fg/70', | ||
| indicatorOuter: 'border-info-subtle-fg/40', | ||
| indicatorInner: 'border-info-subtle-fg/85', | ||
| }, | ||
| warning: { | ||
| root: 'bg-warning-subtle text-warning-subtle-fg **:[.text-muted-fg]:text-warning-subtle-fg/80', | ||
| indicatorOuter: 'border-warning-subtle-fg/40', | ||
| indicatorInner: 'border-warning-subtle-fg/85', | ||
| }, | ||
| danger: { | ||
| root: 'bg-danger-subtle text-danger-subtle-fg **:[.text-muted-fg]:text-danger-subtle-fg/80', | ||
| indicatorOuter: 'border-danger-subtle-fg/40', | ||
| indicatorInner: 'border-danger-subtle-fg/85', | ||
| }, | ||
| success: { | ||
| root: 'bg-success-subtle text-success-subtle-fg **:[.text-muted-fg]:text-success-subtle-fg/80', | ||
| indicatorOuter: 'border-success-subtle-fg/40', | ||
| indicatorInner: 'border-success-subtle-fg/85', | ||
| }, | ||
| }, | ||
| variant: { | ||
| default: { | ||
| root: 'grid grid-cols-[auto_1fr] text-base/6 backdrop-blur-2xl sm:text-sm/6', | ||
| content: 'group-has-data-[slot=icon]:col-start-2', | ||
| }, | ||
| banner: { | ||
| root: 'flex items-center gap-1 shadow-light', | ||
| content: 'flex min-w-0 items-center gap-1', | ||
| }, | ||
| }, | ||
| }, | ||
| compoundVariants: [ | ||
| { | ||
| variant: 'banner', | ||
| intent: 'warning', | ||
| class: { | ||
| root: 'border-primary-orange1 text-neutral-black [background:linear-gradient(rgba(255,255,255,0.92),rgba(255,255,255,0.92)),var(--color-primary-orange1)]', | ||
| }, | ||
| }, | ||
| { | ||
| variant: 'banner', | ||
| intent: 'danger', | ||
| class: { | ||
| root: 'border-functional-red text-neutral-black [background:linear-gradient(rgba(255,255,255,0.96),rgba(255,255,255,0.96)),var(--color-functional-red)]', | ||
| }, | ||
| }, | ||
| { | ||
| variant: 'banner', | ||
| intent: 'default', | ||
| class: { | ||
| root: 'border-neutral-gray2 bg-neutral-offWhite text-neutral-black', | ||
| }, | ||
| }, | ||
| ], | ||
| defaultVariants: { | ||
| intent: 'default', | ||
| variant: 'default', | ||
| }, | ||
| }); | ||
|
|
||
| const iconMap: Record< | ||
| string, | ||
| React.ComponentType<{ className?: string }> | null | ||
| > = { | ||
| info: LuInfo, | ||
| warning: LuCircleAlert, | ||
| danger: LuCircleAlert, | ||
| success: LuCircleCheck, | ||
| default: null, | ||
| }; | ||
|
|
||
| export interface AlertBannerProps | ||
| extends React.HtmlHTMLAttributes<HTMLDivElement> { | ||
| intent?: 'default' | 'info' | 'warning' | 'danger' | 'success'; | ||
| variant?: 'default' | 'banner'; | ||
| indicator?: boolean; | ||
| icon?: ReactNode; | ||
| contentClassName?: string; | ||
| } | ||
|
|
||
| export function AlertBanner({ | ||
| indicator = true, | ||
| intent = 'default', | ||
| variant = 'default', | ||
| icon, | ||
| className, | ||
| contentClassName, | ||
| ...props | ||
| }: AlertBannerProps) { | ||
| const styles = alertBannerStyles({ intent, variant }); | ||
| const IconComponent = iconMap[intent] || null; | ||
|
|
||
| return ( | ||
| <div data-slot="note" className={cn(styles.root(), className)} {...props}> | ||
| {variant === 'banner' ? ( | ||
| <> | ||
| <span className="shrink-0 [&>svg]:size-4"> | ||
| {icon ?? <LuInfo className="size-4" />} | ||
| </span> | ||
| <span className="truncate text-sm leading-[1.5] font-normal"> | ||
| {props.children} | ||
| </span> | ||
| </> | ||
| ) : ( | ||
| <> | ||
| {IconComponent && indicator && ( | ||
| <div className={styles.indicatorOuter()}> | ||
| <div className={styles.indicatorInner()}> | ||
| <IconComponent className="size-5 shrink-0" /> | ||
| </div> | ||
| </div> | ||
| )} | ||
| <div className={cn(styles.content(), contentClassName)}> | ||
| {props.children} | ||
| </div> | ||
| </> | ||
| )} | ||
| </div> | ||
| ); | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,89 @@ | ||
| import type { Meta, StoryObj } from '@storybook/react'; | ||
| import { LuTriangleAlert } from 'react-icons/lu'; | ||
|
|
||
| import { AlertBanner } from '../src/components/AlertBanner'; | ||
|
|
||
| const meta: Meta<typeof AlertBanner> = { | ||
| title: 'AlertBanner', | ||
| component: AlertBanner, | ||
| tags: ['autodocs'], | ||
| args: { | ||
| variant: 'banner', | ||
| }, | ||
| argTypes: { | ||
| intent: { | ||
| control: 'select', | ||
| options: ['default', 'info', 'warning', 'danger', 'success'], | ||
| }, | ||
| variant: { | ||
| control: 'select', | ||
| options: ['default', 'banner'], | ||
| }, | ||
| children: { | ||
| control: 'text', | ||
| }, | ||
| }, | ||
| }; | ||
|
|
||
| export default meta; | ||
|
|
||
| type Story = StoryObj<typeof AlertBanner>; | ||
|
|
||
| export const Warning: Story = { | ||
| args: { | ||
| intent: 'warning', | ||
| children: 'This action requires your attention before proceeding.', | ||
| }, | ||
| }; | ||
|
|
||
| export const Alert: Story = { | ||
| args: { | ||
| intent: 'danger', | ||
| children: 'There was a critical error processing your request.', | ||
| }, | ||
| }; | ||
|
|
||
| export const Neutral: Story = { | ||
| args: { | ||
| intent: 'default', | ||
| children: 'Your session will expire in 5 minutes.', | ||
| }, | ||
| }; | ||
|
|
||
| export const CustomIcon: Story = { | ||
| args: { | ||
| intent: 'warning', | ||
| icon: <LuTriangleAlert className="size-4" />, | ||
| children: 'Warning with a custom triangle icon.', | ||
| }, | ||
| }; | ||
|
|
||
| export const LongText: Story = { | ||
| args: { | ||
| intent: 'warning', | ||
| children: | ||
| 'This is a very long message that should be truncated with an ellipsis when it overflows the container width. It keeps going and going to demonstrate the text-overflow behavior of the AlertBanner component.', | ||
| }, | ||
| }; | ||
|
|
||
| export const BannerVariants = () => ( | ||
| <div className="flex w-96 flex-col gap-4"> | ||
| <AlertBanner variant="banner" intent="warning"> | ||
| Warning: This action requires your attention. | ||
| </AlertBanner> | ||
| <AlertBanner variant="banner" intent="danger"> | ||
| Alert: There was a critical error processing your request. | ||
| </AlertBanner> | ||
| <AlertBanner variant="banner" intent="default"> | ||
| Info: Your session will expire in 5 minutes. | ||
| </AlertBanner> | ||
| </div> | ||
| ); | ||
|
|
||
| export const DefaultVariant: Story = { | ||
| args: { | ||
| variant: 'default', | ||
| intent: 'warning', | ||
| children: 'This uses the default AlertBanner styling with indicator.', | ||
| }, | ||
| }; |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like this gradient is to tint the
--color-primary-orange1to the right shade... we should ideally use a color from our scale. But I checked the lightest orange in that scale and it's too dark. Our core color tokens should be updated, though not in this PR.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great. I think we'll need to update the Figma token as well since it's using this gradient.