diff --git a/docs/content/docs/themes.md b/docs/content/docs/themes.md index f53fc0f56..2c806eed3 100644 --- a/docs/content/docs/themes.md +++ b/docs/content/docs/themes.md @@ -115,7 +115,9 @@ The easiest way to link a local stylesheet is to place it in a folder named `ass There are numerous free to use Bootstrap stylesheets available on the web. The `dash_bootstrap_components.themes` module contains CDN links for Bootstrap and all of the [Bootswatch themes][bootswatch-themes]. Bootstrap also maintains its own [themes website][bootstrap-themes] which lists a number of free and premium themes that you could incorporate into your apps. -To start with, we recommend experimenting with some of the Bootswatch themes available in the `dash_bootstrap_components.themes` module. The full list of available themes is [`CERULEAN`](https://bootswatch.com/cerulean/), [`COSMO`](https://bootswatch.com/cosmo/), [`CYBORG`](https://bootswatch.com/cyborg/), [`DARKLY`](https://bootswatch.com/darkly/), [`FLATLY`](https://bootswatch.com/flatly/), [`JOURNAL`](https://bootswatch.com/journal/), [`LITERA`](https://bootswatch.com/litera/), [`LUMEN`](https://bootswatch.com/lumen/), [`LUX`](https://bootswatch.com/lux/), [`MATERIA`](https://bootswatch.com/materia/), [`MINTY`](https://bootswatch.com/minty/), [`PULSE`](https://bootswatch.com/pulse/), [`SANDSTONE`](https://bootswatch.com/sandstone/), [`SIMPLEX`](https://bootswatch.com/simplex/), [`SKETCHY`](https://bootswatch.com/sketchy/), [`SLATE`](https://bootswatch.com/slate/), [`SOLAR`](https://bootswatch.com/solar/), [`SPACELAB`](https://bootswatch.com/spacelab/), [`SUPERHERO`](https://bootswatch.com/superhero/), [`UNITED`](https://bootswatch.com/united/), [`YETI`](https://bootswatch.com/yeti/) +To start with, we recommend experimenting with some of the Bootswatch themes available in the `dash_bootstrap_components.themes` module. The full list of available themes is [`CERULEAN`](https://bootswatch.com/cerulean/), [`COSMO`](https://bootswatch.com/cosmo/), [`CYBORG`](https://bootswatch.com/cyborg/), [`DARKLY`](https://bootswatch.com/darkly/), [`FLATLY`](https://bootswatch.com/flatly/), [`JOURNAL`](https://bootswatch.com/journal/), [`LITERA`](https://bootswatch.com/litera/), [`LUMEN`](https://bootswatch.com/lumen/), [`LUX`](https://bootswatch.com/lux/), [`MATERIA`](https://bootswatch.com/materia/), [`MINTY`](https://bootswatch.com/minty/), [`PULSE`](https://bootswatch.com/pulse/), [`SANDSTONE`](https://bootswatch.com/sandstone/), [`SIMPLEX`](https://bootswatch.com/simplex/), [`SKETCHY`](https://bootswatch.com/sketchy/), [`SLATE`](https://bootswatch.com/slate/), [`SOLAR`](https://bootswatch.com/solar/), [`SPACELAB`](https://bootswatch.com/spacelab/), [`SUPERHERO`](https://bootswatch.com/superhero/), [`UNITED`](https://bootswatch.com/united/), [`YETI`](https://bootswatch.com/yeti/). + +Check out the [theme explorer](/docs/themes/explorer/) for a live demo of dash-bootstrap-components using all of the different available themes. [dash-docs-external]: https://dash.plotly.com/external-resources/ [bootstrapcdn]: https://www.bootstrapcdn.com/ diff --git a/docs/demos/__init__.py b/docs/demos/__init__.py index e69de29bb..73f7533c9 100644 --- a/docs/demos/__init__.py +++ b/docs/demos/__init__.py @@ -0,0 +1,55 @@ +import os + +import dash +import dash_bootstrap_components as dbc + +from .theme_explorer import app as theme_explorer + +SERVE_LOCALLY = os.getenv("DBC_DOCS_MODE", "production") == "dev" +FA = "https://use.fontawesome.com/releases/v5.15.3/css/all.css" + +SHEETS = [ + ("bootstrap", dbc.themes.BOOTSTRAP), + ("cerulean", dbc.themes.CERULEAN), + ("cosmo", dbc.themes.COSMO), + ("cyborg", dbc.themes.CYBORG), + ("darkly", dbc.themes.DARKLY), + ("flatly", dbc.themes.FLATLY), + ("journal", dbc.themes.JOURNAL), + ("litera", dbc.themes.LITERA), + ("lumen", dbc.themes.LUMEN), + ("lux", dbc.themes.LUX), + ("materia", dbc.themes.MATERIA), + ("minty", dbc.themes.MINTY), + ("pulse", dbc.themes.PULSE), + ("sandstone", dbc.themes.SANDSTONE), + ("simplex", dbc.themes.SIMPLEX), + ("sketchy", dbc.themes.SKETCHY), + ("slate", dbc.themes.SLATE), + ("solar", dbc.themes.SOLAR), + ("spacelab", dbc.themes.SPACELAB), + ("superhero", dbc.themes.SUPERHERO), + ("united", dbc.themes.UNITED), + ("yeti", dbc.themes.YETI), +] + + +def register_apps(): + apps = {} + + for name, sheet in SHEETS: + new_theme_explorer = dash.Dash( + external_stylesheets=[FA, sheet, "/static/loading.css"], + requests_pathname_prefix=f"/docs/themes/explorer/{name}/", + suppress_callback_exceptions=True, + serve_locally=SERVE_LOCALLY, + update_title=None, + ) + + new_theme_explorer.title = f"Theme explorer - {name} - dbc docs" + new_theme_explorer.layout = theme_explorer.layout + new_theme_explorer.callback_map = theme_explorer.callback_map + new_theme_explorer._callback_list = theme_explorer._callback_list + apps[f"/docs/themes/explorer/{name}"] = new_theme_explorer + + return apps diff --git a/docs/demos/theme_explorer/__init__.py b/docs/demos/theme_explorer/__init__.py new file mode 100644 index 000000000..69926559a --- /dev/null +++ b/docs/demos/theme_explorer/__init__.py @@ -0,0 +1,117 @@ +import dash +import dash_bootstrap_components as dbc +from dash.dependencies import Input, Output, State + +from .alert import alerts +from .badge import badges +from .button import buttons +from .card import cards +from .collapse import collapse +from .fade import fade +from .form import form +from .input import checklist_items, input_, input_group, radio_items +from .jumbotron import jumbotron +from .list_group import list_group +from .modal import modal +from .navbar import navbar +from .popover import popover +from .progress import progress +from .spinner import spinner +from .table import table +from .tabs import tabs +from .toast import toast +from .tooltip import tooltip + +FONT_AWESOME = "https://use.fontawesome.com/releases/v5.10.2/css/all.css" +app = dash.Dash(external_stylesheets=[dbc.themes.BOOTSTRAP, FONT_AWESOME]) + +app.layout = dbc.Container( + [ + alerts, + badges, + buttons, + cards, + collapse, + fade, + dbc.Row( + [ + dbc.Col([form, input_group], xs=12, md=6), + dbc.Col([input_], xs=12, md=6), + ] + ), + dbc.Row( + [ + dbc.Col([checklist_items], xs=12, md=6), + dbc.Col([radio_items], xs=12, md=6), + ] + ), + jumbotron, + list_group, + modal, + navbar, + popover, + progress, + spinner, + table, + tabs, + toast, + tooltip, + ], + fluid=True, + className="px-4", +) + + +@app.callback( + Output("collapse", "is_open"), + [Input("collapse-button", "n_clicks")], + [State("collapse", "is_open")], +) +def toggle_collapse(n, is_open): + if n: + return not is_open + return is_open + + +@app.callback( + Output("fade", "is_in"), + [Input("fade-button", "n_clicks")], + [State("fade", "is_in")], +) +def toggle_fade(n, is_in): + if n: + return not is_in + return is_in + + +@app.callback( + Output("popover", "is_open"), + [Input("popover-target", "n_clicks")], + [State("popover", "is_open")], +) +def toggle_popover(n, is_open): + if n: + return not is_open + return is_open + + +@app.callback( + Output("modal", "is_open"), + [Input("button", "n_clicks")], + [State("modal", "is_open")], +) +def toggle_modal(n, is_open): + if n: + return not is_open + return is_open + + +@app.callback( + Output("auto-toast", "is_open"), [Input("auto-toast-toggle", "n_clicks")] +) +def open_toast(_): + return True + + +if __name__ == "__main__": + app.run_server(debug=True) diff --git a/docs/demos/theme_explorer/alert.py b/docs/demos/theme_explorer/alert.py new file mode 100644 index 000000000..69bd1e33c --- /dev/null +++ b/docs/demos/theme_explorer/alert.py @@ -0,0 +1,31 @@ +import dash_bootstrap_components as dbc +import dash_html_components as html + +from .util import make_subheading + +alerts1 = dbc.Col( + [ + dbc.Alert("This is a primary alert", color="primary"), + dbc.Alert("This is a secondary alert", color="secondary"), + dbc.Alert("This is a success alert! Well done!", color="success"), + dbc.Alert("This is a warning alert... be careful...", color="warning"), + ], + md=6, + xs=12, +) + +alerts2 = dbc.Col( + [ + dbc.Alert("This is a danger alert. Scary!", color="danger"), + dbc.Alert("This is an info alert. Good to know!", color="info"), + dbc.Alert("This is a light alert", color="light"), + dbc.Alert("This is a dark alert", color="dark"), + ], + md=6, + xs=12, +) + +alerts = html.Div( + [make_subheading("Alert", "alert"), dbc.Row([alerts1, alerts2])], + className="mb-4", +) diff --git a/docs/demos/theme_explorer/badge.py b/docs/demos/theme_explorer/badge.py new file mode 100644 index 000000000..f14df9b6b --- /dev/null +++ b/docs/demos/theme_explorer/badge.py @@ -0,0 +1,36 @@ +import dash_bootstrap_components as dbc +import dash_html_components as html + +from .util import make_subheading + +badge = html.Div( + [ + dbc.Badge("Primary", color="primary", className="mr-1"), + dbc.Badge("Secondary", color="secondary", className="mr-1"), + dbc.Badge("Success", color="success", className="mr-1"), + dbc.Badge("Warning", color="warning", className="mr-1"), + dbc.Badge("Danger", color="danger", className="mr-1"), + dbc.Badge("Info", color="info", className="mr-1"), + dbc.Badge("Light", color="light", className="mr-1"), + dbc.Badge("Dark", color="dark"), + ], + className="mb-2", +) + +badge_pills = html.Div( + [ + dbc.Badge("Primary", color="primary", className="mr-1", pill=True), + dbc.Badge("Secondary", color="secondary", className="mr-1", pill=True), + dbc.Badge("Success", color="success", className="mr-1", pill=True), + dbc.Badge("Warning", color="warning", className="mr-1", pill=True), + dbc.Badge("Danger", color="danger", className="mr-1", pill=True), + dbc.Badge("Info", color="info", className="mr-1", pill=True), + dbc.Badge("Light", color="light", className="mr-1", pill=True), + dbc.Badge("Dark", color="dark", pill=True), + ], +) + +badges = html.Div( + [make_subheading("Badge", "badge"), badge, badge_pills], + className="mb-4", +) diff --git a/docs/demos/theme_explorer/button.py b/docs/demos/theme_explorer/button.py new file mode 100644 index 000000000..9c56a7000 --- /dev/null +++ b/docs/demos/theme_explorer/button.py @@ -0,0 +1,127 @@ +import dash_bootstrap_components as dbc +import dash_html_components as html + +from .util import make_subheading + +buttons1 = dbc.Col( + [ + make_subheading("Button", "button"), + html.Div( + [ + dbc.Button("Primary", color="primary", className="mr-1 mt-1"), + dbc.Button( + "Secondary", color="secondary", className="mr-1 mt-1" + ), + dbc.Button("Success", color="success", className="mr-1 mt-1"), + dbc.Button("Warning", color="warning", className="mr-1 mt-1"), + dbc.Button("Danger", color="danger", className="mr-1 mt-1"), + dbc.Button("Info", color="info", className="mr-1 mt-1"), + ], + className="mb-2", + ), + html.Div( + [ + dbc.Button( + "Primary", + outline=True, + color="primary", + className="mr-1 mt-1", + ), + dbc.Button( + "Secondary", + outline=True, + color="secondary", + className="mr-1 mt-1", + ), + dbc.Button( + "Success", + outline=True, + color="success", + className="mr-1 mt-1", + ), + dbc.Button( + "Warning", + outline=True, + color="warning", + className="mr-1 mt-1", + ), + dbc.Button( + "Danger", + outline=True, + color="danger", + className="mr-1 mt-1", + ), + dbc.Button( + "Info", outline=True, color="info", className="mr-1 mt-1" + ), + ], + className="mb-2", + ), + html.Div( + [ + dbc.Button("Regular", color="primary", className="mr-1 mt-1"), + dbc.Button( + "Active", + color="primary", + active=True, + className="mr-1 mt-1", + ), + dbc.Button( + "Disabled", + color="primary", + disabled=True, + className="mr-1 mt-1", + ), + ], + className="mb-2", + ), + html.Div( + [ + dbc.Button("Large button", size="lg", className="mr-1 mt-1"), + dbc.Button("Regular button", className="mr-1 mt-1"), + dbc.Button("Small button", size="sm", className="mr-1 mt-1"), + ], + className="mb-2", + ), + ], + lg=6, + xs=12, +) + +buttons2 = dbc.Col( + [ + make_subheading("ButtonGroup", "buttongroups"), + html.Div( + dbc.ButtonGroup( + [ + dbc.Button("Success", color="success"), + dbc.Button("Warning", color="warning"), + dbc.Button("Danger", color="danger"), + ] + ), + className="mb-2", + ), + html.Div( + dbc.ButtonGroup( + [ + dbc.Button("First"), + dbc.Button("Second"), + dbc.DropdownMenu( + [ + dbc.DropdownMenuItem("Item 1"), + dbc.DropdownMenuItem("Item 2"), + ], + label="Dropdown", + group=True, + ), + ], + vertical=True, + ), + className="mb-2", + ), + ], + lg=6, + xs=12, +) + +buttons = dbc.Row([buttons1, buttons2], className="mb-4") diff --git a/docs/demos/theme_explorer/card.py b/docs/demos/theme_explorer/card.py new file mode 100644 index 000000000..ca0a6b1a8 --- /dev/null +++ b/docs/demos/theme_explorer/card.py @@ -0,0 +1,66 @@ +import dash_bootstrap_components as dbc +import dash_html_components as html + +from .util import make_subheading + +cards = html.Div( + [ + make_subheading("Card", "card"), + dbc.CardDeck( + [ + dbc.Card( + [ + dbc.CardHeader("Header"), + dbc.CardBody( + [ + html.H5( + "This card has a title", + className="card-title", + ), + html.P("And some text", className="card-text"), + ] + ), + ] + ), + dbc.Card( + [ + dbc.CardBody( + [ + html.H5( + "This card has a title", + className="card-title", + ), + html.P( + "and some text, but no header", + className="card-text", + ), + ] + ) + ], + outline=True, + color="primary", + ), + dbc.Card( + [ + dbc.CardBody( + [ + html.H5( + "This card has a title", + className="card-title", + ), + html.P( + "and some text, and a footer!", + className="card-text", + ), + ] + ), + dbc.CardFooter("Footer"), + ], + outline=True, + color="dark", + ), + ] + ), + ], + className="mb-4", +) diff --git a/docs/demos/theme_explorer/collapse.py b/docs/demos/theme_explorer/collapse.py new file mode 100644 index 000000000..c2d5ae0e3 --- /dev/null +++ b/docs/demos/theme_explorer/collapse.py @@ -0,0 +1,24 @@ +import dash_bootstrap_components as dbc +import dash_html_components as html + +from .util import make_subheading + +collapse = html.Div( + [ + make_subheading("Collapse", "collapse"), + html.Div( + [ + dbc.Button( + "Open collapse", id="collapse-button", className="mb-2" + ), + dbc.Collapse( + dbc.Card( + dbc.CardBody("This content is hidden in the collapse") + ), + id="collapse", + ), + ] + ), + ], + className="mb-4", +) diff --git a/docs/demos/theme_explorer/fade.py b/docs/demos/theme_explorer/fade.py new file mode 100644 index 000000000..698c8343e --- /dev/null +++ b/docs/demos/theme_explorer/fade.py @@ -0,0 +1,31 @@ +import dash_bootstrap_components as dbc +import dash_html_components as html + +from .util import make_subheading + +fade = html.Div( + [ + make_subheading("Fade", "fade"), + html.Div( + [ + dbc.Button( + "Toggle fade", + id="fade-button", + style={"marginBottom": "1rem"}, + ), + dbc.Fade( + dbc.Card( + dbc.CardBody( + html.P( + "This content fades in and out", + className="card-text", + ) + ) + ), + id="fade", + is_in=True, + ), + ] + ), + ], +) diff --git a/docs/demos/theme_explorer/form.py b/docs/demos/theme_explorer/form.py new file mode 100644 index 000000000..c2b2c7ec4 --- /dev/null +++ b/docs/demos/theme_explorer/form.py @@ -0,0 +1,55 @@ +import dash_bootstrap_components as dbc +import dash_html_components as html + +from .util import make_subheading + +form = html.Div( + [ + make_subheading("Form", "form"), + dbc.Form( + [ + dbc.FormGroup( + [ + dbc.Label("Username"), + dbc.Input( + placeholder="Enter your username", + type="text", + ), + dbc.FormText( + [ + "Can't remember your username? ", + html.A( + "Click here.", + href="#", + className="text-muted", + style={"textDecoration": "underline"}, + ), + ] + ), + ] + ), + dbc.FormGroup( + [ + dbc.Label("Username"), + dbc.Input( + placeholder="Enter your password", + type="password", + ), + dbc.FormText( + [ + "Can't remember your password? ", + html.A( + "Click here.", + href="#", + className="text-muted", + style={"textDecoration": "underline"}, + ), + ] + ), + ] + ), + ] + ), + ], + className="mb-4", +) diff --git a/docs/demos/theme_explorer/input.py b/docs/demos/theme_explorer/input.py new file mode 100644 index 000000000..58b284a3d --- /dev/null +++ b/docs/demos/theme_explorer/input.py @@ -0,0 +1,127 @@ +import dash_bootstrap_components as dbc +import dash_html_components as html + +from .util import make_subheading + +input_ = html.Div( + [ + make_subheading("Input", "input"), + dbc.FormGroup( + [ + dbc.Label("Valid text input"), + dbc.Input(type="text", valid=True), + dbc.FormFeedback("That's a valid input!", valid=True), + ] + ), + dbc.FormGroup( + [ + dbc.Label("Invalid text input"), + dbc.Input(type="text", invalid=True), + dbc.FormFeedback("That's an invalid input..."), + ] + ), + ] +) + +checklist_items = html.Div( + [ + make_subheading("Checklist", "input"), + dbc.Row( + [ + dbc.Col( + dbc.Checklist( + id="gallery_checklist1", + options=[ + { + "label": "Option {}".format(i), + "value": i, + } + for i in range(3) + ], + value=[1, 2], + ) + ), + dbc.Col( + dbc.Checklist( + id="gallery_checklist2", + options=[ + { + "label": "Option {}".format(i), + "value": i, + } + for i in range(3) + ], + value=[1, 2], + switch=True, + ) + ), + ] + ), + html.H5("Inline checklist", className="mt-3"), + dbc.Checklist( + id="gallery_checklist3", + options=[ + {"label": f"Option {i + 1}", "value": i} for i in range(5) + ], + value=[0, 4], + inline=True, + ), + ], + className="mb-4", +) + +radio_items = html.Div( + [ + make_subheading("RadioItems", "input"), + dbc.RadioItems( + id="gallery_radio1", + options=[ + {"label": f"Option {i + 1}", "value": i} for i in range(3) + ], + value=0, + ), + html.H5("Inline radioitems", className="mt-3"), + dbc.RadioItems( + id="gallery_radio2", + options=[ + {"label": f"Option {i + 1}", "value": i} for i in range(5) + ], + value=0, + inline=True, + ), + ] +) + +input_group = html.Div( + [ + make_subheading("InputGroup and addons", "input_group"), + dbc.InputGroup( + [ + dbc.InputGroupAddon( + dbc.Button("To the left!", color="danger"), + addon_type="prepend", + ), + dbc.Input(type="text"), + ], + className="my-3", + ), + dbc.InputGroup( + [ + dbc.Input(type="text"), + dbc.InputGroupAddon( + dbc.Button("To the right!", color="success"), + addon_type="append", + ), + ], + className="mb-3", + ), + dbc.InputGroup( + [ + dbc.InputGroupAddon("@", addon_type="prepend"), + dbc.Input(type="text", placeholder="Enter username"), + ], + className="mb-3", + ), + ], + className="mb-4", +) diff --git a/docs/demos/theme_explorer/jumbotron.py b/docs/demos/theme_explorer/jumbotron.py new file mode 100644 index 000000000..8869c92a7 --- /dev/null +++ b/docs/demos/theme_explorer/jumbotron.py @@ -0,0 +1,18 @@ +import dash_bootstrap_components as dbc +import dash_html_components as html + +from .util import make_subheading + +jumbotron = html.Div( + [ + make_subheading("Jumbotron", "jumbotron"), + dbc.Jumbotron( + [ + html.H2("This is a jumbotron"), + html.P("It makes things big..."), + dbc.Button("Click here", color="danger"), + ] + ), + ], + className="mb-4", +) diff --git a/docs/demos/theme_explorer/list_group.py b/docs/demos/theme_explorer/list_group.py new file mode 100644 index 000000000..8c05d7dad --- /dev/null +++ b/docs/demos/theme_explorer/list_group.py @@ -0,0 +1,24 @@ +import dash_bootstrap_components as dbc +import dash_html_components as html + +from .util import make_subheading + +list_group = html.Div( + [ + make_subheading("ListGroup", "list_group"), + dbc.ListGroup( + [ + dbc.ListGroupItem("Item 1", color="primary", action=True), + dbc.ListGroupItem("Item 2"), + dbc.ListGroupItem("Item 3"), + dbc.ListGroupItem( + [ + dbc.ListGroupItemHeading("Item 4 heading"), + dbc.ListGroupItemText("Item 4 text"), + ] + ), + ] + ), + ], + className="mb-4", +) diff --git a/docs/demos/theme_explorer/modal.py b/docs/demos/theme_explorer/modal.py new file mode 100644 index 000000000..bdf316483 --- /dev/null +++ b/docs/demos/theme_explorer/modal.py @@ -0,0 +1,27 @@ +import dash_bootstrap_components as dbc +import dash_html_components as html + +from .util import make_subheading + +COOKIE = "https://todaysmama.com/.image/t_share/MTU5OTEwMzkyMDIyMTE1NzAz/cookie-monster.png" # noqa +modal = html.Div( + [ + make_subheading("Modal", "modal"), + html.P( + [ + dbc.Button("Show the cookie monster", id="button"), + dbc.Modal( + [ + dbc.ModalHeader("Cookies!"), + dbc.ModalBody( + html.Img(src=COOKIE, style={"width": "100%"}) + ), + ], + id="modal", + is_open=False, + ), + ] + ), + ], + className="mb-4", +) diff --git a/docs/demos/theme_explorer/navbar.py b/docs/demos/theme_explorer/navbar.py new file mode 100644 index 000000000..46584346f --- /dev/null +++ b/docs/demos/theme_explorer/navbar.py @@ -0,0 +1,57 @@ +import dash_bootstrap_components as dbc +import dash_html_components as html + +from .util import make_subheading + +DBC_HOME = "https://dash-bootstrap-components.opensource.faculty.ai/" +DBC_GITHUB = "https://github.com/facultyai/dash-bootstrap-components" + +navbar_children = [ + dbc.NavItem(dbc.NavLink("GitHub", href=DBC_GITHUB, target="_blank")), + dbc.DropdownMenu( + nav=True, + in_navbar=True, + label="Menu", + children=[ + dbc.DropdownMenuItem("Entry 1", href="https://google.com"), + dbc.DropdownMenuItem("Entry 2", href="/test"), + dbc.DropdownMenuItem(divider=True), + dbc.DropdownMenuItem("A heading", header=True), + dbc.DropdownMenuItem( + "Entry 3", + href="/external-relative", + external_link=True, + ), + dbc.DropdownMenuItem("Entry 4 - does nothing"), + ], + ), +] + +navbar = html.Div( + [ + make_subheading("Navbar", "navbar"), + dbc.NavbarSimple( + children=navbar_children, + brand="Navbar", + brand_href=DBC_HOME, + color="primary", + dark=True, + className="mb-3", + ), + dbc.NavbarSimple( + children=navbar_children, + brand="Navbar", + brand_href=DBC_HOME, + color="light", + className="mb-3", + ), + dbc.NavbarSimple( + children=navbar_children, + brand="Navbar", + brand_href=DBC_HOME, + color="dark", + dark=True, + ), + ], + className="mb-4", +) diff --git a/docs/demos/theme_explorer/popover.py b/docs/demos/theme_explorer/popover.py new file mode 100644 index 000000000..42ff09878 --- /dev/null +++ b/docs/demos/theme_explorer/popover.py @@ -0,0 +1,23 @@ +import dash_bootstrap_components as dbc +import dash_html_components as html + +from .util import make_subheading + +popover = html.Div( + [ + make_subheading("Popover", "popover"), + dbc.Button( + "Click to toggle popover", id="popover-target", color="danger" + ), + dbc.Popover( + [ + dbc.PopoverHeader("Popover header"), + dbc.PopoverBody("Popover body"), + ], + id="popover", + is_open=False, + target="popover-target", + ), + ], + className="mb-4", +) diff --git a/docs/demos/theme_explorer/progress.py b/docs/demos/theme_explorer/progress.py new file mode 100644 index 000000000..47ed316fc --- /dev/null +++ b/docs/demos/theme_explorer/progress.py @@ -0,0 +1,14 @@ +import dash_bootstrap_components as dbc +import dash_html_components as html + +from .util import make_subheading + +progress = html.Div( + [ + make_subheading("Progress", "progress"), + dbc.Progress("25%", value=25), + dbc.Progress(value=50, striped=True, className="my-2"), + dbc.Progress(value=75, color="success"), + ], + className="mb-4", +) diff --git a/docs/demos/theme_explorer/spinner.py b/docs/demos/theme_explorer/spinner.py new file mode 100644 index 000000000..917d3a316 --- /dev/null +++ b/docs/demos/theme_explorer/spinner.py @@ -0,0 +1,37 @@ +import dash_bootstrap_components as dbc +import dash_html_components as html + +from .util import make_subheading + +spinner = html.Div( + [ + make_subheading("Spinner", "spinner"), + html.Div( + [ + dbc.Spinner(color=col) + for col in [ + "primary", + "secondary", + "success", + "warning", + "danger", + ] + ], + className="mb-2", + ), + html.Div( + [ + dbc.Spinner(color=col, type="grow") + for col in [ + "primary", + "secondary", + "success", + "warning", + "danger", + ] + ], + className="mb-2", + ), + ], + className="mb-4", +) diff --git a/docs/demos/theme_explorer/table.py b/docs/demos/theme_explorer/table.py new file mode 100644 index 000000000..fba4171e8 --- /dev/null +++ b/docs/demos/theme_explorer/table.py @@ -0,0 +1,52 @@ +import dash_bootstrap_components as dbc +import dash_html_components as html + +from .util import make_subheading + +table = html.Div( + [ + make_subheading("Table", "table"), + dbc.Table( + [ + html.Thead( + html.Tr( + [ + html.Th("#"), + html.Th("First name"), + html.Th("Last name"), + ] + ) + ), + html.Tbody( + [ + html.Tr( + [ + html.Th("1", scope="row"), + html.Td("Tom"), + html.Td("Cruise"), + ] + ), + html.Tr( + [ + html.Th("2", scope="row"), + html.Td("Jodie"), + html.Td("Foster"), + ] + ), + html.Tr( + [ + html.Th("3", scope="row"), + html.Td("Chadwick"), + html.Td("Boseman"), + ] + ), + ] + ), + ], + responsive=True, + striped=True, + hover=True, + ), + ], + className="mb-4", +) diff --git a/docs/demos/theme_explorer/tabs.py b/docs/demos/theme_explorer/tabs.py new file mode 100644 index 000000000..c2d577e30 --- /dev/null +++ b/docs/demos/theme_explorer/tabs.py @@ -0,0 +1,32 @@ +import dash_bootstrap_components as dbc +import dash_html_components as html + +from .util import make_subheading + +tabs = html.Div( + [ + make_subheading("Tabs", "tabs"), + dbc.Tabs( + [ + dbc.Tab( + html.P("This is tab 1", className="py-3"), label="Tab 1" + ), + dbc.Tab( + dbc.Card( + [ + html.P( + "This tab has a card!", + className="card-text", + ), + dbc.Button("Click here", color="success"), + ], + body=True, + ), + label="Tab 2", + style={"padding": "10px"}, + ), + ] + ), + ], + className="mb-4", +) diff --git a/docs/demos/theme_explorer/toast.py b/docs/demos/theme_explorer/toast.py new file mode 100644 index 000000000..0113db16b --- /dev/null +++ b/docs/demos/theme_explorer/toast.py @@ -0,0 +1,24 @@ +import dash_bootstrap_components as dbc +import dash_html_components as html + +from .util import make_subheading + +toast = html.Div( + [ + make_subheading("Toast", "toast"), + dbc.Button( + "Open toast", + id="auto-toast-toggle", + color="primary", + className="mb-3", + ), + dbc.Toast( + html.P("This is the content of the toast", className="mb-0"), + id="auto-toast", + header="This is the header", + icon="primary", + duration=4000, + ), + ], + className="mb-2", +) diff --git a/docs/demos/theme_explorer/tooltip.py b/docs/demos/theme_explorer/tooltip.py new file mode 100644 index 000000000..f5099f9d0 --- /dev/null +++ b/docs/demos/theme_explorer/tooltip.py @@ -0,0 +1,25 @@ +import dash_bootstrap_components as dbc +import dash_html_components as html + +from .util import make_subheading + +tooltip = html.Div( + [ + make_subheading("Tooltip", "tooltip"), + html.P( + [ + "I wonder what ", + html.Span( + "floccinaucinihilipilification", id="tooltip-target" + ), + " means?", + ] + ), + dbc.Tooltip( + "Noun: rare, " + "the action or habit of estimating something as worthless.", + target="tooltip-target", + ), + ], + className="mb-4", +) diff --git a/docs/demos/theme_explorer/util.py b/docs/demos/theme_explorer/util.py new file mode 100644 index 000000000..e693c2c06 --- /dev/null +++ b/docs/demos/theme_explorer/util.py @@ -0,0 +1,34 @@ +import dash_bootstrap_components as dbc +import dash_html_components as html + +DBC_DOCS = ( + "https://dash-bootstrap-components.opensource.faculty.ai/docs/components/" +) + + +def make_subheading(label, link): + slug = label.replace(" ", "") + + heading = html.H2( + html.Span( + [ + label, + html.A( + html.I(className="fas fa-book fa-xs ml-2"), + href=f"{DBC_DOCS}{link}", + target="_blank", + id=f"tooltip_target_{slug}", + ), + ], + ), + ) + + return html.Div( + [ + heading, + dbc.Tooltip( + f"See {label} documentation", target=f"tooltip_target_{slug}" + ), + ], + className="mt-3", + ) diff --git a/docs/requirements.txt b/docs/requirements.txt index 7a99dbab2..748a622c1 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,4 +1,4 @@ -dash==1.14.0 +dash==1.20.0 dash_bootstrap_components==0.12.0 gunicorn markdown diff --git a/docs/run.py b/docs/run.py index 1b437fea1..74b23c9d8 100644 --- a/docs/run.py +++ b/docs/run.py @@ -1,6 +1,7 @@ from werkzeug.middleware.dispatcher import DispatcherMiddleware from components_page import register_apps as register_component_apps +from demos import register_apps as register_demo_apps from examples import register_apps as register_example_apps from markdown_to_html import convert_all_markdown_files from server import create_server @@ -10,7 +11,8 @@ server = create_server() component_routes = register_component_apps() example_routes = register_example_apps() -routes = {**component_routes, **example_routes} +demo_routes = register_demo_apps() +routes = {**component_routes, **example_routes, **demo_routes} application = DispatcherMiddleware( server, {slug: app.server for slug, app in routes.items()} ) diff --git a/docs/runtime.txt b/docs/runtime.txt index 34b35b713..87665291b 100644 --- a/docs/runtime.txt +++ b/docs/runtime.txt @@ -1 +1 @@ -python-3.6.7 +python-3.9.4 diff --git a/docs/server.py b/docs/server.py index 52dec5100..82ccf51c5 100644 --- a/docs/server.py +++ b/docs/server.py @@ -8,6 +8,25 @@ {"name": "components", "href": "/docs/components", "label": "Components"}, ] +THEMES_SIDENAV_ITEMS = DOCS_SIDENAV_ITEMS[:] +THEMES_SIDENAV_ITEMS[1] = { + "name": "themes", + "href": "/docs/themes", + "label": "Themes", + "children": [ + { + "name": "overview", + "href": "/docs/themes/", + "label": "Overview", + }, + { + "name": "explorer", + "href": "/docs/themes/explorer", + "label": "Theme explorer", + }, + ], +} + def create_server(): server = Flask(__name__) @@ -36,12 +55,20 @@ def themes(): try: return render_template( "generated/docs/themes.html", - sidenav_items=DOCS_SIDENAV_ITEMS, + sidenav_items=THEMES_SIDENAV_ITEMS, sidenav_active="themes", + active_child="overview", ) except TemplateNotFound: abort(404) + @server.route("/docs/themes/explorer/") + def theme_explorer(): + try: + return render_template("theme-explorer.html") + except TemplateNotFound: + abort(404) + @server.route("/docs/faq/") def faq(): try: diff --git a/docs/static/js/theme-switcher.js b/docs/static/js/theme-switcher.js new file mode 100644 index 000000000..38d52af78 --- /dev/null +++ b/docs/static/js/theme-switcher.js @@ -0,0 +1,9 @@ +function handleChange(e) { + if (e.target.value) { + document + .getElementById('explorer-iframe') + .setAttribute('src', '/docs/themes/explorer/' + e.target.value); + } +} + +document.getElementById('theme-switcher').onchange = handleChange; diff --git a/docs/static/loading.css b/docs/static/loading.css index 973a8903b..900d7d1c3 100644 --- a/docs/static/loading.css +++ b/docs/static/loading.css @@ -1,8 +1,8 @@ ._dash-loading { margin: auto; color: transparent; - width: 0; - height: 0; + width: 2rem; + height: 2rem; text-align: center; } @@ -11,7 +11,7 @@ display: inline-block; width: 2rem; height: 2rem; - color: black; + color: var(--secondary); vertical-align: text-bottom; border: 0.25em solid currentColor; border-right-color: transparent; diff --git a/docs/templates/macros/theme-explorer-navbar.html b/docs/templates/macros/theme-explorer-navbar.html new file mode 100644 index 000000000..5600adac9 --- /dev/null +++ b/docs/templates/macros/theme-explorer-navbar.html @@ -0,0 +1,20 @@ +{% macro theme_explorer_navbar() -%} + +{%- endmacro %} diff --git a/docs/templates/partials/head.html b/docs/templates/partials/head.html index 11af807b1..d18a5d5c9 100644 --- a/docs/templates/partials/head.html +++ b/docs/templates/partials/head.html @@ -1,6 +1,7 @@ diff --git a/docs/templates/theme-explorer.html b/docs/templates/theme-explorer.html new file mode 100644 index 000000000..df8fc975b --- /dev/null +++ b/docs/templates/theme-explorer.html @@ -0,0 +1,67 @@ +{% from "macros/theme-explorer-navbar.html" import theme_explorer_navbar %} +{% extends "base.html" %} +{% block header %} +{{ theme_explorer_navbar() }} +{% endblock %} +{% block body %} +
+ Choose a theme below to see the different options for styling your app. + Click the book icon next to any of the headings to be taken to the relevant + documentation for that component. +
++ This app only shows Bootstrap components. Check out the original + + Plotly Dash theme explorer app + + made by + @AnnMarieW + for a much more comprehensive demo of different styling options. +
+ + +