Skip to content

Commit 9d996a1

Browse files
authored
add retail dashboard template (#104)
* add retail dashboard template * ruff * deploy
1 parent 81737b7 commit 9d996a1

File tree

22 files changed

+1246
-0
lines changed

22 files changed

+1246
-0
lines changed

.github/workflows/deploy.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,9 @@ jobs:
7474
business_analytics_dashboard)
7575
echo "EXTRA_ARGS=" >> $GITHUB_ENV
7676
;;
77+
retail_dashboard)
78+
echo "EXTRA_ARGS=" >> $GITHUB_ENV
79+
;;
7780
manufacturing_dashboard)
7881
echo "EXTRA_ARGS=" >> $GITHUB_ENV
7982
;;

retail_dashboard/.gitignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
assets/external/
2+
__pycache__/
3+
*.db
4+
.web
5+
.states
6+
*.py[cod]
4.19 KB
Binary file not shown.
344 KB
Loading

retail_dashboard/blocks/__init__.py

Whitespace-only changes.

retail_dashboard/requirements.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
reflex>=0.7.11
2+
pandas

retail_dashboard/retail_dashboard/__init__.py

Whitespace-only changes.

retail_dashboard/retail_dashboard/components/__init__.py

Whitespace-only changes.
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
TOOLTIP_PROPS = {
2+
"cursor": {"fill": "rgba(200, 200, 200, 0.1)"},
3+
"content_style": {
4+
"backgroundColor": "white",
5+
"borderColor": "lightgray",
6+
"borderRadius": "8px",
7+
"boxShadow": "2px 2px 5px rgba(0,0,0,0.1)",
8+
"padding": "10px",
9+
},
10+
"label_style": {"fontWeight": "bold", "color": "#333"},
11+
"item_style": {"fontSize": "12px", "color": "#555"},
12+
}
Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
import reflex as rx
2+
3+
from retail_dashboard.states.dashboard_state import DashboardState
4+
5+
6+
def status_badge(status: rx.Var[str]) -> rx.Component:
7+
"""Creates a colored status badge."""
8+
return rx.el.span(
9+
rx.el.span(
10+
class_name=rx.match(
11+
status,
12+
(
13+
"Live",
14+
"h-1.5 w-1.5 rounded-full bg-emerald-500 mr-1.5",
15+
),
16+
(
17+
"Inactive",
18+
"h-1.5 w-1.5 rounded-full bg-amber-500 mr-1.5",
19+
),
20+
(
21+
"Archived",
22+
"h-1.5 w-1.5 rounded-full bg-slate-500 mr-1.5",
23+
),
24+
"h-1.5 w-1.5 rounded-full bg-slate-400 mr-1.5",
25+
)
26+
),
27+
status,
28+
class_name=rx.match(
29+
status,
30+
(
31+
"Live",
32+
"inline-flex items-center px-2.5 py-1 rounded-md text-xs font-medium bg-emerald-100 text-emerald-700",
33+
),
34+
(
35+
"Inactive",
36+
"inline-flex items-center px-2.5 py-1 rounded-md text-xs font-medium bg-amber-100 text-amber-700",
37+
),
38+
(
39+
"Archived",
40+
"inline-flex items-center px-2.5 py-1 rounded-md text-xs font-medium bg-slate-100 text-slate-600",
41+
),
42+
"inline-flex items-center px-2.5 py-1 rounded-md text-xs font-medium bg-slate-100 text-slate-600",
43+
),
44+
)
45+
46+
47+
def table_header_cell(name: str) -> rx.Component:
48+
"""Creates a table header cell without sorting functionality."""
49+
return rx.el.th(
50+
rx.el.div(
51+
rx.icon(
52+
tag=rx.match(
53+
name,
54+
("Owner", "user"),
55+
("Status", "bar_chart_horizontal_big"),
56+
("Country", "globe_2"),
57+
("Stability", "trending_up"),
58+
("Costs", "banknote"),
59+
("Last edited", "history"),
60+
"table_columns",
61+
),
62+
size=16,
63+
class_name="mr-2 stroke-neutral-400 group-hover:stroke-neutral-500 size-4",
64+
),
65+
name,
66+
rx.el.span(class_name="ml-auto"),
67+
class_name="flex items-center group",
68+
),
69+
scope="col",
70+
class_name="px-6 py-3.5 text-left text-sm font-medium text-gray-600 uppercase tracking-wider select-none",
71+
)
72+
73+
74+
def details_table() -> rx.Component:
75+
"""The main table component displaying details."""
76+
return rx.el.div(
77+
rx.el.div(
78+
rx.el.table(
79+
rx.el.thead(
80+
rx.el.tr(
81+
rx.foreach(
82+
DashboardState.column_names,
83+
lambda col_name: table_header_cell(col_name),
84+
)
85+
)
86+
),
87+
rx.el.tbody(
88+
rx.foreach(
89+
DashboardState.paginated_data,
90+
lambda row: rx.el.tr(
91+
rx.el.td(
92+
row["owner"],
93+
class_name="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-800",
94+
),
95+
rx.el.td(
96+
status_badge(row["status"]),
97+
class_name="px-6 py-4 whitespace-nowrap text-sm",
98+
),
99+
rx.el.td(
100+
rx.el.div(
101+
rx.cond(
102+
row["country"],
103+
rx.fragment(
104+
rx.image(
105+
src=f"https://countryflagsapi.netlify.app/flag/{row['country']}.svg",
106+
class_name="rounded-[2px] w-6 mr-2.5",
107+
alt=row["country"] + " Flag",
108+
),
109+
row["country"],
110+
),
111+
rx.el.span("", class_name="w-6 mr-2.5"),
112+
),
113+
class_name="flex items-center",
114+
),
115+
class_name="px-6 py-4 whitespace-nowrap text-sm text-gray-600",
116+
),
117+
rx.el.td(
118+
f"{row['stability']}%",
119+
class_name=rx.cond(
120+
row["stability"] == 0,
121+
"text-gray-600",
122+
rx.cond(
123+
row["stability"] > 0,
124+
"text-emerald-600",
125+
"text-red-600",
126+
),
127+
)
128+
+ " px-6 py-4 whitespace-nowrap text-sm",
129+
),
130+
rx.el.td(
131+
"$"
132+
+ rx.cond(
133+
row["costs"] == 0,
134+
"0.00",
135+
row["costs"].to_string(),
136+
),
137+
class_name="px-6 py-4 whitespace-nowrap text-sm text-gray-600",
138+
),
139+
rx.el.td(
140+
row["last_edited"],
141+
class_name="px-6 py-4 whitespace-nowrap text-sm text-gray-600",
142+
),
143+
class_name="hover:bg-gray-50/70 border-b border-gray-200/75 last:border-b-0",
144+
),
145+
)
146+
),
147+
class_name="min-w-full divide-y divide-gray-200",
148+
),
149+
class_name="overflow-x-auto rounded-lg border border-gray-200 bg-white",
150+
),
151+
rx.el.div(
152+
rx.el.div(
153+
rx.el.span(
154+
"Showing "
155+
+ DashboardState.current_rows_display
156+
+ " of "
157+
+ DashboardState.total_rows.to_string(),
158+
class_name="text-sm text-gray-600 mr-4",
159+
),
160+
rx.el.button(
161+
rx.icon(tag="chevron_left", size=20),
162+
on_click=DashboardState.previous_page,
163+
disabled=DashboardState.current_page <= 1,
164+
class_name="p-2 border border-gray-300 rounded-md disabled:opacity-50 disabled:cursor-not-allowed hover:bg-gray-100 text-gray-600 focus:outline-none focus:ring-2 focus:ring-offset-1 focus:ring-gray-300",
165+
),
166+
rx.el.button(
167+
rx.icon(tag="chevron_right", size=20),
168+
on_click=DashboardState.next_page,
169+
disabled=DashboardState.current_page >= DashboardState.total_pages,
170+
class_name="p-2 border border-gray-300 rounded-md disabled:opacity-50 disabled:cursor-not-allowed hover:bg-gray-100 ml-2 text-gray-600 focus:outline-none focus:ring-2 focus:ring-offset-1 focus:ring-gray-300",
171+
),
172+
class_name="flex items-center",
173+
),
174+
class_name="flex items-center justify-center sm:justify-end mt-1 md:mt-2 px-2 sm:px-4 py-3.5",
175+
),
176+
class_name="mt-3 md:mt-6",
177+
)

0 commit comments

Comments
 (0)