Skip to content

Commit 2ed4f52

Browse files
Create emcn component
1 parent 8f1a611 commit 2ed4f52

4 files changed

Lines changed: 66 additions & 13 deletions

File tree

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import type * as React from 'react'
2+
import { cva, type VariantProps } from 'class-variance-authority'
3+
import { AlertTriangle, CheckCircle2, Info } from 'lucide-react'
4+
import { cn } from '@/lib/core/utils/cn'
5+
6+
const calloutVariants = cva('flex items-center gap-2 rounded-lg border px-2.5 py-1.5 text-[12px]', {
7+
variants: {
8+
variant: {
9+
default: 'border-[var(--border)] bg-[var(--surface-2)] text-[var(--text-muted)]',
10+
info: 'border-[var(--border)] bg-[var(--surface-2)] text-[var(--text-muted)]',
11+
success:
12+
'border-[color-mix(in_srgb,var(--badge-success-text)_30%,transparent)] bg-[var(--badge-success-bg)] text-[var(--badge-success-text)]',
13+
warning:
14+
'border-[color-mix(in_srgb,var(--badge-amber-text)_30%,transparent)] bg-[var(--badge-amber-bg)] text-[var(--badge-amber-text)]',
15+
destructive:
16+
'border-[color-mix(in_srgb,var(--text-error)_40%,transparent)] bg-[color-mix(in_srgb,var(--text-error)_10%,transparent)] text-[var(--text-error)]',
17+
},
18+
},
19+
defaultVariants: {
20+
variant: 'default',
21+
},
22+
})
23+
24+
const DEFAULT_ICONS = {
25+
default: Info,
26+
info: Info,
27+
success: CheckCircle2,
28+
warning: AlertTriangle,
29+
destructive: AlertTriangle,
30+
} as const
31+
32+
export interface CalloutProps
33+
extends React.HTMLAttributes<HTMLDivElement>,
34+
VariantProps<typeof calloutVariants> {
35+
/** Icon component shown before the content. Pass `null` to hide. Defaults per variant. */
36+
icon?: React.ComponentType<{ className?: string }> | null
37+
}
38+
39+
/**
40+
* Inline note used to highlight short pieces of context inside a page or section.
41+
*
42+
* @example
43+
* ```tsx
44+
* <Callout>Applies organization-wide</Callout>
45+
* <Callout variant='warning'>This action is irreversible</Callout>
46+
* ```
47+
*/
48+
function Callout({ className, variant, icon, children, ...props }: CalloutProps) {
49+
const variantKey = (variant ?? 'default') as keyof typeof DEFAULT_ICONS
50+
const Icon = icon === null ? null : (icon ?? DEFAULT_ICONS[variantKey])
51+
52+
return (
53+
<div className={cn(calloutVariants({ variant }), className)} {...props}>
54+
{Icon && <Icon className='h-3.5 w-3.5 flex-shrink-0' />}
55+
<p>{children}</p>
56+
</div>
57+
)
58+
}
59+
60+
export { Callout, calloutVariants }

apps/sim/components/emcn/components/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ export {
1818
buttonGroupItemVariants,
1919
buttonGroupVariants,
2020
} from './button-group/button-group'
21+
export { Callout, type CalloutProps, calloutVariants } from './callout/callout'
2122
export {
2223
Checkbox,
2324
type CheckboxProps,

apps/sim/ee/data-retention/components/data-retention-settings.tsx

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,7 @@
33
import { useEffect, useState } from 'react'
44
import { createLogger } from '@sim/logger'
55
import { toError } from '@sim/utils/errors'
6-
import { Info } from 'lucide-react'
7-
import { Button, Combobox, toast } from '@/components/emcn'
8-
6+
import { Button, Callout, Combobox, toast } from '@/components/emcn'
97
import { useSession } from '@/lib/auth/auth-client'
108
import { isBillingEnabled } from '@/lib/core/config/feature-flags'
119
import { getUserRole } from '@/lib/workspaces/organization/utils'
@@ -171,10 +169,7 @@ export function DataRetentionSettings() {
171169

172170
return (
173171
<div className='flex flex-col gap-8'>
174-
<div className='flex items-center gap-2 rounded-lg border border-[var(--border)] bg-[var(--surface-2)] px-2.5 py-1.5'>
175-
<Info className='h-3.5 w-3.5 flex-shrink-0 text-[var(--text-muted)]' />
176-
<p className='text-[12px] text-[var(--text-muted)]'>Applies organization-wide</p>
177-
</div>
172+
<Callout>Applies organization-wide</Callout>
178173
<section>
179174
<div className='flex flex-col gap-5'>
180175
<SettingRow

apps/sim/ee/whitelabeling/components/whitelabeling-settings.tsx

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@
33
import { useEffect, useState } from 'react'
44
import { createLogger } from '@sim/logger'
55
import { toError } from '@sim/utils/errors'
6-
import { Info, X } from 'lucide-react'
6+
import { X } from 'lucide-react'
77
import Image from 'next/image'
88
import { useParams } from 'next/navigation'
9-
import { Button, Input, Label, Loader, Skeleton, toast } from '@/components/emcn'
9+
import { Button, Callout, Input, Label, Loader, Skeleton, toast } from '@/components/emcn'
1010
import { useSession } from '@/lib/auth/auth-client'
1111
import { getSubscriptionAccessState } from '@/lib/billing/client/utils'
1212
import { HEX_COLOR_REGEX } from '@/lib/branding'
@@ -318,10 +318,7 @@ export function WhitelabelingSettings() {
318318

319319
return (
320320
<div className='flex flex-col gap-8'>
321-
<div className='flex items-center gap-2 rounded-lg border border-[var(--border)] bg-[var(--surface-2)] px-2.5 py-1.5'>
322-
<Info className='h-3.5 w-3.5 flex-shrink-0 text-[var(--text-muted)]' />
323-
<p className='text-[12px] text-[var(--text-muted)]'>Applies organization-wide</p>
324-
</div>
321+
<Callout>Applies organization-wide</Callout>
325322
<section>
326323
<SectionTitle>Brand Identity</SectionTitle>
327324
<div className='flex flex-col gap-5'>

0 commit comments

Comments
 (0)