Skip to content

Commit

Permalink
Merge pull request #10 from angrybayblade/refactor/css
Browse files Browse the repository at this point in the history
Clean up CSS classes and add support for pseudo selectors
  • Loading branch information
angrybayblade authored Mar 12, 2024
2 parents e8eb227 + 96c34d8 commit 9dd2934
Show file tree
Hide file tree
Showing 13 changed files with 332 additions and 252 deletions.
155 changes: 79 additions & 76 deletions docs/css.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ print(template)
## CSSObject

Using `style` object is not the only way to develop CSS with PH7, You can utilise a special class called `CSSObject` to define stylesheets.

<!-- {"type": "html", "file": "examples/css_cls.py", "class": "side-by-side"} -->
<div class='side-by-side'>
```python
Expand Down Expand Up @@ -96,11 +97,10 @@ print(template)

A `CSSObject` can also be reused via class inheritance. You can define a base CSS class and reuse it however many times you like.

<!-- {"type": "html", "file": "examples/css_inherit.py", "class": "side-by-side"} -->
<!-- {"type": "css", "file": "examples/css_inherit.py", "class": "side-by-side"} -->
<div class='side-by-side'>
```python
from ph7 import CSSObject, include
from ph7.html import body, div, head, html
from ph7 import CSSObject


class flex_center(CSSObject):
Expand All @@ -118,49 +118,27 @@ class textbox(flex_center):
width = "100vw"


template = html(
head(
include(textbox),
),
body(
div(
"Hello, World!",
class_name=[textbox],
)
),
)

print(template)
print(textbox())
```

```html
<html>
<head>
<style>
.textbox {
display: flex;
align-items: center;
justify-content: center;
height: 100vh;
width: 100vw;
}
</style>
</head>
<body>
<div class="textbox">Hello, World!</div>
</body>
</html>
```css
.textbox {
display: flex;
align-items: center;
justify-content: center;
height: 100vh;
width: 100vw;
}
```
</div>
<!-- end -->

Furthermore `CSSObject` also allows for nesting by sub classes.

<!-- {"type": "html", "file": "examples/css_nesting.py", "class": "side-by-side"} -->
<!-- {"type": "css", "file": "examples/css_nesting.py", "class": "side-by-side"} -->
<div class='side-by-side'>
```python
from ph7 import CSSObject, include
from ph7.html import body, div, head, html
from ph7 import CSSObject


class flex_center(CSSObject):
Expand All @@ -185,54 +163,79 @@ class textbox(flex_center):
font_family = "Lucida Console, Monaco, monospace"


template = html(
head(
include(textbox),
),
body(
div(
div(
"Hello, World!",
class_name=[textbox.text],
),
class_name=[textbox],
)
),
)

print(template)
print(textbox())
```

```html
<html>
<head>
<style>
.textbox {
display: flex;
align-items: center;
justify-content: center;
height: 100vh;
width: 100vw;
}
.textbox .text {
font-size: 12px;
font-weight: 500;
font-family: Lucida Console, Monaco, monospace;
}
</style>
</head>
<body>
<div class="textbox">
<div class="text">Hello, World!</div>
</div>
</body>
</html>
```css
.textbox {
display: flex;
align-items: center;
justify-content: center;
height: 100vh;
width: 100vw;
}
.textbox .text {
font-size: 12px;
font-weight: 500;
font-family: Lucida Console, Monaco, monospace;
}
```
</div>
<!-- end -->

To make your styles more manageable and reusable, you can define the styles in a separate module and import them throughout your codebase. Following section provides an example of a reusable stylesheet module.

## Pseudo Classes and Elements

A pseudo class can be defined by adding `_` at the beginning of class name, for selecting a child you can set `child` parameter. For pseudo, elements add `__` at the beginning of the class name.

<!-- {"type": "css", "file": "examples/css_pseudo_class.py", "class": "side-by-side"} -->
<div class='side-by-side'>
```python
from ph7 import CSSObject, include
from ph7.html import body, div, head, html


class item(CSSObject):
"""Flex center."""

height = "30px"
width = "100%"

margin_top = "5px"

class _nth_child(CSSObject):
"""Nth child."""

child = 1
margin_top = "0px"

class __before(CSSObject):
"""Before selector."""

content = '">"'


print(item())
```

```css
.item {
height: 30px;
width: 100%;
margin-top: 5px;
}
.item::before {
content: ">";
}
.item:nth-child(1) {
margin-top: 0px;
}
```
</div>
<!-- end -->


## Static Context

PH7 has a runtime context object which can be used for managing the static resource. To use a static context, import `ph7.context.ctx`, add `ctx.static.view(__name__)` at the top of your template and add `ctx.static.include` in your view. In the following example we'll use an external stylesheet for styling our view.
Expand Down
20 changes: 10 additions & 10 deletions docs/html.md
Original file line number Diff line number Diff line change
Expand Up @@ -246,14 +246,14 @@ You can define your view as a python function create views based on conditions,
```python
import typing as t

