Skip to content

Commit abc570e

Browse files
authored
Merge branch 'main' into ahmad/space-dashboard
2 parents 6dff20a + 1f43e75 commit abc570e

File tree

16 files changed

+752
-2
lines changed

16 files changed

+752
-2
lines changed

.github/workflows/deploy.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ jobs:
3838
space_dashboard)
3939
echo "EXTRA_ARGS=" >> $GITHUB_ENV
4040
;;
41+
company_dashboard)
42+
echo "EXTRA_ARGS=" >> $GITHUB_ENV
43+
;;
4144
account_management_dashboard)
4245
echo "EXTRA_ARGS=" >> $GITHUB_ENV
4346
;;
4.19 KB
Binary file not shown.

company_dashboard/company_dashboard/__init__.py

Whitespace-only changes.
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import reflex as rx
2+
3+
from company_dashboard.components.documents_table import (
4+
documents_table_section,
5+
)
6+
from company_dashboard.components.header import header_bar
7+
from company_dashboard.components.key_metrics import key_metrics_section
8+
from company_dashboard.components.sidebar import sidebar
9+
from company_dashboard.components.visitors_chart import (
10+
visitors_chart_section,
11+
)
12+
from company_dashboard.states.dashboard_state import DashboardState
13+
14+
15+
def index() -> rx.Component:
16+
"""The main dashboard page."""
17+
return rx.el.div(
18+
sidebar(),
19+
rx.el.main(
20+
header_bar(),
21+
rx.el.div(
22+
key_metrics_section(),
23+
visitors_chart_section(),
24+
documents_table_section(),
25+
class_name="p-6 space-y-6",
26+
),
27+
class_name="ml-64 w-full h-[100vh] overflow-y-auto",
28+
),
29+
class_name="flex bg-gray-50 h-[100vh] w-full overflow-hidden",
30+
on_mount=DashboardState.load_initial_data,
31+
)
32+
33+
34+
app = rx.App(
35+
theme=rx.theme(appearance="light"),
36+
stylesheets=["https://cdn.tailwindcss.com"],
37+
style={
38+
rx.el.label: {"font_family": "JetBrains Mono,ui-monospace,monospace"},
39+
rx.el.span: {"font_family": "JetBrains Mono,ui-monospace,monospace"},
40+
rx.el.h1: {"font_family": "JetBrains Mono,ui-monospace,monospace"},
41+
rx.el.h2: {"font_family": "JetBrains Mono,ui-monospace,monospace"},
42+
},
43+
)
44+
app.add_page(index, route="/")

company_dashboard/company_dashboard/components/__init__.py

