diff --git a/aiidalab_widgets_base/__init__.py b/aiidalab_widgets_base/__init__.py index 63b2bf7c2..042117337 100644 --- a/aiidalab_widgets_base/__init__.py +++ b/aiidalab_widgets_base/__init__.py @@ -1,7 +1,5 @@ """Reusable widgets for AiiDAlab applications.""" -from aiida.manage import get_profile - _WARNING_TEMPLATE = """

Warning:

@@ -27,22 +25,34 @@ def is_running_in_jupyter(): return False -# load the default profile if no profile is loaded, and raise a deprecation warning -# this is a temporary solution to avoid breaking existing notebooks -# this will be removed in the next major release -if is_running_in_jupyter() and get_profile() is None: - # if no profile is loaded, load the default profile and raise a deprecation warning - from aiida import load_profile +if is_running_in_jupyter(): + from importlib.resources import files + + from aiida.manage import get_profile from IPython.display import HTML, display - load_profile() + from .assets import css + + # load stylesheet + stylesheet = files(css).joinpath("styles.css").read_text() + display(HTML(f"")) + + # load the default profile if no profile is loaded, and raise a deprecation warning + # this is a temporary solution to avoid breaking existing notebooks + # this will be removed in the next major release + if get_profile() is None: + # if no profile is loaded, load the default profile and raise a deprecation warning + from aiida import load_profile + + load_profile() + + profile = get_profile() + assert profile is not None, "Failed to load the default profile" - profile = get_profile() - assert profile is not None, "Failed to load the default profile" + # raise a deprecation warning + warning = HTML(_WARNING_TEMPLATE.format(profile=profile.name, version="v3.0.0")) + display(warning) - # raise a deprecation warning - warning = HTML(_WARNING_TEMPLATE.format(profile=profile.name, version="v3.0.0")) - display(warning) from .computational_resources import ( ComputationalResourcesWidget, diff --git a/aiidalab_widgets_base/assets/__init__.py b/aiidalab_widgets_base/assets/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/aiidalab_widgets_base/assets/css/README.md b/aiidalab_widgets_base/assets/css/README.md new file mode 100644 index 000000000..ebe3e350d --- /dev/null +++ b/aiidalab_widgets_base/assets/css/README.md @@ -0,0 +1,13 @@ +# Stylesheets for AiiDAlab Widgets Base + +This folder contains two files: + +- `styles.scss` - an SCSS-format stylesheet +- `styles.css` - the `scss` stylesheet compiled as `.css` for the browser + +It is recommended to use the SCSS format for styles for its power and flexibility (see https://sass-lang.com/). + +Compiling SCSS into CSS can be done using: + +- The [Live Sass Compiler](https://marketplace.visualstudio.com/items?itemName=glenn2223.live-sass) extension, if using VS Code +- The `sass` [CLI](https://sass-lang.com/install/) diff --git a/aiidalab_widgets_base/assets/css/__init__.py b/aiidalab_widgets_base/assets/css/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/aiidalab_widgets_base/assets/css/styles.css b/aiidalab_widgets_base/assets/css/styles.css new file mode 100644 index 000000000..8818bc6b3 --- /dev/null +++ b/aiidalab_widgets_base/assets/css/styles.css @@ -0,0 +1,18 @@ +.info-box { + display: none; + margin: 2px; + padding: 1em; + border: 3px solid orangered; + background-color: #ffedcc; + border-radius: 1em; + -webkit-border-radius: 1em; + -moz-border-radius: 1em; + -ms-border-radius: 1em; + -o-border-radius: 1em; +} +.info-box p { + line-height: 24px; +} +.info-box.in-app-guide.show { + display: flex !important; +} diff --git a/aiidalab_widgets_base/assets/css/styles.scss b/aiidalab_widgets_base/assets/css/styles.scss new file mode 100644 index 000000000..bcd51cc37 --- /dev/null +++ b/aiidalab_widgets_base/assets/css/styles.scss @@ -0,0 +1,22 @@ +.info-box { + display: none; + margin: 2px; + padding: 1em; + border: 3px solid orangered; + background-color: #ffedcc; + border-radius: 1em; + -webkit-border-radius: 1em; + -moz-border-radius: 1em; + -ms-border-radius: 1em; + -o-border-radius: 1em; + + p { + line-height: 24px; + } + + &.in-app-guide { + &.show { + display: flex !important; + } + } +} diff --git a/aiidalab_widgets_base/infobox.py b/aiidalab_widgets_base/infobox.py new file mode 100644 index 000000000..66797ff6e --- /dev/null +++ b/aiidalab_widgets_base/infobox.py @@ -0,0 +1,31 @@ +from __future__ import annotations + +import ipywidgets as ipw + + +class InfoBox(ipw.VBox): + """The `InfoBox` component is used to provide additional info regarding a widget or an app.""" + + def __init__(self, **kwargs): + """`InfoBox` constructor.""" + super().__init__(**kwargs) + self.add_class("info-box") + if "custom-css" in kwargs: + self.add_class(kwargs.pop("custom-css")) + + +class InAppGuide(InfoBox): + """The `InfoAppGuide` is used to set up in-app guides that may be toggle in unison.""" + + def __init__(self, guide_class="", **kwargs): + """`InAppGuide` constructor. + + parameters + ---------- + `guide_class` : `str` + A CSS class marking the widget as part of a guide collection. + May also be used for custom styling. + """ + super().__init__(**kwargs) + self.add_class("in-app-guide") + self.add_class(guide_class) diff --git a/tests/test_infobox.py b/tests/test_infobox.py new file mode 100644 index 000000000..277479f1c --- /dev/null +++ b/tests/test_infobox.py @@ -0,0 +1,29 @@ +from aiidalab_widgets_base.infobox import InAppGuide, InfoBox + + +def test_infobox_classes(): + """Test `InfoBox` classes.""" + infobox = InfoBox() + assert "info-box" in infobox._dom_classes + infobox = InfoBox(**{"custom-css": "custom-info-box"}) + assert all( + css_class in infobox._dom_classes + for css_class in ( + "info-box", + "custom-info-box", + ) + ) + + +def test_in_app_guide(): + """Test `InAppGuide` class.""" + guide_class = "some_guide" + in_app_guide = InAppGuide(guide_class=guide_class) + assert all( + css_class in in_app_guide._dom_classes + for css_class in ( + "info-box", + "in-app-guide", + guide_class, + ) + )