1- from typing import Any , Literal
1+ from collections . abc import Sequence
22
33from dash import html
4+ from dash .development .base_component import Component
5+ from dash .html .Section import Section
6+ from dash_iconify import DashIconify
7+
8+ Children = Component | Sequence [Component ] | str | Section
49
510
611def Card (
7- children : Any ,
12+ children : Children ,
13+ header : Children | None = None ,
14+ footer : Children | None = None ,
815 className : str = "" ,
9- title : str | None = None ,
10- grid_cols : Literal [1 , 2 , 3 , 4 , 6 , 12 , "full" ] = 1 ,
11- ** kwargs : Any ,
12- ) -> html .Div :
13- """
14- Reusable card component with consistent dashkit styling and grid support.
16+ header_className : str | None = None ,
17+ body_className : str | None = None ,
18+ ** kwargs ,
19+ ) -> Component :
20+ header_base = (
21+ "flex flex-wrap items-center justify-between gap-4 px-6 py-4 "
22+ "[&:has(+footer)]:border-b [&:has(+footer)]:border-ceramic-bg-separator "
23+ "text-ceramic-secondary leading-5 "
24+ )
25+ return html .Section (
26+ children = [
27+ (
28+ html .Header (
29+ children = header ,
30+ className = (header_base + (header_className .strip () if header_className else "" )).strip (),
31+ )
32+ if header
33+ else None
34+ ),
35+ html .Div (
36+ children = html .Div (
37+ children = children ,
38+ className = (
39+ ("flex flex-col " + (body_className .strip () if body_className else "px-6 py-2" )).strip ()
40+ ),
41+ ),
42+ className = "bg-white dark:bg-dashkit-surface overflow-hidden rounded-2xl ring-1 ring-[#191C21]/4 dark:ring-ceramic-black/20 shadow-[0_1px_2px_0_rgba(25,28,33,.06),0_0_2px_0_theme(colors.ceramic.black/.08)] dark:shadow-[inset_0_0_1px_1px_theme(colors.ceramic.white/.01),0_1px_3px_0_theme(colors.ceramic.black/.4),0_0_3px_0_theme(colors.ceramic.black/.2)] flex-1 min-h-0 " ,
43+ ),
44+ (
45+ html .Footer (
46+ children = html .Div (
47+ children = footer ,
48+ className = "flex items-start px-5 gap-1.5 text-ceramic-body-3 text-ceramic-secondary -mx-5 border-t border-ceramic-bg-separator first:border-none [:where(&)]:py-3 first:[:where(&)]:pt-0 last:[:where(&)]:pb-0 flex-1 leading-5" ,
49+ ),
50+ className = "px-7 pb-3 pt-4" ,
51+ )
52+ if footer
53+ else None
54+ ),
55+ ],
56+ className = "group flex flex-col w-full h-full rounded-2xl px-[4px] [:where(&)]:py-1 bg-dashkit-panel-light dark:bg-dashkit-panel-dark "
57+ + className .strip (),
58+ ** kwargs ,
59+ )
1560
16- Args:
17- children: Content to display inside the card
18- className: Additional CSS classes
19- title: Optional title to display at the top of the card
20- grid_cols: Grid columns span (1-12, or "full" for col-span-full)
21- **kwargs: Additional props passed to the outer div
22- """
23- # Map grid_cols to CSS classes
24- grid_class_map = {
25- 1 : "col-span-1" ,
26- 2 : "col-span-2" ,
27- 3 : "col-span-3" ,
28- 4 : "col-span-4" ,
29- 6 : "col-span-6" ,
30- 12 : "col-span-12" ,
31- "full" : "col-span-full" ,
32- }
33-
34- grid_class = grid_class_map .get (grid_cols , "col-span-1" )
35-
36- # Base card styling with dashkit colors
37- base_classes = "bg-white dark:bg-dashkit-panel-dark p-6 rounded-lg border border-dashkit-border-light dark:border-dashkit-border-dark"
38- combined_classes = f"{ base_classes } { grid_class } { className } " .strip ()
39-
40- # Build card content
41- card_content = []
42-
43- # Add title if provided
44- if title :
45- card_content .append (
46- html .H3 (
47- title ,
48- className = "text-lg font-medium mb-4 text-dashkit-text dark:text-dashkit-text-invert" ,
49- )
50- )
5161
52- # Add children (can be a single element or list)
53- if isinstance (children , list ):
54- card_content .extend (children )
55- else :
56- card_content .append (children )
62+ def CardTitle (
63+ children : Children ,
64+ className : str = "" ,
65+ ** kwargs ,
66+ ) -> html .Span :
67+ return html .Span (
68+ children = children ,
69+ className = "flex flex-wrap items-center gap-x-2 gap-y-0.5 font-medium text-ceramic-primary text-[16px] "
70+ + className .strip (),
71+ )
5772
58- return html .Div (card_content , className = combined_classes , ** kwargs )
73+
74+ def CardTitleWithIcon (
75+ icon : str ,
76+ children : Children ,
77+ className : str = "" ,
78+ ** kwargs ,
79+ ) -> html .Span :
80+ return html .Span (
81+ children = [
82+ DashIconify (icon = icon , className = "stroke-2" ),
83+ CardTitle (children , className = className , ** kwargs ),
84+ ],
85+ className = "flex flex-wrap items-center gap-x-2 gap-y-0.5 font-medium text-ceramic-primary text-[16px] "
86+ + className .strip (),
87+ )
88+
89+
90+ def CardSubtitle (
91+ children : Children ,
92+ className : str = "" ,
93+ ** kwargs ,
94+ ) -> html .Span :
95+ return html .Span (
96+ children = children ,
97+ className = "text-xs text-ceramic-secondary pr-2 " + className .strip (),
98+ )
99+
100+
101+ def CardFooter (
102+ children : Children ,
103+ className : str = "" ,
104+ ** kwargs ,
105+ ) -> html .Span :
106+ return html .Span (
107+ children = children ,
108+ className = "text-xs text-ceramic-secondary " + className .strip (),
109+ )
59110
60111
61112def MetricCard (
62113 title : str ,
63114 value : str ,
64115 trend : str | None = None ,
65116 trend_positive : bool = True ,
66- grid_cols : Literal [1 , 2 , 3 , 4 , 6 , 12 , "full" ] = 1 ,
67117 className : str = "" ,
68- ** kwargs : Any ,
69- ) -> html . Div :
118+ ** kwargs ,
119+ ) -> Component :
70120 """
71121 Specialized card for displaying metrics/KPIs.
72122
@@ -75,7 +125,6 @@ def MetricCard(
75125 value: Metric value to display
76126 trend: Optional trend indicator (e.g., "+2.1%", "↗ +5%")
77127 trend_positive: Whether trend is positive (affects color)
78- grid_cols: Grid columns span
79128 className: Additional CSS classes
80129 **kwargs: Additional props
81130 """
@@ -102,38 +151,29 @@ def MetricCard(
102151
103152 return Card (
104153 html .Div (content , className = "text-center" ),
105- className = f"bg-dashkit-panel-light dark:bg-dashkit-surface { className } " ,
106- grid_cols = grid_cols ,
154+ className = className ,
107155 ** kwargs ,
108156 )
109157
110158
111159def ChartCard (
112160 title : str ,
113- chart : Any ,
114- grid_cols : Literal [1 , 2 , 3 , 4 , 6 , 12 , "full" ] = 1 ,
161+ chart : Children ,
115162 className : str = "" ,
116- ** kwargs : Any ,
117- ) -> html . Div :
163+ ** kwargs ,
164+ ) -> Component :
118165 """
119166 Specialized card for displaying charts with consistent styling.
120167
121168 Args:
122169 title: Chart title
123170 chart: Chart component (e.g., dmc.LineChart, dmc.BarChart, etc.)
124- grid_cols: Grid columns span
125171 className: Additional CSS classes
126172 **kwargs: Additional props
127173 """
128174 return Card (
129- [
130- html .H3 (
131- title ,
132- className = "text-lg font-medium mb-4 text-dashkit-text dark:text-dashkit-text-invert" ,
133- ),
134- chart ,
135- ],
175+ chart ,
176+ header = CardTitle (title ),
136177 className = className ,
137- grid_cols = grid_cols ,
138178 ** kwargs ,
139179 )
0 commit comments