Jelajahi Sumber

remove obsolete code

Falko Schindler 1 tahun lalu
induk
melakukan
1c531cab16

+ 2 - 2
website/__init__.py

@@ -1,8 +1,8 @@
-from . import anti_scroll_hack, documentation_pages, fly, main_page, svg
+from . import anti_scroll_hack, documentation, fly, main_page, svg
 
 __all__ = [
     'anti_scroll_hack',
-    'documentation_pages',
+    'documentation',
     'fly',
     'main_page',
     'svg',

+ 0 - 110
website/documentation/overview.py

@@ -1,110 +0,0 @@
-from typing import Dict
-
-from nicegui import ui
-
-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)
-from .tools import heading
-
-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,
-    ]
-}
-
-
-def create_overview() -> None:
-    ui.markdown('''
-        ### Overview
-                                
-        NiceGUI is an open-source Python library to write graphical user interfaces which run in the browser.
-        It has a very gentle learning curve while still offering the option for advanced customizations.
-        NiceGUI follows a backend-first philosophy:
-        It handles all the web development details.
-        You can focus on writing Python code. 
-        This makes it ideal for a wide range of projects including short 
-        scripts, dashboards, robotics projects, IoT solutions, smart home automation, and machine learning.
-
-        ### How to use this guide
-
-        This documentation explains how to use NiceGUI.
-        Each of the tiles covers a NiceGUI topic in detail.
-        It is recommended to start by reading this entire introduction page, then refer to other sections as needed.
-
-        ### Basic concepts
-
-        NiceGUI provides UI _components_ (or _elements_) such as buttons, sliders, text, images, charts, and more.
-        Your app assembles these components into _pages_.
-        When the user interacts with an item on a page, NiceGUI triggers an _event_ (or _action_).
-        You define code to _handle_ each event, such as what to do when a user clicks a button named "Go".
-
-        Components are arranged on a page using _layouts_.
-        Layouts provide things like grids, tabs, carousels, expansions, menus, and other tools to arrange your components.
-        Many components are linked to a _model_ (data object) in your code, which automatically updates the user interface when the value changes.
-
-        Styling and appearance can be controlled in several ways.
-        NiceGUI accepts optional arguments for certain styling, such as icons on buttons.
-        Other styling can be set with functions such as `.styles`, `.classes`, or `.props` that you'll learn about later.
-        Global styles like colors and fonts can be set with dedicated properties.
-        Or if you prefer, almost anything can be styled with CSS.
-    ''')
-    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}/') \
-                    .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')
-
-    ui.markdown('''
-        ### Actions
-
-        NiceGUI runs an event loop to handle user input and other events like timers and keyboard bindings.
-        You can write asynchronous functions for long-running tasks to keep the UI responsive.
-        The _Actions_ section covers how to work with events.
-
-        ### Implementation
-        
-        NiceGUI is implemented with HTML components served by an HTTP server (FastAPI), even for native windows.
-        If you already know HTML, everything will feel very familiar.
-        If you don't know HTML, that's fine too!
-        NiceGUI abstracts away the details, so you can focus on creating beautiful interfaces without worrying about how they are implemented.
-
-        ### Running NiceGUI Apps
-
-        There are several options for deploying NiceGUI.
-        By default, NiceGUI runs a server on localhost and runs your app as a private web page on the local machine.
-        When run this way, your app appears in a web browser window.
-        You can also run NiceGUI in a native window separate from a web browser.
-        Or you can run NiceGUI on a server that handles many clients - the website you're reading right now is served from NiceGUI.
-
-        After creating your app pages with components, you call `ui.run()` to start the NiceGUI server.
-        Optional parameters to `ui.run` set things like the network address and port the server binds to, 
-        whether the app runs in native mode, initial window size, and many other options.
-        The section _Configuration and Deployment_ covers the options to the `ui.run()` function and the FastAPI framework it is based on.
-
-        ### Customization
-
-        If you want more customization in your app, you can use the underlying Tailwind classes and Quasar components
-        to control the style or behavior of your components.
-        You can also extend the available components by subclassing existing NiceGUI components or importing new ones from Quasar.
-        All of this is optional.
-        Out of the box, NiceGUI provides everything you need to make modern, stylish, responsive user interfaces.
-    ''')
-
-
-def create_section(name: str) -> None:
-    section = SECTIONS[name]
-    heading(section.title)
-    section.content()

+ 0 - 19
website/documentation/section.py

@@ -1,19 +0,0 @@
-from typing import Protocol
-
-
-class Section(Protocol):
-
-    @property
-    def name(self) -> str:
-        ...
-
-    @property
-    def title(self) -> str:
-        ...
-
-    @property
-    def description(self) -> str:
-        ...
-
-    def content(self) -> None:
-        ...

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


+ 0 - 149
website/documentation/sections/action_events.py

