diff --git a/README.md b/README.md index 8d22691..e7f3903 100644 --- a/README.md +++ b/README.md @@ -9,8 +9,11 @@ ``` pip3 install ph7 ``` + ## Quickstart + Write your first block of markup + ```python from ph7.html import body, div, html @@ -35,6 +38,72 @@ print(template) ``` +Or write a CSS class + + +```python +from ph7.css import CSSObject + + +class flex_center(CSSObject): + """Flex center""" + + display = "flex" + align_items = "center" + justify_content = "center" + + +print(flex_center()) +``` + +```css +.flex-center { + display: flex; + align-items: center; + justify-content: center; +} +``` + + +Or use python function as JavaScript functions + + + +```python +from ph7.js import as_js, console, document, fetch + + +async def fetchDog(): + response = await fetch( + "https://dog.ceo/api/breeds/image/random", + {"method": "GET"}, + ) + if response.status != 200: + response_body = await response.text() + console.log(f"Error fetching dog; {response_body}") + return + data = await response.json() + document.getElementById("image").src = data.message + + +print(as_js(fetchDog)) +``` + +```js +async function fetchDog() { + let response = await fetch('https://dog.ceo/api/breeds/image/random', { + 'method': 'GET' + }); + if (response.status != 200) { + let response_body = await response.text(); + console.log('Error fetching dog; ' + response_body); + return; + }; + let data = await response.json(); + document.getElementById('image').src = data.message; +}; +``` + Links: diff --git a/docs/django.md b/docs/django.md index b236f71..86a104c 100644 --- a/docs/django.md +++ b/docs/django.md @@ -14,7 +14,7 @@ TEMPLATES = [ ] ``` -## Write Templates +## Templates ```bash |_ home @@ -60,6 +60,60 @@ def home(request): If you name your view anything other than `template`, you can specify the view name using `module:view` format. For example if you name your view `home`, you can specify the template as `app:home`. + +## Forms + +Forms can be included directly using `form` tag. + + +```python +from django import forms + +from ph7.html import body, div, form, html, title + + +class UserForm(forms.Form): + """User form class.""" + + name = forms.CharField(label="username") + email = forms.EmailField(label="email") + password = forms.CharField(label="password", widget=forms.PasswordInput()) + + +template = html( + title("Forms Example"), + body( + div( + form( + UserForm(), + ), + ) + ), +) +``` + + + +```html + + + Forms example + + +
+
+ + + + + + +
+
+ + +``` + ## Stylesheets Define your stylesheet using [`CSSObject`](/css/#cssobject) and use [`Static Context`](/css/#static-context) to include the stylesheets in your views. First let's define `templates/styles.py` @@ -70,6 +124,10 @@ from ph7.css import CSSObject class main(CSSObject): + display = "flex" + align_items = "center" + justify_content = "center" + height = "100vh" width = "100vw" @@ -108,58 +166,145 @@ template = html( -> Note: In the final render of the stylesheet generated by static context, only the classes which have been used in a template will be included. +This is what the rendered view looks like +```html + + + Static Files Example + + + +
Hello, World!
+ + +``` -## Forms +And this is what the rendered stylesheet looks like + +```css +.main { + display: flex; + align-items: center; + justify-content: center; + height: 100vh; + width: 100vw; + box-sizing: border-box; + margin: 0px; + padding: 0px; +} +``` -Forms can be included directly using `form` tag. +> Note: In the final render of the stylesheet generated by static context, only the classes which have been used in a template will be included. - +## Scripts + +Write your scripts using the [`ph7.js`](/js) APIs. + + ```python -from django import forms +from ph7.js import alert, console, document, fetch, js_callable -from ph7.html import body, div, form, html, title +@js_callable +async def fetchDog(): + console.log("Fetching dog") + response = await fetch( + "https://dog.ceo/api/breeds/image/random", + { + "method": "GET", + }, + ) + data = await response.json() + console.log("Dog fetched") + document.getElementById("image").src = data.message +``` -class UserForm(forms.Form): - """User form class.""" + - name = forms.CharField(label="username") - email = forms.EmailField(label="email") - password = forms.CharField(label="password", widget=forms.PasswordInput()) +Use the function in the view + + +```python +from javascript.templates.script import fetchDog +from javascript.templates.styles import image, main +from ph7.context import ctx +from ph7.html import body, button, div, head, html, img + +ctx.static.view(__name__) template = html( - title("Forms Example"), + head( + ctx.static.include, + ), body( div( - form( - UserForm(), + img( + src="#", + id="image", + alt="Click to fetch dog", + class_name=image, + ), + button( + "Click to fetch a dog", + handlers={ + "onclick": fetchDog(), + }, ), + class_name=main, ) ), ) + + +if __name__ == "__main__": + print(template.render({"_view": __name__})) ``` +This is what the rendered view looks like + ```html - - Forms example - - -
-
- - - - - - -
-
- + + + + + +
+ Click to fetch dog +
+ ``` + +And this is what the rendered script looks like + +```js +async function fetchDog() { + console.log("Fetching dog"); + let response = await fetch("https://dog.ceo/api/breeds/image/random", { + method: "GET", + }); + let data = await response.json(); + console.log("Dog fetched"); + document.getElementById("image").src = data.message; +} +``` diff --git a/docs/html.md b/docs/html.md index f1da34e..8032d40 100644 --- a/docs/html.md +++ b/docs/html.md @@ -338,9 +338,9 @@ print(f"Third render: {time.perf_counter() - tick}") ``` ```stdout -First render: 6.573292917 -Second render: 0.5675741249999993 -Third render: 0.40496804200000014 +First render: 6.121663833 +Second render: 0.3590905419999997 +Third render: 0.3504045420000006 ``` diff --git a/docs/index.md b/docs/index.md index b446a54..af63783 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,3 +1,14 @@ +## Why PH7? + +* Native to python +* More code modularity +* Easy to write reusable components +* Editor support + * Syntax highlighting + * Code navvigation tools + * Auto-completion +* Type safety using MyPy + ## Install ``` pip3 install ph7 diff --git a/examples/css_example.py b/examples/css_example.py new file mode 100644 index 0000000..2ae0c2e --- /dev/null +++ b/examples/css_example.py @@ -0,0 +1,12 @@ +from ph7.css import CSSObject + + +class flex_center(CSSObject): + """Flex center""" + + display = "flex" + align_items = "center" + justify_content = "center" + + +print(flex_center()) diff --git a/examples/django_app/javascript/templates/__init__.py b/examples/django_app/javascript/templates/__init__.py index 341aee1..52e8ac2 100644 --- a/examples/django_app/javascript/templates/__init__.py +++ b/examples/django_app/javascript/templates/__init__.py @@ -1,42 +1,14 @@ -from ph7 import CSSObject, include -from ph7.html import body, button, div, head, html, img -from ph7.js import console, document, fetch, js_callable - - -class main(CSSObject): - display = "flex" - justify_content = "center" - align_items = "center" - flex_direction = "column" - - height = "100%" - width = "100%" - - -class image(CSSObject): - height = "200px" - width = "400px" +from javascript.templates.script import fetchDog +from javascript.templates.styles import image, main - margin_bottom = "25px" - - -@js_callable -async def fetchDog(): - console.log("Fetching dog") - response = await fetch( - "https://dog.ceo/api/breeds/image/random", - { - "method": "GET", - }, - ) - data = await response.json() - console.log("Dog fetched") - document.getElementById("image").src = data.message +from ph7.context import ctx +from ph7.html import body, button, div, head, html, img +ctx.static.view(__name__) template = html( head( - include(image, main, fetchDog), + ctx.static.include, ), body( div( @@ -56,3 +28,7 @@ async def fetchDog(): ) ), ) + + +if __name__ == "__main__": + print(template.render({"_view": __name__})) diff --git a/examples/django_app/javascript/templates/script.py b/examples/django_app/javascript/templates/script.py new file mode 100644 index 0000000..a210f55 --- /dev/null +++ b/examples/django_app/javascript/templates/script.py @@ -0,0 +1,15 @@ +from ph7.js import alert, console, document, fetch, js_callable + + +@js_callable +async def fetchDog(): + console.log("Fetching dog") + response = await fetch( + "https://dog.ceo/api/breeds/image/random", + { + "method": "GET", + }, + ) + data = await response.json() + console.log("Dog fetched") + document.getElementById("image").src = data.message diff --git a/examples/django_app/javascript/templates/styles.py b/examples/django_app/javascript/templates/styles.py new file mode 100644 index 0000000..de1c1ef --- /dev/null +++ b/examples/django_app/javascript/templates/styles.py @@ -0,0 +1,18 @@ +from ph7 import CSSObject + + +class main(CSSObject): + display = "flex" + justify_content = "center" + align_items = "center" + flex_direction = "column" + + height = "100%" + width = "100%" + + +class image(CSSObject): + height = "200px" + width = "400px" + + margin_bottom = "25px" diff --git a/examples/django_app/static_files/templates/styles.py b/examples/django_app/static_files/templates/styles.py index 64bd20b..60e32fd 100644 --- a/examples/django_app/static_files/templates/styles.py +++ b/examples/django_app/static_files/templates/styles.py @@ -2,6 +2,10 @@ class main(CSSObject): + display = "flex" + align_items = "center" + justify_content = "center" + height = "100vh" width = "100vw" diff --git a/examples/js_example.py b/examples/js_example.py new file mode 100644 index 0000000..91a763b --- /dev/null +++ b/examples/js_example.py @@ -0,0 +1,17 @@ +from ph7.js import as_js, console, document, fetch + + +async def fetchDog(): + response = await fetch( + "https://dog.ceo/api/breeds/image/random", + {"method": "GET"}, + ) + if response.status != 200: + response_body = await response.text() + console.log(f"Error fetching dog; {response_body}") + return + data = await response.json() + document.getElementById("image").src = data.message + + +print(as_js(fetchDog)) diff --git a/ph7/context.py b/ph7/context.py index 0432808..8e6ebac 100644 --- a/ph7/context.py +++ b/ph7/context.py @@ -39,7 +39,7 @@ def view(self, name: str) -> None: def _add_css(self, resource: CSSObject) -> None: """Add css resource.""" module = resource.__module__ - if module not in self.resources: + if module not in self.resources["css"]: self.resources["css"][module] = {} cls, *_ = ( @@ -78,7 +78,7 @@ def _add_js(self, resource: JavaScriptObject) -> None: else resource.__module__ ) - if module not in self.resources: + if module not in self.resources["js"]: self.resources["js"][module] = sys.modules[module] self.cache["js"][module] = to_js( diff --git a/ph7/css.py b/ph7/css.py index 8adc924..048496d 100644 --- a/ph7/css.py +++ b/ph7/css.py @@ -1429,6 +1429,12 @@ def subclasses(cls) -> t.List["CSSObject"]: cs.append(c) return cs + def __str__(self) -> str: + """String represenstation.""" + return render(self, minify=False) + + __repr__ = __str__ + def _render( obj: t.Union[CSSObject, t.Type[CSSObject]], parent: str, container: t.Dict diff --git a/ph7/js/__init__.py b/ph7/js/__init__.py index d0d4825..4fdd429 100644 --- a/ph7/js/__init__.py +++ b/ph7/js/__init__.py @@ -8,6 +8,7 @@ from .events import Events from .lib import JSON, alert, console, document from .lib.api import fetch +from .transpile import as_js, to_js Param = ParamSpec("Param") ReturnType = t.TypeVar("ReturnType") @@ -71,4 +72,6 @@ def js_callable(func: OriginalFunc) -> DecoratedFunc: "js_callable", "alert", "JSON", + "to_js", + "as_js", )