Browse Source

improve hierarchy

Falko Schindler 1 năm trước cách đây
mục cha
commit
e39fdcb5c2

+ 18 - 7
main.py

@@ -1,5 +1,4 @@
 #!/usr/bin/env python3
-# pylint: disable=missing-function-docstring
 import os
 from pathlib import Path
 
@@ -8,7 +7,7 @@ from starlette.middleware.sessions import SessionMiddleware
 
 import prometheus
 from nicegui import app, ui
-from website import anti_scroll_hack, documentation_pages, fly, main_page, svg
+from website import anti_scroll_hack, documentation, fly, main_page, svg
 
 prometheus.start_monitor(app)
 
@@ -24,19 +23,31 @@ app.add_static_files('/static', str(Path(__file__).parent / 'website' / 'static'
 app.add_static_file(local_file=svg.PATH / 'logo.png', url_path='/logo.png')
 app.add_static_file(local_file=svg.PATH / 'logo_square.png', url_path='/logo_square.png')
 
+documentation.content.generate()
+
 
 @app.post('/dark_mode')
-async def post_dark_mode(request: Request) -> None:
+async def _post_dark_mode(request: Request) -> None:
     app.storage.browser['dark_mode'] = (await request.json()).get('value')
 
 
-ui.page('/')(main_page.create)
-ui.page('/documentation')(documentation_pages.create_overview)
-ui.page('/documentation/{name}')(documentation_pages.create_page)
+@ui.page('/')
+def _main_page() -> None:
+    main_page.create()
+
+
+@ui.page('/documentation')
+def _documentation_page() -> None:
+    documentation.render_page(documentation.registry.get(''), is_main=True)
+
+
+@ui.page('/documentation/{name}')
+def _documentation_detail_page(name: str) -> None:
+    documentation.render_page(documentation.registry.get(name))
 
 
 @app.get('/status')
-def status():
+def _status():
     return 'Ok'
 
 

+ 4 - 3
website/documentation/__init__.py

@@ -1,8 +1,8 @@
-from . import content, more
+from . import content, more, registry
 from .demo import bash_window, browser_window, python_window
 from .intro import create_intro
 from .overview import create_overview, create_section
-from .rendering import render
+from .rendering import render_page
 from .tools import create_anchor_name, element_demo, generate_class_doc
 
 __all__ = [
@@ -17,5 +17,6 @@ __all__ = [
     'element_demo',
     'generate_class_doc',
     'python_window',
-    'render',
+    'registry',
+    'render_page',
 ]

+ 6 - 0
website/documentation/content/__init__.py

@@ -0,0 +1,6 @@
+from .overview import Overview
+
+
+def generate() -> None:
+    """Generate documentation content."""
+    Overview('/documentation/')

+ 18 - 29
website/documentation/content/overview.py

@@ -1,30 +1,12 @@
-from typing import Dict
+from typing import List, Tuple
 
 from nicegui import ui
 
-from .. import model
-from ..section import Section
-from ..sections import (action_events, audiovisual_elements, binding_properties, configuration_deployment, controls,
-                        data_elements, page_layout, pages_routing, styling_appearance, text_elements)
-
-SECTIONS: Dict[str, Section] = {
-    section.name: section
-    for section in [
-        text_elements,
-        # controls,
-        # audiovisual_elements,
-        # data_elements,
-        # binding_properties,
-        # page_layout,
-        # styling_appearance,
-        # action_events,
-        # pages_routing,
-        # configuration_deployment,
-    ]
-}
-
-
-class Overview(model.Documentation):
+from ..content.sections.text_elements import TextElementsDocumentation
+from ..model import Documentation, SectionDocumentation
+
+
+class Overview(Documentation):
 
     def content(self) -> None:
         self.add_markdown('Overview', '''
@@ -60,15 +42,22 @@ class Overview(model.Documentation):
             Or if you prefer, almost anything can be styled with CSS.
         ''')
 
+        tiles: List[Tuple[SectionDocumentation, str]] = [
+            (TextElementsDocumentation(), '''
+                Elements like `ui.label`, `ui.markdown` and `ui.html` can be used to display text and other content.
+            '''),
+        ]
+
         @self.add_raw_nicegui
-        def tiles():
+        def create_tiles():
             with ui.grid().classes('grid-cols-[1fr] md:grid-cols-[1fr_1fr] xl:grid-cols-[1fr_1fr_1fr]'):
-                for section in SECTIONS.values():
-                    with ui.link(target=f'/documentation/section_{section.name}/') \
+                for documentation, description in tiles:
+                    with ui.link(target=documentation.route) \
                             .classes('bg-[#5898d420] p-4 self-stretch rounded flex flex-col gap-2') \
                             .style('box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1)'):
-                        ui.label(section.title).classes(replace='text-2xl')
-                        ui.markdown(section.description).classes(replace='bold-links arrow-links')
+                        if documentation.title:
+                            ui.label(documentation.title).classes(replace='text-2xl')
+                        ui.markdown(description).classes(replace='bold-links arrow-links')
 
         self.add_markdown('Actions', '''
             NiceGUI runs an event loop to handle user input and other events like timers and keyboard bindings.

+ 0 - 0
website/documentation/content/sections/__init__.py


+ 8 - 0
website/documentation/content/sections/text_elements.py

@@ -0,0 +1,8 @@
+from ...model import SectionDocumentation
+from ...more.label_documentation import LabelDocumentation
+
+
+class TextElementsDocumentation(SectionDocumentation, title='Text Elements', name='text_elements'):
+
+    def content(self) -> None:
+        self.add_element_intro(LabelDocumentation())

+ 19 - 10
website/documentation/model.py

@@ -10,6 +10,8 @@ import docutils.core
 from nicegui.dataclasses import KWONLY_SLOTS
 from nicegui.elements.markdown import apply_tailwind, remove_indentation
 
+from . import registry
+
 
 @dataclass(**KWONLY_SLOTS)
 class DocumentationPart:
@@ -18,15 +20,22 @@ class DocumentationPart:
     link: Optional[str] = None
     function: Optional[Callable] = None
 
+    @property
+    def link_target(self) -> Optional[str]:
+        """Return the link target for in-page navigation."""
+        return self.link.lower().replace(' ', '_') if self.link else None
+
 
 class Documentation(abc.ABC):
-    TITLE: Optional[str] = None
+    title: Optional[str] = None
+    description: Optional[str] = None
 
-    def __init__(self, route: str, back_link: Optional[str] = None) -> None:
+    def __init__(self, route: str, *, back_link: Optional[str] = None) -> None:
         self.route = route
         self.back_link = back_link
         self._content: List[DocumentationPart] = []
         self.content()
+        registry.add(self)
 
     def __iter__(self) -> Iterator[DocumentationPart]:
         return iter(self._content)
@@ -44,6 +53,7 @@ class Documentation(abc.ABC):
 
     def add_element_intro(self, documentation: ElementDocumentation) -> None:
         """Add an element intro section to the documentation."""
+        documentation.back_link = self.route
         self.add_main_element_demo(documentation, intro_only=True)
 
     def add_main_element_demo(self, documentation: ElementDocumentation, *, intro_only: bool = False) -> None:
@@ -71,16 +81,15 @@ class Documentation(abc.ABC):
 
 
 class SectionDocumentation(Documentation):
-    element_documentations: List[ElementDocumentation]
+    route: str
 
-    def __init_subclass__(cls, title: str) -> None:
-        cls.TITLE = title
-        cls.element_documentations = []
+    def __init_subclass__(cls, title: str, name: str) -> None:
+        cls.title = title
+        cls.route = f'/documentation/section_{name}'
         return super().__init_subclass__()
 
-    def add_element_intro(self, documentation: ElementDocumentation) -> None:
-        self.element_documentations.append(documentation)
-        super().add_element_intro(documentation)
+    def __init__(self) -> None:
+        super().__init__(self.route, back_link='/documentation')
 
 
 class ElementDocumentation(Documentation):
@@ -91,7 +100,7 @@ class ElementDocumentation(Documentation):
         return super().__init_subclass__()
 
     def __init__(self) -> None:
-        super().__init__(self.element.__name__.lower())
+        super().__init__(f'/documentation/{self.element.__name__.lower()}')
 
     @abc.abstractmethod
     def main_demo(self) -> None:

+ 18 - 0
website/documentation/registry.py

@@ -0,0 +1,18 @@
+from __future__ import annotations
+
+from typing import TYPE_CHECKING, Dict
+
+if TYPE_CHECKING:
+    from .model import Documentation
+
+registry: Dict[str, Documentation] = {}
+
+
+def add(documentation: Documentation) -> None:
+    """Register a documentation."""
+    registry[documentation.route] = documentation
+
+
+def get(name: str) -> Documentation:
+    """Get a documentation."""
+    return registry[f'/documentation/{name}']

+ 14 - 7
website/documentation/rendering.py

@@ -1,5 +1,3 @@
-from typing import Optional, Tuple
-
 from nicegui import ui
 
 from ..header import add_head_html, add_header
@@ -7,18 +5,20 @@ from ..style import section_heading
 from .model import Documentation
 
 
-def render(documentation: Documentation, heading: Optional[Tuple[str, str]] = None) -> None:
+def render_page(documentation: Documentation, *, is_main: bool = False) -> None:
     """Render the documentation."""
     add_head_html()
     add_header()
     ui.add_head_html('<style>html {scroll-behavior: auto;}</style>')
     with ui.column().classes('w-full p-8 lg:p-16 max-w-[1250px] mx-auto'):
-        if heading:
-            section_heading(*heading)
-        if documentation.TITLE:
-            ui.markdown(f'# {documentation.TITLE}')
+        if is_main:
+            section_heading('Reference, Demos and more', '*NiceGUI* Documentation')
+        if documentation.title:
+            ui.markdown(f'# {documentation.title}')
         for part in documentation:
             if part.title:
+                if part.link_target:
+                    ui.link_target(part.link_target)
                 if part.link:
                     with ui.link(target=part.link):
                         ui.markdown(f'### {part.title}')
@@ -28,3 +28,10 @@ def render(documentation: Documentation, heading: Optional[Tuple[str, str]] = No
                 ui.markdown(part.description)
             if part.function:
                 part.function()
+
+    if not is_main:
+        with ui.left_drawer():
+            ui.markdown(f'[← back]({documentation.back_link})').classes('bold-links')
+            for part in documentation:
+                if part.title and part.link_target:
+                    ui.link(part.title, f'#{part.link_target}')

+ 0 - 8
website/documentation/sections/text_elements.py

@@ -1,7 +1,5 @@
 from nicegui import ui
 
-from ..model import SectionDocumentation
-from ..more.label_documentation import LabelDocumentation
 from ..tools import load_demo
 
 name = 'text_elements'
@@ -19,9 +17,3 @@ def content() -> None:
     load_demo(ui.markdown)
     load_demo(ui.mermaid)
     load_demo(ui.html)
-
-
-class TextElementsDocumentation(SectionDocumentation, title='Text Elements'):
-
-    def content(self) -> None:
-        self.add_element_intro(LabelDocumentation())

+ 0 - 29
website/documentation_pages.py

@@ -1,42 +1,13 @@
 import importlib
 import inspect
 import logging
-from typing import Dict
 
 from nicegui import context, ui
 
 from . import documentation
-from .documentation.content.overview import Overview
-from .documentation.model import ElementDocumentation, SectionDocumentation
-from .documentation.sections.text_elements import TextElementsDocumentation
 from .header import add_head_html, add_header
 from .style import section_heading, side_menu
 
-overview = Overview('/documentation')
-sections: Dict[str, SectionDocumentation] = {
-    d.route.split('/')[-1]: d
-    for d in [
-        TextElementsDocumentation('/documentation/section_text_elements'),
-    ]
-}
-elements: Dict[str, ElementDocumentation] = {
-    element_documentation.route.split('/')[-1]: element_documentation
-    for section in sections.values()
-    for element_documentation in section.element_documentations
-}
-
-
-def create_overview() -> None:
-    """Create the documentation overview."""
-    documentation.render(overview, heading=('Reference, Demos and more', '*NiceGUI* Documentation'))
-
-
-def create_page(name: str) -> None:
-    doc = elements.get(name) or sections.get(name)
-    if not doc:
-        raise ValueError(f'unknown documentation page: {name}')
-    documentation.render(doc)
-
 
 def create_section(name: str) -> None:
     """Create a documentation section."""