Skip to content

Commit 363cf1a

Browse files
committed
05: Bulma and Jinja2
1 parent 6e824bc commit 363cf1a

File tree

13 files changed

+3456
-15
lines changed

13 files changed

+3456
-15
lines changed

docs/building/bulma.md

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
# Bulma and Jinja2
2+
3+
Let's start moving towards the goal of providing attractive examples.
4+
Each example will appear in several "targets", primarily a website like
5+
the [existing examples](https://pyscript.net/examples/).
6+
7+
In this step, we'll start building the PSC website.
8+
We will *not* in this step, though, tackle any concept of a build step, nor anything beyond the homepage.
9+
10+
Big ideas: use off-the-shelf CSS framework, static generation, dead-simple web tech.
11+
12+
## Why Bulma?
13+
14+
We're making a website -- the PyScript Collective.
15+
But we're also making a web app -- the PyScript Gallery.
16+
As it turns out, we're also shipping a PyPI package -- the PyScript Gallery, aka `psga`.
17+
18+
We need a nice-looking web app.
19+
Since we're not designers, let's use a popular, off-the-shelf CSS framework.
20+
I have experience with (and faith in) [Bulma](https://bulma.io): it's attractive out-of-the-box, mature, and strikes the
21+
right balance.
22+
23+
## Bring In Bulma
24+
25+
The tests are in good shape and having `beautifulsoup` will prove...beautiful.
26+
We start with a failing test, one using `BeautifulSoup` to fetch the `link[rel="stylesheet"]` node, then fetch the URL pointed to there.
27+
28+
To make it pass, I:
29+
30+
- Downloaded the bits into static
31+
- Added a `<link rel="stylesheet" href="/static/bulma.min.css" />` to the home page.
32+
33+
I also added the other parts of the Bulma starter (doctype, meta.)
34+
If we open it up in the browser, it looks a bit different.
35+
36+
## Navbar and Footer
37+
38+
We'd like a common navbar on all our pages.
39+
Bulma [has a navbar](https://bulma.io/documentation/components/navbar/).
40+
This also means a download of the PyScript SVG logo, which we'll write a test for.
41+
42+
Ditto for a -- for now, *very* simple -- [footer component](https://bulma.io/documentation/layout/footer/).
43+
44+
## Body
45+
46+
Bulma makes use of `<section>`, `<footer>`, etc.
47+
Let's put the "main" part of our page into a `<main class="section">` tag.
48+
49+
For the failing test, we'll simply look to see there is a `<main>`.
50+
But, as this is no longer a static asset, we'll put this in `test_app.test_homepage`.
51+
52+
## Templating
53+
54+
It sucks to repeat the layout across every static HTML file.
55+
Let's make some Jinja2 templates, then [setup Starlette](https://www.starlette.io/templates/) to use it the templates.
56+
57+
As precursor, install Jinja2 as a dependency.
58+
59+
We'll start by making a templates directory at `src/psc/templates`.
60+
In there, we'll make `page.jinja2` and `layout.jinja2`.
61+
62+
In `layout.jinja2`, take everything out that isn't in `<main>`.
63+
Provide a slot for title and main.
64+
Then change `page.jinja2` to point at `layout.jinja2`, filling those two slots.
65+
66+
In `app.py`, we change the `homepage` route to return a template.
67+
The context dictionary for the template will have two pieces of data:
68+
- The title of the current page
69+
- The HTML that should go in the main block.
70+
71+
Let's do three things:
72+
73+
- Change `index.html` only have the `<main>` part
74+
- In the route, read the file content
75+
- Then pass the file contents into `page.jinja2`, using `| safe`
76+
77+
When done correctly, the tests should pass.
78+
79+
## Future
80+
81+
This PSC prototype just uses downloaded Bulma CSS and other assets.
82+
It doesn't bring in the SASS customizations and software, nor does it look at Bulma forks that bring in CSS Variables.
83+
84+
While we did a little templating, we didn't go far.
85+
It's going to get a lot more interesting and intricate, as we have different ways we want to package things.

docs/building/index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,5 @@ proper_package
3030
cmd_runner
3131
playwright
3232
first_pyscript
33+
bulma
3334
```

poetry.lock

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ typer = { extras = ["all"], version = "^0.6.1" }
2323
starlette = "^0.20.4"
2424
uvicorn = "^0.18.2"
2525
python-frontmatter = "^1.0.0"
26+
Jinja2 = "^3.1.2"
2627

2728
[tool.poetry.dev-dependencies]
2829
Pygments = ">=2.10.0"

src/psc/app.py

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,49 @@
11
"""Provide a web server to browse the examples."""
2+
from pathlib import Path
23

34
from starlette.applications import Starlette
45
from starlette.requests import Request
56
from starlette.responses import FileResponse
6-
from starlette.responses import HTMLResponse
77
from starlette.routing import Mount
88
from starlette.routing import Route
99
from starlette.staticfiles import StaticFiles
10+
from starlette.templating import Jinja2Templates
11+
from starlette.templating import _TemplateResponse
1012

11-
from .here import HERE, PYSCRIPT
12-
from .here import PYODIDE
13-
from .here import STATIC
13+
from psc.here import PYODIDE
14+
from psc.here import PYSCRIPT
15+
from psc.here import STATIC
16+
17+
18+
HERE = Path(__file__).parent
19+
templates = Jinja2Templates(directory=HERE / "templates")
1420

1521

1622
async def favicon(request: Request) -> FileResponse:
17-
"""Route just for serving the favicon."""
23+
"""Handle the favicon."""
1824
return FileResponse(HERE / "favicon.png")
1925

2026

21-
def index_page(request: Request) -> HTMLResponse:
27+
async def homepage(request: Request) -> _TemplateResponse:
2228
"""Handle the home page."""
23-
return HTMLResponse("<h1>Hello, world!</h1>")
29+
index_file = HERE / "index.html"
30+
31+
return templates.TemplateResponse(
32+
"page.jinja2",
33+
dict(
34+
title="Home Page",
35+
main=index_file.read_text(),
36+
request=request,
37+
),
38+
)
2439

2540

2641
routes = [
27-
Route("/", index_page),
28-
Mount("/static", StaticFiles(directory=STATIC)),
42+
Route("/", homepage),
43+
Route("/index.html", homepage),
2944
Route("/favicon.png", favicon),
3045
Mount("/examples", StaticFiles(directory=HERE / "examples")),
46+
Mount("/static", StaticFiles(directory=STATIC)),
3147
Mount("/pyscript", StaticFiles(directory=PYSCRIPT)),
3248
Mount("/pyodide", StaticFiles(directory=PYODIDE)),
3349
]

src/psc/fixtures.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@
1414
from requests.models import Response
1515
from starlette.testclient import TestClient
1616

17-
from psc.here import HERE
1817
from psc.app import app
18+
from psc.here import HERE
1919

2020

2121
@dataclass

src/psc/here.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"""Paths that can be referenced anywhere and get the right target."""
22
from pathlib import Path
33

4+
45
HERE = Path(__file__).parent
56
STATIC = HERE / "static"
67
PYODIDE = HERE / "pyodide"

src/psc/index.html

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<main class="section">
2+
<h1>PyScript Collective</h1>
3+
<h2>Examples</h2>
4+
<ul>
5+
<li><a href="examples/hello_world/index.html">Hello World</a></li>
6+
</ul>
7+
</main>

0 commit comments

Comments
 (0)