├── .gitignore ├── PerryApp ├── __init__.py ├── coolscript.js ├── example_contents.py └── contents.py ├── Perry ├── Extra │ ├── pjec │ │ ├── std │ │ │ ├── __init__.py │ │ │ ├── json.py │ │ │ ├── _random.py │ │ │ └── requests.py │ │ ├── events │ │ │ └── __init__.py │ │ └── __init__.py │ ├── jquery.py │ └── bootstrap.py ├── components │ └── __init__.py └── __init__.py ├── .upload ├── .breakpoints ├── pyproject.toml ├── PerryFlask └── __init__.py ├── pjec.js ├── docs ├── Makefile ├── conf.py └── index.rst ├── setup.py ├── .readthedocs.yaml ├── example.py ├── main.py ├── README.md ├── README.rst └── poetry.lock /.gitignore: -------------------------------------------------------------------------------- 1 | MANIFEST 2 | build 3 | dist 4 | _preped/* 5 | **/__pycache__ 6 | NexomiaApp/* -------------------------------------------------------------------------------- /PerryApp/__init__.py: -------------------------------------------------------------------------------- 1 | from .contents import HomepageContents 2 | 3 | HomepageContents = HomepageContents -------------------------------------------------------------------------------- /Perry/Extra/pjec/std/__init__.py: -------------------------------------------------------------------------------- 1 | from . import _random, requests, json 2 | 3 | random = _random.random 4 | JSON = json.JSON -------------------------------------------------------------------------------- /.upload: -------------------------------------------------------------------------------- 1 | rm -r dist/* 2 | poetry add readme_renderer[md] 3 | poetry run python3 setup.py sdist 4 | poetry run twine upload dist/* --verbose -------------------------------------------------------------------------------- /Perry/Extra/pjec/std/json.py: -------------------------------------------------------------------------------- 1 | from Perry.Extra.pjec import endComponent 2 | 3 | class JSON: 4 | def parse(_Json:'Json variable to be parsed'): 5 | return endComponent("JSON.parse({});".format(_Json), format=False) -------------------------------------------------------------------------------- /Perry/Extra/pjec/std/_random.py: -------------------------------------------------------------------------------- 1 | from Perry.Extra.pjec import endComponent 2 | 3 | class random: 4 | def int(low = 0, max = 1, include=0): 5 | return endComponent(f"Math.floor(Math.random() * ({max} - {low} + {include}) ) + {low};") -------------------------------------------------------------------------------- /.breakpoints: -------------------------------------------------------------------------------- 1 | { 2 | "files": { 3 | "PerryApp/contents.py": [ 4 | { 5 | "id": "8eaf0cf5-d8cb-4726-93ad-8394cc7dd28f", 6 | "line": 81, 7 | "version": 1410, 8 | "index": 2363 9 | } 10 | ] 11 | } 12 | } -------------------------------------------------------------------------------- /PerryApp/coolscript.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function(){ 2 | console.log('JQuery loaded!'); 3 | $("#button").click(function(){ 4 | var str = $("#whatTitle").val(); 5 | $('#CardTitle').text(str); 6 | var str = $("#whatText").val(); 7 | $('#CardText').text(str); 8 | var str = $("#whatImage").val(); 9 | $("#myCoolImage").attr("src",str); 10 | }); 11 | }); -------------------------------------------------------------------------------- /Perry/Extra/pjec/events/__init__.py: -------------------------------------------------------------------------------- 1 | from . import Event 2 | 3 | class onClick(Event): 4 | def __init__(self, _Function: 'Whatever u do here idfk'): 5 | self._event = Event(self, Card) 6 | self.name = f'' 7 | self.func = _Function 8 | self.type = onClick 9 | 10 | def build(self,debug=False): 11 | # here we construct JS for the component 12 | deb = f'Component: {self.name}' if debug else '' 13 | return f"{self.func.caller}() /*{deb}*/" 14 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "repl_python3_Perry" 3 | version = "0.1.0" 4 | description = "" 5 | authors = ["Your Name "] 6 | 7 | [tool.poetry.dependencies] 8 | python = "^3.8" 9 | Flask = "^2.0.2" 10 | twine = "2.0" 11 | readme-renderer = {extras = ["md"], version = "^32.0"} 12 | fastapi = "^0.70.1" 13 | uvicorn = "^0.16.0" 14 | 15 | [tool.poetry.dev-dependencies] 16 | 17 | [build-system] 18 | requires = ["poetry-core>=1.0.0"] 19 | build-backend = "poetry.core.masonry.api" 20 | -------------------------------------------------------------------------------- /PerryFlask/__init__.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, render_template 2 | app = Flask(__name__) 3 | 4 | def ext_serve(port, debug, host, pages): 5 | 6 | routes = [ ['/'+page['path'], page['func']] for page in pages] 7 | 8 | for route, func in routes: 9 | print('[Flask] Mapped route',route,'with',func) 10 | view_func = app.route(route)(func) 11 | 12 | app.run(debug=debug, port=port, host=host) 13 | 14 | 15 | class _Serve: 16 | def __le__(self, _Pages: 'Composite class of pages', debug=False, port=8080, host='0.0.0.0'): 17 | ext_serve(debug=debug, port=port, host=host, pages=_Pages.pages) 18 | 19 | serve = _Serve() -------------------------------------------------------------------------------- /pjec.js: -------------------------------------------------------------------------------- 1 | /* Just a collection of functions used by PJEC */ 2 | 3 | function getCookie(cName) { 4 | const name = cName + "="; 5 | const cDecoded = decodeURIComponent(document.cookie); 6 | const cArr = cDecoded.split('; '); 7 | let res; 8 | cArr.forEach(val => { 9 | if (val.indexOf(name) === 0) res = val.substring(name.length); 10 | }); 11 | return res; 12 | } 13 | 14 | function empty(e) { 15 | switch (e) { 16 | case "": 17 | case 0: 18 | case "0": 19 | case null: 20 | case false: 21 | case typeof(e) == "undefined": 22 | return true; 23 | default: 24 | return false; 25 | } 26 | } -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line, and also 5 | # from the environment for the first two. 6 | SPHINXOPTS ?= 7 | SPHINXBUILD ?= sphinx-build 8 | SOURCEDIR = source 9 | BUILDDIR = build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from distutils.core import setup, find_packages 2 | 3 | setup( 4 | name="Perry", 5 | version="0.1.12", 6 | author="HUSKI3", 7 | author_email="ignispy@protonmail.com", 8 | description=""" A framework that let's you compose websites in Python with ease! """, 9 | long_description_content_type="text/markdown", 10 | long_description=f"""{open('README.rst','r').read()}""", 11 | packages=find_packages('Perry'), 12 | url="http://pypi.python.org/pypi/Perry/", 13 | project_urls={ 14 | "Bug Tracker": "https://github.com/HUSKI3/Perry/issues", 15 | }, 16 | classifiers=[ 17 | "Programming Language :: Python :: 3", 18 | "Operating System :: OS Independent", 19 | ], 20 | install_requires=[ 21 | "Flask" 22 | ], 23 | python_requires=">=3.6", 24 | ) -------------------------------------------------------------------------------- /.readthedocs.yaml: -------------------------------------------------------------------------------- 1 | # .readthedocs.yaml 2 | # Read the Docs configuration file 3 | # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details 4 | 5 | # Required 6 | version: 2 7 | 8 | # Set the version of Python and other tools you might need 9 | build: 10 | os: ubuntu-20.04 11 | tools: 12 | python: "3.9" 13 | # You can also specify other tool versions: 14 | # nodejs: "16" 15 | # rust: "1.55" 16 | # golang: "1.17" 17 | 18 | # Build documentation in the docs/ directory with Sphinx 19 | sphinx: 20 | configuration: docs/conf.py 21 | 22 | # If using Sphinx, optionally build your docs in additional formats such as PDF 23 | # formats: 24 | # - pdf 25 | 26 | # Optionally declare the Python requirements required to build your docs 27 | python: 28 | install: 29 | - requirements: docs/requirements.txt -------------------------------------------------------------------------------- /docs/conf.py: -------------------------------------------------------------------------------- 1 | # Configuration file for the Sphinx documentation builder. 2 | 3 | # -- Project information 4 | 5 | project = 'Perry' 6 | copyright = '2022, Artur Z' 7 | author = 'Artur Z' 8 | 9 | release = '0.1' 10 | version = '0.1.0' 11 | 12 | # -- General configuration 13 | 14 | extensions = [ 15 | 'sphinx.ext.duration', 16 | 'sphinx.ext.doctest', 17 | 'sphinx.ext.autodoc', 18 | 'sphinx.ext.autosummary', 19 | 'sphinx.ext.intersphinx', 20 | ] 21 | 22 | intersphinx_mapping = { 23 | 'python': ('https://docs.python.org/3/', None), 24 | 'sphinx': ('https://www.sphinx-doc.org/en/master/', None), 25 | } 26 | 27 | intersphinx_disabled_domains = ['std'] 28 | 29 | templates_path = ['_templates'] 30 | 31 | # -- Options for HTML output 32 | 33 | html_theme = 'sphinx_rtd_theme' 34 | 35 | # -- Options for EPUB output 36 | epub_show_urls = 'footnote' -------------------------------------------------------------------------------- /example.py: -------------------------------------------------------------------------------- 1 | from Perry import component, pageView, styleGlobal, styles, serve, Composite 2 | from Perry.components import Label 3 | 4 | # Create our pages, we want them to inherit pageView behaviour 5 | Homepage = component(pageView, _Inherit = True) 6 | About = component(pageView, _Inherit = True) 7 | 8 | # Create page contens 9 | HomepageContents = ( 10 | # Our first hello world! 11 | Label('Hello World!', 'h1'), 12 | # Then we can place some other stuff 13 | Label('Bye!', 'p') 14 | ) 15 | 16 | # Assign page contents 17 | Homepage <= { 18 | 'title': 'Home', 19 | 'path':'', 20 | 'style': styleGlobal( 21 | styles.all['basic'] 22 | ), 23 | 'DOM': pageView.DOM, 24 | 'components': HomepageContents 25 | } 26 | About <= { 27 | 'title': 'About', 28 | 'path':'about', 29 | 'style': styleGlobal( 30 | styles.all['basic'] 31 | ), 32 | 'DOM': Homepage 33 | } 34 | 35 | # Serve our pages as a composite collection 36 | serve <= Composite(Homepage, About) -------------------------------------------------------------------------------- /Perry/Extra/jquery.py: -------------------------------------------------------------------------------- 1 | # A simple JQuery processor 2 | # To be added to the start of a component tuple 3 | from Perry import component 4 | 5 | class JQueryEngine(component): 6 | def __init__(self, _DOM: 'PageView DOM', cid=None): 7 | self._component = component(self, JQueryEngine) 8 | self.name = f'' 9 | self.id = cid if cid is not None else '' 10 | self.dom = _DOM 11 | self.type = JQueryEngine 12 | 13 | def __le__(self, _JQ: 'Pure JQuery code'): 14 | self.code = _JQ 15 | 16 | def build(self, debug=False): 17 | # here we construct HTML for the component 18 | deb = f'' if debug else '' 19 | return self._component.build( 20 | 'literal', 21 | f"" + deb 22 | ) 23 | 24 | class JQueryEngineStrapper: 25 | source = "https://getbootstrap.com/" 26 | ctype = 'mixed' 27 | html = ''' 28 | 29 | 30 | ''' 31 | -------------------------------------------------------------------------------- /PerryApp/example_contents.py: -------------------------------------------------------------------------------- 1 | from Perry.components import Label, Image, DIV, Form, Input, Button 2 | from Perry import ComponentSource, pageView 3 | from Perry.Extra.jquery import JQueryEngine 4 | from Perry.Extra.bootstrap import Card, CardTitle,CardText 5 | from Perry.Extra.pjec import PjecLoader, PjEngine, console, Events 6 | from Perry.Extra.pjec.std import random 7 | 8 | # Let's add JQuery to our website! 9 | js = JQueryEngine(pageView, cid = 'coolscript') 10 | js <= ( 11 | # It's best to load it as a file read, but for demo purposes here's a string 12 | open('PerryApp/coolscript.js','r').read() 13 | ) 14 | 15 | engine = PjEngine() 16 | @engine.function 17 | def hello( page ): 18 | window = page.window 19 | 20 | events = Events( 21 | window.get('text').set( 22 | random.int(0,20) 23 | ) 24 | ) 25 | return page.connector('hello', events) 26 | 27 | # Create page contens 28 | HomepageContents = ComponentSource( 29 | ######## This is the meme maker 30 | DIV( 31 | Label('WHAT meme maker', 'h1'), 32 | Card( 33 | Image('https://tse3.mm.bing.net/th?id=OIP.f1BTli7-ohJqh0cTJLIaDwHaE8&pid=Api', 34 | cid='myCoolImage', 35 | style=''' 36 | max-width: 100%; 37 | display: block; 38 | height: auto 39 | ''' 40 | ), 41 | CardTitle('Red Panda', 'h5', cid='CardTitle'), 42 | CardText("It's a red panda", 'p', cid='CardText'), 43 | cclass = 'mycooldiv' 44 | ), 45 | Form( 46 | DIV( 47 | Input('whatTitle','text', placeholder='Title', cid='whatTitle'), 48 | Input('whatText','text', placeholder='Text', cid='whatText'), 49 | Input('whatImage','text', placeholder='Image URL', cid='whatImage'), 50 | Button('Create','button', cid='button'), 51 | cclass = 'inputs' 52 | ) 53 | ) 54 | ), 55 | DIV( 56 | js, 57 | cclass = 'forjs', 58 | cid = 'script' 59 | ), 60 | ####### This is for PJEC testing 61 | Label('Random number generator!', 'h1'), 62 | DIV( 63 | Label('Random number here', 'p',cid='text'), 64 | Button('Next random number','button', onClick='hello()', cid='button'), 65 | PjecLoader(engine, hello()) 66 | ) 67 | ) 68 | -------------------------------------------------------------------------------- /Perry/Extra/pjec/std/requests.py: -------------------------------------------------------------------------------- 1 | from Perry.Extra.pjec import endComponent 2 | 3 | post_code = ''' 4 | var url = "{url}"; 5 | 6 | var xhr = new XMLHttpRequest(); 7 | xhr.open("POST", url); 8 | 9 | xhr.setRequestHeader("Accept", "application/json"); 10 | xhr.setRequestHeader("Content-Type", "application/json"); 11 | ''' 12 | 13 | get_code = ''' 14 | var url = "{url}"; 15 | 16 | var xhr = new XMLHttpRequest(); 17 | xhr.open("GET", url, false); 18 | ''' 19 | 20 | class Then: 21 | def __init__(self, _Component, data='console.log("No data?");', extra='', headers=''): 22 | self.head = _Component 23 | self.data = data 24 | self.extra= extra 25 | self.headers= headers 26 | 27 | def then(self, *_Events): 28 | built = [] 29 | for event in _Events: 30 | built.append((event.build('global'))) 31 | return endComponent(self.head.format(extra=self.extra.format(then=' '.join(built),data=self.data), headers=self.headers )) 32 | 33 | 34 | class request: 35 | def __init__(self): 36 | pass 37 | def post(self, _Url: 'URL of the server', _Data: 'A Dict or JSON string of data', _varName='response', _Headers = {}): 38 | headers = [] 39 | for header in _Headers: 40 | headers.append(f'xhr.setRequestHeader("{header}", "{_Headers[header]}");') 41 | return Then( 42 | str( 43 | post_code.format(url=_Url) + '\n{headers} \n{extra}' 44 | ), 45 | data=str(_Data).replace("'",'"'), 46 | extra = '''xhr.onreadystatechange = function () {{ 47 | if (xhr.readyState === 4) {{ 48 | console.log(xhr.responseText); 49 | response = xhr.responseText; 50 | {then} 51 | }}}}; 52 | var data = {data}; 53 | console.log(data); 54 | 55 | xhr.send(JSON.stringify(data));''', 56 | headers = '\n'.join(headers) 57 | ) 58 | 59 | def get(self, _Url: 'URL of the server', _Headers = {}): 60 | headers = [] 61 | for header in _Headers: 62 | value = _Headers[header].raw() if type(_Headers[header]) == endComponent else '"'+str(_Headers[header])+'"' 63 | headers.append(f'xhr.setRequestHeader("{header}", {value});') 64 | return Then( 65 | str( 66 | get_code.format(url=_Url)+'\n {headers} \n{extra}' 67 | ), 68 | extra = ''' 69 | xhr.send(null); 70 | response = JSON.parse(xhr.responseText); 71 | {then}''', 72 | headers = '\n'.join(headers) 73 | ) -------------------------------------------------------------------------------- /PerryApp/contents.py: -------------------------------------------------------------------------------- 1 | from Perry.components import Label, Image, DIV, Form, Input, Button 2 | from Perry import ComponentSource, pageView 3 | from Perry.Extra.jquery import JQueryEngine 4 | from Perry.Extra.bootstrap import Card, CardTitle,CardText 5 | from Perry.Extra.pjec import PjecLoader, PjEngine, console, Events 6 | from Perry.Extra.pjec.std import random 7 | 8 | # Let's add JQuery to our website! 9 | js = JQueryEngine(pageView, cid = 'coolscript') 10 | js <= ( 11 | # It's best to load it as a file read, but for demo purposes here's a string 12 | open('PerryApp/coolscript.js','r').read() 13 | ) 14 | 15 | engine = PjEngine() 16 | @engine.function 17 | def hello( page ): 18 | window = page.window 19 | events = Events( 20 | window.get('text').set(random.int(0,20)), 21 | debug=True 22 | ) 23 | return page.connector('hello', events) 24 | 25 | @engine.function 26 | def alert( page ): 27 | window = page.window 28 | events = Events( 29 | window.alert('Howdy, this is a test pjec function with multiple events'), 30 | window.get('rand').set('Howdy'), 31 | debug=True 32 | ) 33 | return page.connector('amber', events) 34 | 35 | # Create page contens 36 | HomepageContents = ComponentSource( 37 | ######## This is the meme maker 38 | DIV( 39 | Label('WHAT meme maker', 'h1'), 40 | Card( 41 | Image('https://tse3.mm.bing.net/th?id=OIP.f1BTli7-ohJqh0cTJLIaDwHaE8&pid=Api', 42 | cid='myCoolImage', 43 | style=''' 44 | max-width: 100%; 45 | display: block; 46 | height: auto 47 | ''' 48 | ), 49 | CardTitle('Red Panda', 'h5', cid='CardTitle'), 50 | CardText("It's a red panda", 'p', cid='CardText'), 51 | cclass = 'mycooldiv' 52 | ), 53 | Form( 54 | DIV( 55 | Input('whatTitle','text', placeholder='Title', cid='whatTitle'), 56 | Input('whatText','text', placeholder='Text', cid='whatText'), 57 | Input('whatImage','text', placeholder='Image URL', cid='whatImage'), 58 | Button('Create','button', cid='button'), 59 | cclass = 'inputs' 60 | ) 61 | ) 62 | ), 63 | DIV( 64 | js, 65 | cclass = 'forjs', 66 | cid = 'script' 67 | ), 68 | ####### This is for PJEC testing 69 | Label('Random number generator!', 'h1'), 70 | DIV( 71 | Label('Random number here', 'p',cid='text'), 72 | Button('Next random number','button', onClick='hello()', cid='button') 73 | ), 74 | DIV( 75 | Label('Text here', 'p', cid='rand'), 76 | Button('Alert test', 'button',onClick='amber()') 77 | ), 78 | # Recommneded to put the PJEC Loader component in the bottom 79 | PjecLoader(engine, hello(), alert()) 80 | ) 81 | -------------------------------------------------------------------------------- /Perry/Extra/bootstrap.py: -------------------------------------------------------------------------------- 1 | from Perry import component 2 | from Perry.components import DIV 3 | 4 | class bootstrap: 5 | source = "https://getbootstrap.com/" 6 | ctype = 'mixed' 7 | html = ''' 8 | 9 | 10 | 11 | 12 | ''' 13 | 14 | class Card(component): 15 | def __init__(self, *args, cid = None, cclass = None): 16 | self._component = component(self, Card) 17 | self.name = f'' 18 | self.children = args 19 | self.id = cid if cid is not None else '' 20 | self.cclass = cclass if cclass is not None else '' 21 | self.type = DIV 22 | 23 | def build(self, _HTML: 'Raw html of built objects' ,debug=False): 24 | # here we construct HTML for the component 25 | _HTML = ' '.join(_HTML) 26 | deb = f'' if debug else '' 27 | return self._component.build( 28 | 'literal', 29 | f"
{_HTML}
" + deb 30 | ) 31 | 32 | class CardTitle(component): 33 | def __init__(self, _Text: str, _Type: 'p', cid = None): 34 | self._component = component(self, CardTitle) 35 | self.name = f'' 36 | self._text = _Text 37 | self.id = cid if cid is not None else '' 38 | self.type = _Type 39 | 40 | def build(self, debug=False): 41 | # here we construct HTML for the component 42 | deb = f'' if debug else '' 43 | return self._component.build( 44 | 'literal', 45 | f"<{self.type} id = {self.id} class='card-title'> {self._text} " + deb 46 | ) 47 | 48 | class CardText(component): 49 | def __init__(self, _Text: str, _Type: 'p', cid = None): 50 | self._component = component(self, CardText) 51 | self.name = f'' 52 | self._text = _Text 53 | self.id = cid if cid is not None else '' 54 | self.type = _Type 55 | 56 | def build(self, debug=False): 57 | # here we construct HTML for the component 58 | deb = f'' if debug else '' 59 | return self._component.build( 60 | 'literal', 61 | f"<{self.type} id = {self.id} class='card-text'> {self._text} " + deb 62 | ) -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | from Perry import component, pageView, Composite, style 2 | from Perry.Extra.bootstrap import bootstrap 3 | from Perry.Extra.jquery import JQueryEngineStrapper 4 | from Perry.Extra.pjec import PJECStrapper 5 | import uvicorn 6 | 7 | # Create our pages, we want them to inherit pageView behaviour. 8 | # As well as other components 9 | Homepage = component(pageView, _Inherit = True) 10 | About = component(pageView, _Inherit = True) 11 | LoginPage = component(pageView, _Inherit = True) 12 | ourCustomStyle = style() 13 | 14 | 15 | # Import contents for a pageView 16 | from NexomiaApp import HomepageContents, LoginPageContents 17 | 18 | # Custom style 19 | ourCustomStyle <= { 20 | 'author':'Us', 21 | 'ctype':'css', 22 | 'css' : ''' 23 | * { 24 | text-align: center; 25 | margin: 0; 26 | font-family: "Inter",sans-serif; 27 | -webkit-font-smoothing: antialiased; 28 | box-sizing: border-box; 29 | --background-light: #4c5360; 30 | --background-primary-alt: #404754; 31 | --background-primary: #373d49; 32 | --background-secondary-alt2: #363b47; 33 | --background-secondary-alt: #333844; 34 | --background-secondary: #2c313d; 35 | --accent: #7794ce; 36 | --accent-green: #52c96c; 37 | --accent-yellow: #dcdd6e; 38 | --accent-alt: #6d87bc; 39 | --accent-dark: #4e5f82; 40 | --text-primary: #dadfea; 41 | --text-secondary: #68707f; 42 | --text-negative: #ff3d70; 43 | } 44 | div { 45 | display: block; 46 | } 47 | '''} 48 | 49 | # Assign page contents 50 | Homepage <= { 51 | 'title': 'Home', 52 | 'path':'', 53 | 'styles': [bootstrap, ourCustomStyle, PJECStrapper], 54 | 'DOM': pageView.DOM, 55 | 'components': HomepageContents 56 | } 57 | 58 | LoginPage <= { 59 | 'title': 'Login', 60 | 'path':'login', 61 | 'styles': [bootstrap, ourCustomStyle, PJECStrapper], 62 | 'DOM': pageView.DOM, 63 | 'components': LoginPageContents 64 | } 65 | 66 | About <= { 67 | 'title': 'About', 68 | 'path':'about', 69 | 'DOM': Homepage 70 | } 71 | 72 | Pages = Composite(Homepage, About, LoginPage) 73 | 74 | # Multiple types of serving the pages are supported 75 | # 76 | 'Flask' 77 | # from PerryFlask import serve 78 | # Serve our pages as a composite collection 79 | # serve <= Pages 80 | # 81 | 82 | 83 | 'FastAPI (Single page)' 84 | from fastapi import FastAPI, Response 85 | 86 | app = FastAPI() 87 | # pages = Pages 88 | 89 | # You can check all page info by printing the Composite component 90 | # print(pages) 91 | 92 | # You can also get page info by querying it's route, 93 | # NOTE: The routes do not contain the initial '/' 94 | # print(pages.get('')) 95 | 96 | @app.get("/") 97 | def read_root(): 98 | return Response(content=Pages.get('').run(), media_type="text/html") 99 | 100 | @app.get("/login") 101 | def read_login(): 102 | return Response(content=Pages.get('login').run(), media_type="text/html") 103 | 104 | # Uvicorn for FastAPI 105 | # uvicorn main:app --reload --host=0.0.0.0 --port=8080 -------------------------------------------------------------------------------- /Perry/components/__init__.py: -------------------------------------------------------------------------------- 1 | from Perry import component 2 | 3 | class Label(component): 4 | def __init__(self, _Text: str, _Type: 'p', cid = '', style=''): 5 | self._component = component(self, Label) 6 | self.name = f'