File size: 3,377 Bytes
ebec85b
84e55f1
0760113
ebec85b
9d8008e
 
0760113
9d8008e
 
 
ebec85b
 
9d8008e
 
0760113
9d8008e
0760113
 
073cfb5
ebec85b
9d8008e
0760113
 
 
 
 
9d8008e
 
ebec85b
9d8008e
 
 
b5bffcc
 
 
d1c33d3
 
 
b5bffcc
 
 
ebec85b
 
9d8008e
b139dbe
9d8008e
 
b139dbe
9d8008e
 
 
 
 
 
 
b139dbe
 
 
 
ebec85b
 
 
 
0760113
 
 
 
 
 
 
 
 
 
 
84e55f1
 
 
 
0760113
 
 
84e55f1
 
0760113
 
 
 
 
ebec85b
9d8008e
ebec85b
 
 
 
 
9d8008e
ebec85b
 
 
 
073cfb5
ebec85b
 
 
9d8008e
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
import importlib
import json
from dataclasses import dataclass
from pathlib import Path

import fasthtml.common as fh
from fasthtml.common import H4, A, Div, Pre, Table, Tbody, Td, Th, Thead, Tr

from tutorial import utils
from tutorial.example import Example

hdrs = (
    fh.MarkdownJS(),
    utils.HighlightJS(langs=["python", "javascript", "html", "css"]),
    utils.social_card(),
    utils.alpine(),
    fh.Script(src="/script.js"),
    fh.Script("init_main_page()"),
    utils.piwik(),
)
html_kv = {
    "x-data": """{
        showRequests: localStorage.getItem('showRequests') == 'true',
        darkMode: localStorage.getItem('darkMode') || (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light')
    }""",
    "x-init": "$watch('darkMode', val => localStorage.setItem('darkMode', val));$watch('showRequests', val => localStorage.setItem('showRequests', val))",
    "x-bind:data-theme": "darkMode !== 'system'? darkMode : (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light')",
}

app, rt = fh.fast_app(hdrs=hdrs, static_path="public", htmlkw=html_kv, surreal=False)

htmx_examples = sorted([f.stem for f in Path(__file__).parent.glob("htmx/*.py") if f.stem not in ["__init__"]])
INTRO = """
# HTMX examples with FastHTML

Reproduction of HTMX official [examples](https://htmx.org/examples/) with Python [FastHTML](https://docs.fastht.ml/).

The code can be found on [GitHub](https://github.com/phihung/fasthtml_examples).
"""


@app.get("/")
def homepage():
    ls = [get_example(name) for name in htmx_examples]
    return (
        fh.Title("HTMX examples with FastHTML"),
        fh.Main(cls="container")(
            Div(INTRO, cls="marked"),
            Div(
                "Choose theme ",
                fh.Select(style="display:inline-block;max-width:100px;", **{"x-model": "darkMode"})(
                    fh.Option("Light", value="light"),
                    fh.Option("Dark", value="dark"),
                ),
            ),
            Table(
                Thead(Tr(Th("Pattern"), Th("Description"))),
                Tbody(tuple(Tr(Td(A(ex.title, href="/" + ex.slug)), Td(ex.desc)) for ex in ls)),
            ),
        ),
    )


@dataclass
class RequestInfo:
    verb: str
    path: str
    parameters: str
    headers: str
    response: str


@app.put("/requests")
def requests(r: RequestInfo):
    headers = json.loads(r.headers)
    headers = {
        k: v for k, v in headers.items() if k in ("HX-Trigger", "HX-Trigger-Name", "HX-Target", "HX-Prompt") and v
    }
    return Div(**{"x-data": "{show: false}", "@click": "show = !show"})(
        H4(x_text="(show?'▽':'▶') + ' " + r.verb.upper() + " " + r.path + "'"),
        Div(**{"x-show": "show"})(
            Div(Pre("Input: " + r.parameters)) if r.parameters != "{}" else None,
            Div(Pre("Headers: " + str(headers))) if headers else None,
            Div(Pre(r.response or "(empty response)"), style="max-height:150px;overflow:scroll;"),
        ),
    )


def get_app():
    for name in htmx_examples:
        get_example(name).create_routes(app)
    return app


def get_example(name):
    module = importlib.import_module(f"tutorial.htmx.{name}")
    return Example(module, name[4:])


def start():
    fh.serve("tutorial.__init__", app="get_app", reload=False)


if __name__ == "__main__":
    fh.serve(app="get_app")