Update base template (#2027)
This commit is contained in:
parent
f66c6c3361
commit
8133aa10c9
72
reflex/.templates/apps/base/README.md
Normal file
72
reflex/.templates/apps/base/README.md
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
# Welcome to Reflex!
|
||||||
|
|
||||||
|
This is the base Reflex template - installed when you run `reflex init`.
|
||||||
|
|
||||||
|
If you want to use a different template, pass the `--template` flag to `reflex init`.
|
||||||
|
For example, if you want a more basic starting point, you can run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
reflex init --template blank
|
||||||
|
```
|
||||||
|
|
||||||
|
## About this Template
|
||||||
|
|
||||||
|
This template has the following directory structure:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
.
|
||||||
|
├── assets
|
||||||
|
├── requirements.txt
|
||||||
|
├── rxconfig.py
|
||||||
|
└── {your_app}
|
||||||
|
├── __init__.py
|
||||||
|
├── components
|
||||||
|
│ └── sidebar.py
|
||||||
|
├── pages
|
||||||
|
│ ├── __init__.py
|
||||||
|
│ ├── dashboard.py
|
||||||
|
│ ├── index.py
|
||||||
|
│ ├── settings.py
|
||||||
|
│ └── template.py
|
||||||
|
├── state.py
|
||||||
|
├── styles.py
|
||||||
|
└── {your_app}.py
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
See the [Project Structure docs](https://reflex.dev/docs/getting-started/project-structure/) for more information on general Reflex project structure.
|
||||||
|
|
||||||
|
### Adding Pages
|
||||||
|
|
||||||
|
In this template, the pages in your app are defined in `{your_app}/pages/`.
|
||||||
|
Each page is a function that returns a Reflex component.
|
||||||
|
For example, to edit this page you can modify `{your_app}/pages/index.py`.
|
||||||
|
See the [pages docs](https://reflex.dev/docs/components/pages/) for more information on pages.
|
||||||
|
|
||||||
|
In this template, instead of using `rx.add_page` or the `@rx.page` decorator,
|
||||||
|
we use the `@template` decorator from `{your_app}/pages/template.py`.
|
||||||
|
|
||||||
|
To add a new page:
|
||||||
|
|
||||||
|
1. Add a new file in `{your_app}/pages/`. We recommend using one file per page, but you can also group pages in a single file.
|
||||||
|
2. Add a new function with the `@template` decorator, which takes the same arguments as `@rx.page`.
|
||||||
|
3. Import the page in your `{your_app}/{your_app}.py` file and it will automatically be added to the app.
|
||||||
|
|
||||||
|
|
||||||
|
### Adding Components
|
||||||
|
|
||||||
|
In order to keep your code organized, we recommend putting components that are
|
||||||
|
used across multiple pages in the `{your_app}/components/` directory.
|
||||||
|
|
||||||
|
In this template, we have a sidebar component in `{your_app}/components/sidebar.py`.
|
||||||
|
|
||||||
|
### Adding State
|
||||||
|
|
||||||
|
In this template, we define the base state of the app in `{your_app}/state.py`.
|
||||||
|
The base state is useful for general app state that is used across multiple pages.
|
||||||
|
|
||||||
|
In this template, the base state handles the toggle for the sidebar.
|
||||||
|
|
||||||
|
As your app grows, we recommend using [substates](https://reflex.dev/docs/state/substates/)
|
||||||
|
to organize your state. You can either define substates in their own files, or if the state is
|
||||||
|
specific to a page, you can define it in the page file itself.
|
@ -1,101 +1,12 @@
|
|||||||
"""Welcome to Reflex! This file outlines the steps to create a basic app."""
|
"""Welcome to Reflex!."""
|
||||||
from typing import Callable
|
|
||||||
|
from code import styles
|
||||||
|
|
||||||
|
# Import all the pages.
|
||||||
|
from code.pages import *
|
||||||
|
|
||||||
import reflex as rx
|
import reflex as rx
|
||||||
|
|
||||||
from .pages import dashboard_page, home_page, settings_page
|
# Create the app and compile it.
|
||||||
from .sidebar import sidebar
|
app = rx.App(style=styles.base_style)
|
||||||
from .state import State
|
|
||||||
from .styles import *
|
|
||||||
|
|
||||||
meta = [
|
|
||||||
{
|
|
||||||
"name": "viewport",
|
|
||||||
"content": "width=device-width, shrink-to-fit=no, initial-scale=1",
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
def template(main_content: Callable[[], rx.Component]) -> rx.Component:
|
|
||||||
"""The template for each page of the app.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
main_content (Callable[[], rx.Component]): The main content of the page.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
rx.Component: The template for each page of the app.
|
|
||||||
"""
|
|
||||||
menu_button = rx.box(
|
|
||||||
rx.menu(
|
|
||||||
rx.menu_button(
|
|
||||||
rx.icon(
|
|
||||||
tag="hamburger",
|
|
||||||
size="4em",
|
|
||||||
color=text_color,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
rx.menu_list(
|
|
||||||
rx.menu_item(rx.link("Home", href="/", width="100%")),
|
|
||||||
rx.menu_divider(),
|
|
||||||
rx.menu_item(
|
|
||||||
rx.link("About", href="https://github.com/reflex-dev", width="100%")
|
|
||||||
),
|
|
||||||
rx.menu_item(
|
|
||||||
rx.link("Contact", href="mailto:founders@=reflex.dev", width="100%")
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
position="fixed",
|
|
||||||
right="1.5em",
|
|
||||||
top="1.5em",
|
|
||||||
z_index="500",
|
|
||||||
)
|
|
||||||
|
|
||||||
return rx.hstack(
|
|
||||||
sidebar(),
|
|
||||||
main_content(),
|
|
||||||
rx.spacer(),
|
|
||||||
menu_button,
|
|
||||||
align_items="flex-start",
|
|
||||||
transition="left 0.5s, width 0.5s",
|
|
||||||
position="relative",
|
|
||||||
left=rx.cond(State.sidebar_displayed, "0px", f"-{sidebar_width}"),
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@rx.page("/", meta=meta)
|
|
||||||
@template
|
|
||||||
def home() -> rx.Component:
|
|
||||||
"""Home page.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
rx.Component: The home page.
|
|
||||||
"""
|
|
||||||
return home_page()
|
|
||||||
|
|
||||||
|
|
||||||
@rx.page("/settings", meta=meta)
|
|
||||||
@template
|
|
||||||
def settings() -> rx.Component:
|
|
||||||
"""Settings page.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
rx.Component: The settings page.
|
|
||||||
"""
|
|
||||||
return settings_page()
|
|
||||||
|
|
||||||
|
|
||||||
@rx.page("/dashboard", meta=meta)
|
|
||||||
@template
|
|
||||||
def dashboard() -> rx.Component:
|
|
||||||
"""Dashboard page.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
rx.Component: The dashboard page.
|
|
||||||
"""
|
|
||||||
return dashboard_page()
|
|
||||||
|
|
||||||
|
|
||||||
# Add state and page to the app.
|
|
||||||
app = rx.App(style=base_style)
|
|
||||||
app.compile()
|
app.compile()
|
||||||
|
@ -1,23 +1,25 @@
|
|||||||
"""Sidebar component for the app."""
|
"""Sidebar component for the app."""
|
||||||
|
|
||||||
import reflex as rx
|
from code import styles
|
||||||
|
from code.state import State
|
||||||
|
|
||||||
from .state import State
|
import reflex as rx
|
||||||
from .styles import *
|
|
||||||
|
|
||||||
|
|
||||||
def sidebar_header() -> rx.Component:
|
def sidebar_header() -> rx.Component:
|
||||||
"""Sidebar header.
|
"""Sidebar header.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
rx.Component: The sidebar header component.
|
The sidebar header component.
|
||||||
"""
|
"""
|
||||||
return rx.hstack(
|
return rx.hstack(
|
||||||
|
# The logo.
|
||||||
rx.image(
|
rx.image(
|
||||||
src="/icon.svg",
|
src="/icon.svg",
|
||||||
height="2em",
|
height="2em",
|
||||||
),
|
),
|
||||||
rx.spacer(),
|
rx.spacer(),
|
||||||
|
# Link to Reflex GitHub repo.
|
||||||
rx.link(
|
rx.link(
|
||||||
rx.center(
|
rx.center(
|
||||||
rx.image(
|
rx.image(
|
||||||
@ -25,17 +27,17 @@ def sidebar_header() -> rx.Component:
|
|||||||
height="3em",
|
height="3em",
|
||||||
padding="0.5em",
|
padding="0.5em",
|
||||||
),
|
),
|
||||||
box_shadow=box_shadow,
|
box_shadow=styles.box_shadow,
|
||||||
bg="transparent",
|
bg="transparent",
|
||||||
border_radius=border_radius,
|
border_radius=styles.border_radius,
|
||||||
_hover={
|
_hover={
|
||||||
"bg": accent_color,
|
"bg": styles.accent_color,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
href="https://github.com/reflex-dev/reflex",
|
href="https://github.com/reflex-dev/reflex",
|
||||||
),
|
),
|
||||||
width="100%",
|
width="100%",
|
||||||
border_bottom=border,
|
border_bottom=styles.border,
|
||||||
padding="1em",
|
padding="1em",
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -44,7 +46,7 @@ def sidebar_footer() -> rx.Component:
|
|||||||
"""Sidebar footer.
|
"""Sidebar footer.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
rx.Component: The sidebar footer component.
|
The sidebar footer component.
|
||||||
"""
|
"""
|
||||||
return rx.hstack(
|
return rx.hstack(
|
||||||
rx.link(
|
rx.link(
|
||||||
@ -55,15 +57,15 @@ def sidebar_footer() -> rx.Component:
|
|||||||
padding="0.5em",
|
padding="0.5em",
|
||||||
),
|
),
|
||||||
bg="transparent",
|
bg="transparent",
|
||||||
border_radius=border_radius,
|
border_radius=styles.border_radius,
|
||||||
**hover_accent_bg,
|
**styles.hover_accent_bg,
|
||||||
),
|
),
|
||||||
on_click=State.toggle_sidebar_displayed,
|
on_click=State.toggle_sidebar_displayed,
|
||||||
transform=rx.cond(~State.sidebar_displayed, "rotate(180deg)", ""),
|
transform=rx.cond(~State.sidebar_displayed, "rotate(180deg)", ""),
|
||||||
transition="transform 0.5s, left 0.5s",
|
transition="transform 0.5s, left 0.5s",
|
||||||
position="relative",
|
position="relative",
|
||||||
left=rx.cond(State.sidebar_displayed, "0px", "20.5em"),
|
left=rx.cond(State.sidebar_displayed, "0px", "20.5em"),
|
||||||
**overlapping_button_style,
|
**styles.overlapping_button_style,
|
||||||
),
|
),
|
||||||
rx.spacer(),
|
rx.spacer(),
|
||||||
rx.link(
|
rx.link(
|
||||||
@ -79,7 +81,7 @@ def sidebar_footer() -> rx.Component:
|
|||||||
href="https://reflex.dev/blog/",
|
href="https://reflex.dev/blog/",
|
||||||
),
|
),
|
||||||
width="100%",
|
width="100%",
|
||||||
border_top=border,
|
border_top=styles.border,
|
||||||
padding="1em",
|
padding="1em",
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -88,13 +90,18 @@ def sidebar_item(text: str, icon: str, url: str) -> rx.Component:
|
|||||||
"""Sidebar item.
|
"""Sidebar item.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
text (str): The text of the item.
|
text: The text of the item.
|
||||||
icon (str): The icon of the item.
|
icon: The icon of the item.
|
||||||
url (str): The URL of the item.
|
url: The URL of the item.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
rx.Component: The sidebar item component.
|
rx.Component: The sidebar item component.
|
||||||
"""
|
"""
|
||||||
|
# Whether the item is active.
|
||||||
|
active = (State.router.page.path == f"/{text.lower()}") | (
|
||||||
|
(State.router.page.path == "/") & text == "Home"
|
||||||
|
)
|
||||||
|
|
||||||
return rx.link(
|
return rx.link(
|
||||||
rx.hstack(
|
rx.hstack(
|
||||||
rx.image(
|
rx.image(
|
||||||
@ -106,17 +113,17 @@ def sidebar_item(text: str, icon: str, url: str) -> rx.Component:
|
|||||||
text,
|
text,
|
||||||
),
|
),
|
||||||
bg=rx.cond(
|
bg=rx.cond(
|
||||||
State.origin_url == f"/{text.lower()}/",
|
active,
|
||||||
accent_color,
|
styles.accent_color,
|
||||||
"transparent",
|
"transparent",
|
||||||
),
|
),
|
||||||
color=rx.cond(
|
color=rx.cond(
|
||||||
State.origin_url == f"/{text.lower()}/",
|
active,
|
||||||
accent_text_color,
|
styles.accent_text_color,
|
||||||
text_color,
|
styles.text_color,
|
||||||
),
|
),
|
||||||
border_radius=border_radius,
|
border_radius=styles.border_radius,
|
||||||
box_shadow=box_shadow,
|
box_shadow=styles.box_shadow,
|
||||||
width="100%",
|
width="100%",
|
||||||
padding_x="1em",
|
padding_x="1em",
|
||||||
),
|
),
|
||||||
@ -126,25 +133,26 @@ def sidebar_item(text: str, icon: str, url: str) -> rx.Component:
|
|||||||
|
|
||||||
|
|
||||||
def sidebar() -> rx.Component:
|
def sidebar() -> rx.Component:
|
||||||
"""Sidebar.
|
"""The sidebar.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
rx.Component: The sidebar component.
|
The sidebar component.
|
||||||
"""
|
"""
|
||||||
|
# Get all the decorated pages and add them to the sidebar.
|
||||||
|
from reflex.page import get_decorated_pages
|
||||||
|
|
||||||
return rx.box(
|
return rx.box(
|
||||||
rx.vstack(
|
rx.vstack(
|
||||||
sidebar_header(),
|
sidebar_header(),
|
||||||
rx.vstack(
|
rx.vstack(
|
||||||
sidebar_item(
|
*[
|
||||||
"Dashboard",
|
sidebar_item(
|
||||||
"/github.svg",
|
text=page.get("title", page["route"].strip("/").capitalize()),
|
||||||
"/dashboard",
|
icon=page.get("image", "/github.svg"),
|
||||||
),
|
url=page["route"],
|
||||||
sidebar_item(
|
)
|
||||||
"Settings",
|
for page in get_decorated_pages()
|
||||||
"/github.svg",
|
],
|
||||||
"/settings",
|
|
||||||
),
|
|
||||||
width="100%",
|
width="100%",
|
||||||
overflow_y="auto",
|
overflow_y="auto",
|
||||||
align_items="flex-start",
|
align_items="flex-start",
|
||||||
@ -154,9 +162,9 @@ def sidebar() -> rx.Component:
|
|||||||
sidebar_footer(),
|
sidebar_footer(),
|
||||||
height="100dvh",
|
height="100dvh",
|
||||||
),
|
),
|
||||||
min_width=sidebar_width,
|
min_width=styles.sidebar_width,
|
||||||
height="100%",
|
height="100%",
|
||||||
position="sticky",
|
position="sticky",
|
||||||
top="0px",
|
top="0px",
|
||||||
border_right=border,
|
border_right=styles.border,
|
||||||
)
|
)
|
@ -1,4 +1,3 @@
|
|||||||
"""The pages of the app."""
|
from .dashboard import dashboard
|
||||||
from .dashboard import dashboard_page
|
from .index import index
|
||||||
from .home import home_page
|
from .settings import settings
|
||||||
from .settings import settings_page
|
|
||||||
|
@ -1,28 +1,21 @@
|
|||||||
"""The dashboard page for the template."""
|
"""The dashboard page."""
|
||||||
|
from code.templates import template
|
||||||
|
|
||||||
import reflex as rx
|
import reflex as rx
|
||||||
|
|
||||||
from ..styles import *
|
|
||||||
|
|
||||||
|
@template(route="/dashboard", title="Dashboard")
|
||||||
def dashboard_page() -> rx.Component:
|
def dashboard() -> rx.Component:
|
||||||
"""The UI for the dashboard page.
|
"""The dashboard page.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
rx.Component: The UI for the dashboard page.
|
The UI for the dashboard page.
|
||||||
"""
|
"""
|
||||||
return rx.box(
|
return rx.vstack(
|
||||||
rx.vstack(
|
rx.heading("Dashboard", font_size="3em"),
|
||||||
rx.heading(
|
rx.text("Welcome to Reflex!"),
|
||||||
"Dashboard",
|
rx.text(
|
||||||
font_size="3em",
|
"You can edit this page in ",
|
||||||
),
|
rx.code("{your_app}/pages/dashboard.py"),
|
||||||
rx.text(
|
|
||||||
"Welcome to Reflex!",
|
|
||||||
),
|
|
||||||
rx.text(
|
|
||||||
"You can use this template to get started with Reflex.",
|
|
||||||
),
|
|
||||||
style=template_content_style,
|
|
||||||
),
|
),
|
||||||
style=template_page_style,
|
|
||||||
)
|
)
|
||||||
|
@ -1,28 +0,0 @@
|
|||||||
"""The home page of the app."""
|
|
||||||
import reflex as rx
|
|
||||||
|
|
||||||
from ..styles import *
|
|
||||||
|
|
||||||
|
|
||||||
def home_page() -> rx.Component:
|
|
||||||
"""The UI for the home page.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
rx.Component: The UI for the home page.
|
|
||||||
"""
|
|
||||||
return rx.box(
|
|
||||||
rx.vstack(
|
|
||||||
rx.heading(
|
|
||||||
"Home",
|
|
||||||
font_size="3em",
|
|
||||||
),
|
|
||||||
rx.text(
|
|
||||||
"Welcome to Reflex!",
|
|
||||||
),
|
|
||||||
rx.text(
|
|
||||||
"You can use this template to get started with Reflex.",
|
|
||||||
),
|
|
||||||
style=template_content_style,
|
|
||||||
),
|
|
||||||
style=template_page_style,
|
|
||||||
)
|
|
18
reflex/.templates/apps/base/code/pages/index.py
Normal file
18
reflex/.templates/apps/base/code/pages/index.py
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
"""The home page of the app."""
|
||||||
|
|
||||||
|
from code import styles
|
||||||
|
from code.templates import template
|
||||||
|
|
||||||
|
import reflex as rx
|
||||||
|
|
||||||
|
|
||||||
|
@template(route="/", title="Home", image="/logo.svg")
|
||||||
|
def index() -> rx.Component:
|
||||||
|
"""The home page.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The UI for the home page.
|
||||||
|
"""
|
||||||
|
with open("README.md") as readme:
|
||||||
|
content = readme.read()
|
||||||
|
return rx.markdown(content, component_map=styles.markdown_style)
|
@ -1,28 +1,22 @@
|
|||||||
"""The settings page for the template."""
|
"""The settings page."""
|
||||||
|
|
||||||
|
from code.templates import template
|
||||||
|
|
||||||
import reflex as rx
|
import reflex as rx
|
||||||
|
|
||||||
from ..styles import *
|
|
||||||
|
|
||||||
|
@template(route="/settings", title="Settings")
|
||||||
def settings_page() -> rx.Component:
|
def settings() -> rx.Component:
|
||||||
"""The UI for the settings page.
|
"""The settings page.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
rx.Component: The UI for the settings page.
|
The UI for the settings page.
|
||||||
"""
|
"""
|
||||||
return rx.box(
|
return rx.vstack(
|
||||||
rx.vstack(
|
rx.heading("Settings", font_size="3em"),
|
||||||
rx.heading(
|
rx.text("Welcome to Reflex!"),
|
||||||
"Settings",
|
rx.text(
|
||||||
font_size="3em",
|
"You can edit this page in ",
|
||||||
),
|
rx.code("{your_app}/pages/settings.py"),
|
||||||
rx.text(
|
|
||||||
"Welcome to Reflex!",
|
|
||||||
),
|
|
||||||
rx.text(
|
|
||||||
"You can use this template to get started with Reflex.",
|
|
||||||
),
|
|
||||||
style=template_content_style,
|
|
||||||
),
|
),
|
||||||
style=template_page_style,
|
|
||||||
)
|
)
|
||||||
|
@ -6,17 +6,9 @@ import reflex as rx
|
|||||||
class State(rx.State):
|
class State(rx.State):
|
||||||
"""State for the app."""
|
"""State for the app."""
|
||||||
|
|
||||||
|
# Whether the sidebar is displayed.
|
||||||
sidebar_displayed: bool = True
|
sidebar_displayed: bool = True
|
||||||
|
|
||||||
@rx.var
|
|
||||||
def origin_url(self) -> str:
|
|
||||||
"""Get the url of the current page.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
str: The url of the current page.
|
|
||||||
"""
|
|
||||||
return self.router_data.get("asPath", "")
|
|
||||||
|
|
||||||
def toggle_sidebar_displayed(self) -> None:
|
def toggle_sidebar_displayed(self) -> None:
|
||||||
"""Toggle the sidebar displayed."""
|
"""Toggle the sidebar displayed."""
|
||||||
self.sidebar_displayed = not self.sidebar_displayed
|
self.sidebar_displayed = not self.sidebar_displayed
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
"""Styles for the app."""
|
"""Styles for the app."""
|
||||||
import reflex as rx
|
from code.state import State
|
||||||
|
|
||||||
from .state import State
|
import reflex as rx
|
||||||
|
|
||||||
border_radius = "0.375rem"
|
border_radius = "0.375rem"
|
||||||
box_shadow = "0px 0px 0px 1px rgba(84, 82, 95, 0.14)"
|
box_shadow = "0px 0px 0px 1px rgba(84, 82, 95, 0.14)"
|
||||||
@ -53,3 +53,20 @@ base_style = {
|
|||||||
},
|
},
|
||||||
rx.MenuItem: hover_accent_bg,
|
rx.MenuItem: hover_accent_bg,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
markdown_style = {
|
||||||
|
"code": lambda text: rx.code(text, color="#1F1944", bg="#EAE4FD"),
|
||||||
|
"a": lambda text, **props: rx.link(
|
||||||
|
text,
|
||||||
|
**props,
|
||||||
|
font_weight="bold",
|
||||||
|
color="#03030B",
|
||||||
|
text_decoration="underline",
|
||||||
|
text_decoration_color="#AD9BF8",
|
||||||
|
_hover={
|
||||||
|
"color": "#AD9BF8",
|
||||||
|
"text_decoration": "underline",
|
||||||
|
"text_decoration_color": "#03030B",
|
||||||
|
},
|
||||||
|
),
|
||||||
|
}
|
||||||
|
1
reflex/.templates/apps/base/code/templates/__init__.py
Normal file
1
reflex/.templates/apps/base/code/templates/__init__.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
from .template import template
|
99
reflex/.templates/apps/base/code/templates/template.py
Normal file
99
reflex/.templates/apps/base/code/templates/template.py
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
"""Common templates used between pages in the app."""
|
||||||
|
|
||||||
|
from code import styles
|
||||||
|
from code.components.sidebar import sidebar
|
||||||
|
from code.state import State
|
||||||
|
from typing import Callable
|
||||||
|
|
||||||
|
import reflex as rx
|
||||||
|
|
||||||
|
# Meta tags for the app.
|
||||||
|
default_meta = [
|
||||||
|
{
|
||||||
|
"name": "viewport",
|
||||||
|
"content": "width=device-width, shrink-to-fit=no, initial-scale=1",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def menu_button() -> rx.Component:
|
||||||
|
"""The menu button on the top right of the page.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The menu button component.
|
||||||
|
"""
|
||||||
|
return rx.box(
|
||||||
|
rx.menu(
|
||||||
|
rx.menu_button(
|
||||||
|
rx.icon(
|
||||||
|
tag="hamburger",
|
||||||
|
size="4em",
|
||||||
|
color=styles.text_color,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
rx.menu_list(
|
||||||
|
rx.menu_item(rx.link("Home", href="/", width="100%")),
|
||||||
|
rx.menu_divider(),
|
||||||
|
rx.menu_item(
|
||||||
|
rx.link("About", href="https://github.com/reflex-dev", width="100%")
|
||||||
|
),
|
||||||
|
rx.menu_item(
|
||||||
|
rx.link("Contact", href="mailto:founders@=reflex.dev", width="100%")
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
position="fixed",
|
||||||
|
right="1.5em",
|
||||||
|
top="1.5em",
|
||||||
|
z_index="500",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def template(
|
||||||
|
**page_kwargs: dict,
|
||||||
|
) -> Callable[[Callable[[], rx.Component]], rx.Component]:
|
||||||
|
"""The template for each page of the app.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
page_kwargs: Keyword arguments to pass to the page.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The template with the page content.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def decorator(page_content: Callable[[], rx.Component]) -> rx.Component:
|
||||||
|
"""The template for each page of the app.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
page_content: The content of the page.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The template with the page content.
|
||||||
|
"""
|
||||||
|
# Get the meta tags for the page.
|
||||||
|
page_kwargs["meta"] = [*default_meta, *page_kwargs.get("meta", [])]
|
||||||
|
|
||||||
|
@rx.page(**page_kwargs)
|
||||||
|
def templated_page():
|
||||||
|
return rx.hstack(
|
||||||
|
sidebar(),
|
||||||
|
rx.box(
|
||||||
|
rx.box(
|
||||||
|
page_content(),
|
||||||
|
**styles.template_content_style,
|
||||||
|
),
|
||||||
|
**styles.template_page_style,
|
||||||
|
),
|
||||||
|
rx.spacer(),
|
||||||
|
menu_button(),
|
||||||
|
align_items="flex-start",
|
||||||
|
transition="left 0.5s, width 0.5s",
|
||||||
|
position="relative",
|
||||||
|
left=rx.cond(
|
||||||
|
State.sidebar_displayed, "0px", f"-{styles.sidebar_width}"
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
return templated_page
|
||||||
|
|
||||||
|
return decorator
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 4.2 KiB |
0
reflex/.templates/apps/blank/code/__init__.py
Normal file
0
reflex/.templates/apps/blank/code/__init__.py
Normal file
@ -62,7 +62,7 @@ def get_base_component_map() -> dict[str, Callable]:
|
|||||||
"p": lambda value: Text.create(value, margin_y="1em"),
|
"p": lambda value: Text.create(value, margin_y="1em"),
|
||||||
"ul": lambda value: UnorderedList.create(value, margin_y="1em"), # type: ignore
|
"ul": lambda value: UnorderedList.create(value, margin_y="1em"), # type: ignore
|
||||||
"ol": lambda value: OrderedList.create(value, margin_y="1em"), # type: ignore
|
"ol": lambda value: OrderedList.create(value, margin_y="1em"), # type: ignore
|
||||||
"li": lambda value: ListItem.create(value),
|
"li": lambda value: ListItem.create(value, margin_y="0.5em"),
|
||||||
"a": lambda value: Link.create(value),
|
"a": lambda value: Link.create(value),
|
||||||
"code": lambda value: Code.create(value),
|
"code": lambda value: Code.create(value),
|
||||||
"codeblock": lambda *_, **props: CodeBlock.create(
|
"codeblock": lambda *_, **props: CodeBlock.create(
|
||||||
|
@ -89,6 +89,8 @@ class Templates(SimpleNamespace):
|
|||||||
WEB_TEMPLATE = os.path.join(BASE, "web")
|
WEB_TEMPLATE = os.path.join(BASE, "web")
|
||||||
# The jinja template directory.
|
# The jinja template directory.
|
||||||
JINJA_TEMPLATE = os.path.join(BASE, "jinja")
|
JINJA_TEMPLATE = os.path.join(BASE, "jinja")
|
||||||
|
# Where the code for the templates is stored.
|
||||||
|
CODE = "code"
|
||||||
|
|
||||||
|
|
||||||
class Next(SimpleNamespace):
|
class Next(SimpleNamespace):
|
||||||
|
@ -61,3 +61,15 @@ def page(
|
|||||||
return render_fn
|
return render_fn
|
||||||
|
|
||||||
return decorator
|
return decorator
|
||||||
|
|
||||||
|
|
||||||
|
def get_decorated_pages() -> list[dict]:
|
||||||
|
"""Get the decorated pages.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The decorated pages.
|
||||||
|
"""
|
||||||
|
return sorted(
|
||||||
|
[page_data for render_fn, page_data in DECORATED_PAGES],
|
||||||
|
key=lambda x: x["route"],
|
||||||
|
)
|
||||||
|
@ -71,7 +71,7 @@ def init(
|
|||||||
None, metavar="APP_NAME", help="The name of the app to initialize."
|
None, metavar="APP_NAME", help="The name of the app to initialize."
|
||||||
),
|
),
|
||||||
template: constants.Templates.Kind = typer.Option(
|
template: constants.Templates.Kind = typer.Option(
|
||||||
constants.Templates.Kind.DEFAULT.value,
|
constants.Templates.Kind.BASE.value,
|
||||||
help="The template to initialize the app with.",
|
help="The template to initialize the app with.",
|
||||||
),
|
),
|
||||||
loglevel: constants.LogLevel = typer.Option(
|
loglevel: constants.LogLevel = typer.Option(
|
||||||
|
@ -154,7 +154,7 @@ class AppHarness:
|
|||||||
with chdir(self.app_path):
|
with chdir(self.app_path):
|
||||||
reflex.reflex.init(
|
reflex.reflex.init(
|
||||||
name=self.app_name,
|
name=self.app_name,
|
||||||
template=reflex.constants.Templates.Kind.DEFAULT,
|
template=reflex.constants.Templates.Kind.BLANK,
|
||||||
loglevel=reflex.constants.LogLevel.INFO,
|
loglevel=reflex.constants.LogLevel.INFO,
|
||||||
)
|
)
|
||||||
self.app_module_path.write_text(source_code)
|
self.app_module_path.write_text(source_code)
|
||||||
|
@ -34,7 +34,7 @@ def detect_package_change(json_file_path: str) -> str:
|
|||||||
"""Calculates the SHA-256 hash of a JSON file and returns it as a hexadecimal string.
|
"""Calculates the SHA-256 hash of a JSON file and returns it as a hexadecimal string.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
json_file_path (str): The path to the JSON file to be hashed.
|
json_file_path: The path to the JSON file to be hashed.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
str: The SHA-256 hash of the JSON file as a hexadecimal string.
|
str: The SHA-256 hash of the JSON file as a hexadecimal string.
|
||||||
|
@ -4,6 +4,7 @@ from __future__ import annotations
|
|||||||
|
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
|
import re
|
||||||
import shutil
|
import shutil
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
@ -173,3 +174,21 @@ def update_json_file(file_path: str, update_dict: dict[str, int | str]):
|
|||||||
# Write the updated json object to the file
|
# Write the updated json object to the file
|
||||||
with open(fp, "w") as f:
|
with open(fp, "w") as f:
|
||||||
json.dump(json_object, f, ensure_ascii=False)
|
json.dump(json_object, f, ensure_ascii=False)
|
||||||
|
|
||||||
|
|
||||||
|
def find_replace(directory: str, find: str, replace: str):
|
||||||
|
"""Recursively find and replace text in files in a directory.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
directory: The directory to search.
|
||||||
|
find: The text to find.
|
||||||
|
replace: The text to replace.
|
||||||
|
"""
|
||||||
|
for root, _dirs, files in os.walk(directory):
|
||||||
|
for file in files:
|
||||||
|
filepath = os.path.join(root, file)
|
||||||
|
with open(filepath, "r", encoding="utf-8") as f:
|
||||||
|
text = f.read()
|
||||||
|
text = re.sub(find, replace, text)
|
||||||
|
with open(filepath, "w") as f:
|
||||||
|
f.write(text)
|
||||||
|
@ -249,17 +249,25 @@ def initialize_app_directory(app_name: str, template: constants.Templates.Kind):
|
|||||||
template: The template to use.
|
template: The template to use.
|
||||||
"""
|
"""
|
||||||
console.log("Initializing the app directory.")
|
console.log("Initializing the app directory.")
|
||||||
path_ops.cp(
|
|
||||||
os.path.join(constants.Templates.Dirs.BASE, "apps", template.value, "code"),
|
# Copy the template to the current directory.
|
||||||
app_name,
|
template_dir = os.path.join(constants.Templates.Dirs.BASE, "apps", template.value)
|
||||||
)
|
for file in os.listdir(template_dir):
|
||||||
|
# Copy the file but keep the name the same.
|
||||||
|
path_ops.cp(os.path.join(template_dir, file), file)
|
||||||
|
|
||||||
|
# Rename the template app to the app name.
|
||||||
|
path_ops.mv(constants.Templates.Dirs.CODE, app_name)
|
||||||
path_ops.mv(
|
path_ops.mv(
|
||||||
os.path.join(app_name, template.value + ".py"),
|
os.path.join(app_name, template.value + constants.Ext.PY),
|
||||||
os.path.join(app_name, app_name + constants.Ext.PY),
|
os.path.join(app_name, app_name + constants.Ext.PY),
|
||||||
)
|
)
|
||||||
path_ops.cp(
|
|
||||||
os.path.join(constants.Templates.Dirs.BASE, "apps", template.value, "assets"),
|
# Fix up the imports.
|
||||||
constants.Dirs.APP_ASSETS,
|
path_ops.find_replace(
|
||||||
|
app_name,
|
||||||
|
f"from {constants.Templates.Dirs.CODE}",
|
||||||
|
f"from {app_name}",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user