瀏覽代碼

Added base template + improve templating code (#1937)

Alek Petuskey 1 年之前
父節點
當前提交
7d4194be34

二進制
reflex/.templates/apps/base/assets/favicon.ico


+ 10 - 0
reflex/.templates/apps/base/assets/github.svg

@@ -0,0 +1,10 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="Github" clip-path="url(#clip0_469_1929)">
+<path id="Vector" d="M8.0004 0.587524C3.80139 0.587524 0.400391 3.98851 0.400391 8.1875C0.400391 11.5505 2.57589 14.391 5.59689 15.398C5.97689 15.4645 6.11939 15.2365 6.11939 15.037C6.11939 14.8565 6.10989 14.258 6.10989 13.6215C4.20039 13.973 3.70639 13.156 3.55439 12.7285C3.46889 12.51 3.09839 11.8355 2.77539 11.655C2.50939 11.5125 2.12939 11.161 2.76589 11.1515C3.36439 11.142 3.79189 11.7025 3.93439 11.9305C4.61839 13.08 5.71089 12.757 6.14789 12.5575C6.21439 12.0635 6.41388 11.731 6.6324 11.541C4.94139 11.351 3.17439 10.6955 3.17439 7.7885C3.17439 6.962 3.46889 6.27801 3.95339 5.74601C3.87739 5.55601 3.61139 4.77701 4.02939 3.73201C4.02939 3.73201 4.66589 3.53251 6.11939 4.51101C6.7274 4.34001 7.3734 4.25451 8.0194 4.25451C8.6654 4.25451 9.3114 4.34001 9.9194 4.51101C11.3729 3.52301 12.0094 3.73201 12.0094 3.73201C12.4274 4.77701 12.1614 5.55601 12.0854 5.74601C12.5699 6.27801 12.8644 6.9525 12.8644 7.7885C12.8644 10.705 11.0879 11.351 9.3969 11.541C9.6724 11.7785 9.9099 12.2345 9.9099 12.947C9.9099 13.9635 9.9004 14.7805 9.9004 15.037C9.9004 15.2365 10.0429 15.474 10.4229 15.398C13.5165 14.3536 15.5996 11.4527 15.6004 8.1875C15.6004 3.98851 12.1994 0.587524 8.0004 0.587524Z" fill="#494369"/>
+</g>
+<defs>
+<clipPath id="clip0_469_1929">
+<rect width="16" height="16" fill="white"/>
+</clipPath>
+</defs>
+</svg>

+ 37 - 0
reflex/.templates/apps/base/assets/icon.svg

@@ -0,0 +1,37 @@
+<svg width="67" height="14" viewBox="0 0 67 14" fill="none" xmlns="http://www.w3.org/2000/svg">
+<rect width="67" height="14" fill="#1E1E1E"/>
+<g id="Nav Template &#62; Initial" clip-path="url(#clip0_0_1)">
+<rect width="1440" height="1024" transform="translate(-16 -17)" fill="white"/>
+<g id="Sidebar">
+<g clip-path="url(#clip1_0_1)">
+<path d="M-16 -17H264V1007H-16V-17Z" fill="white"/>
+<g id="Header">
+<path d="M-16 -17H264V31H-16V-17Z" fill="white"/>
+<g id="Button">
+<rect x="-4" y="-3" width="74.316" height="20" rx="6" fill="white"/>
+<g id="Logo">
+<g id="Reflex">
+<path d="M0 13.6316V0.368408H10.6106V5.67369H7.95792V3.02105H2.65264V5.67369H7.95792V8.32633H2.65264V13.6316H0ZM7.95792 13.6316V8.32633H10.6106V13.6316H7.95792Z" fill="#110F1F"/>
+<path d="M13.2632 13.6316V0.368408H21.2211V3.02105H15.9158V5.67369H21.2211V8.32633H15.9158V10.979H21.2211V13.6316H13.2632Z" fill="#110F1F"/>
+<path d="M23.8738 13.6316V0.368408H31.8317V3.02105H26.5264V5.67369H31.8317V8.32633H26.5264V13.6316H23.8738Z" fill="#110F1F"/>
+<path d="M34.4843 13.6316V0.368408H37.137V10.979H42.4422V13.6316H34.4843Z" fill="#110F1F"/>
+<path d="M45.0949 13.6316V0.368408H53.0528V3.02105H47.7475V5.67369H53.0528V8.32633H47.7475V10.979H53.0528V13.6316H45.0949Z" fill="#110F1F"/>
+<path d="M55.7054 5.67369V0.368408H58.3581V5.67369H55.7054ZM63.6634 5.67369V0.368408H66.316V5.67369H63.6634ZM58.3581 8.32633V5.67369H63.6634V8.32633H58.3581ZM55.7054 13.6316V8.32633H58.3581V13.6316H55.7054ZM63.6634 13.6316V8.32633H66.316V13.6316H63.6634Z" fill="#110F1F"/>
+</g>
+</g>
+</g>
+<path d="M264 30.5H-16V31.5H264V30.5Z" fill="#F4F3F6"/>
+</g>
+</g>
+<path d="M263.5 -17V1007H264.5V-17H263.5Z" fill="#F4F3F6"/>
+</g>
+</g>
+<defs>
+<clipPath id="clip0_0_1">
+<rect width="1440" height="1024" fill="white" transform="translate(-16 -17)"/>
+</clipPath>
+<clipPath id="clip1_0_1">
+<path d="M-16 -17H264V1007H-16V-17Z" fill="white"/>
+</clipPath>
+</defs>
+</svg>

+ 68 - 0
reflex/.templates/apps/base/assets/logo.svg

@@ -0,0 +1,68 @@
+<svg width="80" height="78" viewBox="0 0 80 78" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g filter="url(#filter0_ddddi_449_2821)">
+<path d="M13 11C13 6.58172 16.5817 3 21 3H59C63.4183 3 67 6.58172 67 11V49C67 52.3137 64.3137 55 61 55H19C15.6863 55 13 52.3137 13 49V11Z" fill="url(#paint0_radial_449_2821)"/>
+<path d="M13 11C13 6.58172 16.5817 3 21 3H59C63.4183 3 67 6.58172 67 11V49C67 52.3137 64.3137 55 61 55H19C15.6863 55 13 52.3137 13 49V11Z" fill="url(#paint1_radial_449_2821)"/>
+<g filter="url(#filter1_i_449_2821)">
+<path d="M31 37.5C30.4477 37.5 30 37.0523 30 36.5V13.5001C30 12.9478 30.4477 12.5001 31 12.5001H49C49.5523 12.5001 50 12.9478 50 13.5001V21.5001C50 22.0524 49.5523 22.5001 49 22.5001H45V18.5001C45 17.9478 44.5523 17.5001 44 17.5001H36C35.4477 17.5001 35 17.9478 35 18.5001V21.5001C35 22.0524 35.4477 22.5001 36 22.5001H45V27.5001H36C35.4477 27.5001 35 27.9478 35 28.5001V36.5C35 37.0523 34.5523 37.5 34 37.5H31ZM46 37.5C45.4477 37.5 45 37.0523 45 36.5V27.5001H49C49.5523 27.5001 50 27.9478 50 28.5001V36.5C50 37.0523 49.5523 37.5 49 37.5H46Z" fill="url(#paint2_radial_449_2821)"/>
+</g>
+<path d="M13 11C13 6.58172 16.5817 3 21 3H59C63.4183 3 67 6.58172 67 11V49C67 52.3137 64.3137 55 61 55H19C15.6863 55 13 52.3137 13 49V11Z" stroke="#20117E" stroke-opacity="0.04"/>
+</g>
+<defs>
+<filter id="filter0_ddddi_449_2821" x="0.5" y="0.5" width="79" height="77" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
+<feFlood flood-opacity="0" result="BackgroundImageFix"/>
+<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
+<feMorphology radius="4" operator="erode" in="SourceAlpha" result="effect1_dropShadow_449_2821"/>
+<feOffset dy="10"/>
+<feGaussianBlur stdDeviation="8"/>
+<feColorMatrix type="matrix" values="0 0 0 0 0.0784314 0 0 0 0 0.0705882 0 0 0 0 0.231373 0 0 0 0.06 0"/>
+<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_449_2821"/>
+<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
+<feMorphology radius="6" operator="erode" in="SourceAlpha" result="effect2_dropShadow_449_2821"/>
+<feOffset dy="12"/>
+<feGaussianBlur stdDeviation="3"/>
+<feColorMatrix type="matrix" values="0 0 0 0 0.0784314 0 0 0 0 0.0705882 0 0 0 0 0.231373 0 0 0 0.1 0"/>
+<feBlend mode="normal" in2="effect1_dropShadow_449_2821" result="effect2_dropShadow_449_2821"/>
+<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
+<feMorphology radius="4" operator="erode" in="SourceAlpha" result="effect3_dropShadow_449_2821"/>
+<feOffset dy="10"/>
+<feGaussianBlur stdDeviation="3"/>
+<feColorMatrix type="matrix" values="0 0 0 0 0.12549 0 0 0 0 0.0666667 0 0 0 0 0.494118 0 0 0 0.16 0"/>
+<feBlend mode="normal" in2="effect2_dropShadow_449_2821" result="effect3_dropShadow_449_2821"/>
+<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
+<feMorphology radius="1" operator="dilate" in="SourceAlpha" result="effect4_dropShadow_449_2821"/>
+<feOffset dy="2"/>
+<feGaussianBlur stdDeviation="1"/>
+<feColorMatrix type="matrix" values="0 0 0 0 0.12549 0 0 0 0 0.0666667 0 0 0 0 0.494118 0 0 0 0.05 0"/>
+<feBlend mode="normal" in2="effect3_dropShadow_449_2821" result="effect4_dropShadow_449_2821"/>
+<feBlend mode="normal" in="SourceGraphic" in2="effect4_dropShadow_449_2821" result="shape"/>
+<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
+<feOffset dy="-8"/>
+<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/>
+<feColorMatrix type="matrix" values="0 0 0 0 0.678431 0 0 0 0 0.607843 0 0 0 0 0.972549 0 0 0 0.2 0"/>
+<feBlend mode="normal" in2="shape" result="effect5_innerShadow_449_2821"/>
+</filter>
+<filter id="filter1_i_449_2821" x="30" y="12.5001" width="20" height="26.9999" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
+<feFlood flood-opacity="0" result="BackgroundImageFix"/>
+<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
+<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
+<feOffset dy="2"/>
+<feGaussianBlur stdDeviation="1.5"/>
+<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/>
+<feColorMatrix type="matrix" values="0 0 0 0 0.12549 0 0 0 0 0.0666667 0 0 0 0 0.494118 0 0 0 0.32 0"/>
+<feBlend mode="normal" in2="shape" result="effect1_innerShadow_449_2821"/>
+</filter>
+<radialGradient id="paint0_radial_449_2821" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(40 3) rotate(90) scale(52 54)">
+<stop stop-color="white" stop-opacity="0.9"/>
+<stop offset="1" stop-color="#4E3DB9" stop-opacity="0.24"/>
+</radialGradient>
+<radialGradient id="paint1_radial_449_2821" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(40 3) rotate(90) scale(52 54)">
+<stop stop-color="white"/>
+<stop offset="1" stop-color="#F7F7F7"/>
+</radialGradient>
+<radialGradient id="paint2_radial_449_2821" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(40 12.5001) rotate(90) scale(24.9999 20)">
+<stop stop-color="#F5F3FF"/>
+<stop stop-color="white"/>
+<stop offset="1" stop-color="#E1DDF4"/>
+</radialGradient>
+</defs>
+</svg>

+ 13 - 0
reflex/.templates/apps/base/assets/paneleft.svg

@@ -0,0 +1,13 @@
+<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="PaneLeft" clip-path="url(#clip0_469_1942)">
+<g id="Vector">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M7.80217 0.525009C7.34654 0.525009 6.97717 0.894373 6.97717 1.35001V10.65C6.97717 11.1056 7.34654 11.475 7.80217 11.475H10.6522C11.1078 11.475 11.4772 11.1056 11.4772 10.65V1.35001C11.4772 0.894373 11.1078 0.525009 10.6522 0.525009H7.80217ZM8.02717 10.425V1.57501H10.4272V10.425H8.02717Z" fill="#494369"/>
+<path d="M3.78215 8.14502L2.16213 6.525H5.92717V5.475H2.16213L3.78215 3.85498L3.03969 3.11252L0.523438 5.62877V6.37123L3.03969 8.88748L3.78215 8.14502Z" fill="#494369"/>
+</g>
+</g>
+<defs>
+<clipPath id="clip0_469_1942">
+<rect width="12" height="12" fill="white"/>
+</clipPath>
+</defs>
+</svg>

+ 1 - 0
reflex/.templates/apps/base/code/__init__.py

@@ -0,0 +1 @@
+"""Base template for Reflex."""

+ 90 - 0
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()

+ 4 - 0
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

+ 28 - 0
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,
+    )

+ 28 - 0
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,
+    )

+ 28 - 0
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,
+    )

+ 159 - 0
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,
+    )

+ 16 - 0
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", "")

+ 41 - 0
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,
+        },
+    },
+}

+ 0 - 53
reflex/.templates/apps/counter/counter.py

@@ -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()

+ 0 - 0
reflex/.templates/apps/default/__init__.py


二進制
reflex/.templates/apps/default/assets/favicon.ico


+ 0 - 0
reflex/.templates/apps/counter/__init__.py → reflex/.templates/apps/default/code/__init__.py


+ 0 - 0
reflex/.templates/apps/default/default.py → reflex/.templates/apps/default/code/default.py


二進制
reflex/.templates/assets/favicon.ico


+ 5 - 6
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")
 

+ 1 - 1
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(

+ 6 - 2
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():