from ph7.html import body, div, html, node
from ph7.html import HtmlNode, body, div, html

user = div(class_name="user")
users = div(class_name="user")
nousers = div("Error, Users not found", class_name="error")


def render_users(context: t.Dict) -> node:
def render_users(context: t.Dict) -> HtmlNode:
"""Render users."""
if "number_of_users" not in context:
return nousers
Expand Down Expand Up @@ -301,14 +301,14 @@ You can also use named arguments instead of context argument to make thing more
```python
import typing as t

from ph7.html import body, div, html, node
from ph7.html import HtmlNode, body, div, html

user = div(class_name="user")
users = div(class_name="user")
nousers = div("Error, Users not found", class_name="error")


def render_users(number_of_users: t.Optional[int] = None) -> node:
def render_users(number_of_users: t.Optional[int] = None) -> HtmlNode:
"""Render users."""
if number_of_users is None:
return nousers
Expand Down Expand Up @@ -361,20 +361,20 @@ import time
import typing as t
from functools import lru_cache

from ph7.html import body, div, html, node
from ph7.html import HtmlNode, body, div, html

user = div(class_name="user")
users = div(class_name="user")
nousers = div("Error, Users not found", class_name="error")


@lru_cache
def _render_users(n: int) -> node:
def _render_users(n: int) -> HtmlNode:
"""Render users."""
return users(user(f"User {i}") for i in range(n))


def render_users(context: t.Dict) -> node:
def render_users(context: t.Dict) -> HtmlNode:
"""Render users."""
if "number_of_users" not in context:
return nousers
Expand All @@ -401,9 +401,9 @@ print(f"Third render: {time.perf_counter() - tick}")
```

```stdout
First render: 6.87079775
Second render: 0.3591619169999998
Third render: 0.3592319160000006
First render: 6.493273332999999
Second render: 0.4277449579999999
Third render: 0.3591492089999999
```
<!-- end -->

Expand Down
6 changes: 3 additions & 3 deletions docs/js.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ If you want to render a function call with arguments you can decorate a method w
<!-- {"type": "html", "file": "examples/js_function_arguments.py"} -->
```python
from ph7 import include
from ph7.html import body, button, div, head, html, img, node
from ph7.html import HtmlNode, body, button, div, head, html, img
from ph7.js import document, fetch, js_callable


Expand All @@ -106,7 +106,7 @@ async def fetchUserProfilePicture(user: str) -> None:
document.getElementById(f"image-{user}").src = data.profile_picture


def _user(name: str) -> node:
def _user(name: str) -> HtmlNode:
return div(
img(src="#", style={"height": "200px", "width": "400px"}, id=f"image-{name}"),
button(
Expand All @@ -118,7 +118,7 @@ def _user(name: str) -> node:
)


def _users(context: dict) -> node:
def _users(context: dict) -> HtmlNode:
"""List users."""
return div(_user(name=name) for name in context["users"])

Expand Down
17 changes: 2 additions & 15 deletions examples/css_inherit.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
from ph7 import CSSObject, include
from ph7.html import body, div, head, html
from ph7 import CSSObject


class flex_center(CSSObject):
Expand All @@ -17,16 +16,4 @@ class textbox(flex_center):
width = "100vw"


template = html(
head(
include(textbox),
),
body(
div(
"Hello, World!",
class_name=[textbox],
)
),
)

print(template)
print(textbox())
20 changes: 2 additions & 18 deletions examples/css_nesting.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
from ph7 import CSSObject, include
from ph7.html import body, div, head, html
from ph7 import CSSObject


class flex_center(CSSObject):
Expand All @@ -24,19 +23,4 @@ class text(CSSObject):
font_family = "Lucida Console, Monaco, monospace"


template = html(
head(
include(textbox),
),
body(
div(
div(
"Hello, World!",
class_name=[textbox.text],
),
class_name=[textbox],
)
),
)

print(template)
print(textbox())
24 changes: 24 additions & 0 deletions examples/css_pseudo_class.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
from ph7 import CSSObject


class item(CSSObject):
"""Flex center."""

height = "30px"
width = "100%"

margin_top = "5px"

class _nth_child(CSSObject):
"""Nth child."""

child = 1
margin_top = "0px"

class __before(CSSObject):
"""Before selector."""

content = '">"'


print(item())
3 changes: 1 addition & 2 deletions ph7/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@
import typing as t
from pathlib import Path

from ph7.css import CSSObject
from ph7.css import render as to_css
from ph7.css import CSSObject, to_css
from ph7.js import JavaScriptObject, JSCallable
from ph7.js.transpile import to_js

Expand Down
Loading

0 comments on commit 9dd2934

Please sign in to comment.