From 698c60d26b90f229fda28079a2a1124a8535ed4c Mon Sep 17 00:00:00 2001 From: Larry Ogrodnek Date: Tue, 14 May 2024 20:43:13 -0400 Subject: [PATCH] some cleanup around the root template (#9) * some cleanup around the root template * bump version --- .gitignore | 1 + examples/app.py | 8 +++- pyproject.toml | 2 +- pyview/pyview.py | 66 ++++------------------------- pyview/template/__init__.py | 1 + pyview/template/root_template.py | 71 ++++++++++++++++++++++++++++++++ 6 files changed, 89 insertions(+), 60 deletions(-) create mode 100644 pyview/template/root_template.py diff --git a/.gitignore b/.gitignore index 29aa1ae..0a84836 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +.vscode/ node_modules/ _site/ # Byte-compiled / optimized / DLL files diff --git a/examples/app.py b/examples/app.py index 0f190bf..ba5ecdc 100644 --- a/examples/app.py +++ b/examples/app.py @@ -2,6 +2,7 @@ from fastapi.staticfiles import StaticFiles from starlette.routing import Route from pyview import PyView, defaultRootTemplate +from markupsafe import Markup from .views import ( CountLiveView, @@ -24,7 +25,12 @@ """ -app.rootTemplate = defaultRootTemplate(css) + +def content_wrapper(_context, content: Markup) -> Markup: + return Markup("Home") + content + + +app.rootTemplate = defaultRootTemplate(css=Markup(css), content_wrapper=content_wrapper) routes = [ ( diff --git a/pyproject.toml b/pyproject.toml index 8fe3110..92a90fa 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,7 +5,7 @@ packages = [ { include = "pyview" }, ] -version = "0.0.7a" +version = "0.0.8a" description = "LiveView in Python" authors = ["Larry Ogrodnek "] license = "MIT" diff --git a/pyview/pyview.py b/pyview/pyview.py index 06a996d..56daab3 100644 --- a/pyview/pyview.py +++ b/pyview/pyview.py @@ -14,19 +14,7 @@ from .ws_handler import LiveSocketHandler from .live_view import LiveView from .live_routes import LiveViewLookup -from typing import Callable, Optional, TypedDict - - -class RootTemplateContext(TypedDict): - id: str - content: str - title: Optional[str] - css: Optional[str] - csrf_token: str - session: Optional[str] - - -RootTemplate = Callable[[RootTemplateContext], str] +from .template import RootTemplate, RootTemplateContext, defaultRootTemplate class PyView(Starlette): @@ -34,7 +22,7 @@ class PyView(Starlette): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - self.rootTemplate = defaultRootTemplate("") + self.rootTemplate = defaultRootTemplate() self.view_lookup = LiveViewLookup() self.live_handler = LiveSocketHandler(self.view_lookup) @@ -46,14 +34,18 @@ async def live_websocket_endpoint(websocket: WebSocket): def add_live_view(self, path: str, view: type[LiveView]): async def lv(request: Request): - return await liveview_container(self.rootTemplate, self.view_lookup, request) + return await liveview_container( + self.rootTemplate, self.view_lookup, request + ) self.view_lookup.add(path, view) auth = AuthProviderFactory.get(view) self.routes.append(Route(path, auth.wrap(lv), methods=["GET"])) -async def liveview_container(template: RootTemplate, view_lookup: LiveViewLookup, request: Request): +async def liveview_container( + template: RootTemplate, view_lookup: LiveViewLookup, request: Request +): url = request.url path = url.path lv: LiveView = view_lookup.get(path) @@ -72,49 +64,7 @@ async def liveview_container(template: RootTemplate, view_lookup: LiveViewLookup "content": r.text(), "title": s.live_title, "csrf_token": generate_csrf_token("lv:phx-" + id), - "css": None, "session": serialize_session(session), } return HTMLResponse(template(context)) - - -def defaultRootTemplate(css: str) -> RootTemplate: - def template(context: RootTemplateContext) -> str: - context["css"] = css - return _defaultRootTemplate(context) - - return template - - -def _defaultRootTemplate(context: RootTemplateContext) -> str: - suffix = " | LiveView" - render_title = (context["title"] + suffix) if context.get("title", None) is not None else "LiveView" # type: ignore - css = context["css"] if context.get("css", None) is not None else "" - return f""" - - - - {render_title} - - - - - - {css} - - -
- Home -
- {context['content']} -
-
- - -""" diff --git a/pyview/template/__init__.py b/pyview/template/__init__.py index 73b978f..f7db6e3 100644 --- a/pyview/template/__init__.py +++ b/pyview/template/__init__.py @@ -1,2 +1,3 @@ from pyview.vendor.ibis import Template from .live_template import LiveTemplate, template_file, RenderedContent, LiveRender +from .root_template import RootTemplate, RootTemplateContext, defaultRootTemplate diff --git a/pyview/template/root_template.py b/pyview/template/root_template.py new file mode 100644 index 0000000..b023a68 --- /dev/null +++ b/pyview/template/root_template.py @@ -0,0 +1,71 @@ +from typing import Callable, Optional, TypedDict +from markupsafe import Markup + + +class RootTemplateContext(TypedDict): + id: str + content: str + title: Optional[str] + csrf_token: str + session: Optional[str] + + +RootTemplate = Callable[[RootTemplateContext], str] +ContentWrapper = Callable[[RootTemplateContext, Markup], Markup] + + +def defaultRootTemplate( + css: Optional[Markup] = None, content_wrapper: Optional[ContentWrapper] = None +) -> RootTemplate: + content_wrapper = content_wrapper or (lambda c, m: m) + + def template(context: RootTemplateContext) -> str: + return _defaultRootTemplate(context, css or Markup(""), content_wrapper) + + return template + + +def _defaultRootTemplate( + context: RootTemplateContext, css: Markup, contentWrapper: ContentWrapper +) -> str: + suffix = " | LiveView" + render_title = (context["title"] + suffix) if context.get("title", None) is not None else "LiveView" # type: ignore + main_content = contentWrapper( + context, + Markup( + f""" +
+ {context['content']} +
""" + ), + ) + + return ( + Markup( + f""" + + + + {render_title} + + + + + + {css} + + """ + ) + + main_content + + Markup( + """ + + +""" + ) + )