Skip to content

Commit

Permalink
rewrite label documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
falkoschindler committed Nov 24, 2023
1 parent 6b0dc56 commit 5458b84
Show file tree
Hide file tree
Showing 7 changed files with 136 additions and 53 deletions.
21 changes: 3 additions & 18 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,24 +30,9 @@ async def post_dark_mode(request: Request) -> None:
app.storage.browser['dark_mode'] = (await request.json()).get('value')


@ui.page('/')
def main_page_() -> None:
main_page.create()


@ui.page('/documentation')
def documentation_page() -> None:
documentation_pages.create_overview()


@ui.page('/documentation/section_{name}')
def documentation_section(name: str) -> None:
documentation_pages.create_section(name)


@ui.page('/documentation/{name}')
async def documentation_page_more(name: str) -> None:
await documentation_pages.create_more(name)
ui.page('/')(main_page.create)
ui.page('/documentation')(documentation_pages.create_overview)
ui.page('/documentation/{name}')(documentation_pages.create_page)


@app.get('/status')
Expand Down
18 changes: 9 additions & 9 deletions website/documentation/content/overview.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,15 @@
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,
# controls,
# audiovisual_elements,
# data_elements,
# binding_properties,
# page_layout,
# styling_appearance,
# action_events,
# pages_routing,
# configuration_deployment,
]
}

Expand Down
72 changes: 67 additions & 5 deletions website/documentation/model.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,30 @@
from __future__ import annotations

import abc
import re
from dataclasses import dataclass
from typing import Callable, Iterator, List, Optional

import docutils.core

from nicegui.dataclasses import KWONLY_SLOTS
from nicegui.elements.markdown import apply_tailwind, remove_indentation


@dataclass(**KWONLY_SLOTS)
class DocumentationPart:
title: Optional[str] = None
description: Optional[str] = None
link: Optional[str] = None
function: Optional[Callable] = None


class Documentation(abc.ABC):
TITLE: Optional[str] = None

def __init__(self) -> 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()

Expand All @@ -25,14 +35,31 @@ def add_markdown(self, title: str, description: str) -> None:
"""Add a markdown section to the documentation."""
self._content.append(DocumentationPart(title=title, description=description))

def add_element_demo(self, element: type) -> Callable[[Callable], Callable]:
"""Add a demo section for an element to the documentation."""
def add_markdown_demo(self, title: str, description: str) -> Callable[[Callable], Callable]:
"""Add a markdown section to the documentation."""
def decorator(function: Callable) -> Callable:
part = DocumentationPart(title=element.__name__, description=element.__doc__ or '', function=function)
self._content.append(part)
self._content.append(DocumentationPart(title=title, description=description, function=function))
return function
return decorator

def add_element_intro(self, documentation: ElementDocumentation) -> None:
"""Add an element intro section to the documentation."""
self.add_main_element_demo(documentation, intro_only=True)

def add_main_element_demo(self, documentation: ElementDocumentation, *, intro_only: bool = False) -> None:
"""Add a demo section for an element to the documentation."""
title, doc = documentation.element.__init__.__doc__.split('\n', 1) # type: ignore
doc = remove_indentation(doc).replace('param ', '')
html = apply_tailwind(docutils.core.publish_parts(doc, writer_name='html5_polyglot')['html_body'])
if intro_only:
html = re.sub(r'<dl class=".* simple">.*?</dl>', '', html, flags=re.DOTALL)
self._content.append(DocumentationPart(
title=title,
description=html,
link=documentation.route if intro_only else None,
function=documentation.main_demo,
))

def add_raw_nicegui(self, function: Callable) -> Callable:
"""Add a raw NiceGUI section to the documentation."""
self._content.append(DocumentationPart(function=function))
Expand All @@ -41,3 +68,38 @@ def add_raw_nicegui(self, function: Callable) -> Callable:
@abc.abstractmethod
def content(self) -> None:
"""Add documentation content here."""


class SectionDocumentation(Documentation):
element_documentations: List[ElementDocumentation]

def __init_subclass__(cls, title: str) -> None:
cls.TITLE = title
cls.element_documentations = []
return super().__init_subclass__()

def add_element_intro(self, documentation: ElementDocumentation) -> None:
self.element_documentations.append(documentation)
super().add_element_intro(documentation)


class ElementDocumentation(Documentation):
element: type

def __init_subclass__(cls, element: type) -> None:
cls.element = element
return super().__init_subclass__()

def __init__(self) -> None:
super().__init__(self.element.__name__.lower())

@abc.abstractmethod
def main_demo(self) -> None:
"""Add a demo for the element here."""

def more_demos(self) -> None:
"""Add more demos for the element here."""

def content(self) -> None:
self.add_main_element_demo(self)
self.more_demos()
39 changes: 20 additions & 19 deletions website/documentation/more/label_documentation.py
Original file line number Diff line number Diff line change
@@ -1,26 +1,27 @@
from nicegui import ui

from ..tools import text_demo
from ..model import ElementDocumentation


def main_demo() -> None:
ui.label('some label')
class LabelDocumentation(ElementDocumentation, element=ui.label):

def main_demo(self) -> None:
ui.label('some label')

def more() -> None:
@text_demo('Change Appearance Depending on the Content', '''
You can overwrite the `_handle_text_change` method to update other attributes of a label depending on its content.
This technique also works for bindings as shown in the example below.
''')
def status():
class status_label(ui.label):
def _handle_text_change(self, text: str) -> None:
super()._handle_text_change(text)
if text == 'ok':
self.classes(replace='text-positive')
else:
self.classes(replace='text-negative')
def more_demos(self) -> None:
@self.add_markdown_demo('Change Appearance Depending on the Content', '''
You can overwrite the `_handle_text_change` method to update other attributes of a label depending on its content.
This technique also works for bindings as shown in the example below.
''')
def status():
class status_label(ui.label):
def _handle_text_change(self, text: str) -> None:
super()._handle_text_change(text)
if text == 'ok':
self.classes(replace='text-positive')
else:
self.classes(replace='text-negative')

model = {'status': 'error'}
status_label().bind_text_from(model, 'status')
ui.switch(on_change=lambda e: model.update(status='ok' if e.value else 'error'))
model = {'status': 'error'}
status_label().bind_text_from(model, 'status')
ui.switch(on_change=lambda e: model.update(status='ok' if e.value else 'error'))
8 changes: 7 additions & 1 deletion website/documentation/rendering.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,15 @@ def render(documentation: Documentation) -> None:
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 documentation.TITLE:
ui.markdown(f'# {documentation.TITLE}')
for part in documentation:
if part.title:
ui.markdown(f'### {part.title}')
if part.link:
with ui.link(target=part.link):
ui.markdown(f'### {part.title}')
else:
ui.markdown(f'### {part.title}')
if part.description:
ui.markdown(part.description)
if part.function:
Expand Down
8 changes: 8 additions & 0 deletions website/documentation/sections/text_elements.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
from nicegui import ui

from ..model import SectionDocumentation
from ..more.label_documentation import LabelDocumentation
from ..tools import load_demo

name = 'text_elements'
Expand All @@ -17,3 +19,9 @@ 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())
23 changes: 22 additions & 1 deletion website/documentation_pages.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,43 @@
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()
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)


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."""
add_head_html()
Expand Down

0 comments on commit 5458b84

Please sign in to comment.