Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add busy/loading indicators and enable on Template #1493

Merged
merged 16 commits into from
Jul 24, 2020
Merged
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ jobs:
stage: test
env: DESC="dev test_all"
before_install:
- python --version
# install doit/pyctdev and use to install miniconda...
- pip install pyctdev && doit miniconda_install && pip uninstall -y doit pyctdev
- export PATH="$HOME/miniconda/bin:$PATH" && hash -r
Expand Down
103 changes: 103 additions & 0 deletions examples/reference/indicators/BooleanStatus.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import panel as pn\n",
"\n",
"from panel.widgets.indicators import BooleanStatus\n",
"\n",
"pn.extension()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The ``BooleanStatus`` is a boolean indicator providing a visual representation of a boolean status as filled or non-filled circle. If the `value` is set to `True` the indicator will be filled while setting it to `False` will cause it to be non-filled.\n",
"\n",
"#### Parameters:\n",
"\n",
"For layout and styling related parameters see the [customization user guide](../../user_guide/Customization.ipynb).\n",
"\n",
"* **``color``** (str): The color of the bar, one of 'primary', 'secondary', 'success', 'info', 'warn', 'danger', 'light', 'dark'\n",
"* **``value``** (int or None): Whether the status indicator is filled or not.\n",
"\n",
"___"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The `BooleanStatus` widget can be instantiated as either `False` or `True`:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"false_status = BooleanStatus(value=False)\n",
"true_status = BooleanStatus(value=True)\n",
"\n",
"pn.Row(false_status, true_status)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The `BooleanStatus` indicator also supports a range of colors:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"grid = pn.GridBox('', 'False', 'True', ncols=3)\n",
"\n",
"for color in BooleanStatus.param.color.objects:\n",
" false = BooleanStatus(width=50, height=50, value=False, color=color)\n",
" true = BooleanStatus(width=50, height=50, value=True, color=color)\n",
" grid.extend((color, false, true))\n",
"\n",
"grid"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.5"
},
"widgets": {
"application/vnd.jupyter.widget-state+json": {
"state": {},
"version_major": 2,
"version_minor": 0
}
}
},
"nbformat": 4,
"nbformat_minor": 4
}
104 changes: 104 additions & 0 deletions examples/reference/indicators/LoadingSpinner.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import panel as pn\n",
"from panel.widgets.indicators import LoadingSpinner\n",
"\n",
"\n",
"pn.extension()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The ``LoadingSpinner`` is a boolean indicator providing a visual representation of the loading status. If the `value` is set to `True` the spinner will rotate while setting it to `False` will disable the rotating segment.\n",
"\n",
"#### Parameters:\n",
"\n",
"For layout and styling related parameters see the [customization user guide](../../user_guide/Customization.ipynb).\n",
"\n",
"* **``bgcolor``** (str): The color of spinner background segment, either 'light' or 'dark'\n",
"* **``color``** (str): The color of the spinning segment, one of 'primary', 'secondary', 'success', 'info', 'warn', 'danger', 'light', 'dark'\n",
"* **``value``** (boolean): Whether the indicator is spinning or not.\n",
"\n",
"___"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The `LoadingSpinner` can be instantiated in a spinning or idle state:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"idle = LoadingSpinner(value=False, width=100, height=100)\n",
"loading = LoadingSpinner(value=True, width=100, height=100)\n",
"\n",
"pn.Row(idle, loading)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The `LoadingSpinner` indicator also supports a range of spinner colors and backgrounds:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"grid = pn.GridBox('', 'light', 'dark', ncols=3)\n",
"\n",
"for color in LoadingSpinner.param.color.objects:\n",
" dark = LoadingSpinner(width=50, height=50, value=True, color=color, bgcolor='dark')\n",
" light = LoadingSpinner(width=50, height=50, value=True, color=color, bgcolor='light')\n",
" grid.extend((color, light, dark))\n",
"\n",
"grid"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.5"
},
"widgets": {
"application/vnd.jupyter.widget-state+json": {
"state": {},
"version_major": 2,
"version_minor": 0
}
}
},
"nbformat": 4,
"nbformat_minor": 4
}
147 changes: 147 additions & 0 deletions panel/_styles/widgets.css
Original file line number Diff line number Diff line change
Expand Up @@ -139,3 +139,150 @@ progress:not([value])::before {
from {background-position: 0%}
to {background-position: 100%}
}

.bk.loader::after {
content: "";
border-radius: 50%;
-webkit-mask-image: radial-gradient(transparent 50%, rgba(0, 0, 0, 1) 54%);
width: 100%;
height: 100%;
left: 0;
top: 0;
position: absolute;
}

.bk-root .bk.loader.dark::after {
background: #0f0f0f;
}

.bk-root .bk.loader.light::after {
background: #f0f0f0;
}

.bk-root .bk.loader.spin::after {
animation: spin 2s linear infinite;
}

