Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions nicegui/elements/sub_pages.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,6 @@ def __init__(self,
Routes are defined as path patterns mapping to page builder functions.
Path parameters like "/user/{id}" are extracted and passed to the builder function.

**This is an experimental feature, and the API is subject to change.**

*Added in version 2.22.0*

:param routes: dictionary mapping path patterns to page builder functions
Expand Down
2 changes: 0 additions & 2 deletions nicegui/sub_pages_router.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,6 @@ def __init__(self, request: Request | None) -> None:
def on_path_changed(self, handler: Callable[[str], None]) -> None:
"""Register a callback to be invoked when the path changes.

**This is an experimental feature, and the API is subject to change.**

:param handler: callback function that receives the new path as its argument
"""
self._path_changed_handlers.append(handler)
Expand Down
6 changes: 5 additions & 1 deletion website/documentation/code_extraction.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,11 @@ def get_full_code(f: Callable) -> str:
code = [line[indentation:] for line in code]
code = ['from nicegui import ui'] + [_uncomment(line) for line in code]
code = ['' if line == '#' else line for line in code]
if not code[-1].startswith('ui.run('):

if any(line.strip().startswith('def root(') for line in code):
code = [line for line in code if line.strip() != 'return root']
code.append('ui.run(root)')
elif not code[-1].startswith('ui.run('):
code.append('')
code.append('ui.run()')
full_code = isort.code('\n'.join(code), no_sections=True, lines_after_imports=1)
Expand Down
6 changes: 2 additions & 4 deletions website/documentation/content/sub_pages_documentation.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ def init(self) -> None:
self._render('/')
self.move() # move to end

def link(self, text: str, route: str, **kwargs: Any) -> None:
ui.label(text).classes('nicegui-link cursor-pointer').on('click', lambda: self._render(route, **kwargs))
def link(self, text: str, route: str, **kwargs: Any) -> ui.label:
return ui.label(text).classes('nicegui-link cursor-pointer').on('click', lambda: self._render(route, **kwargs))

def _render(self, route: str, **kwargs: Any) -> None:
if self.task and not self.task.done():
Expand All @@ -46,8 +46,6 @@ def __init__(self, **kwargs: Any) -> None:
The `ui.sub_pages` element itself functions as the container for the currently active sub page.
You only need to provide the routes for each view builder function.
NiceGUI takes care of replacing the content without triggering a full page reload when the URL changes.

**NOTE: This is an experimental feature, and the API is subject to change.**
''')
def main_demo() -> None:
from uuid import uuid4
Expand Down
17 changes: 11 additions & 6 deletions website/documentation/demo.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,18 @@ def demo(f: Callable, *, lazy: bool = True, tab: Optional[Union[str, Callable]]

async def handle_intersection():
window.remove(spinner)
if helpers.is_coroutine_function(f):
await f()
else:
f()
result = f()
if callable(result):
if helpers.is_coroutine_function(result):
await result()
else:
result()
intersection_observer(on_intersection=handle_intersection)
else:
assert not helpers.is_coroutine_function(f), 'async functions are not supported in non-lazy demos'
f()
result = f()
if callable(result):
assert not helpers.is_coroutine_function(result), \
'async functions are not supported in non-lazy demos'
result()

return f
79 changes: 40 additions & 39 deletions website/documentation/intro.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,57 +3,58 @@
from nicegui import ui

from ..style import subheading
from .content.sub_pages_documentation import FakeSubPages
from .demo import demo


def create_intro() -> None:
@_main_page_demo('Styling', '''
While having reasonable defaults, you can still modify the look of your app with CSS as well as Tailwind and Quasar classes.
''')
def formatting_demo():
ui.icon('thumb_up')
ui.markdown('This is **Markdown**.')
ui.html('This is <strong>HTML</strong>.', sanitize=False)
with ui.row():
ui.label('CSS').style('color: #888; font-weight: bold')
ui.label('Tailwind').classes('font-serif')
ui.label('Quasar').classes('q-ml-xl')
ui.link('NiceGUI on GitHub', 'https://github.com/zauberzeug/nicegui')
@_main_page_demo('Single Page App', '''
Build applications with fast client-side routing using [`ui.sub_pages`](/documentation/sub_pages) and a `root` function as single entry point.
For each visitor, the `root` function is executed and generates the interface.
[`ui.link`](/documentation/link) and [`ui.navigate`](/documentation/navigate) can be used to navigate to other sub pages.
@_main_page_demo('Common UI Elements', '''
NiceGUI comes with a collection of commonly used UI elements.
If you do not want a Single Page App, you can also use [`@ui.page('/your/path')`](/documentation/page) to define standalone content available at a specific path.
''')
def common_elements_demo():
from nicegui.events import ValueChangeEventArguments
def spa_demo():
def root():
# ui.link.default_classes('no-underline text-white')
# with ui.header():
# ui.link('Home', '/')
# ui.link('About', '/about')
# ui.sub_pages({
# '/': home_page,
# '/about': about_page,
# })
ui.context.slot_stack[-1].parent.classes(remove='p-4') # HIDE
sub_pages = FakeSubPages({'/': home_page, '/about': about_page}).classes('mx-4') # HIDE
with ui.row().classes('bg-primary w-full p-4'): # HIDE
sub_pages.link('Home', '/').classes('no-underline text-white') # HIDE
sub_pages.link('About', '/about').classes('no-underline text-white') # HIDE
sub_pages.init() # HIDE

def home_page():
ui.label('Home page').classes('text-2xl')

def show(event: ValueChangeEventArguments):
name = type(event.sender).__name__
ui.notify(f'{name}: {event.value}')
def about_page():
ui.label('About page').classes('text-2xl')

ui.button('Button', on_click=lambda: ui.notify('Click'))
with ui.row():
ui.checkbox('Checkbox', on_change=show)
ui.switch('Switch', on_change=show)
ui.radio(['A', 'B', 'C'], value='A', on_change=show).props('inline')
with ui.row():
ui.input('Text input', on_change=show)
ui.select(['One', 'Two'], value='One', on_change=show)
ui.link('And many more...', '/documentation').classes('mt-8')
return root

@_main_page_demo('Value Binding', '''
Binding values between UI elements and data models is built into NiceGUI.
@_main_page_demo('Reactive Transformations', '''
Create real-time interfaces with automatic updates.
Type and watch text flow in both directions.
When input changes, the [binding](/documentation/section_binding_properties) transforms the text with a custom python function and updates the label.
''')
def binding_demo():
class Demo:
def __init__(self):
self.number = 1
def root():
with ui.column():
user_input = ui.input(value='Hello')
ui.label().bind_text_from(user_input, 'value', reverse)

def reverse(text: str) -> str:
return text[::-1]

demo = Demo()
v = ui.checkbox('visible', value=True)
with ui.column().bind_visibility_from(v, 'value'):
ui.slider(min=1, max=3).bind_value(demo, 'number')
ui.toggle({1: 'A', 2: 'B', 3: 'C'}).bind_value(demo, 'number')
ui.number().bind_value(demo, 'number')
return root


def _main_page_demo(title: str, explanation: str) -> Callable:
Expand Down
6 changes: 3 additions & 3 deletions website/main_page.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,13 +121,13 @@ def create() -> None:
'customizable [color themes](/documentation/section_styling_appearance#color_theming)',
'custom CSS and classes',
'modern look with material design',
'[Tailwind CSS](https://tailwindcss.com/) auto-completion',
'[Tailwind CSS](https://tailwindcss.com/)',
])
features('source', 'Coding', [
'routing for multiple [pages](/documentation/page)',
'single page apps with [ui.sub_pages](/documentation/sub_pages)',
'auto-reload on code change',
'persistent [user sessions](/documentation/storage)',
'super nice [testing framework](/documentation/section_testing)',
'super powerful [testing framework](/documentation/section_testing)',
])
features('anchor', 'Foundation', [
'generic [Vue](https://vuejs.org/) to Python bridge',
Expand Down