reflex-site-shared 0.0.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- reflex_site_shared/__init__.py +1 -0
- reflex_site_shared/backend/__init__.py +1 -0
- reflex_site_shared/backend/get_blogs.py +44 -0
- reflex_site_shared/backend/signup.py +112 -0
- reflex_site_shared/components/__init__.py +1 -0
- reflex_site_shared/components/blocks/__init__.py +6 -0
- reflex_site_shared/components/blocks/code.py +111 -0
- reflex_site_shared/components/blocks/collapsible.py +63 -0
- reflex_site_shared/components/blocks/demo.py +173 -0
- reflex_site_shared/components/blocks/flexdown.py +170 -0
- reflex_site_shared/components/blocks/headings.py +274 -0
- reflex_site_shared/components/blocks/typography.py +135 -0
- reflex_site_shared/components/code_card.py +206 -0
- reflex_site_shared/components/docs.py +122 -0
- reflex_site_shared/components/hosting_banner.py +5 -0
- reflex_site_shared/components/icons.py +698 -0
- reflex_site_shared/components/image_zoom.py +23 -0
- reflex_site_shared/components/marketing_button.py +41 -0
- reflex_site_shared/components/marquee.py +33 -0
- reflex_site_shared/components/patterns.py +125 -0
- reflex_site_shared/constants.py +38 -0
- reflex_site_shared/gallery/__init__.py +3 -0
- reflex_site_shared/gallery/apps.py +306 -0
- reflex_site_shared/gallery/common.py +278 -0
- reflex_site_shared/gallery/gallery.py +301 -0
- reflex_site_shared/gallery/r_svg_loader.py +140 -0
- reflex_site_shared/gallery/sidebar.py +238 -0
- reflex_site_shared/gallery/templates/api-admin-panel.md +34 -0
- reflex_site_shared/gallery/templates/chat-app.md +42 -0
- reflex_site_shared/gallery/templates/ci-job.md +30 -0
- reflex_site_shared/gallery/templates/customer-app.md +50 -0
- reflex_site_shared/gallery/templates/dalle.md +37 -0
- reflex_site_shared/gallery/templates/dashboard.md +48 -0
- reflex_site_shared/gallery/templates/image-gen.md +41 -0
- reflex_site_shared/gallery/templates/llamaindex-app.md +68 -0
- reflex_site_shared/gallery/templates/nba-app.md +29 -0
- reflex_site_shared/gallery/templates/sales-app.md +40 -0
- reflex_site_shared/lib/__init__.py +1 -0
- reflex_site_shared/lib/meta/__init__.py +1 -0
- reflex_site_shared/lib/meta/meta.py +362 -0
- reflex_site_shared/lib/route.py +61 -0
- reflex_site_shared/meta/__init__.py +1 -0
- reflex_site_shared/meta/meta.py +362 -0
- reflex_site_shared/pages/__init__.py +1 -0
- reflex_site_shared/pages/page404.py +24 -0
- reflex_site_shared/route.py +5 -0
- reflex_site_shared/styles/__init__.py +3 -0
- reflex_site_shared/styles/colors.py +17 -0
- reflex_site_shared/styles/custom-colors.css +182 -0
- reflex_site_shared/styles/fonts.py +95 -0
- reflex_site_shared/styles/globals.css +2051 -0
- reflex_site_shared/styles/shadows.py +8 -0
- reflex_site_shared/styles/styles.py +81 -0
- reflex_site_shared/telemetry/__init__.py +3 -0
- reflex_site_shared/telemetry/pixels.py +30 -0
- reflex_site_shared/templates/__init__.py +1 -0
- reflex_site_shared/templates/gallery_app_page.py +89 -0
- reflex_site_shared/templates/marketing_page.py +101 -0
- reflex_site_shared/templates/webpage.py +92 -0
- reflex_site_shared/utils/__init__.py +1 -0
- reflex_site_shared/utils/docpage.py +120 -0
- reflex_site_shared/utils/md.py +52 -0
- reflex_site_shared/views/__init__.py +1 -0
- reflex_site_shared/views/cta_card.py +55 -0
- reflex_site_shared/views/footer.py +317 -0
- reflex_site_shared/views/hosting_banner.py +154 -0
- reflex_site_shared/views/marketing_navbar.py +650 -0
- reflex_site_shared/views/sidebar/__init__.py +203 -0
- reflex_site_shared-0.0.1.dist-info/METADATA +14 -0
- reflex_site_shared-0.0.1.dist-info/RECORD +71 -0
- reflex_site_shared-0.0.1.dist-info/WHEEL +4 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Reflex Site Shared module."""
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Backend module."""
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"""Get Blogs module."""
|
|
2
|
+
|
|
3
|
+
from typing import TypedDict
|
|
4
|
+
|
|
5
|
+
import httpx
|
|
6
|
+
|
|
7
|
+
import reflex as rx
|
|
8
|
+
from reflex_site_shared.constants import RECENT_BLOGS_API_URL
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class BlogPostDict(TypedDict):
|
|
12
|
+
"""BlogPostDict."""
|
|
13
|
+
|
|
14
|
+
title: str
|
|
15
|
+
description: str
|
|
16
|
+
author: str
|
|
17
|
+
date: str
|
|
18
|
+
image: str
|
|
19
|
+
tag: str
|
|
20
|
+
url: str
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class RecentBlogsState(rx.State):
|
|
24
|
+
"""RecentBlogsState."""
|
|
25
|
+
|
|
26
|
+
posts: rx.Field[list[BlogPostDict]] = rx.field(default_factory=list)
|
|
27
|
+
_fetched: bool = False
|
|
28
|
+
|
|
29
|
+
@rx.event(background=True, temporal=True)
|
|
30
|
+
async def fetch_recent_blogs(self):
|
|
31
|
+
"""Fetch recent blogs."""
|
|
32
|
+
if self._fetched:
|
|
33
|
+
return
|
|
34
|
+
try:
|
|
35
|
+
async with httpx.AsyncClient() as client:
|
|
36
|
+
resp = await client.get(RECENT_BLOGS_API_URL, timeout=10)
|
|
37
|
+
resp.raise_for_status()
|
|
38
|
+
data = resp.json()
|
|
39
|
+
async with self:
|
|
40
|
+
self.posts = data.get("posts", [])
|
|
41
|
+
self._fetched = True
|
|
42
|
+
except Exception:
|
|
43
|
+
async with self:
|
|
44
|
+
self.posts = []
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
"""Signup module."""
|
|
2
|
+
|
|
3
|
+
import contextlib
|
|
4
|
+
import os
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
import httpx
|
|
8
|
+
from email_validator import EmailNotValidError, ValidatedEmail, validate_email
|
|
9
|
+
|
|
10
|
+
import reflex as rx
|
|
11
|
+
from reflex_site_shared.constants import (
|
|
12
|
+
API_BASE_URL_LOOPS,
|
|
13
|
+
REFLEX_DEV_WEB_NEWSLETTER_FORM_WEBHOOK_URL,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class IndexState(rx.State):
|
|
18
|
+
"""Hold the state for the home page."""
|
|
19
|
+
|
|
20
|
+
# Whether the user signed up for the newsletter.
|
|
21
|
+
signed_up: bool = False
|
|
22
|
+
|
|
23
|
+
# Whether to show the confetti.
|
|
24
|
+
show_confetti: bool = False
|
|
25
|
+
|
|
26
|
+
@rx.event(background=True)
|
|
27
|
+
async def send_contact_to_webhook(
|
|
28
|
+
self,
|
|
29
|
+
email: str | None,
|
|
30
|
+
) -> None:
|
|
31
|
+
"""Send contact to webhook."""
|
|
32
|
+
with contextlib.suppress(httpx.HTTPError):
|
|
33
|
+
async with httpx.AsyncClient() as client:
|
|
34
|
+
response = await client.post(
|
|
35
|
+
REFLEX_DEV_WEB_NEWSLETTER_FORM_WEBHOOK_URL,
|
|
36
|
+
json={
|
|
37
|
+
"email": email,
|
|
38
|
+
},
|
|
39
|
+
)
|
|
40
|
+
response.raise_for_status()
|
|
41
|
+
|
|
42
|
+
@rx.event(background=True)
|
|
43
|
+
async def add_contact_to_loops(
|
|
44
|
+
self,
|
|
45
|
+
email: str | None,
|
|
46
|
+
):
|
|
47
|
+
"""Add contact to loops."""
|
|
48
|
+
url: str = f"{API_BASE_URL_LOOPS}/contacts/create"
|
|
49
|
+
loops_api_key: str | None = os.getenv("LOOPS_API_KEY")
|
|
50
|
+
if loops_api_key is None:
|
|
51
|
+
return
|
|
52
|
+
|
|
53
|
+
headers = {
|
|
54
|
+
"Accept": "application/json",
|
|
55
|
+
"Authorization": f"Bearer {loops_api_key}",
|
|
56
|
+
}
|
|
57
|
+
try:
|
|
58
|
+
async with httpx.AsyncClient() as client:
|
|
59
|
+
response = await client.post(
|
|
60
|
+
url,
|
|
61
|
+
headers=headers,
|
|
62
|
+
json={
|
|
63
|
+
"email": email,
|
|
64
|
+
},
|
|
65
|
+
)
|
|
66
|
+
response.raise_for_status() # Raise an exception for HTTP errors (4xx and 5xx)
|
|
67
|
+
|
|
68
|
+
except httpx.HTTPError:
|
|
69
|
+
pass
|
|
70
|
+
|
|
71
|
+
@rx.event
|
|
72
|
+
def signup_for_another_user(self):
|
|
73
|
+
"""Signup for another user."""
|
|
74
|
+
self.signed_up = False
|
|
75
|
+
|
|
76
|
+
@rx.event(background=True)
|
|
77
|
+
async def signup(
|
|
78
|
+
self,
|
|
79
|
+
form_data: dict[str, Any],
|
|
80
|
+
):
|
|
81
|
+
"""Sign the user up for the newsletter.
|
|
82
|
+
|
|
83
|
+
Yields:
|
|
84
|
+
The event actions.
|
|
85
|
+
"""
|
|
86
|
+
email: str | None = None
|
|
87
|
+
if email_to_validate := form_data.get("input_email"):
|
|
88
|
+
try:
|
|
89
|
+
validated_email: ValidatedEmail = validate_email(
|
|
90
|
+
email_to_validate,
|
|
91
|
+
check_deliverability=True,
|
|
92
|
+
)
|
|
93
|
+
email = validated_email.normalized
|
|
94
|
+
|
|
95
|
+
except EmailNotValidError as e:
|
|
96
|
+
# Alert the error message.
|
|
97
|
+
yield rx.toast.warning(
|
|
98
|
+
str(e),
|
|
99
|
+
style={
|
|
100
|
+
"border": "1px solid #3C3646",
|
|
101
|
+
"background": "linear-gradient(218deg, #1D1B23 -35.66%, #131217 100.84%)",
|
|
102
|
+
},
|
|
103
|
+
)
|
|
104
|
+
return
|
|
105
|
+
yield IndexState.send_contact_to_webhook(email)
|
|
106
|
+
yield IndexState.add_contact_to_loops(email)
|
|
107
|
+
async with self:
|
|
108
|
+
self.signed_up = True
|
|
109
|
+
yield
|
|
110
|
+
yield [
|
|
111
|
+
rx.toast.success("Thanks for signing up to the Newsletter!"),
|
|
112
|
+
]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Components module."""
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
"""Code block components for documentation pages."""
|
|
2
|
+
|
|
3
|
+
import reflex as rx
|
|
4
|
+
import reflex_site_shared.styles.fonts as fonts
|
|
5
|
+
from reflex_site_shared import styles
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@rx.memo
|
|
9
|
+
def code_block(code: str, language: str):
|
|
10
|
+
"""Code block.
|
|
11
|
+
|
|
12
|
+
Returns:
|
|
13
|
+
The component.
|
|
14
|
+
"""
|
|
15
|
+
return rx.box(
|
|
16
|
+
rx._x.code_block(
|
|
17
|
+
code,
|
|
18
|
+
language=language,
|
|
19
|
+
class_name="code-block",
|
|
20
|
+
can_copy=True,
|
|
21
|
+
),
|
|
22
|
+
class_name="relative mb-4",
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@rx.memo
|
|
27
|
+
def code_block_dark(code: str, language: str):
|
|
28
|
+
"""Code block dark.
|
|
29
|
+
|
|
30
|
+
Returns:
|
|
31
|
+
The component.
|
|
32
|
+
"""
|
|
33
|
+
return rx.box(
|
|
34
|
+
rx._x.code_block(
|
|
35
|
+
code,
|
|
36
|
+
language=language,
|
|
37
|
+
class_name="code-block",
|
|
38
|
+
can_copy=True,
|
|
39
|
+
),
|
|
40
|
+
class_name="relative mb-4",
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def code_block_markdown(*children, **props):
|
|
45
|
+
"""Code block markdown.
|
|
46
|
+
|
|
47
|
+
Returns:
|
|
48
|
+
The component.
|
|
49
|
+
"""
|
|
50
|
+
language = props.get("language", "plain")
|
|
51
|
+
return code_block(code=children[0], language=language)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def code_block_markdown_dark(*children, **props):
|
|
55
|
+
"""Code block markdown dark.
|
|
56
|
+
|
|
57
|
+
Returns:
|
|
58
|
+
The component.
|
|
59
|
+
"""
|
|
60
|
+
language = props.get("language", "plain")
|
|
61
|
+
return code_block_dark(code=children[0], language=language)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def doccmdoutput(
|
|
65
|
+
command: str,
|
|
66
|
+
output: str,
|
|
67
|
+
) -> rx.Component:
|
|
68
|
+
"""Create a documentation code snippet.
|
|
69
|
+
|
|
70
|
+
Args:
|
|
71
|
+
command: The command to display.
|
|
72
|
+
output: The output of the command.
|
|
73
|
+
|
|
74
|
+
Returns:
|
|
75
|
+
The styled command and its example output.
|
|
76
|
+
"""
|
|
77
|
+
return rx.vstack(
|
|
78
|
+
rx._x.code_block(
|
|
79
|
+
command,
|
|
80
|
+
can_copy=True,
|
|
81
|
+
border_radius=styles.DOC_BORDER_RADIUS,
|
|
82
|
+
background="transparent",
|
|
83
|
+
theme="ayu-dark",
|
|
84
|
+
language="bash",
|
|
85
|
+
code_tag_props={
|
|
86
|
+
"style": {
|
|
87
|
+
"fontFamily": "inherit",
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
style=fonts.code,
|
|
91
|
+
font_family="JetBrains Mono",
|
|
92
|
+
width="100%",
|
|
93
|
+
),
|
|
94
|
+
rx._x.code_block(
|
|
95
|
+
output,
|
|
96
|
+
can_copy=False,
|
|
97
|
+
border_radius="12px",
|
|
98
|
+
background="transparent",
|
|
99
|
+
theme="ayu-dark",
|
|
100
|
+
language="log",
|
|
101
|
+
code_tag_props={
|
|
102
|
+
"style": {
|
|
103
|
+
"fontFamily": "inherit",
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
style=fonts.code,
|
|
107
|
+
font_family="JetBrains Mono",
|
|
108
|
+
width="100%",
|
|
109
|
+
),
|
|
110
|
+
padding_y="1em",
|
|
111
|
+
)
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"""Collapsible accordion box used by alert and video blocks."""
|
|
2
|
+
|
|
3
|
+
from collections.abc import Sequence
|
|
4
|
+
|
|
5
|
+
from reflex_base.constants.colors import ColorType
|
|
6
|
+
|
|
7
|
+
import reflex as rx
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def collapsible_box(
|
|
11
|
+
trigger_children: Sequence[rx.Component],
|
|
12
|
+
body: rx.Component,
|
|
13
|
+
color: ColorType,
|
|
14
|
+
*,
|
|
15
|
+
item_border_radius: str = "12px",
|
|
16
|
+
) -> rx.Component:
|
|
17
|
+
"""Collapsible accordion wrapper shared by alert and video directives.
|
|
18
|
+
|
|
19
|
+
Returns:
|
|
20
|
+
The component.
|
|
21
|
+
"""
|
|
22
|
+
return rx.box(
|
|
23
|
+
rx.accordion.root(
|
|
24
|
+
rx.accordion.item(
|
|
25
|
+
rx.accordion.header(
|
|
26
|
+
rx.accordion.trigger(
|
|
27
|
+
rx.hstack(
|
|
28
|
+
*trigger_children,
|
|
29
|
+
rx.spacer(),
|
|
30
|
+
rx.accordion.icon(color=f"{rx.color(color, 11)}"),
|
|
31
|
+
align_items="center",
|
|
32
|
+
justify_content="left",
|
|
33
|
+
text_align="left",
|
|
34
|
+
spacing="2",
|
|
35
|
+
width="100%",
|
|
36
|
+
),
|
|
37
|
+
padding="0px",
|
|
38
|
+
color=f"{rx.color(color, 11)} !important",
|
|
39
|
+
background_color="transparent !important",
|
|
40
|
+
border_radius="12px",
|
|
41
|
+
_hover={},
|
|
42
|
+
),
|
|
43
|
+
),
|
|
44
|
+
body,
|
|
45
|
+
border_radius=item_border_radius,
|
|
46
|
+
padding=["16px", "24px"],
|
|
47
|
+
background_color=f"{rx.color(color, 3)}",
|
|
48
|
+
border="none",
|
|
49
|
+
),
|
|
50
|
+
background="transparent !important",
|
|
51
|
+
border_radius="12px",
|
|
52
|
+
box_shadow="none !important",
|
|
53
|
+
collapsible=True,
|
|
54
|
+
width="100%",
|
|
55
|
+
),
|
|
56
|
+
border=f"1px solid {rx.color(color, 4)}",
|
|
57
|
+
border_radius="12px",
|
|
58
|
+
background_color=f"{rx.color(color, 3)} !important",
|
|
59
|
+
width="100%",
|
|
60
|
+
margin_bottom="16px",
|
|
61
|
+
margin_top="16px",
|
|
62
|
+
overflow="hidden",
|
|
63
|
+
)
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
"""Components for rendering code demos in the documentation."""
|
|
2
|
+
|
|
3
|
+
import textwrap
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
import ruff_format
|
|
7
|
+
|
|
8
|
+
import reflex as rx
|
|
9
|
+
|
|
10
|
+
from .code import code_block, code_block_dark
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def docdemobox(*children, **props) -> rx.Component:
|
|
14
|
+
"""Create a documentation demo box with the output of the code.
|
|
15
|
+
|
|
16
|
+
Args:
|
|
17
|
+
children: The children to display.
|
|
18
|
+
props: Additional props to apply to the box.
|
|
19
|
+
|
|
20
|
+
Returns:
|
|
21
|
+
The styled demo box.
|
|
22
|
+
"""
|
|
23
|
+
return rx.box(
|
|
24
|
+
*children,
|
|
25
|
+
**props,
|
|
26
|
+
class_name="flex flex-col p-6 rounded-xl overflow-x-auto border border-slate-4 bg-slate-2 items-center justify-center w-full",
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def doccode(
|
|
31
|
+
code: str,
|
|
32
|
+
language: str = "python",
|
|
33
|
+
lines: tuple[int, int] | None = None,
|
|
34
|
+
theme: str = "light",
|
|
35
|
+
) -> rx.Component:
|
|
36
|
+
"""Create a documentation code snippet.
|
|
37
|
+
|
|
38
|
+
Args:
|
|
39
|
+
code: The code to display.
|
|
40
|
+
language: The language of the code.
|
|
41
|
+
lines: The start/end lines to display.
|
|
42
|
+
theme: The theme for the code snippet.
|
|
43
|
+
|
|
44
|
+
Returns:
|
|
45
|
+
The styled code snippet.
|
|
46
|
+
"""
|
|
47
|
+
# For Python snippets, lint the code with black.
|
|
48
|
+
if language == "python":
|
|
49
|
+
code = ruff_format.format_string(textwrap.dedent(code)).strip()
|
|
50
|
+
|
|
51
|
+
# If needed, only display a subset of the lines.
|
|
52
|
+
if lines is not None:
|
|
53
|
+
code = textwrap.dedent(
|
|
54
|
+
"\n".join(code.strip().splitlines()[lines[0] : lines[1]])
|
|
55
|
+
).strip()
|
|
56
|
+
|
|
57
|
+
# Create the code snippet.
|
|
58
|
+
cb = code_block_dark if theme == "dark" else code_block
|
|
59
|
+
return cb(
|
|
60
|
+
code=code,
|
|
61
|
+
language=language,
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def docdemo(
|
|
66
|
+
code: str,
|
|
67
|
+
state: str | None = None,
|
|
68
|
+
comp: rx.Component | None = None,
|
|
69
|
+
context: bool = False,
|
|
70
|
+
demobox_props: dict[str, Any] | None = None,
|
|
71
|
+
theme: str | None = None,
|
|
72
|
+
**props,
|
|
73
|
+
) -> rx.Component:
|
|
74
|
+
"""Create a documentation demo with code and output.
|
|
75
|
+
|
|
76
|
+
Args:
|
|
77
|
+
code: The code to render the component.
|
|
78
|
+
state: Code for any state needed for the component.
|
|
79
|
+
comp: The pre-rendered component.
|
|
80
|
+
context: Whether to wrap the render code in a function.
|
|
81
|
+
demobox_props: Props to apply to the demo box.
|
|
82
|
+
theme: The theme for the code snippet.
|
|
83
|
+
props: Additional props to apply to the component.
|
|
84
|
+
|
|
85
|
+
Returns:
|
|
86
|
+
The styled demo.
|
|
87
|
+
"""
|
|
88
|
+
demobox_props = demobox_props or {}
|
|
89
|
+
# Render the component if necessary.
|
|
90
|
+
if comp is None:
|
|
91
|
+
comp = eval(code)
|
|
92
|
+
|
|
93
|
+
# Wrap the render code in a function if needed.
|
|
94
|
+
if context:
|
|
95
|
+
code = f"""def index():
|
|
96
|
+
return {code}
|
|
97
|
+
"""
|
|
98
|
+
|
|
99
|
+
# Add the state code
|
|
100
|
+
if state is not None:
|
|
101
|
+
code = state + code
|
|
102
|
+
|
|
103
|
+
if demobox_props.pop("toggle", False):
|
|
104
|
+
return rx.tabs.root(
|
|
105
|
+
rx.tabs.list(
|
|
106
|
+
rx.tabs.trigger(
|
|
107
|
+
rx.box(
|
|
108
|
+
"UI",
|
|
109
|
+
),
|
|
110
|
+
value="tab1",
|
|
111
|
+
class_name="tab-style",
|
|
112
|
+
),
|
|
113
|
+
rx.tabs.trigger(
|
|
114
|
+
rx.box(
|
|
115
|
+
"Code",
|
|
116
|
+
),
|
|
117
|
+
value="tab2",
|
|
118
|
+
class_name="tab-style",
|
|
119
|
+
),
|
|
120
|
+
class_name="justify-end",
|
|
121
|
+
),
|
|
122
|
+
rx.tabs.content(
|
|
123
|
+
rx.box(docdemobox(comp, **(demobox_props or {})), class_name="my-4"),
|
|
124
|
+
value="tab1",
|
|
125
|
+
),
|
|
126
|
+
rx.tabs.content(
|
|
127
|
+
rx.box(doccode(code, theme=theme or "light"), class_name="my-4"),
|
|
128
|
+
value="tab2",
|
|
129
|
+
),
|
|
130
|
+
default_value="tab1",
|
|
131
|
+
)
|
|
132
|
+
# Create the demo.
|
|
133
|
+
return rx.box(
|
|
134
|
+
docdemobox(comp, **(demobox_props or {})),
|
|
135
|
+
doccode(code, theme=theme or "light"),
|
|
136
|
+
class_name="py-4 gap-4 flex flex-col w-full",
|
|
137
|
+
**props,
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def docgraphing(
|
|
142
|
+
code: str,
|
|
143
|
+
comp: rx.Component | None = None,
|
|
144
|
+
data: str | None = None,
|
|
145
|
+
):
|
|
146
|
+
"""Docgraphing.
|
|
147
|
+
|
|
148
|
+
Returns:
|
|
149
|
+
The component.
|
|
150
|
+
"""
|
|
151
|
+
return rx.box(
|
|
152
|
+
rx.flex(
|
|
153
|
+
comp,
|
|
154
|
+
class_name="w-full flex flex-col p-6 rounded-xl overflow-x-auto border border-slate-4 bg-slate-2 items-center justify-center",
|
|
155
|
+
),
|
|
156
|
+
rx.tabs.root(
|
|
157
|
+
rx.tabs.list(
|
|
158
|
+
rx.tabs.trigger("Code", value="code", class_name="tab-style"),
|
|
159
|
+
rx.tabs.trigger("Data", value="data", class_name="tab-style"),
|
|
160
|
+
justify_content="end",
|
|
161
|
+
),
|
|
162
|
+
rx.box(
|
|
163
|
+
rx.tabs.content(doccode(code), value="code", class_name="w-full px-0"),
|
|
164
|
+
rx.tabs.content(
|
|
165
|
+
doccode(data or ""), value="data", class_name="w-full px-0"
|
|
166
|
+
),
|
|
167
|
+
class_name="w-full my-4",
|
|
168
|
+
),
|
|
169
|
+
default_value="code",
|
|
170
|
+
class_name="w-full mt-6 justify-end",
|
|
171
|
+
),
|
|
172
|
+
class_name="w-full py-4 flex flex-col",
|
|
173
|
+
)
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
"""Flexdown module — component maps and markdown helpers."""
|
|
2
|
+
|
|
3
|
+
# pyright: reportAttributeAccessIssue=false
|
|
4
|
+
from reflex_base.constants.colors import ColorType
|
|
5
|
+
|
|
6
|
+
import reflex as rx
|
|
7
|
+
from reflex_site_shared.components.blocks.code import (
|
|
8
|
+
code_block_markdown,
|
|
9
|
+
code_block_markdown_dark,
|
|
10
|
+
)
|
|
11
|
+
from reflex_site_shared.components.blocks.headings import (
|
|
12
|
+
h1_comp_xd,
|
|
13
|
+
h2_comp_xd,
|
|
14
|
+
h3_comp_xd,
|
|
15
|
+
h4_comp_xd,
|
|
16
|
+
img_comp_xd,
|
|
17
|
+
)
|
|
18
|
+
from reflex_site_shared.components.blocks.typography import (
|
|
19
|
+
code_comp,
|
|
20
|
+
doclink2,
|
|
21
|
+
list_comp,
|
|
22
|
+
ordered_list_comp,
|
|
23
|
+
text_comp,
|
|
24
|
+
unordered_list_comp,
|
|
25
|
+
)
|
|
26
|
+
from reflex_site_shared.styles.fonts import base, code
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def get_code_style(color: ColorType):
|
|
30
|
+
"""Get code style.
|
|
31
|
+
|
|
32
|
+
Returns:
|
|
33
|
+
The component.
|
|
34
|
+
"""
|
|
35
|
+
return {
|
|
36
|
+
"p": {"margin_y": "0px"},
|
|
37
|
+
"code": {
|
|
38
|
+
"color": rx.color(color, 11),
|
|
39
|
+
"border_radius": "4px",
|
|
40
|
+
"border": f"1px solid {rx.color(color, 5)}",
|
|
41
|
+
"background": rx.color(color, 4),
|
|
42
|
+
**code,
|
|
43
|
+
},
|
|
44
|
+
**base,
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def _markdown_table(*children, **props) -> rx.Component:
|
|
49
|
+
return rx.box(
|
|
50
|
+
rx.el.table(
|
|
51
|
+
*children,
|
|
52
|
+
class_name="w-full border-collapse text-sm border border-secondary-4 rounded-lg overflow-hidden bg-white-1 ",
|
|
53
|
+
**props,
|
|
54
|
+
),
|
|
55
|
+
class_name="w-full rounded-xl border border-secondary-a4 my-6 max-w-full overflow-hidden",
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def _markdown_thead(*children, **props) -> rx.Component:
|
|
60
|
+
return rx.el.thead(
|
|
61
|
+
*children,
|
|
62
|
+
class_name="bg-secondary-1 border-b border-secondary-4",
|
|
63
|
+
**props,
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def _markdown_tbody(*children, **props) -> rx.Component:
|
|
68
|
+
return rx.el.tbody(
|
|
69
|
+
*children,
|
|
70
|
+
class_name="[&_tr:nth-child(even)]:bg-secondary-1",
|
|
71
|
+
**props,
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def _markdown_tr(*children, **props) -> rx.Component:
|
|
76
|
+
return rx.el.tr(
|
|
77
|
+
*children,
|
|
78
|
+
class_name="border-b border-secondary-4 last:border-b-0",
|
|
79
|
+
**props,
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def _markdown_th(*children, **props) -> rx.Component:
|
|
84
|
+
return rx.el.th(
|
|
85
|
+
*children,
|
|
86
|
+
class_name="px-3 py-2.5 text-left text-xs font-[575] text-secondary-12 align-top",
|
|
87
|
+
**props,
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def _markdown_td(*children, **props) -> rx.Component:
|
|
92
|
+
return rx.el.td(
|
|
93
|
+
*children,
|
|
94
|
+
class_name="px-3 py-2.5 text-xs font-medium first:font-[575] text-secondary-11 align-top",
|
|
95
|
+
**props,
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
_markdown_table_component_map: dict[str, object] = {
|
|
100
|
+
"table": _markdown_table,
|
|
101
|
+
"thead": _markdown_thead,
|
|
102
|
+
"tbody": _markdown_tbody,
|
|
103
|
+
"tr": _markdown_tr,
|
|
104
|
+
"th": _markdown_th,
|
|
105
|
+
"td": _markdown_td,
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
component_map = {
|
|
109
|
+
"h1": lambda text: h1_comp_xd(text=text),
|
|
110
|
+
"h2": lambda text: h2_comp_xd(text=text),
|
|
111
|
+
"h3": lambda text: h3_comp_xd(text=text),
|
|
112
|
+
"h4": lambda text: h4_comp_xd(text=text),
|
|
113
|
+
"p": lambda text: text_comp(text=text),
|
|
114
|
+
"li": lambda text: list_comp(text=text),
|
|
115
|
+
"a": doclink2,
|
|
116
|
+
"code": lambda text: code_comp(text=text),
|
|
117
|
+
"pre": code_block_markdown,
|
|
118
|
+
"img": lambda src: img_comp_xd(src=src),
|
|
119
|
+
**_markdown_table_component_map,
|
|
120
|
+
}
|
|
121
|
+
comp2 = component_map.copy()
|
|
122
|
+
comp2["pre"] = code_block_markdown_dark
|
|
123
|
+
comp2["ul"] = lambda items: unordered_list_comp(items=items)
|
|
124
|
+
comp2["ol"] = lambda items: ordered_list_comp(items=items)
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def markdown(text: str):
|
|
128
|
+
"""Markdown.
|
|
129
|
+
|
|
130
|
+
Returns:
|
|
131
|
+
The component.
|
|
132
|
+
"""
|
|
133
|
+
return rx.markdown(text, component_map=component_map)
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def markdown_codeblock(value: str, **props: object) -> rx.Component:
|
|
137
|
+
"""Render a code block using the Shiki-based code block component.
|
|
138
|
+
|
|
139
|
+
Returns:
|
|
140
|
+
The component.
|
|
141
|
+
"""
|
|
142
|
+
return rx._x.code_block(value, **props)
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
def markdown_with_shiki(*args, **kwargs):
|
|
146
|
+
"""Wrapper for the markdown component with a customized component map.
|
|
147
|
+
Uses the experimental Shiki-based code block (rx._x.code_block)
|
|
148
|
+
instead of the default CodeBlock component for code blocks.
|
|
149
|
+
|
|
150
|
+
Note: This wrapper should be removed once the default codeblock
|
|
151
|
+
in rx.markdown component map is updated to the Shiki-based code block.
|
|
152
|
+
|
|
153
|
+
Returns:
|
|
154
|
+
The component.
|
|
155
|
+
"""
|
|
156
|
+
return rx.markdown(
|
|
157
|
+
*args,
|
|
158
|
+
component_map={
|
|
159
|
+
"h1": lambda text: h1_comp_xd(text=text),
|
|
160
|
+
"h2": lambda text: h2_comp_xd(text=text),
|
|
161
|
+
"h3": lambda text: h3_comp_xd(text=text),
|
|
162
|
+
"h4": lambda text: h4_comp_xd(text=text),
|
|
163
|
+
"p": lambda text: text_comp(text=text),
|
|
164
|
+
"li": lambda text: list_comp(text=text),
|
|
165
|
+
"a": doclink2,
|
|
166
|
+
"pre": markdown_codeblock,
|
|
167
|
+
"img": lambda src: img_comp_xd(src=src),
|
|
168
|
+
},
|
|
169
|
+
**kwargs,
|
|
170
|
+
)
|