Panel.tsx153 lines · main
1import { Megaphone } from 'lucide-react'
2import { forwardRef, type PropsWithChildren, type ReactNode } from 'react'
3import { Badge, Button, cn, Loading } from 'ui'
4
5interface PanelProps {
6 className?: string
7 id?: string
8 footer?: ReactNode
9 loading?: boolean
10 noMargin?: boolean
11 title?: ReactNode | false
12 wrapWithLoading?: boolean
13 noHideOverflow?: boolean
14 titleClasses?: string
15 footerClasses?: string
16}
17
18/**
19 * @deprecated Use Card component from ui package instead
20 */
21function Panel(props: PropsWithChildren<PanelProps>) {
22 const content = (
23 <div
24 className={cn(
25 'bg-surface-100',
26 'rounded-md border shadow-xs',
27 props.noHideOverflow ? '' : 'overflow-hidden',
28 props.noMargin ? '' : 'mb-4 md:mb-8',
29 props.className
30 )}
31 id={props.id}
32 >
33 {props.title && (
34 <div
35 className={cn(
36 'bg-surface-100 border-b border-default flex items-center px-card py-4',
37 props.titleClasses
38 )}
39 >
40 {props.title}
41 </div>
42 )}
43 {props.children}
44 {props.footer && <Footer className={props.footerClasses}>{props.footer}</Footer>}
45 </div>
46 )
47
48 if (props.wrapWithLoading === false) {
49 return content
50 }
51
52 return <Loading active={Boolean(props.loading)}>{content}</Loading>
53}
54
55function Content({ children, className }: { children: ReactNode; className?: string | false }) {
56 return <div className={cn('px-card py-4', className)}>{children}</div>
57}
58
59function Footer({ children, className }: { children: ReactNode; className?: string }) {
60 return (
61 <div className={cn('bg-surface-100 border-t border-default', className)}>
62 <div className="flex h-12 items-center px-card">{children}</div>
63 </div>
64 )
65}
66
67const PanelNotice = forwardRef<
68 HTMLDivElement,
69 {
70 className?: string | false
71 title?: string
72 description?: ReactNode
73 href?: string
74 buttonText?: string
75 layout?: 'horizontal' | 'vertical'
76 badgeLabel?: string
77 }
78>(
79 (
80 {
81 className,
82 title,
83 description,
84 href,
85 buttonText,
86 layout = 'horizontal',
87 badgeLabel,
88 ...props
89 },
90 ref
91 ) => {
92 return (
93 <div
94 ref={ref}
95 {...props}
96 className={cn(
97 'relative px-card py-5 bg-studio flex flex-col lg:flex-row lg:justify-between gap-6 overflow-hidden lg:items-center',
98 layout === 'vertical' && 'flex-col! items-start! gap-y-2',
99 className
100 )}
101 >
102 <div
103 className="absolute inset-0 mt-[-5px]"
104 style={{
105 backgroundImage: `
106 linear-gradient(to right, hsl(var(--background-200)/1) 0%, hsl(var(--background-200)/1) 30%, hsl(var(--background-200)/0) 100%),
107 linear-gradient(to right, hsl(var(--border-default)/0.33) 1px, transparent 1px),
108 linear-gradient(to bottom, hsl(var(--border-default)/0.33) 1px, transparent 1px)
109 `,
110 backgroundSize: '100% 100%, 15px 15px, 15px 15px',
111 backgroundPosition: '0 0, 0 0, 0 0',
112 }}
113 />
114 <div className="relative flex flex-col gap-y-2">
115 <div className="flex flex-row items-center -space-x-px">
116 <Badge
117 variant={'default'}
118 className="rounded-r-none pr-2 shrink-0 gap-1.5 border-dashed bg-surface-400/0 text-foreground-lighter"
119 >
120 <Megaphone size={16} strokeWidth={1.2} />
121 <span className="text-foreground-lighter">{badgeLabel ?? 'Upcoming change'}</span>
122 </Badge>
123 <Badge
124 variant="default"
125 className="rounded-l-none shrink-0 gap-1.5 bg-surface-400/0 text-foreground-lighter border-l-0"
126 >
127 <span className="text-foreground text-xs">{title}</span>
128 </Badge>
129 </div>
130 {description && (
131 <div className="text-foreground-light text-sm flex flex-col gap-0">
132 <div className="prose text-xs max-w-none [&_p]:mt-2 [&_p]:mb-0">{description}</div>
133 </div>
134 )}
135 </div>
136 {href && (
137 <Button size="tiny" type="default" className="text-xs" asChild>
138 <a href={href} target="_blank" rel="noreferrer noopener">
139 {buttonText ?? 'Read the accouncement'}
140 </a>
141 </Button>
142 )}
143 </div>
144 )
145 }
146)
147
148PanelNotice.displayName = 'PanelNotice'
149
150Panel.Content = Content
151Panel.Footer = Footer
152Panel.Notice = PanelNotice
153export default Panel