Spaces:
Running
Running
File size: 4,257 Bytes
ebec85b d1c33d3 ebec85b b5bffcc d1c33d3 b5bffcc ebec85b 3b5501b b5bffcc ebec85b 3b5501b d1c33d3 ebec85b 3b5501b ebec85b |
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 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 |
import importlib
import inspect
import re
from dataclasses import dataclass
from functools import cached_property
from pathlib import Path
from types import ModuleType
from fasthtml.common import (
H1,
A,
Code,
Div,
Hgroup,
HighlightJS,
Iframe,
Main,
MarkdownJS,
P,
Pre,
Script,
Table,
Tbody,
Td,
Th,
Thead,
Tr,
fast_app,
serve,
)
hdrs = (
MarkdownJS(),
HighlightJS(langs=["python", "javascript", "html", "css"]),
)
app, rt = fast_app(hdrs=hdrs, static_path="public")
examples = sorted([f.stem for f in Path(__file__).parent.glob("*.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 examples]
return Main(cls="container")(
Div(INTRO, cls="marked"),
Table(
Thead(Tr(Th("Pattern"), Th("Description"))),
Tbody(tuple(Tr(Td(A(ex.title, href="/" + ex.slug)), Td(ex.desc)) for ex in ls)),
),
)
def get_app():
for name in examples:
get_example(name).create_routes(app)
return app
def get_example(name):
module = importlib.import_module(f"tutorial.{name}")
return Example(module, name[4:])
@dataclass
class Example:
module: ModuleType
name: str
@cached_property
def title(self):
return self.name.replace("_", " ").title()
@cached_property
def desc(self):
return self.module.DESC
@cached_property
def doc(self):
return self.module.DOC
@cached_property
def slug(self):
return self.name.replace("_", "-")
@cached_property
def htmx_url(self):
return getattr(self.module, "HTMX_URL", f"https://htmx.org/examples/{self.slug}/")
@cached_property
def start_url(self):
module, slug = self.module, self.slug
url = getattr(module, "START_URL", module.app.routes[1].path)
return f"/{slug}{url}"
def create_routes(self, app):
module, slug = self.module, self.slug
self._fix_url()
app.mount(f"/{slug}", module.app)
app.get(f"/{slug}")(self.main_page)
def main_page(self, tab: str = "explain"):
module = self.module
if tab == "code":
code = Path(module.__file__).read_text().split("DESC = ")[0]
code = code.strip().replace("# fmt: on\n", "").replace("# fmt: off\n", "")
content = Pre(Code(code))
else:
doc = re.sub("::([a-zA-Z_0-9\s]+)::", lambda x: code_block(module, x.group(1)), self.doc)
content = Div(doc, cls="marked")
return Main(cls="container")(
Hgroup(H1(self.title), P(self.desc)),
Div(
A("Back", href="/"),
"|",
A("Explain", href=f"/{self.slug}?tab=explain"),
"|",
A("Code", href=f"/{self.slug}?tab=code"),
"|",
A("Htmx Docs", href=self.htmx_url),
),
Div(cls="grid")(
Div(content, style="height:80vh;overflow:scroll"),
Div(P(A("Direct url", href=self.start_url)), Iframe(src=self.start_url, height="500px", width="100%")),
),
)
def _fix_url(self):
module, slug = self.module, self.slug
code = f"""
document.addEventListener('htmx:configRequest', (event) => {{
event.detail.path = `/{slug}${{event.detail.path}}`
}})
"""
module.app.hdrs.append(Script(code))
def code_block(module, obj):
code = ""
for o in obj.strip().split():
func = getattr(module, o)
if callable(func):
func = getattr(func, "__wrapped__", func)
code += inspect.getsource(func)
else:
code += str(func).strip()
code += "\n"
code = code.strip()
return f"```\n{code.strip()}\n```"
def start():
serve("tutorial.__init__", app="get_app")
if __name__ == "__main__":
serve(app="get_app")
|