@@ -1,149 +0,0 @@
-from nicegui import app, ui
-
-from ..tools import element_demo, load_demo, subheading, text_demo
-
-name = 'action_events'
-title = 'Action & Events'
-description = '''
-    This section covers timers, UI events, and the lifecycle of NiceGUI apps.
-'''
-
-
-def content() -> None:
-    load_demo(ui.timer)
-    load_demo(ui.keyboard)
-
-    @text_demo('UI Updates', '''
-        NiceGUI tries to automatically synchronize the state of UI elements with the client,
-        e.g. when a label text, an input value or style/classes/props of an element have changed.
-        In other cases, you can explicitly call `element.update()` or `ui.update(*elements)` to update.
-        The demo code shows both methods for a `ui.echart`, where it is difficult to automatically detect changes in the `options` dictionary.
-    ''')
-    def ui_updates_demo():
-        from random import random
-
-        chart = ui.echart({
-            'xAxis': {'type': 'value'},
-            'yAxis': {'type': 'value'},
-            'series': [{'type': 'line', 'data': [[0, 0], [1, 1]]}],
-        })
-
-        def add():
-            chart.options['series'][0]['data'].append([random(), random()])
-            chart.update()
-
-        def clear():
-            chart.options['series'][0]['data'].clear()
-            ui.update(chart)
-
-        with ui.row():
-            ui.button('Add', on_click=add)
-            ui.button('Clear', on_click=clear)
-
-    load_demo(ui.refreshable)
-
-    @text_demo('Async event handlers', '''
-        Most elements also support asynchronous event handlers.
-
-        Note: You can also pass a `functools.partial` into the `on_click` property to wrap async functions with parameters.
-    ''')
-    def async_handlers_demo():
-        import asyncio
-
-        async def async_task():
-            ui.notify('Asynchronous task started')
-            await asyncio.sleep(5)
-            ui.notify('Asynchronous task finished')
-
-        ui.button('start async task', on_click=async_task)
-
-    load_demo('generic_events')
-
-    @text_demo('Running CPU-bound tasks', '''
-        NiceGUI provides a `cpu_bound` function for running CPU-bound tasks in a separate process.
-        This is useful for long-running computations that would otherwise block the event loop and make the UI unresponsive.
-        The function returns a future that can be awaited.
-    ''')
-    def cpu_bound_demo():
-        import time
-
-        from nicegui import run
-
-        def compute_sum(a: float, b: float) -> float:
-            time.sleep(1)  # simulate a long-running computation
-            return a + b
-
-        async def handle_click():
-            result = await run.cpu_bound(compute_sum, 1, 2)
-            ui.notify(f'Sum is {result}')
-
-        # ui.button('Compute', on_click=handle_click)
-        # END OF DEMO
-        async def mock_click():
-            import asyncio
-            await asyncio.sleep(1)
-            ui.notify('Sum is 3')
-        ui.button('Compute', on_click=mock_click)
-
-    @text_demo('Running I/O-bound tasks', '''
-        NiceGUI provides an `io_bound` function for running I/O-bound tasks in a separate thread.
-        This is useful for long-running I/O operations that would otherwise block the event loop and make the UI unresponsive.
-        The function returns a future that can be awaited.
-    ''')
-    def io_bound_demo():
-        import requests
-
-        from nicegui import run
-
-        async def handle_click():
-            URL = 'https://httpbin.org/delay/1'
-            response = await run.io_bound(requests.get, URL, timeout=3)
-            ui.notify(f'Downloaded {len(response.content)} bytes')
-
-        ui.button('Download', on_click=handle_click)
-
-    load_demo(ui.run_javascript)
-
-    @text_demo('Events', '''
-        You can register coroutines or functions to be called for the following events:
-
-        - `app.on_startup`: called when NiceGUI is started or restarted
-        - `app.on_shutdown`: called when NiceGUI is shut down or restarted
-        - `app.on_connect`: called for each client which connects (optional argument: nicegui.Client)
-        - `app.on_disconnect`: called for each client which disconnects (optional argument: nicegui.Client)
-        - `app.on_exception`: called when an exception occurs (optional argument: exception)
-
-        When NiceGUI is shut down or restarted, all tasks still in execution will be automatically canceled.
-    ''')
-    def lifecycle_demo():
-        from datetime import datetime
-
-        from nicegui import app
-
-        # dt = datetime.now()
-
-        def handle_connection():
-            global dt
-            dt = datetime.now()
-        app.on_connect(handle_connection)
-
-        label = ui.label()
-        ui.timer(1, lambda: label.set_text(f'Last new connection: {dt:%H:%M:%S}'))
-        # END OF DEMO
-        global dt
-        dt = datetime.now()
-
-    subheading('Shutdown')
-
-    @element_demo(app.shutdown)
-    def shutdown_demo():
-        from nicegui import app
-
-        # ui.button('shutdown', on_click=app.shutdown)
-        #
-        # ui.run(reload=False)
-        # END OF DEMO
-        ui.button('shutdown', on_click=lambda: ui.notify(
-            'Nah. We do not actually shutdown the documentation server. Try it in your own app!'))
-
-    load_demo('storage')

+ 0 - 48
website/documentation/sections/audiovisual_elements.py

@@ -1,48 +0,0 @@
-from nicegui import ui
-
-from ..tools import load_demo, text_demo
-
-name = 'audiovisual_elements'
-title = 'Audiovisual Elements'
-description = '''
-    You can use elements like `ui.image`, `ui.audio`, `ui.video`, etc. to display audiovisual content.
-'''
-
-
-def content() -> None:
-    load_demo(ui.image)
-
-    @text_demo('Captions and Overlays', '''
-        By nesting elements inside a `ui.image` you can create augmentations.
-
-        Use [Quasar classes](https://quasar.dev/vue-components/img) for positioning and styling captions.
-        To overlay an SVG, make the `viewBox` exactly the size of the image and provide `100%` width/height to match the actual rendered size.
-    ''')
-    def captions_and_overlays_demo():
-        with ui.image('https://picsum.photos/id/29/640/360'):
-            ui.label('Nice!').classes('absolute-bottom text-subtitle2 text-center')
-
-        with ui.image('https://cdn.stocksnap.io/img-thumbs/960w/airplane-sky_DYPWDEEILG.jpg'):
-            ui.html('''
-                <svg viewBox="0 0 960 638" width="100%" height="100%" xmlns="http://www.w3.org/2000/svg">
-                <circle cx="445" cy="300" r="100" fill="none" stroke="red" stroke-width="20" />
-                </svg>
-            ''').classes('bg-transparent')
-
-    load_demo(ui.interactive_image)
-    load_demo(ui.audio)
-    load_demo(ui.video)
-    load_demo(ui.icon)
-    load_demo(ui.avatar)
-
-    @text_demo('SVG',
-               'You can add Scalable Vector Graphics using the `ui.html` element.')
-    def svg_demo():
-        content = '''
-            <svg viewBox="0 0 200 200" width="100" height="100" xmlns="http://www.w3.org/2000/svg">
-            <circle cx="100" cy="100" r="78" fill="#ffde34" stroke="black" stroke-width="3" />
-            <circle cx="80" cy="85" r="8" />
-            <circle cx="120" cy="85" r="8" />
-            <path d="m60,120 C75,150 125,150 140,120" style="fill:none; stroke:black; stroke-width:8; stroke-linecap:round" />
-            </svg>'''
-        ui.html(content)

+ 0 - 11
website/documentation/sections/binding_properties.py

@@ -1,11 +0,0 @@
-from ..tools import load_demo
-
-name = 'binding_properties'
-title = 'Binding Properties'
-description = '''
-    To update UI elements automatically, you can bind them to each other or to your data model.
-'''
-
-
-def content() -> None:
-    load_demo('bindings')

+ 0 - 260
website/documentation/sections/configuration_deployment.py

@@ -1,260 +0,0 @@
-from nicegui import ui
-
-from ..demo import bash_window, python_window
-from ..tools import load_demo, subheading, text_demo
-
-name = 'configuration_deployment'
-title = 'Configuration & Deployment'
-description = '''
-    Whether you want to run your app locally or on a server, native or in a browser, we got you covered.
-'''
-
-
-def content() -> None:
-    @text_demo('URLs', '''
-        You can access the list of all URLs on which the NiceGUI app is available via `app.urls`.
-        The URLs are not available in `app.on_startup` because the server is not yet running.
-        Instead, you can access them in a page function or register a callback with `app.urls.on_change`.
-    ''')
-    def urls_demo():
-        from nicegui import app
-
-        # @ui.page('/')
-        # def index():
-        #     for url in app.urls:
-        #         ui.link(url, target=url)
-        # END OF DEMO
-        ui.link('https://nicegui.io', target='https://nicegui.io')
-
-    load_demo(ui.run)
-
-    @text_demo('Native Mode', '''
-        You can enable native mode for NiceGUI by specifying `native=True` in the `ui.run` function.
-        To customize the initial window size and display mode, use the `window_size` and `fullscreen` parameters respectively.
-        Additionally, you can provide extra keyword arguments via `app.native.window_args` and `app.native.start_args`.
-        Pick any parameter as it is defined by the internally used [pywebview module](https://pywebview.flowrl.com/guide/api.html)
-        for the `webview.create_window` and `webview.start` functions.
-        Note that these keyword arguments will take precedence over the parameters defined in `ui.run`.
-
-        In native mode the `app.native.main_window` object allows you to access the underlying window.
-        It is an async version of [`Window` from pywebview](https://pywebview.flowrl.com/guide/api.html#window-object).
-    ''', tab=lambda: ui.label('NiceGUI'))
-    def native_mode_demo():
-        from nicegui import app
-
-        app.native.window_args['resizable'] = False
-        app.native.start_args['debug'] = True
-
-        ui.label('app running in native mode')
-        # ui.button('enlarge', on_click=lambda: app.native.main_window.resize(1000, 700))
-        #
-        # ui.run(native=True, window_size=(400, 300), fullscreen=False)
-        # END OF DEMO
-        ui.button('enlarge', on_click=lambda: ui.notify('window will be set to 1000x700 in native mode'))
-
-    # Show a helpful workaround until issue is fixed upstream.
-    # For more info see: https://github.com/r0x0r/pywebview/issues/1078
-    ui.markdown('''
-        If webview has trouble finding required libraries, you may get an error relating to "WebView2Loader.dll".
-        To work around this issue, try moving the DLL file up a directory, e.g.:
-        
-        * from `.venv/Lib/site-packages/webview/lib/x64/WebView2Loader.dll`
-        * to `.venv/Lib/site-packages/webview/lib/WebView2Loader.dll`
-    ''')
-
-    @text_demo('Environment Variables', '''
-        You can set the following environment variables to configure NiceGUI:
-
-        - `MATPLOTLIB` (default: true) can be set to `false` to avoid the potentially costly import of Matplotlib.
-            This will make `ui.pyplot` and `ui.line_plot` unavailable.
-        - `NICEGUI_STORAGE_PATH` (default: local ".nicegui") can be set to change the location of the storage files.
-        - `MARKDOWN_CONTENT_CACHE_SIZE` (default: 1000): The maximum number of Markdown content snippets that are cached in memory.
-    ''')
-    def env_var_demo():
-        from nicegui.elements import markdown
-
-        ui.label(f'Markdown content cache size is {markdown.prepare_content.cache_info().maxsize}')
-
-    subheading('Server Hosting')
-
-    ui.markdown('''
-        To deploy your NiceGUI app on a server, you will need to execute your `main.py` (or whichever file contains your `ui.run(...)`) on your cloud infrastructure.
-        You can, for example, just install the [NiceGUI python package via pip](https://pypi.org/project/nicegui/) and use systemd or similar service to start the main script.
-        In most cases, you will set the port to 80 (or 443 if you want to use HTTPS) with the `ui.run` command to make it easily accessible from the outside.
-
-        A convenient alternative is the use of our [pre-built multi-arch Docker image](https://hub.docker.com/r/zauberzeug/nicegui) which contains all necessary dependencies.
-        With this command you can launch the script `main.py` in the current directory on the public port 80:
-    ''').classes('bold-links arrow-links')
-    with bash_window(classes='max-w-lg w-full h-44'):
-        ui.markdown('''
-            ```bash
-            docker run -it --restart always \\
-              -p 80:8080 \\
-              -e PUID=$(id -u) \\
-              -e PGID=$(id -g) \\
-              -v $(pwd)/:/app/ \\
-              zauberzeug/nicegui:latest
-            ```
-        ''')
-    ui.markdown('''
-        The demo assumes `main.py` uses the port 8080 in the `ui.run` command (which is the default).
-        The `-d` tells docker to run in background and `--restart always` makes sure the container is restarted if the app crashes or the server reboots.
-        Of course this can also be written in a Docker compose file:
-    ''')
-    with python_window('docker-compose.yml', classes='max-w-lg w-full h-60'):
-        ui.markdown('''
-            ```yaml
-            app:
-                image: zauberzeug/nicegui:latest
-                restart: always
-                ports:
-                    - 80:8080
-                environment:
-                    - PUID=1000 # change this to your user id
-                    - PGID=1000 # change this to your group id
-                volumes:
-                    - ./:/app/
-            ```
-        ''')
-    ui.markdown('''
-        There are other handy features in the Docker image like non-root user execution and signal pass-through.
-        For more details we recommend to have a look at our [Docker example](https://github.com/zauberzeug/nicegui/tree/main/examples/docker_image).
-    ''').classes('bold-links arrow-links')
-
-    ui.markdown('''
-        You can provide SSL certificates directly using [FastAPI](https://fastapi.tiangolo.com/deployment/https/).
-        In production we also like using reverse proxies like [Traefik](https://doc.traefik.io/traefik/) or [NGINX](https://www.nginx.com/) to handle these details for us.
-        See our development [docker-compose.yml](https://github.com/zauberzeug/nicegui/blob/main/docker-compose.yml) as an example.
-
-        You may also have a look at [our demo for using a custom FastAPI app](https://github.com/zauberzeug/nicegui/tree/main/examples/fastapi).
-        This will allow you to do very flexible deployments as described in the [FastAPI documentation](https://fastapi.tiangolo.com/deployment/).
-        Note that there are additional steps required to allow multiple workers.
-    ''').classes('bold-links arrow-links')
-
-    subheading('Package for Installation')
-
-    ui.markdown('''
-        NiceGUI apps can also be bundled into an executable with [PyInstaller](https://www.pyinstaller.org/).
-        This allows you to distribute your app as a single file that can be executed on any computer.
-
-        Just take care your `ui.run` command does not use the `reload` argument.
-        Running the `build.py` below will create an executable `myapp` in the `dist` folder:
-    ''').classes('bold-links arrow-links')
-
-    with ui.row().classes('w-full items-stretch'):
-        with python_window(classes='max-w-lg w-full'):
-            ui.markdown('''
-                ```python
-                from nicegui import native, ui
-
-                ui.label('Hello from PyInstaller')
-
-                ui.run(reload=False, port=native.find_open_port())
-                ```
-            ''')
-        with python_window('build.py', classes='max-w-lg w-full'):
-            ui.markdown('''
-                ```python
-                import os
-                import subprocess
-                from pathlib import Path
-                import nicegui
-
-                cmd = [
-                    'python',
-                    '-m', 'PyInstaller',
-                    'main.py', # your main file with ui.run()
-                    '--name', 'myapp', # name of your app
-                    '--onefile',
-                    #'--windowed', # prevent console appearing, only use with ui.run(native=True, ...)
-                    '--add-data', f'{Path(nicegui.__file__).parent}{os.pathsep}nicegui'
-                ]
-                subprocess.call(cmd)
-                ```
-            ''')
-
-    ui.markdown('''
-        **Packaging Tips**
-
-        - When building a PyInstaller app, your main script can use a native window (rather than a browser window) by
-          using `ui.run(reload=False, native=True)`.
-          The `native` parameter can be `True` or `False` depending on whether you want a native window or to launch a
-          page in the user's browser - either will work in the PyInstaller generated app.
-
-        - Specifying `--windowed` to PyInstaller will prevent a terminal console from appearing.
-          However you should only use this option if you have also specified `native=True` in your `ui.run` command.
-          Without a terminal console the user won't be able to exit the app by pressing Ctrl-C.
-          With the `native=True` option, the app will automatically close when the window is closed, as expected.
-
-        - Specifying `--windowed` to PyInstaller will create an `.app` file on Mac which may be more convenient to distribute.
-          When you double-click the app to run it, it will not show any console output.
-          You can also run the app from the command line with `./myapp.app/Contents/MacOS/myapp` to see the console output.
-
-        - Specifying `--onefile` to PyInstaller will create a single executable file.
-          Whilst convenient for distribution, it will be slower to start up.
-          This is not NiceGUI's fault but just the way Pyinstaller zips things into a single file, then unzips everything
-          into a temporary directory before running.
-          You can mitigate this by removing `--onefile` from the PyInstaller command,
-          and zip up the generated `dist` directory yourself, distribute it,
-          and your end users can unzip once and be good to go,
-          without the constant expansion of files due to the `--onefile` flag.
-          
-        - Summary of user experience for different options:
-
-            | PyInstaller              | `ui.run(...)`  | Explanation |
-            | :---                     | :---           | :---        |
-            | `onefile`                | `native=False` | Single executable generated in `dist/`, runs in browser |
-            | `onefile`                | `native=True`  | Single executable generated in `dist/`, runs in popup window |
-            | `onefile` and `windowed` | `native=True`  | Single executable generated in `dist/` (on Mac a proper `dist/myapp.app` generated incl. icon), runs in popup window, no console appears |
-            | `onefile` and `windowed` | `native=False` | Avoid (no way to exit the app) |
-            | Specify neither          |                | A `dist/myapp` directory created which can be zipped manually and distributed; run with `dist/myapp/myapp` |
-
-        - If you are using a Python virtual environment, ensure you `pip install pyinstaller` within your virtual environment
-          so that the correct PyInstaller is used, or you may get broken apps due to the wrong version of PyInstaller being picked up.
-          That is why the build script invokes PyInstaller using `python -m PyInstaller` rather than just `pyinstaller`.
-    ''').classes('bold-links arrow-links')
-
-    with bash_window(classes='max-w-lg w-full h-42 self-center'):
-        ui.markdown('''
-            ```bash
-            python -m venv venv
-            source venv/bin/activate
-            pip install nicegui
-            pip install pyinstaller
-            ```
-        ''')
-
-    ui.markdown('''
-        **Note:**
-        If you're getting an error "TypeError: a bytes-like object is required, not 'str'", try adding the following lines to the top of your `main.py` file:
-        ```py
-        import sys
-        sys.stdout = open('logs.txt', 'w')
-        ```
-        See <https://github.com/zauberzeug/nicegui/issues/681> for more information.
-    ''').classes('bold-links arrow-links')
-
-    subheading('NiceGUI On Air')
-
-    ui.markdown('''
-        By using `ui.run(on_air=True)` you can share your local app with others over the internet 🧞.
-
-        When accessing the on-air URL, all libraries (like Vue, Quasar, ...) are loaded from our CDN.
-        Thereby only the raw content and events need to be transmitted by your local app.
-        This makes it blazing fast even if your app only has a poor internet connection (e.g. a mobile robot in the field).
-
-        By setting `on_air=True` you will get a random URL which is valid for 1 hour.
-        If you sign-up at <https://on-air.nicegui.io> you get a token which could be used to identify your device: `ui.run(on_air='<your token>'`).
-        This will give you a fixed URL and the possibility to protect remote access with a passphrase.
-
-        Currently On Air is available as a tech preview and can be used free of charge (for now).
-        We will gradually improve stability, introduce payment options and extend the service with multi-device management, remote terminal access and more.
-        Please let us know your feedback on [GitHub](https://github.com/zauberzeug/nicegui/discussions),
-        [Reddit](https://www.reddit.com/r/nicegui/), or [Discord](https://discord.gg/TEpFeAaF4f).
-
-        **Data Privacy:**
-        We take your privacy very serious.
-        NiceGUI On Air does not log or store any content of the relayed data.
-    ''').classes('bold-links arrow-links')
-
-    ui.element('div').classes('h-32')

+ 0 - 30
website/documentation/sections/controls.py

@@ -1,30 +0,0 @@
-from nicegui import ui
-
-from ..tools import load_demo
-
-name = 'controls'
-title = 'Controls'
-description = '''
-    NiceGUI provides a variety of elements for user interaction, e.g. `ui.button`, `ui.slider`, `ui.inputs`, etc.
-'''
-
-
-def content() -> None:
-    load_demo(ui.button)
-    load_demo(ui.badge)
-    load_demo(ui.toggle)
-    load_demo(ui.radio)
-    load_demo(ui.select)
-    load_demo(ui.checkbox)
-    load_demo(ui.switch)
-    load_demo(ui.slider)
-    load_demo(ui.joystick)
-    load_demo(ui.input)
-    load_demo(ui.textarea)
-    load_demo(ui.number)
-    load_demo(ui.knob)
-    load_demo(ui.color_input)
-    load_demo(ui.color_picker)
-    load_demo(ui.date)
-    load_demo(ui.time)
-    load_demo(ui.upload)

+ 0 - 31
website/documentation/sections/data_elements.py

@@ -1,31 +0,0 @@
-from nicegui import optional_features, ui
-
-from ..tools import load_demo
-
-name = 'data_elements'
-title = 'Data Elements'
-description = '''
-    There are several elements for displaying data, e.g. `ui.table`, `ui.aggrid`, `ui.highchart`, `ui.echart`, etc.
-'''
-
-
-def content() -> None:
-    load_demo(ui.table)
-    load_demo(ui.aggrid)
-    if optional_features.has('highcharts'):
-        load_demo(ui.highchart)
-    load_demo(ui.echart)
-    if optional_features.has('matplotlib'):
-        load_demo(ui.pyplot)
-        load_demo(ui.line_plot)
-    if optional_features.has('plotly'):
-        load_demo(ui.plotly)
-    load_demo(ui.linear_progress)
-    load_demo(ui.circular_progress)
-    load_demo(ui.spinner)
-    load_demo(ui.scene)
-    load_demo(ui.tree)
-    load_demo(ui.log)
-    load_demo(ui.editor)
-    load_demo(ui.code)
-    load_demo(ui.json_editor)

+ 0 - 84
website/documentation/sections/page_layout.py

@@ -1,84 +0,0 @@
-from nicegui import ui
-
-from ..tools import load_demo, text_demo
-
-name = 'page_layout'
-title = 'Page Layout'
-description = '''
-    This section covers fundamental techniques as well as several elements to structure your UI.
-'''
-
-
-def content() -> None:
-    @text_demo('Auto-context', '''
-        In order to allow writing intuitive UI descriptions, NiceGUI automatically tracks the context in which elements are created.
-        This means that there is no explicit `parent` parameter.
-        Instead the parent context is defined using a `with` statement.
-        It is also passed to event handlers and timers.
-
-        In the demo, the label "Card content" is added to the card.
-        And because the `ui.button` is also added to the card, the label "Click!" will also be created in this context.
-        The label "Tick!", which is added once after one second, is also added to the card.
-
-        This design decision allows for easily creating modular components that keep working after moving them around in the UI.
-        For example, you can move label and button somewhere else, maybe wrap them in another container, and the code will still work.
-    ''')
-    def auto_context_demo():
-        with ui.card():
-            ui.label('Card content')
-            ui.button('Add label', on_click=lambda: ui.label('Click!'))
-            ui.timer(1.0, lambda: ui.label('Tick!'), once=True)
-
-    load_demo(ui.card)
-    load_demo(ui.column)
-    load_demo(ui.row)
-    load_demo(ui.grid)
-
-    @text_demo('Clear Containers', '''
-        To remove all elements from a row, column or card container, use can call
-        ```py
-        container.clear()
-        ```
-
-        Alternatively, you can remove individual elements by calling
-        
-        - `container.remove(element: Element)`,
-        - `container.remove(index: int)`, or
-        - `element.delete()`.
-    ''')
-    def clear_containers_demo():
-        container = ui.row()
-
-        def add_face():
-            with container:
-                ui.icon('face')
-        add_face()
-
-        ui.button('Add', on_click=add_face)
-        ui.button('Remove', on_click=lambda: container.remove(0) if list(container) else None)
-        ui.button('Clear', on_click=container.clear)
-
-    load_demo(ui.expansion)
-    load_demo(ui.scroll_area)
-    load_demo(ui.separator)
-    load_demo(ui.splitter)
-    load_demo('tabs')
-    load_demo(ui.stepper)
-    load_demo(ui.timeline)
-    load_demo(ui.carousel)
-    load_demo(ui.pagination)
-    load_demo(ui.menu)
-    load_demo(ui.context_menu)
-
-    @text_demo('Tooltips', '''
-        Simply call the `tooltip(text:str)` method on UI elements to provide a tooltip.
-
-        For more artistic control you can nest tooltip elements and apply props, classes and styles.
-    ''')
-    def tooltips_demo():
-        ui.label('Tooltips...').tooltip('...are shown on mouse over')
-        with ui.button(icon='thumb_up'):
-            ui.tooltip('I like this').classes('bg-green')
-
-    load_demo(ui.notify)
-    load_demo(ui.dialog)

+ 0 - 139
website/documentation/sections/pages_routing.py

@@ -1,139 +0,0 @@
-import uuid
-
-from nicegui import app, ui
-
-from ..tools import element_demo, load_demo, subheading, text_demo
-
-CONSTANT_UUID = str(uuid.uuid4())
-
-name = 'pages_routing'
-title = 'Pages & Routing'
-description = '''
-    A NiceGUI app can consist of multiple pages and other FastAPI endpoints.
-'''
-
-
-def content() -> None:
-    load_demo(ui.page)
-
-    @text_demo('Auto-index page', '''
-        Pages created with the `@ui.page` decorator are "private".
-        Their content is re-created for each client.
-        Thus, in the demo to the right, the displayed ID on the private page changes when the browser reloads the page.
-
-        UI elements that are not wrapped in a decorated page function are placed on an automatically generated index page at route "/".
-        This auto-index page is created once on startup and *shared* across all clients that might connect.
-        Thus, each connected client will see the *same* elements.
-        In the demo to the right, the displayed ID on the auto-index page remains constant when the browser reloads the page.
-    ''')
-    def auto_index_page():
-        from uuid import uuid4
-
-        @ui.page('/private_page')
-        async def private_page():
-            ui.label(f'private page with ID {uuid4()}')
-
-        # ui.label(f'shared auto-index page with ID {uuid4()}')
-        # ui.link('private page', private_page)
-        # END OF DEMO
-        ui.label(f'shared auto-index page with ID {CONSTANT_UUID}')
-        ui.link('private page', private_page)
-
-    @text_demo('Page Layout', '''
-        With `ui.header`, `ui.footer`, `ui.left_drawer` and `ui.right_drawer` you can add additional layout elements to a page.
-        The `fixed` argument controls whether the element should scroll or stay fixed on the screen.
-        The `top_corner` and `bottom_corner` arguments indicate whether a drawer should expand to the top or bottom of the page.
-        See <https://quasar.dev/layout/header-and-footer> and <https://quasar.dev/layout/drawer> for more information about possible props.
-        With `ui.page_sticky` you can place an element "sticky" on the screen.
-        See <https://quasar.dev/layout/page-sticky> for more information.
-    ''')
-    def page_layout_demo():
-        @ui.page('/page_layout')
-        def page_layout():
-            ui.label('CONTENT')
-            [ui.label(f'Line {i}') for i in range(100)]
-            with ui.header(elevated=True).style('background-color: #3874c8').classes('items-center justify-between'):
-                ui.label('HEADER')
-                ui.button(on_click=lambda: right_drawer.toggle(), icon='menu').props('flat color=white')
-            with ui.left_drawer(top_corner=True, bottom_corner=True).style('background-color: #d7e3f4'):
-                ui.label('LEFT DRAWER')
-            with ui.right_drawer(fixed=False).style('background-color: #ebf1fa').props('bordered') as right_drawer:
-                ui.label('RIGHT DRAWER')
-            with ui.footer().style('background-color: #3874c8'):
-                ui.label('FOOTER')
-
-        ui.link('show page with fancy layout', page_layout)
-
-    @text_demo('Parameter injection', '''
-        Thanks to FastAPI, a page function accepts optional parameters to provide
-        [path parameters](https://fastapi.tiangolo.com/tutorial/path-params/), 
-        [query parameters](https://fastapi.tiangolo.com/tutorial/query-params/) or the whole incoming
-        [request](https://fastapi.tiangolo.com/advanced/using-request-directly/) for accessing
-        the body payload, headers, cookies and more.
-    ''')
-    def parameter_demo():
-        @ui.page('/icon/{icon}')
-        def icons(icon: str, amount: int = 1):
-            ui.label(icon).classes('text-h3')
-            with ui.row():
-                [ui.icon(icon).classes('text-h3') for _ in range(amount)]
-        ui.link('Star', '/icon/star?amount=5')
-        ui.link('Home', '/icon/home')
-        ui.link('Water', '/icon/water_drop?amount=3')
-
-    load_demo(ui.open)
-    load_demo(ui.download)
-
-    subheading('Static files')
-
-    @element_demo(app.add_static_files)
-    def add_static_files_demo():
-        from nicegui import app
-
-        app.add_static_files('/examples', 'examples')
-        ui.label('Some NiceGUI Examples').classes('text-h5')
-        ui.link('AI interface', '/examples/ai_interface/main.py')
-        ui.link('Custom FastAPI app', '/examples/fastapi/main.py')
-        ui.link('Authentication', '/examples/authentication/main.py')
-
-    subheading('Media files')
-
-    @element_demo(app.add_media_files)
-    def add_media_files_demo():
-        from pathlib import Path
-
-        import requests
-
-        from nicegui import app
-
-        media = Path('media')
-        # media.mkdir(exist_ok=True)
-        # r = requests.get('https://cdn.coverr.co/videos/coverr-cloudy-sky-2765/1080p.mp4')
-        # (media  / 'clouds.mp4').write_bytes(r.content)
-        # app.add_media_files('/my_videos', media)
-        # ui.video('/my_videos/clouds.mp4')
-        # END OF DEMO
-        ui.video('https://cdn.coverr.co/videos/coverr-cloudy-sky-2765/1080p.mp4')
-
-    @text_demo('API Responses', '''
-        NiceGUI is based on [FastAPI](https://fastapi.tiangolo.com/).
-        This means you can use all of FastAPI's features.
-        For example, you can implement a RESTful API in addition to your graphical user interface.
-        You simply import the `app` object from `nicegui`.
-        Or you can run NiceGUI on top of your own FastAPI app by using `ui.run_with(app)` instead of starting a server automatically with `ui.run()`.
-
-        You can also return any other FastAPI response object inside a page function.
-        For example, you can return a `RedirectResponse` to redirect the user to another page if certain conditions are met.
-        This is used in our [authentication demo](https://github.com/zauberzeug/nicegui/tree/main/examples/authentication/main.py).
-    ''')
-    def fastapi_demo():
-        import random
-
-        from nicegui import app
-
-        @app.get('/random/{max}')
-        def generate_random_number(max: int):
-            return {'min': 0, 'max': max, 'value': random.randint(0, max)}
-
-        max = ui.number('max', value=100)
-        ui.button('generate random number', on_click=lambda: ui.open(f'/random/{max.value:.0f}'))

+ 0 - 126
website/documentation/sections/styling_appearance.py

@@ -1,126 +0,0 @@
-from nicegui import events, ui
-
-from ..demo import browser_window, python_window
-from ..tools import load_demo, subheading, text_demo
-
-name = 'styling_appearance'
-title = 'Styling & Appearance'
-description = '''
-    NiceGUI allows to customize the appearance of UI elements in various ways, including CSS, Tailwind CSS and Quasar properties.
-'''
-
-
-def content() -> None:
-    @text_demo('Styling', '''
-        NiceGUI uses the [Quasar Framework](https://quasar.dev/) version 1.0 and hence has its full design power.
-        Each NiceGUI element provides a `props` method whose content is passed [to the Quasar component](https://justpy.io/quasar_tutorial/introduction/#props-of-quasar-components):
-        Have a look at [the Quasar documentation](https://quasar.dev/vue-components/button#design) for all styling props.
-        Props with a leading `:` can contain JavaScript expressions that are evaluated on the client.
-        You can also apply [Tailwind CSS](https://tailwindcss.com/) utility classes with the `classes` method.
-
-        If you really need to apply CSS, you can use the `style` method. Here the delimiter is `;` instead of a blank space.
-
-        All three functions also provide `remove` and `replace` parameters in case the predefined look is not wanted in a particular styling.
-    ''')
-    def design_demo():
-        ui.radio(['x', 'y', 'z'], value='x').props('inline color=green')
-        ui.button(icon='touch_app').props('outline round').classes('shadow-lg')
-        ui.label('Stylish!').style('color: #6E93D6; font-size: 200%; font-weight: 300')
-
-    subheading('Try styling NiceGUI elements!')
-    ui.markdown('''
-        Try out how
-        [Tailwind CSS classes](https://tailwindcss.com/),
-        [Quasar props](https://justpy.io/quasar_tutorial/introduction/#props-of-quasar-components),
-        and CSS styles affect NiceGUI elements.
-    ''').classes('bold-links arrow-links mb-[-1rem]')
-    with ui.row():
-        ui.label('Select an element from those available and start styling it!').classes('mx-auto my-auto')
-        select_element = ui.select({
-            ui.label: 'ui.label',
-            ui.checkbox: 'ui.checkbox',
-            ui.switch: 'ui.switch',
-            ui.input: 'ui.input',
-            ui.textarea: 'ui.textarea',
-            ui.button: 'ui.button',
-        }, value=ui.button, on_change=lambda: live_demo_ui.refresh()).props('dense')
-
-    @ui.refreshable
-    def live_demo_ui():
-        with ui.column().classes('w-full items-stretch gap-8 no-wrap min-[1500px]:flex-row'):
-            with python_window(classes='w-full max-w-[44rem]'):
-                with ui.column().classes('w-full gap-4'):
-                    ui.markdown(f'''
-                        ```py
-                        from nicegui import ui
-
-                        element = {select_element.options[select_element.value]}('element')
-                        ```
-                    ''').classes('mb-[-0.25em]')
-                    with ui.row().classes('items-center gap-0 w-full px-2'):
-                        def handle_classes(e: events.ValueChangeEventArguments):
-                            try:
-                                element.classes(replace=e.value)
-                            except ValueError:
-                                pass
-                        ui.markdown("`element.classes('`")
-                        ui.input(on_change=handle_classes).classes('mt-[-0.5em] text-mono grow').props('dense')
-                        ui.markdown("`')`")
-                    with ui.row().classes('items-center gap-0 w-full px-2'):
-                        def handle_props(e: events.ValueChangeEventArguments):
-                            element._props = {'label': 'Button', 'color': 'primary'}
-                            try:
-                                element.props(e.value)
-                            except ValueError:
-                                pass
-                            element.update()
-                        ui.markdown("`element.props('`")
-                        ui.input(on_change=handle_props).classes('mt-[-0.5em] text-mono grow').props('dense')
-                        ui.markdown("`')`")
-                    with ui.row().classes('items-center gap-0 w-full px-2'):
-                        def handle_style(e: events.ValueChangeEventArguments):
-                            try:
-                                element.style(replace=e.value)
-                            except ValueError:
-                                pass
-                        ui.markdown("`element.style('`")
-                        ui.input(on_change=handle_style).classes('mt-[-0.5em] text-mono grow').props('dense')
-                        ui.markdown("`')`")
-                    ui.markdown('''
-                        ```py
-                        ui.run()
-                        ```
-                    ''')
-            with browser_window(classes='w-full max-w-[44rem] min-[1500px]:max-w-[20rem] min-h-[10rem] browser-window'):
-                element: ui.element = select_element.value("element")
-    live_demo_ui()
-
-    @text_demo('Tailwind CSS', '''
-        [Tailwind CSS](https://tailwindcss.com/) is a CSS framework for rapidly building custom user interfaces.
-        NiceGUI provides a fluent, auto-complete friendly interface for adding Tailwind classes to UI elements.
-        
-        You can discover available classes by navigating the methods of the `tailwind` property.
-        The builder pattern allows you to chain multiple classes together (as shown with "Label A").
-        You can also call the `tailwind` property with a list of classes (as shown with "Label B").
-
-        Although this is very similar to using the `classes` method, it is more convenient for Tailwind classes due to auto-completion.
-
-        Last but not least, you can also predefine a style and apply it to multiple elements (labels C and D).
-               
-        Note that sometimes Tailwind is overruled by Quasar styles, e.g. when using `ui.button('Button').tailwind('bg-red-500')`.
-        This is a known limitation and not fully in our control.
-        But we try to provide solutions like the `color` parameter: `ui.button('Button', color='red-500')`.
-    ''')
-    def tailwind_demo():
-        from nicegui import Tailwind
-        ui.label('Label A').tailwind.font_weight('extrabold').text_color('blue-600').background_color('orange-200')
-        ui.label('Label B').tailwind('drop-shadow', 'font-bold', 'text-green-600')
-
-        red_style = Tailwind().text_color('red-600').font_weight('bold')
-        label_c = ui.label('Label C')
-        red_style.apply(label_c)
-        ui.label('Label D').tailwind(red_style)
-
-    load_demo(ui.query)
-    load_demo(ui.colors)
-    load_demo(ui.dark_mode)

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

@@ -1,19 +0,0 @@
-from nicegui import ui
-
-from ..tools import load_demo
-
-name = 'text_elements'
-title = 'Text Elements'
-description = '''
-    Elements like `ui.label`, `ui.markdown` and `ui.html` can be used to display text and other content.
-'''
-
-
-def content() -> None:
-    load_demo(ui.label)
-    load_demo(ui.link)
-    load_demo(ui.chat_message)
-    load_demo(ui.element)
-    load_demo(ui.markdown)
-    load_demo(ui.mermaid)
-    load_demo(ui.html)

+ 0 - 51
website/documentation_pages.py

@@ -1,51 +0,0 @@
-import importlib
-import inspect
-import logging
-
-from nicegui import context, ui
-
-from . import documentation
-from .header import add_head_html, add_header
-from .style import section_heading, side_menu
-
-
-def create_section(name: str) -> None:
-    """Create a documentation section."""
-    add_head_html()
-    with side_menu() as menu:
-        ui.markdown('[← Overview](/documentation)').classes('bold-links')
-    add_header(menu)
-    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'):
-        documentation.create_section(name)
-
-
-async def create_more(name: str) -> None:
-    """Create a documentation page for a "more" page."""
-    if name in {'ag_grid', 'e_chart'}:
-        name = name.replace('_', '')  # NOTE: "AG Grid" leads to anchor name "ag_grid", but class is `ui.aggrid`
-    module = importlib.import_module(f'website.documentation.more.{name}_documentation')
-    more = getattr(module, 'more', None)
-    api = getattr(ui, name, name)
-
-    add_head_html()
-    add_header()
-    with side_menu() as menu:
-        ui.markdown('[← Overview](/documentation)').classes('bold-links')  # TODO: back to section
-    with ui.column().classes('w-full p-8 lg:p-16 max-w-[1250px] mx-auto'):
-        section_heading('Documentation', f'ui.*{name}*' if hasattr(ui, name) else f'*{name.replace("_", " ").title()}*')
-        with menu:
-            ui.markdown('**Demos**' if more else '**Demo**').classes('mt-4')
-        documentation.element_demo(api)(getattr(module, 'main_demo'))
-        if more:
-            more()
-        if inspect.isclass(api):
-            with menu:
-                ui.markdown('**Reference**').classes('mt-4')
-            ui.markdown('## Reference').classes('mt-16')
-            documentation.generate_class_doc(api)
-    try:
-        await context.get_client().connected()
-        ui.run_javascript(f'document.title = "{name} • NiceGUI";')
-    except TimeoutError:
-        logging.warning(f'client did not connect for page /documentation/{name}')