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+ ) -> Component :
19+ header_base = (
20+ "flex flex-wrap items-center justify-between gap-4 px-6 py-4 "
21+ "[&:has(+footer)]:border-b [&:has(+footer)]:border-ceramic-bg-separator "
22+ "text-ceramic-secondary leading-5 "
23+ )
24+ return html .Section (
25+ children = [
26+ (
27+ html .Header (
28+ children = header ,
29+ className = (header_base + (header_className .strip () if header_className else "" )).strip (),
30+ )
31+ if header
32+ else None
33+ ),
34+ html .Div (
35+ children = html .Div (
36+ children = children ,
37+ className = (
38+ ("flex flex-col " + (body_className .strip () if body_className else "px-6 py-2" )).strip ()
39+ ),
40+ ),
41+ 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 " ,
42+ ),
43+ (
44+ html .Footer (
45+ children = html .Div (
46+ children = footer ,
47+ 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" ,
48+ ),
49+ className = "px-7 pb-3 pt-4" ,
50+ )
51+ if footer
52+ else None
53+ ),
54+ ],
55+ 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 "
56+ + className .strip (),
57+ )
1558
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- )
5159
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 )
60+ def CardTitle (
61+ children : Children ,
62+ className : str = "" ,
63+ ** kwargs ,
64+ ) -> html .Span :
65+ return html .Span (
66+ children = children ,
67+ className = "flex flex-wrap items-center gap-x-2 gap-y-0.5 font-medium text-ceramic-primary text-[16px] "
68+ + className .strip (),
69+ )
70+
71+
72+ def CardTitleWithIcon (
73+ icon : str ,
74+ children : Children ,
75+ className : str = "" ,
76+ ** kwargs ,
77+ ) -> html .Span :
78+ return html .Span (
79+ children = [
80+ DashIconify (icon = icon , className = "stroke-2" ),
81+ CardTitle (children , className = className , ** kwargs ),
82+ ],
83+ className = "flex flex-wrap items-center gap-x-2 gap-y-0.5 font-medium text-ceramic-primary text-[16px] "
84+ + className .strip (),
85+ )
86+
5787
58- return html .Div (card_content , className = combined_classes , ** kwargs )
88+ def CardSubtitle (
89+ children : Children ,
90+ className : str = "" ,
91+ ** kwargs ,
92+ ) -> html .Span :
93+ return html .Span (
94+ children = children ,
95+ className = "text-xs text-ceramic-secondary pr-2 " + className .strip (),
96+ )
97+
98+
99+ def CardFooter (
100+ children : Children ,
101+ className : str = "" ,
102+ ** kwargs ,
103+ ) -> html .Span :
104+ return html .Span (
105+ children = children ,
106+ className = "text-xs text-ceramic-secondary " + className .strip (),
107+ )
59108
60109
61110def MetricCard (
62111 title : str ,
63112 value : str ,
64113 trend : str | None = None ,
65114 trend_positive : bool = True ,
66- grid_cols : Literal [1 , 2 , 3 , 4 , 6 , 12 , "full" ] = 1 ,
67115 className : str = "" ,
68- ** kwargs : Any ,
69- ) -> html . Div :
116+ ** kwargs ,
117+ ) -> Component :
70118 """
71119 Specialized card for displaying metrics/KPIs.
72120
@@ -75,7 +123,6 @@ def MetricCard(
75123 value: Metric value to display
76124 trend: Optional trend indicator (e.g., "+2.1%", "↗ +5%")
77125 trend_positive: Whether trend is positive (affects color)
78- grid_cols: Grid columns span
79126 className: Additional CSS classes
80127 **kwargs: Additional props
81128 """
@@ -102,38 +149,29 @@ def MetricCard(
102149
103150 return Card (
104151 html .Div (content , className = "text-center" ),
105- className = f"bg-dashkit-panel-light dark:bg-dashkit-surface { className } " ,
106- grid_cols = grid_cols ,
152+ className = className ,
107153 ** kwargs ,
108154 )
109155
110156
111157def ChartCard (
112158 title : str ,
113- chart : Any ,
114- grid_cols : Literal [1 , 2 , 3 , 4 , 6 , 12 , "full" ] = 1 ,
159+ chart : Children ,
115160 className : str = "" ,
116- ** kwargs : Any ,
117- ) -> html . Div :
161+ ** kwargs ,
162+ ) -> Component :
118163 """
119164 Specialized card for displaying charts with consistent styling.
120165
121166 Args:
122167 title: Chart title
123168 chart: Chart component (e.g., dmc.LineChart, dmc.BarChart, etc.)
124- grid_cols: Grid columns span
125169 className: Additional CSS classes
126170 **kwargs: Additional props
127171 """
128172 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- ],
173+ chart ,
174+ header = CardTitle (title ),
136175 className = className ,
137- grid_cols = grid_cols ,
138176 ** kwargs ,
139177 )
0 commit comments