From 3e2ebd9deac8b540bf3c9c4acc574f775695af09 Mon Sep 17 00:00:00 2001 From: Alek Petuskey Date: Sat, 15 Apr 2023 20:51:18 -0700 Subject: [PATCH] Added base templating (#824) * Added base templating --- .../{app => apps/counter}/__init__.py | 0 pynecone/.templates/apps/counter/counter.py | 53 +++++++++++++++++++ pynecone/.templates/apps/default/__init__.py | 0 .../tutorial.py => apps/default/default.py} | 0 pynecone/constants.py | 12 +++-- pynecone/pc.py | 9 +++- pynecone/utils/prerequisites.py | 7 +-- 7 files changed, 72 insertions(+), 9 deletions(-) rename pynecone/.templates/{app => apps/counter}/__init__.py (100%) create mode 100644 pynecone/.templates/apps/counter/counter.py create mode 100644 pynecone/.templates/apps/default/__init__.py rename pynecone/.templates/{app/tutorial.py => apps/default/default.py} (100%) diff --git a/pynecone/.templates/app/__init__.py b/pynecone/.templates/apps/counter/__init__.py similarity index 100% rename from pynecone/.templates/app/__init__.py rename to pynecone/.templates/apps/counter/__init__.py diff --git a/pynecone/.templates/apps/counter/counter.py b/pynecone/.templates/apps/counter/counter.py new file mode 100644 index 000000000..23f8a52e4 --- /dev/null +++ b/pynecone/.templates/apps/counter/counter.py @@ -0,0 +1,53 @@ +"""Welcome to Pynecone! This file create a counter app.""" +import random + +import pynecone as pc + + +class State(pc.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() -> pc.Component: + return pc.center( + pc.vstack( + pc.heading(State.count), + pc.hstack( + pc.button("Decrement", on_click=State.decrement, color_scheme="red"), + pc.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", + ), + pc.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 = pc.App(state=State) +app.add_page(index, title="Counter") +app.compile() diff --git a/pynecone/.templates/apps/default/__init__.py b/pynecone/.templates/apps/default/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/pynecone/.templates/app/tutorial.py b/pynecone/.templates/apps/default/default.py similarity index 100% rename from pynecone/.templates/app/tutorial.py rename to pynecone/.templates/apps/default/default.py diff --git a/pynecone/constants.py b/pynecone/constants.py index ea423024a..9aba8b769 100644 --- a/pynecone/constants.py +++ b/pynecone/constants.py @@ -25,16 +25,12 @@ INVALID_BUN_VERSIONS = ["0.5.6", "0.5.7"] # Files and directories used to init a new project. # The root directory of the pynecone library. ROOT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) -# The name of the file used for pc init. -APP_TEMPLATE_FILE = "tutorial.py" # The name of the assets directory. APP_ASSETS_DIR = "assets" # The template directory used during pc init. TEMPLATE_DIR = os.path.join(ROOT_DIR, MODULE_NAME, ".templates") # The web subdirectory of the template directory. WEB_TEMPLATE_DIR = os.path.join(TEMPLATE_DIR, "web") -# The app subdirectory of the template directory. -APP_TEMPLATE_DIR = os.path.join(TEMPLATE_DIR, "app") # The assets subdirectory of the template directory. ASSETS_TEMPLATE_DIR = os.path.join(TEMPLATE_DIR, APP_ASSETS_DIR) @@ -171,6 +167,14 @@ class LogLevel(str, Enum): CRITICAL = "critical" +# Templates +class Template(str, Enum): + """The templates to use for the app.""" + + DEFAULT = "default" + COUNTER = "counter" + + class Endpoint(Enum): """Endpoints for the pynecone backend API.""" diff --git a/pynecone/pc.py b/pynecone/pc.py index c05fcf09f..56303aa2d 100644 --- a/pynecone/pc.py +++ b/pynecone/pc.py @@ -23,7 +23,12 @@ def version(): @cli.command() -def init(name: str = typer.Option(None, help="Name of the app to be initialized.")): +def init( + name: str = typer.Option(None, help="Name of the app to be initialized."), + template: constants.Template = typer.Option( + constants.Template.DEFAULT, help="Template to use for the app." + ), +): """Initialize a new Pynecone app in the current directory.""" app_name = prerequisites.get_default_app_name() if name is None else name @@ -42,7 +47,7 @@ def init(name: str = typer.Option(None, help="Name of the app to be initialized. # Set up the app directory, only if the config doesn't exist. if not os.path.exists(constants.CONFIG_FILE): prerequisites.create_config(app_name) - prerequisites.initialize_app_directory(app_name) + prerequisites.initialize_app_directory(app_name, template) build.set_pynecone_project_hash() pynecone_telemetry("init", get_config().telemetry_enabled) else: diff --git a/pynecone/utils/prerequisites.py b/pynecone/utils/prerequisites.py index 75f4c8eec..533f327cd 100644 --- a/pynecone/utils/prerequisites.py +++ b/pynecone/utils/prerequisites.py @@ -181,16 +181,17 @@ def initialize_gitignore(): f.write(path_ops.join(files)) -def initialize_app_directory(app_name: str): +def initialize_app_directory(app_name: str, template: constants.Template): """Initialize the app directory on pc init. Args: app_name: The name of the app. + template: The template to use. """ console.log("Initializing the app directory.") - path_ops.cp(constants.APP_TEMPLATE_DIR, app_name) + path_ops.cp(os.path.join(constants.TEMPLATE_DIR, "apps", template.value), app_name) path_ops.mv( - os.path.join(app_name, constants.APP_TEMPLATE_FILE), + os.path.join(app_name, template.value + ".py"), os.path.join(app_name, app_name + constants.PY_EXT), ) path_ops.cp(constants.ASSETS_TEMPLATE_DIR, constants.APP_ASSETS_DIR)