11import { type ComponentProps , splitProps } from "solid-js"
2+ import { Icon , type IconProps } from "./icon"
3+
4+ type Variant = "normal" | "error" | "warning" | "success" | "info"
25
36export interface CardProps extends ComponentProps < "div" > {
4- variant ?: "normal" | "error" | "warning" | "success" | "info"
7+ variant ?: Variant
8+ }
9+
10+ export interface CardTitleProps extends ComponentProps < "div" > {
11+ variant ?: Variant
12+
13+ /**
14+ * Optional title icon.
15+ *
16+ * - `undefined`: picks a default icon based on `variant` (error/warning/success/info)
17+ * - `false`/`null`: disables the icon
18+ * - `Icon` name: forces a specific icon
19+ */
20+ icon ?: IconProps [ "name" ] | false | null
21+ }
22+
23+ function pick ( variant : Variant ) {
24+ if ( variant === "error" ) return "circle-ban-sign" as const
25+ if ( variant === "warning" ) return "warning" as const
26+ if ( variant === "success" ) return "circle-check" as const
27+ if ( variant === "info" ) return "help" as const
28+ return
29+ }
30+
31+ function mix ( style : ComponentProps < "div" > [ "style" ] , value ?: string ) {
32+ if ( ! value ) return style
33+ if ( ! style ) return { "--card-accent" : value }
34+ if ( typeof style === "string" ) return `${ style } ;--card-accent:${ value } ;`
35+ return { ...( style as Record < string , string | number > ) , "--card-accent" : value }
536}
637
738export function Card ( props : CardProps ) {
8- const [ split , rest ] = splitProps ( props , [ "variant" , "class" , "classList" ] )
39+ const [ split , rest ] = splitProps ( props , [ "variant" , "style" , "class" , "classList" ] )
40+ const variant = ( ) => split . variant ?? "normal"
41+ const accent = ( ) => {
42+ const v = variant ( )
43+ if ( v === "error" ) return "var(--icon-critical-base)"
44+ if ( v === "warning" ) return "var(--icon-warning-active)"
45+ if ( v === "success" ) return "var(--icon-success-active)"
46+ if ( v === "info" ) return "var(--icon-info-active)"
47+ return
48+ }
949 return (
1050 < div
1151 { ...rest }
1252 data-component = "card"
13- data-variant = { split . variant || "normal" }
53+ data-variant = { variant ( ) }
54+ style = { mix ( split . style , accent ( ) ) }
1455 classList = { {
1556 ...( split . classList ?? { } ) ,
1657 [ split . class ?? "" ] : ! ! split . class ,
@@ -20,3 +61,63 @@ export function Card(props: CardProps) {
2061 </ div >
2162 )
2263}
64+
65+ export function CardTitle ( props : CardTitleProps ) {
66+ const [ split , rest ] = splitProps ( props , [ "variant" , "icon" , "class" , "classList" , "children" ] )
67+ const show = ( ) => split . icon !== false && split . icon !== null
68+ const name = ( ) => {
69+ if ( split . icon === false || split . icon === null ) return
70+ if ( typeof split . icon === "string" ) return split . icon
71+ return pick ( split . variant ?? "normal" )
72+ }
73+ const placeholder = ( ) => ! name ( )
74+ return (
75+ < div
76+ { ...rest }
77+ data-slot = "card-title"
78+ classList = { {
79+ ...( split . classList ?? { } ) ,
80+ [ split . class ?? "" ] : ! ! split . class ,
81+ } }
82+ >
83+ { show ( ) ? (
84+ < span data-slot = "card-title-icon" data-placeholder = { placeholder ( ) || undefined } >
85+ < Icon name = { name ( ) ?? "dash" } size = "small" />
86+ </ span >
87+ ) : null }
88+ { split . children }
89+ </ div >
90+ )
91+ }
92+
93+ export function CardDescription ( props : ComponentProps < "div" > ) {
94+ const [ split , rest ] = splitProps ( props , [ "class" , "classList" , "children" ] )
95+ return (
96+ < div
97+ { ...rest }
98+ data-slot = "card-description"
99+ classList = { {
100+ ...( split . classList ?? { } ) ,
101+ [ split . class ?? "" ] : ! ! split . class ,
102+ } }
103+ >
104+ { split . children }
105+ </ div >
106+ )
107+ }
108+
109+ export function CardActions ( props : ComponentProps < "div" > ) {
110+ const [ split , rest ] = splitProps ( props , [ "class" , "classList" , "children" ] )
111+ return (
112+ < div
113+ { ...rest }
114+ data-slot = "card-actions"
115+ classList = { {
116+ ...( split . classList ?? { } ) ,
117+ [ split . class ?? "" ] : ! ! split . class ,
118+ } }
119+ >
120+ { split . children }
121+ </ div >
122+ )
123+ }
0 commit comments