194 lines
6.6 KiB
Python
194 lines
6.6 KiB
Python
"""
|
|
This app creates a collapsible, responsive sidebar layout with
|
|
dash-bootstrap-components and some custom css with media queries.
|
|
|
|
When the screen is small, the sidebar moved to the top of the page, and the
|
|
links get hidden in a collapse element. We use a callback to toggle the
|
|
collapse when on a small screen, and the custom CSS to hide the toggle, and
|
|
force the collapse to stay open when the screen is large.
|
|
|
|
dcc.Location is used to track the current location, a callback uses the current
|
|
location to render the appropriate page content. The active prop of each
|
|
NavLink is set automatically according to the current pathname. To use this
|
|
feature you must install dash-bootstrap-components >= 0.11.0.
|
|
|
|
For more details on building multi-page Dash applications, check out the Dash
|
|
documentation: https://dash.plotly.com/urls
|
|
"""
|
|
import sys
|
|
sys.path.append('/workspace')
|
|
import dash
|
|
import dash_bootstrap_components as dbc
|
|
from dash import Input, Output, State, dcc, html, page_container
|
|
from dash_iconify import DashIconify
|
|
# import callbacks.ui_callbacks
|
|
import dashboard.callbacks.appointments_callbacks
|
|
import dashboard.callbacks.appointment_modal_callbacks
|
|
import dash_mantine_components as dmc
|
|
|
|
app = dash.Dash(
|
|
external_stylesheets=[dbc.themes.BOOTSTRAP],
|
|
# these meta_tags ensure content is scaled correctly on different devices
|
|
# see: https://www.w3schools.com/css/css_rwd_viewport.asp for more
|
|
meta_tags=[{"name": "viewport", "content": "width=device-width, initial-scale=1"}],
|
|
use_pages=True,
|
|
suppress_callback_exceptions=True,
|
|
)
|
|
|
|
nav_items = [
|
|
{"label": "Übersicht", "href": "/overview", "icon": "mdi:view-dashboard"},
|
|
{"label": "Termine", "href": "/appointments","icon": "mdi:calendar"},
|
|
{"label": "Bildschirme", "href": "/clients", "icon": "mdi:monitor"},
|
|
{"label": "Einstellungen","href": "/settings", "icon": "mdi:cog"},
|
|
{"label": "Benutzer", "href": "/users", "icon": "mdi:account"},
|
|
]
|
|
|
|
nav_links = []
|
|
|
|
for item in nav_items:
|
|
# Create a NavLink for each item
|
|
link_id = {"type": "nav-item", "index": item["label"]}
|
|
nav_link = dbc.NavLink(
|
|
[
|
|
DashIconify(icon=item["icon"], width=24),
|
|
html.Span(item["label"], className="ms-2 sidebar-label"),
|
|
],
|
|
href=item["href"],
|
|
active="exact",
|
|
className="sidebar-item",
|
|
id=link_id,
|
|
)
|
|
nav_links.append(
|
|
html.Div(
|
|
children=nav_link,
|
|
className="nav-item-container"
|
|
)
|
|
)
|
|
# we use the Row and Col components to construct the sidebar header
|
|
# it consists of a title, and a toggle, the latter is hidden on large screens
|
|
sidebar_header = dbc.Row(
|
|
[
|
|
dbc.Col(html.H2("Sidebar", className="display-4")),
|
|
dbc.Col(
|
|
[
|
|
html.Button(
|
|
# use the Bootstrap navbar-toggler classes to style
|
|
html.Span(className="navbar-toggler-icon"),
|
|
className="navbar-toggler",
|
|
# the navbar-toggler classes don't set color
|
|
style={
|
|
"color": "rgba(0,0,0,.5)",
|
|
"border-color": "rgba(0,0,0,.1)",
|
|
},
|
|
id="navbar-toggle",
|
|
),
|
|
html.Button(
|
|
# use the Bootstrap navbar-toggler classes to style
|
|
html.Span(className="navbar-toggler-icon"),
|
|
className="navbar-toggler",
|
|
# the navbar-toggler classes don't set color
|
|
style={
|
|
"color": "rgba(0,0,0,.5)",
|
|
"border-color": "rgba(0,0,0,.1)",
|
|
},
|
|
id="sidebar-toggle",
|
|
),
|
|
],
|
|
# the column containing the toggle will be only as wide as the
|
|
# toggle, resulting in the toggle being right aligned
|
|
width="auto",
|
|
# vertically align the toggle in the center
|
|
align="center",
|
|
),
|
|
]
|
|
)
|
|
|
|
sidebar = html.Div(
|
|
[
|
|
sidebar_header,
|
|
# we wrap the horizontal rule and short blurb in a div that can be
|
|
# hidden on a small screen
|
|
html.Div(
|
|
[
|
|
html.Hr(),
|
|
html.P(
|
|
"A responsive sidebar layout with collapsible navigation " "links.",
|
|
className="lead",
|
|
),
|
|
],
|
|
id="blurb",
|
|
),
|
|
# use the Collapse component to animate hiding / revealing links
|
|
dbc.Collapse(
|
|
dbc.Nav(
|
|
nav_links, # <-- Korrigiert: keine zusätzliche Liste
|
|
vertical=True,
|
|
pills=True,
|
|
),
|
|
id="collapse",
|
|
),
|
|
],
|
|
id="sidebar",
|
|
)
|
|
|
|
content = dmc.MantineProvider([
|
|
html.Div(
|
|
html.Div(page_container, className="page-content"),style={"flex": "1", "padding": "20px"}
|
|
)
|
|
])
|
|
|
|
|
|
app.layout = html.Div([dcc.Location(id="url"), sidebar, content])
|
|
|
|
|
|
# @app.callback(Output("page-content", "children"), [Input("url", "pathname")])
|
|
# def render_page_content(pathname):
|
|
# if pathname == "/":
|
|
# return html.P("This is the content of the home page!")
|
|
# elif pathname == "/page-1":
|
|
# return html.P("This is the content of page 1. Yay!")
|
|
# elif pathname == "/page-2":
|
|
# return html.P("Oh cool, this is page 2!")
|
|
# # If the user tries to reach a different page, return a 404 message
|
|
# return html.Div(
|
|
# [
|
|
# html.H1("404: Not found", className="text-danger"),
|
|
# html.Hr(),
|
|
# html.P(f"The pathname {pathname} was not recognised..."),
|
|
# ],
|
|
# className="p-3 bg-light rounded-3",
|
|
# )
|
|
|
|
|
|
@app.callback(
|
|
[Output("sidebar", "className"), Output("collapse", "is_open")],
|
|
[
|
|
Input("sidebar-toggle", "n_clicks"),
|
|
Input("navbar-toggle", "n_clicks"),
|
|
],
|
|
[
|
|
State("sidebar", "className"),
|
|
State("collapse", "is_open"),
|
|
],
|
|
)
|
|
def toggle_sidebar_and_collapse(sidebar_n, navbar_n, classname, is_open):
|
|
ctx = dash.callback_context
|
|
if not ctx.triggered:
|
|
return classname, is_open
|
|
trigger_id = ctx.triggered[0]["prop_id"].split(".")[0]
|
|
if trigger_id == "sidebar-toggle":
|
|
# Toggle sidebar collapse
|
|
if sidebar_n and classname == "":
|
|
return "collapsed", is_open
|
|
return "", is_open
|
|
elif trigger_id == "navbar-toggle":
|
|
# Toggle collapse
|
|
if navbar_n:
|
|
return classname, not is_open
|
|
return classname, is_open
|
|
return classname, is_open
|
|
|
|
|
|
if __name__ == "__main__":
|
|
app.run(port=8888, debug=True)
|