.bk-root div.bk.loader.spin.primary-light::after {
background: linear-gradient(135deg, #f0f0f0 50%, transparent 50%), linear-gradient(45deg, #f0f0f0 50%, #007bff 50%);
}

.bk-root div.bk.loader.spin.secondary-light::after {
background: linear-gradient(135deg, #f0f0f0 50%, transparent 50%), linear-gradient(45deg, #f0f0f0 50%, #6c757d 50%);
}

.bk-root div.bk.loader.spin.success-light::after {
background: linear-gradient(135deg, #f0f0f0 50%, transparent 50%), linear-gradient(45deg, #f0f0f0 50%, #28a745 50%);
}

.bk-root div.bk.loader.spin.danger-light::after {
background: linear-gradient(135deg, #f0f0f0 50%, transparent 50%), linear-gradient(45deg, #f0f0f0 50%, #dc3545 50%);
}

.bk-root div.bk.loader.spin.warning-light::after {
background: linear-gradient(135deg, #f0f0f0 50%, transparent 50%), linear-gradient(45deg, #f0f0f0 50%, #ffc107 50%);
}

.bk-root div.bk.loader.spin.info-light::after {
background: linear-gradient(135deg, #f0f0f0 50%, transparent 50%), linear-gradient(45deg, #f0f0f0 50%, #17a2b8 50%);
}

.bk-root div.bk.loader.spin.light-light::after {
background: linear-gradient(135deg, #f0f0f0 50%, transparent 50%), linear-gradient(45deg, #f0f0f0 50%, #f8f9fa 50%);
}

.bk-root div.bk.loader.dark-light::after {
background: linear-gradient(135deg, #f0f0f0 50%, transparent 50%), linear-gradient(45deg, #f0f0f0 50%, #343a40 50%);
}

.bk-root div.bk.loader.spin.primary-dark::after {
background: linear-gradient(135deg, #0f0f0f 50%, transparent 50%), linear-gradient(45deg, #0f0f0f 50%, #007bff 50%);
}

.bk-root div.bk.loader.spin.secondary-dark::after {
background: linear-gradient(135deg, #0f0f0f 50%, transparent 50%), linear-gradient(45deg, #0f0f0f 50%, #6c757d 50%);
}

.bk-root div.bk.loader.spin.success-dark::after {
background: linear-gradient(135deg, #0f0f0f 50%, transparent 50%), linear-gradient(45deg, #0f0f0f 50%, #28a745 50%);
}

.bk-root div.bk.loader.spin.danger-dark::after {
background: linear-gradient(135deg, #0f0f0f 50%, transparent 50%), linear-gradient(45deg, #0f0f0f 50%, #dc3545 50%)
}

.bk-root div.bk.loader.spin.warning-dark::after {
background: linear-gradient(135deg, #0f0f0f 50%, transparent 50%), linear-gradient(45deg, #0f0f0f 50%, #ffc107 50%);
}

.bk-root div.bk.loader.spin.info-dark::after {
background: linear-gradient(135deg, #0f0f0f 50%, transparent 50%), linear-gradient(45deg, #0f0f0f 50%, #17a2b8 50%);
}

.bk-root div.bk.loader.spin.light-dark::after {
background: linear-gradient(135deg, #0f0f0f 50%, transparent 50%), linear-gradient(45deg, #0f0f0f 50%, #f8f9fa 50%);
}

.bk-root div.bk.loader.spin.dark-dark::after {
background: linear-gradient(135deg, #0f0f0f 50%, transparent 50%), linear-gradient(45deg, #0f0f0f 50%, #343a40 50%);
}

/* Safari */
@-webkit-keyframes spin {
0% { -webkit-transform: rotate(0deg); }
100% { -webkit-transform: rotate(360deg); }
}

@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}

.dot div {
height: 100%;
width: 100%;
border: 1px solid #000 !important;
background-color: #fff;
border-radius: 50%;
display: inline-block;
}

.dot-filled div {
height: 100%;
width: 100%;
border: 1px solid #000 !important;
border-radius: 50%;
display: inline-block;
}

.dot-filled.primary div {
background-color: #007bff;
}

.dot-filled.secondary div {
background-color: #6c757d;
}

.dot-filled.success div {
background-color: #28a745;
}

.dot-filled.danger div {
background-color: #dc3545;
}

.dot-filled.warning div {
background-color: #ffc107;
}

.dot-filled.info div {
background-color: #17a2b8;
}

.dot-filled.dark div {
background-color: #343a40;
}

.dot-filled.light div {
background-color: #f8f9fa;
}
2 changes: 1 addition & 1 deletion panel/io/state.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ def sync_busy(self, indicator):
"""
self._indicators.append(indicator)

@param.depends('busy')
@param.depends('busy', watch=True)
def _update_busy(self):
for indicator in self._indicators:
indicator.value = self.busy
Expand Down
Loading