StatusIcon.tsx195 lines · main
1import { forwardRef, SVGProps } from 'react'
2
3import { cn } from '../lib/utils'
4
5export interface StatusIconProps {
6 hideBackground?: boolean
7}
8
9export const StatusIcon = forwardRef<
10 HTMLOrSVGElement,
11 React.ComponentPropsWithoutRef<'svg'> & {
12 variant: 'success' | 'warning' | 'destructive' | 'default'
13 } & StatusIconProps
14>(({ variant = 'default', ...props }, ref) => {
15 let Icon: React.ElementType | undefined
16 if (variant === 'warning') {
17 Icon = WarningIcon
18 } else if (variant === 'destructive') {
19 Icon = CriticalIcon
20 } else if (variant === 'success') {
21 Icon = CheckIcon
22 } else {
23 Icon = InfoIcon
24 }
25
26 return Icon ? <Icon ref={ref} {...props} /> : null
27})
28
29const InfoIcon: React.FC<SVGProps<SVGSVGElement> & StatusIconProps> = ({
30 hideBackground = false,
31 ...props
32}) => {
33 return (
34 <svg
35 xmlns="http://www.w3.org/2000/svg"
36 viewBox="0 0 16 16"
37 fill="currentColor"
38 {...props}
39 className={cn(
40 !hideBackground
41 ? 'w-4 h-4 p-0.5 bg-foreground-lighter text-background-surface-200 rounded-sm'
42 : 'w-3 h-3 text-foreground-lighter',
43 props.className
44 )}
45 >
46 <path
47 fillRule="evenodd"
48 d="M15 8A7 7 0 1 1 1 8a7 7 0 0 1 14 0ZM9 5a1 1 0 1 1-2 0 1 1 0 0 1 2 0ZM6.75 8a.75.75 0 0 0 0 1.5h.75v1.75a.75.75 0 0 0 1.5 0v-2.5A.75.75 0 0 0 8.25 8h-1.5Z"
49 clipRule="evenodd"
50 />
51 </svg>
52 )
53}
54
55const CriticalIcon: React.FC<SVGProps<SVGSVGElement> & StatusIconProps> = ({
56 hideBackground = false,
57 ...props
58}) => {
59 return (
60 <svg
61 xmlns="http://www.w3.org/2000/svg"
62 viewBox="0 0 16 16"
63 fill="currentColor"
64 {...props}
65 className={cn(
66 !hideBackground
67 ? 'w-4 h-4 p-0.5 bg-destructive-600 text-destructive-200 rounded-sm'
68 : 'w-3 h-3 text-destructive-600',
69 props.className
70 )}
71 >
72 <path
73 fillRule="evenodd"
74 d="M6.701 2.25c.577-1 2.02-1 2.598 0l5.196 9a1.5 1.5 0 0 1-1.299 2.25H2.804a1.5 1.5 0 0 1-1.3-2.25l5.197-9ZM8 4a.75.75 0 0 1 .75.75v3a.75.75 0 1 1-1.5 0v-3A.75.75 0 0 1 8 4Zm0 8a1 1 0 1 0 0-2 1 1 0 0 0 0 2Z"
75 clipRule="evenodd"
76 />
77 </svg>
78 )
79}
80
81const WarningIcon: React.FC<SVGProps<SVGSVGElement> & StatusIconProps> = ({
82 hideBackground = false,
83 ...props
84}) => {
85 return (
86 <svg
87 xmlns="http://www.w3.org/2000/svg"
88 viewBox="0 0 16 16"
89 fill="currentColor"
90 {...props}
91 className={cn(
92 !hideBackground
93 ? 'w-4 h-4 p-0.5 bg-warning-600 text-warning-200 rounded-sm'
94 : 'w-3 h-3 text-warning',
95 props.className
96 )}
97 >
98 <path
99 fillRule="evenodd"
100 d="M8 15A7 7 0 1 0 8 1a7 7 0 0 0 0 14ZM8 4a.75.75 0 0 1 .75.75v3a.75.75 0 0 1-1.5 0v-3A.75.75 0 0 1 8 4Zm0 8a1 1 0 1 0 0-2 1 1 0 0 0 0 2Z"
101 clipRule="evenodd"
102 />
103 </svg>
104 )
105}
106
107const CheckIcon: React.FC<SVGProps<SVGSVGElement> & StatusIconProps> = ({
108 hideBackground = false,
109 ...props
110}) => {
111 return (
112 <svg
113 xmlns="http://www.w3.org/2000/svg"
114 viewBox="0 0 24 24"
115 fill="none"
116 stroke="currentColor"
117 {...props}
118 className={cn(
119 !hideBackground
120 ? 'w-4 h-4 p-0.5 bg-foreground text-background rounded-sm'
121 : 'w-3 h-3 text-success-600',
122 props.className
123 )}
124 >
125 <path
126 strokeLinecap="round"
127 strokeLinejoin="round"
128 strokeWidth={3}
129 d="m4.5 12.75 6 6 9-13.5"
130 />
131 </svg>
132 )
133}
134
135const EyeIcon: React.FC<SVGProps<SVGSVGElement> & StatusIconProps> = ({
136 hideBackground = false,
137 ...props
138}) => {
139 return (
140 <svg
141 xmlns="http://www.w3.org/2000/svg"
142 width="24"
143 height="24"
144 viewBox="0 0 24 24"
145 fill="none"
146 stroke="currentColor"
147 strokeWidth="2"
148 strokeLinecap="round"
149 strokeLinejoin="round"
150 {...props}
151 className={cn(
152 !hideBackground
153 ? 'w-4 h-4 p-0.5 bg-warning-600 text-warning-200 rounded-sm'
154 : 'w-3 h-3 text-warning',
155 props.className
156 )}
157 >
158 <path d="M2.062 12.348a1 1 0 0 1 0-.696 10.75 10.75 0 0 1 19.876 0 1 1 0 0 1 0 .696 10.75 10.75 0 0 1-19.876 0" />
159 <circle cx="12" cy="12" r="3" />
160 </svg>
161 )
162}
163
164const EyeOffIcon: React.FC<SVGProps<SVGSVGElement> & StatusIconProps> = ({
165 hideBackground = false,
166 ...props
167}) => {
168 return (
169 <svg
170 xmlns="http://www.w3.org/2000/svg"
171 width="24"
172 height="24"
173 viewBox="0 0 24 24"
174 fill="none"
175 stroke="currentColor"
176 strokeWidth="2"
177 strokeLinecap="round"
178 strokeLinejoin="round"
179 {...props}
180 className={cn(
181 !hideBackground
182 ? 'w-4 h-4 p-0.5 bg-foreground-light text-background rounded-sm'
183 : 'w-3 h-3 text-warning',
184 props.className
185 )}
186 >
187 <path d="M10.733 5.076a10.744 10.744 0 0 1 11.205 6.575 1 1 0 0 1 0 .696 10.747 10.747 0 0 1-1.444 2.49" />
188 <path d="M14.084 14.158a3 3 0 0 1-4.242-4.242" />
189 <path d="M17.479 17.499a10.75 10.75 0 0 1-15.417-5.151 1 1 0 0 1 0-.696 10.75 10.75 0 0 1 4.446-5.143" />
190 <path d="m2 2 20 20" />
191 </svg>
192 )
193}
194
195export { CriticalIcon, InfoIcon, WarningIcon, CheckIcon, EyeIcon, EyeOffIcon }