Whitespace-only changes.
Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
import reflex as rx
2+
3+
from company_dashboard.states.dashboard_state import (
4+
DashboardState,
5+
)
6+
7+
8+
def document_tab_button(text: str, count: int = 0) -> rx.Component:
9+
"""Button for selecting document table tabs."""
10+
return rx.el.button(
11+
text,
12+
rx.cond(
13+
count > 0,
14+
rx.el.span(
15+
count,
16+
class_name="ml-1.5 px-1.5 py-0.5 text-xs font-medium rounded-full bg-gray-200 text-gray-600",
17+
),
18+
rx.fragment(),
19+
),
20+
on_click=lambda: DashboardState.set_document_tab(text),
21+
class_name=rx.cond(
22+
DashboardState.selected_document_tab == text,
23+
"px-3 py-1.5 text-sm font-medium text-gray-700 bg-gray-100 border border-gray-300 rounded-md shadow-sm",
24+
"px-3 py-1.5 text-sm font-medium text-gray-500 bg-white border border-transparent rounded-md hover:bg-gray-50 hover:text-gray-700",
25+
),
26+
)
27+
28+
29+
def status_badge(status: rx.Var[str]) -> rx.Component:
30+
"""Displays a status badge based on the status string."""
31+
return rx.el.span(
32+
rx.icon(
33+
tag=rx.match(
34+
status,
35+
("Done", "check-circle"),
36+
("In Process", "loader"),
37+
("Pending", "alert-circle"),
38+
"help-circle",
39+
),
40+
class_name="mr-1.5 size-4",
41+
),
42+
status,
43+
class_name=rx.match(
44+
status,
45+
(
46+
"Done",
47+
"inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-green-100 text-green-800",
48+
),
49+
(
50+
"In Process",
51+
"inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-yellow-100 text-yellow-800",
52+
),
53+
(
54+
"Pending",
55+
"inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-red-100 text-red-800",
56+
),
57+
"inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-gray-100 text-gray-800",
58+
),
59+
)
60+
61+
62+
def documents_table_section() -> rx.Component:
63+
"""The section displaying the documents table."""
64+
return rx.el.div(
65+
rx.el.div(
66+
rx.el.div(
67+
document_tab_button("Outline"),
68+
document_tab_button("Past Performance", 3),
69+
document_tab_button("Key Personnel", 2),
70+
document_tab_button("Focus Documents"),
71+
class_name="flex items-center space-x-2 border-b border-gray-200 pb-2 mb-4",
72+
),
73+
rx.el.div(
74+
rx.el.button(
75+
rx.icon(
76+
tag="list-filter",
77+
class_name="w-4 h-4 mr-2",
78+
),
79+
"Customize Columns",
80+
rx.icon(
81+
tag="chevron-down",
82+
class_name="w-4 h-4 ml-1",
83+
),
84+
class_name="flex items-center px-3 py-1.5 text-sm font-medium text-gray-700 bg-white border border-gray-300 rounded-md shadow-sm hover:bg-gray-50",
85+
),
86+
rx.el.button(
87+
rx.icon(
88+
tag="plus",
89+
class_name="w-4 h-4 mr-2",
90+
),
91+
"Add Section",
92+
class_name="flex items-center px-3 py-1.5 text-sm font-medium text-white bg-gray-800 border border-transparent rounded-md shadow-sm hover:bg-gray-700",
93+
),
94+
class_name="flex items-center space-x-3",
95+
),
96+
class_name="flex items-center justify-between mb-4",
97+
),
98+
rx.el.div(
99+
rx.el.table(
100+
rx.el.thead(
101+
rx.el.tr(
102+
rx.foreach(
103+
DashboardState.document_columns,
104+
lambda col_name: rx.el.th(
105+
col_name,
106+
scope="col",
107+
class_name="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider",
108+
),
109+
)
110+
),
111+
class_name="bg-gray-50",
112+
),
113+
rx.el.tbody(
114+
rx.foreach(
115+
DashboardState.document_data,
116+
lambda row: rx.el.tr(
117+
rx.el.td(
118+
rx.el.div(
119+
rx.icon(
120+
tag="grip-vertical",
121+
class_name="w-4 h-4 text-gray-400 mr-3 cursor-grab",
122+
),
123+
rx.el.input(
124+
type="checkbox",
125+
class_name="h-4 w-4 text-indigo-600 border-gray-300 rounded focus:ring-indigo-500",
126+
),
127+
class_name="flex items-center",
128+
),
129+
class_name="px-4 py-3 whitespace-nowrap",
130+
),
131+
rx.el.td(
132+
row["header"],
133+
class_name="px-4 py-3 whitespace-nowrap text-sm font-medium text-gray-900",
134+
),
135+
rx.el.td(
136+
row["section_type"],
137+
class_name="px-4 py-3 whitespace-nowrap text-sm text-gray-500",
138+
),
139+
rx.el.td(
140+
status_badge(row["status"]),
141+
class_name="px-4 py-3 whitespace-nowrap text-sm text-gray-500",
142+
),
143+
rx.el.td(
144+
row["target"],
145+
class_name="px-4 py-3 whitespace-nowrap text-sm text-gray-500",
146+
),
147+
rx.el.td(
148+
row["limit"],
149+
class_name="px-4 py-3 whitespace-nowrap text-sm text-gray-500",
150+
),
151+
rx.el.td(
152+
row["reviewer"],
153+
class_name="px-4 py-3 whitespace-nowrap text-sm text-gray-500",
154+
),
155+
),
156+
),
157+
class_name="bg-white divide-y divide-gray-200",
158+
),
159+
class_name="min-w-full divide-y divide-gray-200",
160+
),
161+
class_name="overflow-hidden border border-gray-200 rounded-lg shadow-sm",
162+
),
163+
class_name="p-5 bg-white border border-gray-200 rounded-lg shadow-sm mt-5",
164+
)
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import reflex as rx
2+
3+
4+
def header_bar() -> rx.Component:
5+
"""The header bar component."""
6+
return rx.el.div(
7+
rx.el.div(
8+
rx.el.label(
9+
"reflex > build > ",
10+
class_name="text-sm font-semibold text-gray-500",
11+
),
12+
rx.el.label(
13+
"dashboard",
14+
class_name="text-sm font-semibold text-gray-900",
15+
),
16+
),
17+
rx.el.div(),
18+
class_name="flex items-center justify-between h-12 px-6 bg-white border-b border-gray-200",
19+
)
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
import reflex as rx
2+
3+
from company_dashboard.states.dashboard_state import (
4+
DashboardState,
5+
Metric,
6+
)
7+
8+
9+
def metric_card(metric: Metric) -> rx.Component:
10+
"""A card displaying a single key metric."""
11+
return rx.el.div(
12+
rx.el.div(
13+
rx.el.p(
14+
metric["title"],
15+
class_name="text-sm font-medium text-gray-500",
16+
),
17+
rx.el.div(
18+
rx.el.span(
19+
metric["change"],
20+
class_name=rx.cond(
21+
metric["change_direction"] == "up",
22+
"text-xs font-medium px-2 py-0.5 rounded-full bg-green-100 text-green-800",
23+
rx.cond(
24+
metric["change_direction"] == "down",
25+
"text-xs font-medium px-2 py-0.5 rounded-full bg-red-100 text-red-800",
26+
"text-xs font-medium px-2 py-0.5 rounded-full bg-gray-100 text-gray-800",
27+
),
28+
),
29+
),
30+
rx.icon(
31+
tag=rx.cond(
32+
metric["change_direction"] == "up",
33+
"trending-up",
34+
rx.cond(
35+
metric["change_direction"] == "down",
36+
"trending-down",
37+
"minus",
38+
),
39+
),
40+
size=16,
41+
class_name=rx.cond(
42+
metric["change_direction"] == "up",
43+
"text-green-600 ml-1",
44+
rx.cond(
45+
metric["change_direction"] == "down",
46+
"text-red-600 ml-1",
47+
"text-gray-600 ml-1",
48+
),
49+
),
50+
),
51+
class_name="flex items-center",
52+
),
53+
class_name="flex items-center justify-between mb-1",
54+
),
55+
rx.el.p(
56+
metric["value"],
57+
class_name="text-3xl font-semibold text-gray-900 mb-2",
58+
),
59+
rx.el.div(
60+
rx.el.p(
61+
metric["description"],
62+
class_name="text-sm text-gray-700 mr-1",
63+
),
64+
rx.icon(
65+
tag="bar-chart-2",
66+
size=16,
67+
class_name="text-gray-500",
68+
),
69+
class_name="flex items-center text-sm text-gray-500",
70+
),
71+
rx.el.p(
72+
metric["trend_description"],
73+
class_name="text-xs text-gray-400 mt-1",
74+
),
75+
class_name="p-5 bg-white border border-gray-200 rounded-lg shadow-sm",
76+
)
77+
78+
79+
def key_metrics_section() -> rx.Component:
80+
"""The section displaying key metric cards."""
81+
return rx.el.div(
82+
rx.foreach(DashboardState.key_metrics, metric_card),
83+
class_name="grid grid-cols-1 gap-5 sm:grid-cols-2 lg:grid-cols-4",
84+
)
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import reflex as rx
2+
3+
4+
def sidebar_item(
5+
text: str,
6+
icon: str,
7+
href: str = "#",
8+
is_active: bool = False,
9+
) -> rx.Component:
10+
"""A reusable sidebar item component."""
11+
return rx.el.a(
12+
rx.icon(tag=icon, class_name="mr-3 size-4"),
13+
rx.el.label(text, class_name="text-sm"),
14+
href=href,
15+
class_name=rx.cond(
16+
is_active,
17+
"flex items-center px-4 py-2 text-sm font-medium text-gray-900 bg-gray-100 rounded-lg",
18+
"flex items-center px-4 py-2 text-sm font-medium text-gray-600 hover:bg-gray-50 hover:text-gray-900 rounded-lg",
19+
),
20+
)
21+
22+
23+
def sidebar() -> rx.Component:
24+
"""The sidebar component for the dashboard."""
25+
return rx.el.div(
26+
rx.el.div(
27+
rx.el.div(
28+
rx.el.label(
29+
"Reflex Build",
30+
class_name="text-sm font-semibold text-gray-900",
31+
),
32+
rx.el.label(
33+
"v.0.0.1",
34+
class_name="text-sm font-regular text-gray-500",
35+
),
36+
class_name="flex items-center px-2 h-12 justify-between",
37+
),
38+
rx.el.label(
39+
"Projects",
40+
class_name="px-4 mb-2 text-sm font-semibold tracking-wider text-gray-500 uppercase",
41+
),
42+
rx.el.nav(
43+
sidebar_item(
44+
"Dashboard",
45+
"layout-dashboard",
46+
is_active=True,
47+
),
48+
sidebar_item("Lifecycle", "recycle"),
49+
sidebar_item("Analytics", "bar-chart-3"),
50+
sidebar_item("Projects", "folder"),
51+
sidebar_item("Team", "users"),
52+
class_name="space-y-1 mb-6 pt-2",
53+
),
54+
rx.el.label(
55+
"Documents",
56+
class_name="px-4 mb-2 text-sm font-semibold tracking-wider text-gray-500 uppercase",
57+
),
58+
rx.el.nav(
59+
sidebar_item("Data Library", "database"),
60+
sidebar_item("Reports", "file-text"),
61+
sidebar_item("Word Assistant", "file-input"),
62+
sidebar_item("More", "send_horizontal"),
63+
class_name="space-y-1",
64+
),
65+
),
66+
class_name="flex flex-col justify-between w-64 h-screen px-2 bg-white border-r border-gray-200 fixed",
67+
)

0 commit comments

Comments
 (0)