소스 검색

Allow specializations of @ui.page decoroator.
The usage is shown in examples/customization.

Rodja Trappe 2 년 전
부모
커밋
7104fd2612

+ 24 - 0
examples/customization/custom.py

@@ -0,0 +1,24 @@
+from nicegui import ui
+
+from navbar import navbar
+
+
+class page(ui.page):
+
+    def __init__(self, route: str, **kwargs):
+        '''Custom page decorator to share the same styling and behavior across all pages'''
+        super().__init__(route, classes='fit column items-start', title='Modularization Demo')
+        self.kwargs = kwargs
+
+    async def head(self) -> None:
+        await super().head()
+        navbar(**self.kwargs)
+        self.content = ui.row().classes('justify-center fit mt-10').__enter__()
+
+    async def tail(self) -> None:
+        await super().tail()
+        self.content.__exit__(None, None, None)
+
+
+def headline(text: str) -> ui.label:
+    return ui.label(text).classes('text-h4 text-weight-bold text-grey-8')

+ 5 - 0
examples/customization/home.py

@@ -0,0 +1,5 @@
+import custom
+
+
+def content():
+    custom.headline('This is the home page')

+ 17 - 0
examples/customization/main.py

@@ -0,0 +1,17 @@
+from nicegui import ui
+
+import custom
+import home
+import pages
+
+
+# here we use our custom page decorator directly and just put the content creation into a spereate function
+@custom.page('/', navtitle='Homepage')
+def homepage():
+    home.content()
+
+
+# this call shows that you can also move the whole page creation into a separate file
+pages.create()
+
+ui.run()

+ 9 - 0
examples/customization/menu.py

@@ -0,0 +1,9 @@
+from nicegui import ui
+
+
+def menu():
+    ui.link('Home', '/').classes(replace='text-white')
+    ui.link('A', '/a').classes(replace='text-white')
+    ui.link('B', '/b').classes(replace='text-white')
+    ui.link('C', '/c').classes(replace='text-white')
+    ui.link('D', '/d').classes(replace='text-white')

+ 13 - 0
examples/customization/navbar.py

@@ -0,0 +1,13 @@
+from nicegui import ui
+
+from menu import menu
+
+
+def navbar(navtitle: str = 'No Title'):
+    ui.colors(primary='#6E93D6', secondary='#53B689', accent='#111B1E', positive='#53B689')
+    with ui.row().classes('fit bg-primary q-py-sm q-px-md q-ma-none no-wrap shadow-2', remove='q-gutter-sm').style('gap:0px'):
+        ui.label('Modularization Demo').classes('text-white text-weight-bold col-3')
+        with ui.row().classes('col-6'):
+            ui.label(navtitle).classes('text-white text-center fit')
+        with ui.row().classes('col-3 justify-end'):
+            menu()

+ 12 - 0
examples/customization/pages.py

@@ -0,0 +1,12 @@
+import custom
+
+
+def create():
+    for name in ['A', 'B', 'C', 'D']:
+        # here we store the custom page builder in a variable and pass the specific contend for every page
+        page_builder = custom.page(f'/{name.lower()}', navtitle=f'- {name} -')
+        page_builder(create_content, title=name)
+
+
+def create_content(title: str) -> None:
+    custom.headline(f'Page {title}')

+ 64 - 43
nicegui/page.py

@@ -126,57 +126,78 @@ async def await_javascript(self, code: str, *, check_interval: float = 0.01, tim
         return await page.await_javascript(code)
 
 
-def page(self,
-         route: str,
-         title: Optional[str] = None,
-         *,
-         favicon: Optional[str] = None,
-         dark: Optional[bool] = ...,
-         classes: str = 'q-ma-md column items-start',
-         css: str = HtmlFormatter().get_style_defs('.codehilite'),
-         on_connect: Optional[Callable] = None,
-         on_page_ready: Optional[Callable] = None,
-         on_disconnect: Optional[Callable] = None,
-         shared: bool = False,
-         ):
-    """Page
-
-    Creates a new page at the given route.
-
-    :param route: route of the new page (path must start with '/')
-    :param title: optional page title
-    :param favicon: optional favicon
-    :param dark: whether to use Quasar's dark mode (defaults to `dark` argument of `run` command)
-    :param classes: tailwind classes for the container div (default: `'q-ma-md column items-start'`)
-    :param css: CSS definitions
-    :param on_connect: optional function or coroutine which is called for each new client connection
-    :param on_page_ready: optional function or coroutine which is called when the websocket is connected
-    :param on_disconnect: optional function or coroutine which is called when a client disconnects
-    :param shared: whether the page instance is shared between multiple clients (default: `False`)
-    """
-    def decorator(func):
+class page:
+    def __init__(
+        self,
+        route: str,
+        title: Optional[str] = None,
+        *,
+        favicon: Optional[str] = None,
+        dark: Optional[bool] = ...,
+        classes: str = 'q-ma-md column items-start',
+        css: str = HtmlFormatter().get_style_defs('.codehilite'),
+        on_connect: Optional[Callable] = None,
+        on_page_ready: Optional[Callable] = None,
+        on_disconnect: Optional[Callable] = None,
+        shared: bool = False,
+    ):
+        """Page
+
+        Creates a new page at the given route.
+
+        :param route: route of the new page (path must start with '/')
+        :param title: optional page title
+        :param favicon: optional favicon
+        :param dark: whether to use Quasar's dark mode (defaults to `dark` argument of `run` command)
+        :param classes: tailwind classes for the container div (default: `'q-ma-md column items-start'`)
+        :param css: CSS definitions
+        :param on_connect: optional function or coroutine which is called for each new client connection
+        :param on_page_ready: optional function or coroutine which is called when the websocket is connected
+        :param on_disconnect: optional function or coroutine which is called when a client disconnects
+        :param shared: whether the page instance is shared between multiple clients (default: `False`)
+        """
+        self.route = route
+        self.title = title
+        self.favicon = favicon
+        self.dark = dark
+        self.classes = classes
+        self.css = css
+        self.on_connect = on_connect
+        self.on_page_ready = on_page_ready
+        self.on_disconnect = on_disconnect
+        self.shared = shared
+
+    def __call__(self, func, *args, **kwargs):
+
         @wraps(func)
         async def decorated():
             page = Page(
-                title=title,
-                favicon=favicon,
-                dark=dark,
-                classes=classes,
-                css=css,
-                on_connect=on_connect,
-                on_page_ready=on_page_ready,
-                on_disconnect=on_disconnect,
-                shared=shared,
+                title=self.title,
+                favicon=self.favicon,
+                dark=self.dark,
+                classes=self.classes,
+                css=self.css,
+                on_connect=self.on_connect,
+                on_page_ready=self.on_page_ready,
+                on_disconnect=self.on_disconnect,
+                shared=self.shared,
             )
             with globals.within_view(page.view):
-                await func() if is_coroutine(func) else func()
+                await self.head()
+                await func(*args, **kwargs) if is_coroutine(func) else func(*args, **kwargs)
+                await self.tail()
             return page
-        builder = PageBuilder(decorated, shared)
+        builder = PageBuilder(decorated, self.shared)
         if globals.server:
-            builder.create_route(route)
-        globals.page_builders[route] = builder
+            builder.create_route(self.route)
+        globals.page_builders[self.route] = builder
         return decorated
-    return decorator
+
+    async def head(self):
+        pass
+
+    async def tail(self):
+        pass
 
 
 def find_parent_view() -> jp.HTMLBaseComponent: