|
@@ -10,10 +10,10 @@ if True:
|
|
|
|
|
|
import os
|
|
|
from pathlib import Path
|
|
|
-from typing import Optional
|
|
|
+from typing import Awaitable, Callable, Optional
|
|
|
|
|
|
from fastapi import Request
|
|
|
-from fastapi.responses import FileResponse, RedirectResponse
|
|
|
+from fastapi.responses import FileResponse, RedirectResponse, Response
|
|
|
from starlette.middleware.sessions import SessionMiddleware
|
|
|
|
|
|
import prometheus
|
|
@@ -23,6 +23,7 @@ from nicegui import ui
|
|
|
from website import documentation, example_card, svg
|
|
|
from website.demo import bash_window, browser_window, python_window
|
|
|
from website.documentation_tools import create_anchor_name, element_demo, generate_class_doc
|
|
|
+from website.search import Search
|
|
|
from website.star import add_star
|
|
|
from website.style import example_link, features, heading, link_target, section_heading, side_menu, subtitle, title
|
|
|
|
|
@@ -33,20 +34,22 @@ app.add_middleware(SessionMiddleware, secret_key=os.environ.get('NICEGUI_SECRET_
|
|
|
|
|
|
app.add_static_files('/favicon', str(Path(__file__).parent / 'website' / 'favicon'))
|
|
|
app.add_static_files('/fonts', str(Path(__file__).parent / 'website' / 'fonts'))
|
|
|
+app.add_static_files('/static', str(Path(__file__).parent / 'website' / 'static'))
|
|
|
|
|
|
|
|
|
@app.get('/logo.png')
|
|
|
-def logo():
|
|
|
+def logo() -> FileResponse:
|
|
|
return FileResponse(svg.PATH / 'logo.png', media_type='image/png')
|
|
|
|
|
|
|
|
|
@app.get('/logo_square.png')
|
|
|
-def logo():
|
|
|
+def logo_square() -> FileResponse:
|
|
|
return FileResponse(svg.PATH / 'logo_square.png', media_type='image/png')
|
|
|
|
|
|
|
|
|
@app.middleware('http')
|
|
|
-async def redirect_reference_to_documentation(request: Request, call_next):
|
|
|
+async def redirect_reference_to_documentation(request: Request,
|
|
|
+ call_next: Callable[[Request], Awaitable[Response]]) -> Response:
|
|
|
if request.url.path == '/reference':
|
|
|
return RedirectResponse('/documentation')
|
|
|
return await call_next(request)
|
|
@@ -75,29 +78,31 @@ def add_header(menu: Optional[ui.left_drawer] = None) -> None:
|
|
|
.classes('items-center duration-200 p-0 px-4 no-wrap') \
|
|
|
.style('box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1)'):
|
|
|
if menu:
|
|
|
- ui.button(on_click=menu.toggle).props('flat color=white icon=menu round').classes('lg:hidden')
|
|
|
+ ui.button(on_click=menu.toggle, icon='menu').props('flat color=white round').classes('lg:hidden')
|
|
|
with ui.link(target=index_page).classes('row gap-4 items-center no-wrap mr-auto'):
|
|
|
- svg.face().classes('w-8 stroke-white stroke-2')
|
|
|
+ svg.face().classes('w-8 stroke-white stroke-2 max-[550px]:hidden')
|
|
|
svg.word().classes('w-24')
|
|
|
with ui.row().classes('max-lg:hidden'):
|
|
|
for title, target in menu_items.items():
|
|
|
ui.link(title, target).classes(replace='text-lg text-white')
|
|
|
- with ui.link(target='https://discord.gg/TEpFeAaF4f').classes('max-[435px]:hidden'):
|
|
|
+ search = Search()
|
|
|
+ search.create_button()
|
|
|
+ with ui.link(target='https://discord.gg/TEpFeAaF4f').classes('max-[445px]:hidden').tooltip('Discord'):
|
|
|
svg.discord().classes('fill-white scale-125 m-1')
|
|
|
- with ui.link(target='https://www.reddit.com/r/nicegui/').classes('max-[385px]:hidden'):
|
|
|
+ with ui.link(target='https://www.reddit.com/r/nicegui/').classes('max-[395px]:hidden').tooltip('Reddit'):
|
|
|
svg.reddit().classes('fill-white scale-125 m-1')
|
|
|
- with ui.link(target='https://github.com/zauberzeug/nicegui/'):
|
|
|
+ with ui.link(target='https://github.com/zauberzeug/nicegui/').tooltip('GitHub'):
|
|
|
svg.github().classes('fill-white scale-125 m-1')
|
|
|
- add_star().classes('max-[480px]:hidden')
|
|
|
+ add_star().classes('max-[490px]:hidden')
|
|
|
with ui.row().classes('lg:hidden'):
|
|
|
- with ui.button().props('flat color=white icon=more_vert round'):
|
|
|
+ with ui.button(icon='more_vert').props('flat color=white round'):
|
|
|
with ui.menu().classes('bg-primary text-white text-lg').props(remove='no-parent-event'):
|
|
|
for title, target in menu_items.items():
|
|
|
- ui.menu_item(title, on_click=lambda _, target=target: ui.open(target))
|
|
|
+ ui.menu_item(title, on_click=lambda target=target: ui.open(target))
|
|
|
|
|
|
|
|
|
@ui.page('/')
|
|
|
-async def index_page(client: Client):
|
|
|
+async def index_page(client: Client) -> None:
|
|
|
client.content.classes('p-0 gap-0')
|
|
|
add_head_html()
|
|
|
add_header()
|
|
@@ -204,7 +209,7 @@ async def index_page(client: Client):
|
|
|
features('insights', 'Visualization', [
|
|
|
'charts, diagrams and tables',
|
|
|
'3D scenes',
|
|
|
- 'progress bars',
|
|
|
+ 'straight-forward data binding',
|
|
|
'built-in timer for data refresh',
|
|
|
])
|
|
|
features('brush', 'Styling', [
|
|
@@ -216,7 +221,7 @@ async def index_page(client: Client):
|
|
|
features('source', 'Coding', [
|
|
|
'routing for multiple pages',
|
|
|
'auto-reload on code change',
|
|
|
- 'straight-forward data binding',
|
|
|
+ 'persistent user sessions',
|
|
|
'Jupyter notebook compatibility',
|
|
|
])
|
|
|
features('anchor', 'Foundation', [
|
|
@@ -269,6 +274,7 @@ async def index_page(client: Client):
|
|
|
example_link('Local File Picker', 'demonstrates a dialog for selecting files locally on the server')
|
|
|
example_link('Search as you type', 'using public API of thecocktaildb.com to search for cocktails')
|
|
|
example_link('Menu and Tabs', 'uses Quasar to create foldable menu and tabs inside a header bar')
|
|
|
+ example_link('Todo list', 'shows a simple todo list with checkboxes and text input')
|
|
|
example_link('Trello Cards', 'shows Trello-like cards that can be dragged and dropped into columns')
|
|
|
example_link('Slots', 'shows how to use scoped slots to customize Quasar elements')
|
|
|
example_link('Table and slots', 'shows how to use component slots in a table')
|
|
@@ -277,6 +283,7 @@ async def index_page(client: Client):
|
|
|
example_link('Chat with AI', 'a simple chat app with AI')
|
|
|
example_link('SQLite Database', 'CRUD operations on a SQLite database')
|
|
|
example_link('Pandas DataFrame', 'displays an editable [pandas](https://pandas.pydata.org) DataFrame')
|
|
|
+ example_link('Lightbox', 'A thumbnail gallery where each image can be clicked to enlarge')
|
|
|
|
|
|
with ui.row().classes('bg-primary w-full min-h-screen mt-16'):
|
|
|
link_target('why')
|
|
@@ -317,7 +324,7 @@ async def index_page(client: Client):
|
|
|
|
|
|
|
|
|
@ui.page('/documentation')
|
|
|
-def documentation_page():
|
|
|
+def documentation_page() -> None:
|
|
|
add_head_html()
|
|
|
menu = side_menu()
|
|
|
add_header(menu)
|
|
@@ -332,9 +339,9 @@ def documentation_page():
|
|
|
|
|
|
|
|
|
@ui.page('/documentation/{name}')
|
|
|
-async def documentation_page_more(name: str, client: Client):
|
|
|
- if not hasattr(ui, name):
|
|
|
- name = name.replace('_', '') # NOTE: "AG Grid" leads to anchor name "ag_grid", but class is `ui.aggrid`
|
|
|
+async def documentation_page_more(name: str, client: Client) -> None:
|
|
|
+ if name == 'ag_grid':
|
|
|
+ name = 'aggrid' # NOTE: "AG Grid" leads to anchor name "ag_grid", but class is `ui.aggrid`
|
|
|
module = importlib.import_module(f'website.more_documentation.{name}_documentation')
|
|
|
more = getattr(module, 'more', None)
|
|
|
if hasattr(ui, name):
|
|
@@ -349,7 +356,7 @@ async def documentation_page_more(name: str, client: Client):
|
|
|
with side_menu() as menu:
|
|
|
ui.markdown(f'[← back](/documentation#{create_anchor_name(back_link_target)})').classes('bold-links')
|
|
|
with ui.column().classes('w-full p-8 lg:p-16 max-w-[1250px] mx-auto'):
|
|
|
- section_heading('Documentation', f'ui.*{name}*')
|
|
|
+ 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')
|
|
|
element_demo(api)(getattr(module, 'main_demo'))
|