diff --git a/reflex/.templates/apps/base/assets/favicon.ico b/reflex/.templates/apps/base/assets/favicon.ico
new file mode 100644
index 000000000..166ae995e
Binary files /dev/null and b/reflex/.templates/apps/base/assets/favicon.ico differ
diff --git a/reflex/.templates/apps/base/assets/github.svg b/reflex/.templates/apps/base/assets/github.svg
new file mode 100644
index 000000000..61c9d791b
--- /dev/null
+++ b/reflex/.templates/apps/base/assets/github.svg
@@ -0,0 +1,10 @@
+
diff --git a/reflex/.templates/apps/base/assets/icon.svg b/reflex/.templates/apps/base/assets/icon.svg
new file mode 100644
index 000000000..b9cc89da9
--- /dev/null
+++ b/reflex/.templates/apps/base/assets/icon.svg
@@ -0,0 +1,37 @@
+
diff --git a/reflex/.templates/apps/base/assets/logo.svg b/reflex/.templates/apps/base/assets/logo.svg
new file mode 100644
index 000000000..94fe1f511
--- /dev/null
+++ b/reflex/.templates/apps/base/assets/logo.svg
@@ -0,0 +1,68 @@
+
diff --git a/reflex/.templates/apps/base/assets/paneleft.svg b/reflex/.templates/apps/base/assets/paneleft.svg
new file mode 100644
index 000000000..ac9c5040a
--- /dev/null
+++ b/reflex/.templates/apps/base/assets/paneleft.svg
@@ -0,0 +1,13 @@
+
diff --git a/reflex/.templates/apps/base/code/__init__.py b/reflex/.templates/apps/base/code/__init__.py
new file mode 100644
index 000000000..e1d286346
--- /dev/null
+++ b/reflex/.templates/apps/base/code/__init__.py
@@ -0,0 +1 @@
+"""Base template for Reflex."""
diff --git a/reflex/.templates/apps/base/code/base.py b/reflex/.templates/apps/base/code/base.py
new file mode 100644
index 000000000..a0f9654d9
--- /dev/null
+++ b/reflex/.templates/apps/base/code/base.py
@@ -0,0 +1,90 @@
+"""Welcome to Reflex! This file outlines the steps to create a basic app."""
+from typing import Callable
+
+import reflex as rx
+
+from .pages import dashboard_page, home_page, settings_page
+from .sidebar import sidebar
+from .styles import *
+
+
+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",
+ )
+
+
+@rx.page("/")
+@template
+def home() -> rx.Component:
+ """Home page.
+
+ Returns:
+ rx.Component: The home page.
+ """
+ return home_page()
+
+
+@rx.page("/settings")
+@template
+def settings() -> rx.Component:
+ """Settings page.
+
+ Returns:
+ rx.Component: The settings page.
+ """
+ return settings_page()
+
+
+@rx.page("/dashboard")
+@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()
diff --git a/reflex/.templates/apps/base/code/pages/__init__.py b/reflex/.templates/apps/base/code/pages/__init__.py
new file mode 100644
index 000000000..b8bb99da9
--- /dev/null
+++ b/reflex/.templates/apps/base/code/pages/__init__.py
@@ -0,0 +1,4 @@
+"""The pages of the app."""
+from .dashboard import dashboard_page
+from .home import home_page
+from .settings import settings_page
diff --git a/reflex/.templates/apps/base/code/pages/dashboard.py b/reflex/.templates/apps/base/code/pages/dashboard.py
new file mode 100644
index 000000000..81beb4a74
--- /dev/null
+++ b/reflex/.templates/apps/base/code/pages/dashboard.py
@@ -0,0 +1,28 @@
+"""The dashboard page for the template."""
+import reflex as rx
+
+from ..styles import *
+
+
+def dashboard_page() -> rx.Component:
+ """The UI for the dashboard page.
+
+ Returns:
+ rx.Component: The UI for the dashboard page.
+ """
+ return rx.box(
+ rx.vstack(
+ rx.heading(
+ "Dashboard",
+ 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,
+ )
diff --git a/reflex/.templates/apps/base/code/pages/home.py b/reflex/.templates/apps/base/code/pages/home.py
new file mode 100644
index 000000000..aae7f1fb6
--- /dev/null
+++ b/reflex/.templates/apps/base/code/pages/home.py
@@ -0,0 +1,28 @@
+"""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",
+ 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,
+ )
diff --git a/reflex/.templates/apps/base/code/pages/settings.py b/reflex/.templates/apps/base/code/pages/settings.py
new file mode 100644
index 000000000..fdd4eeb52
--- /dev/null
+++ b/reflex/.templates/apps/base/code/pages/settings.py
@@ -0,0 +1,28 @@
+"""The settings page for the template."""
+import reflex as rx
+
+from ..styles import *
+
+
+def settings_page() -> rx.Component:
+ """The UI for the settings page.
+
+ Returns:
+ rx.Component: The UI for the settings page.
+ """
+ return rx.box(
+ rx.vstack(
+ rx.heading(
+ "Settings",
+ 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,
+ )
diff --git a/reflex/.templates/apps/base/code/sidebar.py b/reflex/.templates/apps/base/code/sidebar.py
new file mode 100644
index 000000000..342d52633
--- /dev/null
+++ b/reflex/.templates/apps/base/code/sidebar.py
@@ -0,0 +1,159 @@
+"""Sidebar component for the app."""
+
+import reflex as rx
+
+from .state import State
+from .styles import *
+
+
+def sidebar_header() -> rx.Component:
+ """Sidebar header.
+
+ Returns:
+ rx.Component: The sidebar header component.
+ """
+ return rx.hstack(
+ rx.image(
+ src="/icon.svg",
+ height="2em",
+ ),
+ rx.spacer(),
+ rx.link(
+ rx.center(
+ rx.image(
+ src="/github.svg",
+ height="3em",
+ padding="0.5em",
+ ),
+ box_shadow=box_shadow,
+ bg="transparent",
+ border_radius=border_radius,
+ _hover={
+ "bg": accent_color,
+ },
+ ),
+ href="https://github.com/reflex-dev/reflex",
+ ),
+ width="100%",
+ border_bottom=border,
+ padding="1em",
+ )
+
+
+def sidebar_footer() -> rx.Component:
+ """Sidebar footer.
+
+ Returns:
+ rx.Component: The sidebar footer component.
+ """
+ return rx.hstack(
+ rx.link(
+ rx.center(
+ rx.image(
+ src="/paneleft.svg",
+ height="2em",
+ padding="0.5em",
+ ),
+ bg="transparent",
+ border_radius=border_radius,
+ _hover={
+ "bg": accent_color,
+ },
+ ),
+ href="https://github.com/reflex-dev/reflex",
+ ),
+ rx.spacer(),
+ rx.link(
+ rx.text(
+ "Docs",
+ ),
+ href="https://reflex.dev/docs/getting-started/introduction/",
+ ),
+ rx.link(
+ rx.text(
+ "Blog",
+ ),
+ href="https://reflex.dev/blog/",
+ ),
+ width="100%",
+ border_top=border,
+ padding="1em",
+ )
+
+
+def sidebar_item(text: str, icon: str, url: str) -> rx.Component:
+ """Sidebar item.
+
+ Args:
+ text (str): The text of the item.
+ icon (str): The icon of the item.
+ url (str): The URL of the item.
+
+ Returns:
+ rx.Component: The sidebar item component.
+ """
+ return rx.link(
+ rx.hstack(
+ rx.image(
+ src=icon,
+ height="2.5em",
+ padding="0.5em",
+ ),
+ rx.text(
+ text,
+ ),
+ bg=rx.cond(
+ State.origin_url == f"/{text.lower()}/",
+ accent_color,
+ "transparent",
+ ),
+ color=rx.cond(
+ State.origin_url == f"/{text.lower()}/",
+ accent_text_color,
+ text_color,
+ ),
+ border_radius=border_radius,
+ box_shadow=box_shadow,
+ width="100%",
+ padding_x="1em",
+ ),
+ href=url,
+ width="100%",
+ )
+
+
+def sidebar() -> rx.Component:
+ """Sidebar.
+
+ Returns:
+ rx.Component: The sidebar component.
+ """
+ return rx.box(
+ rx.vstack(
+ sidebar_header(),
+ rx.vstack(
+ sidebar_item(
+ "Dashboard",
+ "/github.svg",
+ "/dashboard",
+ ),
+ sidebar_item(
+ "Settings",
+ "/github.svg",
+ "/settings",
+ ),
+ width="100%",
+ align_items="flex-start",
+ padding="1em",
+ ),
+ rx.spacer(),
+ sidebar_footer(),
+ height="100vh",
+ ),
+ min_width="20em",
+ width="25em",
+ height="100%",
+ left="0px",
+ top="0px",
+ border_right=border,
+ )
diff --git a/reflex/.templates/apps/base/code/state.py b/reflex/.templates/apps/base/code/state.py
new file mode 100644
index 000000000..573f12684
--- /dev/null
+++ b/reflex/.templates/apps/base/code/state.py
@@ -0,0 +1,16 @@
+"""Base state for the app."""
+
+import reflex as rx
+
+
+class State(rx.State):
+ """State for the app."""
+
+ @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", "")
diff --git a/reflex/.templates/apps/base/code/styles.py b/reflex/.templates/apps/base/code/styles.py
new file mode 100644
index 000000000..0290d0bec
--- /dev/null
+++ b/reflex/.templates/apps/base/code/styles.py
@@ -0,0 +1,41 @@
+"""Styles for the app."""
+import reflex as rx
+
+border_radius = ("0.375rem",)
+box_shadow = ("0px 0px 0px 1px rgba(84, 82, 95, 0.14)",)
+border = "1px solid #F4F3F6"
+text_color = "black"
+accent_text_color = "#1A1060"
+accent_color = "#F5EFFE"
+
+template_page_style = {
+ "height": "100vh",
+ "width": "100%",
+ "padding_top": "5em",
+ "padding_x": "2em",
+}
+
+template_content_style = {
+ "width": "100%",
+ "align_items": "flex-start",
+ "height": "90%",
+ "box_shadow": "0px 0px 0px 1px rgba(84, 82, 95, 0.14)",
+ "border_radius": border_radius,
+ "padding": "1em",
+}
+
+link_style = {
+ "color": text_color,
+ "text_decoration": "none",
+ "_hover": {
+ "color": accent_color,
+ },
+}
+
+base_style = {
+ rx.MenuItem: {
+ "_hover": {
+ "bg": accent_color,
+ },
+ },
+}
diff --git a/reflex/.templates/apps/counter/counter.py b/reflex/.templates/apps/counter/counter.py
deleted file mode 100644
index 5bf2ab4ae..000000000
--- a/reflex/.templates/apps/counter/counter.py
+++ /dev/null
@@ -1,53 +0,0 @@
-"""Welcome to Reflex! This file creates a counter app."""
-import random
-
-import reflex as rx
-
-
-class State(rx.State):
- """The app state."""
-
- count = 0
-
- def increment(self):
- """Increment the count."""
- self.count += 1
-
- def decrement(self):
- """Decrement the count."""
- self.count -= 1
-
- def random(self):
- """Randomize the count."""
- self.count = random.randint(0, 100)
-
-
-def index() -> rx.Component:
- return rx.center(
- rx.vstack(
- rx.heading(State.count),
- rx.hstack(
- rx.button("Decrement", on_click=State.decrement, color_scheme="red"),
- rx.button(
- "Randomize",
- on_click=State.random,
- background_image="linear-gradient(90deg, rgba(255,0,0,1) 0%, rgba(0,176,34,1) 100%)",
- color="white",
- ),
- rx.button("Increment", on_click=State.increment, color_scheme="green"),
- ),
- padding="1em",
- bg="#ededed",
- border_radius="1em",
- box_shadow="lg",
- ),
- padding_y="5em",
- font_size="2em",
- text_align="center",
- )
-
-
-# Add state and page to the app.
-app = rx.App()
-app.add_page(index, title="Counter")
-app.compile()
diff --git a/reflex/.templates/apps/default/__init__.py b/reflex/.templates/apps/default/__init__.py
deleted file mode 100644
index e69de29bb..000000000
diff --git a/reflex/.templates/apps/default/assets/favicon.ico b/reflex/.templates/apps/default/assets/favicon.ico
new file mode 100644
index 000000000..166ae995e
Binary files /dev/null and b/reflex/.templates/apps/default/assets/favicon.ico differ
diff --git a/reflex/.templates/apps/counter/__init__.py b/reflex/.templates/apps/default/code/__init__.py
similarity index 100%
rename from reflex/.templates/apps/counter/__init__.py
rename to reflex/.templates/apps/default/code/__init__.py
diff --git a/reflex/.templates/apps/default/default.py b/reflex/.templates/apps/default/code/default.py
similarity index 100%
rename from reflex/.templates/apps/default/default.py
rename to reflex/.templates/apps/default/code/default.py
diff --git a/reflex/.templates/assets/favicon.ico b/reflex/.templates/assets/favicon.ico
deleted file mode 100644
index 609f6abcb..000000000
Binary files a/reflex/.templates/assets/favicon.ico and /dev/null differ
diff --git a/reflex/constants/base.py b/reflex/constants/base.py
index 490ea2887..ca173d792 100644
--- a/reflex/constants/base.py
+++ b/reflex/constants/base.py
@@ -77,11 +77,12 @@ class Reflex(SimpleNamespace):
class Templates(SimpleNamespace):
"""Constants related to Templates."""
- class Kind(str, Enum):
- """The templates to use for the app."""
+ # Dynamically get the enum values from the .templates folder
+ template_dir = os.path.join(Reflex.ROOT_DIR, Reflex.MODULE_NAME, ".templates/apps")
+ template_dirs = next(os.walk(template_dir))[1]
- DEFAULT = "default"
- COUNTER = "counter"
+ # Create an enum value for each directory in the .templates folder
+ Kind = Enum("Kind", {template.upper(): template for template in template_dirs})
class Dirs(SimpleNamespace):
"""Folders used by the template system of Reflex."""
@@ -90,8 +91,6 @@ class Templates(SimpleNamespace):
BASE = os.path.join(Reflex.ROOT_DIR, Reflex.MODULE_NAME, ".templates")
# The web subdirectory of the template directory.
WEB_TEMPLATE = os.path.join(BASE, "web")
- # The assets subdirectory of the template directory.
- ASSETS_TEMPLATE = os.path.join(BASE, Dirs.APP_ASSETS)
# The jinja template directory.
JINJA_TEMPLATE = os.path.join(BASE, "jinja")
diff --git a/reflex/reflex.py b/reflex/reflex.py
index 1c4ce739d..3dc792d63 100644
--- a/reflex/reflex.py
+++ b/reflex/reflex.py
@@ -54,7 +54,7 @@ def init(
None, metavar="APP_NAME", help="The name of the app to initialize."
),
template: constants.Templates.Kind = typer.Option(
- constants.Templates.Kind.DEFAULT,
+ constants.Templates.Kind.DEFAULT.value,
help="The template to initialize the app with.",
),
loglevel: constants.LogLevel = typer.Option(
diff --git a/reflex/utils/prerequisites.py b/reflex/utils/prerequisites.py
index fa78acfb8..fd81419d3 100644
--- a/reflex/utils/prerequisites.py
+++ b/reflex/utils/prerequisites.py
@@ -209,13 +209,17 @@ def initialize_app_directory(app_name: str, template: constants.Templates.Kind):
"""
console.log("Initializing the app directory.")
path_ops.cp(
- os.path.join(constants.Templates.Dirs.BASE, "apps", template.value), app_name
+ os.path.join(constants.Templates.Dirs.BASE, "apps", template.value, "code"),
+ app_name,
)
path_ops.mv(
os.path.join(app_name, template.value + ".py"),
os.path.join(app_name, app_name + constants.Ext.PY),
)
- path_ops.cp(constants.Templates.Dirs.ASSETS_TEMPLATE, constants.Dirs.APP_ASSETS)
+ path_ops.cp(
+ os.path.join(constants.Templates.Dirs.BASE, "apps", template.value, "assets"),
+ constants.Dirs.APP_ASSETS,
+ )
def initialize_web_directory():