Skip to content
This repository was archived by the owner on Apr 28, 2026. It is now read-only.

Commit 69a8992

Browse files
committed
template
1 parent e1ab6fb commit 69a8992

8 files changed

Lines changed: 614 additions & 478 deletions

File tree

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
from typing import TypedDict
2+
3+
import reflex as rx
4+
import reflex_ui as ui
5+
6+
7+
class ComparisonItem(TypedDict):
8+
title: str
9+
icon: str
10+
pros: list[str]
11+
cons: list[str]
12+
13+
14+
def comparison_title(title: str, icon: str) -> rx.Component:
15+
return rx.el.div(
16+
ui.icon(icon, stroke_width=1.5, class_name="shrink-0 lg:size-7 size-6"),
17+
rx.el.span(
18+
title,
19+
class_name="text-m-slate-12 dark:text-m-slate-3 lg:text-lg text-base font-[575]",
20+
),
21+
class_name="flex flex-row items-center gap-3 lg:p-12 p-6 border-y border-r border-m-slate-4 dark:border-m-slate-10",
22+
)
23+
24+
25+
def pros_card(pros: list[str]) -> rx.Component:
26+
return rx.el.ul(
27+
*[
28+
rx.el.li(
29+
ui.icon(
30+
"Tick02Icon",
31+
class_name="shrink-0 text-primary-9 dark:text-primary-10 h-[1.5rem]",
32+
),
33+
rx.el.span(
34+
pro,
35+
class_name="text-m-slate-12 dark:text-m-slate-3 text-sm font-[525]",
36+
),
37+
class_name="flex flex-row items-start gap-2.5",
38+
)
39+
for pro in pros
40+
],
41+
class_name="list-inside flex flex-col gap-2 lg:p-12 p-6 [box-shadow:0_0_0_1px_rgba(0,_0,_0,_0.12)_inset,_0_6px_12px_0_rgba(0,_0,_0,_0.06),_0_1px_1px_0_rgba(0,_0,_0,_0.01),_0_4px_6px_0_rgba(0,_0,_0,_0.02)] dark:shadow-none rounded-xl bg-white-1 dark:bg-m-slate-11 w-full",
42+
)
43+
44+
45+
def cons_card(cons: list[str]) -> rx.Component:
46+
return rx.el.ul(
47+
*[
48+
rx.el.li(
49+
ui.icon(
50+
"MultiplicationSignIcon",
51+
stroke_width=1.5,
52+
class_name="shrink-0 text-m-slate-7 dark:text-m-slate-6 h-[1.5rem]",
53+
),
54+
rx.el.span(
55+
con,
56+
class_name="text-m-slate-7 dark:text-m-slate-6 text-sm font-[525]",
57+
),
58+
class_name="flex flex-row items-start gap-2.5",
59+
)
60+
for con in cons
61+
],
62+
class_name="list-inside flex flex-col gap-2 lg:p-12 p-6 w-full lg:border-x border-l border-m-slate-4 dark:border-m-slate-10",
63+
)
64+
65+
66+
def pros_cons_cards(pros: list[str], cons: list[str]) -> rx.Component:
67+
return rx.el.div(
68+
pros_card(pros),
69+
cons_card(cons),
70+
class_name="grid lg:grid-cols-2 grid-cols-1 max-lg:border-r",
71+
)
72+
73+
74+
def top_title(title: str) -> rx.Component:
75+
return rx.el.span(
76+
title,
77+
class_name="text-m-slate-12 dark:text-m-slate-3 text-xs leading-[1.5rem] font-medium font-mono border-r border-m-slate-4 dark:border-m-slate-10 lg:px-8 lg:py-3 p-6 bg-secondary-1 dark:bg-m-slate-10 border-t",
78+
)
79+
80+
81+
def heading_with_breaks(lines: list[str]) -> list[rx.Component | str]:
82+
heading_parts: list[rx.Component | str] = []
83+
for index, line in enumerate(lines):
84+
heading_parts.append(line)
85+
if index < len(lines) - 1:
86+
heading_parts.append(rx.el.br(class_name="max-lg:hidden"))
87+
return heading_parts
88+
89+
90+
def comparison_cards(
91+
top_left_title: str,
92+
top_right_title: str,
93+
comparison_items: list[ComparisonItem],
94+
) -> rx.Component:
95+
return rx.el.div(
96+
rx.el.div(
97+
top_title(top_left_title),
98+
top_title(top_right_title),
99+
class_name="grid grid-cols-2",
100+
),
101+
*[
102+
rx.fragment(
103+
comparison_title(item["title"], item["icon"]),
104+
pros_cons_cards(item["pros"], item["cons"]),
105+
)
106+
for item in comparison_items
107+
],
108+
rx.el.div(
109+
class_name="absolute -top-24 right-0 w-px h-24 bg-gradient-to-b from-transparent to-current text-m-slate-4 dark:text-m-slate-10 max-lg:hidden"
110+
),
111+
rx.el.div(
112+
class_name="absolute -top-24 -left-px w-px h-24 bg-gradient-to-b from-transparent to-current text-m-slate-4 dark:text-m-slate-10 max-lg:hidden"
113+
),
114+
rx.el.div(
115+
class_name="absolute -bottom-24 right-0 w-px h-24 bg-gradient-to-b from-current to-transparent text-m-slate-4 dark:text-m-slate-10"
116+
),
117+
rx.el.div(
118+
class_name="absolute -bottom-24 -left-px w-px h-24 bg-gradient-to-b from-current to-transparent text-m-slate-4 dark:text-m-slate-10"
119+
),
120+
class_name="flex flex-col w-full max-w-[45rem] ml-auto border-l border-m-slate-4 dark:border-m-slate-10 mt-18 border-b mb-24 relative",
121+
)
122+
123+
124+
def compare(
125+
*,
126+
kicker: str,
127+
heading_lines: list[str],
128+
description: str,
129+
top_left_title: str,
130+
top_right_title: str,
131+
comparison_items: list[ComparisonItem],
132+
) -> rx.Component:
133+
return rx.el.section(
134+
rx.el.div(
135+
rx.el.div(
136+
rx.el.p(
137+
kicker,
138+
class_name="text-sm font-[525] text-primary-10 max-lg:text-center dark:text-m-slate-6",
139+
),
140+
rx.el.h1(
141+
*heading_with_breaks(heading_lines),
142+
class_name="text-m-slate-12 dark:text-m-slate-3 text-3xl font-[575]",
143+
),
144+
rx.el.h2(
145+
description,
146+
class_name="text-m-slate-7 dark:text-m-slate-6 text-base font-[475]",
147+
),
148+
class_name="flex flex-col gap-6 lg:max-w-[18rem] lg:sticky lg:top-[11rem] lg:self-start max-lg:self-center max-lg:items-center max-lg:text-center",
149+
),
150+
comparison_cards(top_left_title, top_right_title, comparison_items),
151+
class_name="flex lg:flex-row flex-col max-lg:gap-6 max-w-(--docs-layout-max-width) mx-auto relative py-24 max-lg:px-6",
152+
),
153+
class_name="bg-gradient-to-b from-white-1 to-m-slate-1 dark:from-m-slate-11 dark:to-m-slate-12 w-full relative",
154+
)
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
from typing import TypedDict
2+
3+
import reflex as rx
4+
import reflex_ui as ui
5+
6+
7+
class Feature(TypedDict):
8+
title: str
9+
description: str
10+
icon: str
11+
12+
13+
def feature_card(feature: Feature) -> rx.Component:
14+
return rx.el.div(
15+
rx.el.div(
16+
ui.icon(
17+
feature["icon"], class_name="text-primary-10 dark:text-primary-9 size-5"
18+
),
19+
rx.el.span(
20+
feature["title"],
21+
class_name="text-m-slate-12 dark:text-m-slate-3 text-sm font-[525]",
22+
),
23+
class_name="flex flex-row gap-2.5 items-center",
24+
),
25+
rx.el.p(
26+
feature["description"],
27+
class_name="text-m-slate-7 dark:text-m-slate-6 text-sm font-[475] text-start",
28+
),
29+
class_name="flex flex-col gap-2 justify-start",
30+
)
31+
32+
33+
def feature_grid(features: list[Feature]) -> rx.Component:
34+
return rx.el.div(
35+
*[feature_card(feature) for feature in features],
36+
class_name="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-x-12 gap-y-16",
37+
)
38+
39+
40+
def explore(
41+
*,
42+
kicker: str,
43+
title_prefix: str,
44+
title_suffix: str,
45+
description: str,
46+
features: list[Feature],
47+
) -> rx.Component:
48+
return rx.el.section(
49+
rx.el.div(
50+
rx.el.div(
51+
rx.el.p(
52+
kicker,
53+
class_name="text-sm font-[525] text-primary-10 max-lg:text-center dark:text-m-slate-6",
54+
),
55+
rx.el.div(
56+
rx.el.h1(
57+
title_prefix,
58+
rx.el.br(),
59+
title_suffix,
60+
class_name="text-m-slate-12 dark:text-m-slate-3 lg:text-4xl text-3xl font-[575] shrink-0",
61+
),
62+
rx.el.p(
63+
description,
64+
class_name="text-base text-m-slate-7 dark:text-m-slate-6 font-[475]",
65+
),
66+
class_name="flex lg:flex-row flex-col gap-8 lg:gap-36",
67+
),
68+
class_name="relative flex flex-col gap-6 lg:py-24 py-16",
69+
),
70+
feature_grid(features),
71+
class_name="flex flex-col gap-16 max-w-(--layout-max-width) mx-auto lg:px-24 px-6 max-lg:text-center relative lg:pb-24 pb-16",
72+
),
73+
class_name="bg-gradient-to-b from-white-1 to-m-slate-1 dark:from-m-slate-11 dark:to-m-slate-12 w-full",
74+
)
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
from typing import TypedDict
2+
3+
import reflex as rx
4+
import reflex_ui as ui
5+
from reflex_ui.blocks.demo_form import demo_form_dialog
6+
7+
from pcweb.components.marketing_button import button
8+
9+
10+
class HeroLogo(TypedDict):
11+
image_name: str
12+
alt: str
13+
class_name: str
14+
15+
16+
def floating_logo(logo: HeroLogo, logo_base_path: str) -> rx.Component:
17+
return rx.el.div(
18+
rx.image(
19+
src=f"{logo_base_path}/{rx.color_mode_cond('light', 'dark')}/{logo['image_name']}",
20+
alt=logo["alt"],
21+
loading="eager",
22+
custom_attrs={"fetchPriority": "high"},
23+
),
24+
class_name=ui.cn(
25+
logo["class_name"],
26+
"absolute left-1/2 -translate-x-1/2 -translate-y-1/2 z-[-1] pointer-events-none size-16 rounded-[1rem] bg-m-slate-1 dark:bg-m-slate-12 [box-shadow:0_1px_0_0_#FFF_inset,_0_0_0_1px_rgba(0,_0,_0,_0.12),_0_8px_16px_0_rgba(0,_0,_0,_0.06),_0_1px_1px_0_rgba(0,_0,_0,_0.01),_0_4px_8px_0_rgba(0,_0,_0,_0.02)] dark:shadow-none dark:border dark:border-m-slate-9 flex items-center justify-center",
27+
),
28+
)
29+
30+
31+
def gradient_logo() -> rx.Component:
32+
return rx.el.div(
33+
rx.image(
34+
src=f"/logos/{rx.color_mode_cond('light', 'dark')}/gradient_r.svg",
35+
alt="Gradient Reflex Logo",
36+
loading="eager",
37+
custom_attrs={"fetchPriority": "high"},
38+
),
39+
class_name="size-24 rounded-[1rem] bg-gradient-to-b from-m-slate-2 to-white-1 dark:from-m-slate-11 dark:to-m-slate-12 [box-shadow:0_1px_0_0_#FFF_inset,_0_0_0_1px_rgba(0,_0,_0,_0.12),_0_8px_16px_0_rgba(0,_0,_0,_0.06),_0_1px_1px_0_rgba(0,_0,_0,_0.01),_0_4px_8px_0_rgba(0,_0,_0,_0.02)] dark:shadow-none dark:border dark:border-m-slate-9 flex items-center justify-center absolute left-1/2 -translate-x-1/2 -translate-y-1/2 z-[1] pointer-events-none top-[13.5rem]",
40+
)
41+
42+
43+
def hero(
44+
*,
45+
kicker: str,
46+
title: str,
47+
subtitle: str,
48+
cta_text: str,
49+
logos: list[HeroLogo],
50+
logo_base_path: str,
51+
) -> rx.Component:
52+
return rx.el.section(
53+
rx.el.div(
54+
rx.el.div(
55+
rx.image(
56+
src=f"/common/{rx.color_mode_cond('light', 'dark')}/grid.svg",
57+
alt="Grid",
58+
loading="eager",
59+
custom_attrs={"fetchPriority": "high"},
60+
class_name=ui.cn(
61+
"absolute left-1/2 -translate-x-1/2 z-[-1] pointer-events-none top-0",
62+
),
63+
),
64+
*[floating_logo(logo, logo_base_path=logo_base_path) for logo in logos],
65+
gradient_logo(),
66+
class_name="max-lg:hidden",
67+
),
68+
rx.el.p(
69+
kicker,
70+
class_name="text-sm font-[525] text-primary-10 dark:text-m-slate-6 -mt-6",
71+
),
72+
rx.el.h1(
73+
title,
74+
class_name="text-m-slate-12 dark:text-m-slate-3 lg:text-5xl text-3xl font-[575]",
75+
),
76+
rx.el.h2(
77+
subtitle,
78+
class_name="text-m-slate-7 dark:text-m-slate-6 text-base font-[475]",
79+
),
80+
demo_form_dialog(
81+
trigger=button(
82+
cta_text,
83+
variant="primary",
84+
size="lg",
85+
native_button=False,
86+
),
87+
),
88+
rx.el.div(
89+
class_name="absolute -bottom-px -right-24 w-24 h-px bg-gradient-to-l from-transparent to-current text-m-slate-4 dark:text-m-slate-10"
90+
),
91+
rx.el.div(
92+
class_name="absolute -bottom-px -left-24 w-24 h-px bg-gradient-to-r from-transparent to-current text-m-slate-4 dark:text-m-slate-10"
93+
),
94+
class_name=ui.cn(
95+
"flex flex-col gap-6 items-center justify-center text-center max-w-[45rem] pb-16 border-b border-m-slate-4 dark:border-m-slate-10 relative isolate lg:pt-[21.75rem] pt-[10.5rem]",
96+
),
97+
),
98+
class_name=ui.cn(
99+
"flex lg:flex-row flex-col max-w-(--layout-max-width) mx-auto lg:px-24 px-6 overflow-hidden",
100+
),
101+
)

0 commit comments

Comments
 (0)