Browse Source

Add skeleton element (#3202)

* feat: Add skeleton element to UI module

The skeleton element is added to the UI module to provide a loading placeholder for content.

* code review

---------

Co-authored-by: Falko Schindler <falko@zauberzeug.com>
frankvp 11 months ago
parent
commit
c35a612ba9

+ 77 - 0
nicegui/elements/skeleton.py

@@ -0,0 +1,77 @@
+from typing import Literal, Optional
+
+from ..element import Element
+
+
+class Skeleton(Element):
+
+    def __init__(self,
+                 type: Literal[  # pylint: disable=redefined-builtin
+                     'text',
+                     'rect',
+                     'circle',
+                     'QBtn',
+                     'QBadge',
+                     'QChip',
+                     'QToolbar',
+                     'QCheckbox',
+                     'QRadio',
+                     'QToggle',
+                     'QSlider',
+                     'QRange',
+                     'QInput',
+                     'QAvatar',
+                 ] = 'rect',
+                 *,
+                 tag: str = 'div',
+                 animation: Literal[
+                     'wave',
+                     'pulse',
+                     'pulse-x',
+                     'pulse-y',
+                     'fade',
+                     'blink',
+                     'none',
+                 ] = 'wave',
+                 animation_speed: float = 1.5,
+                 square: bool = False,
+                 bordered: bool = False,
+                 size: Optional[str] = None,
+                 width: Optional[str] = None,
+                 height: Optional[str] = None,
+                 ) -> None:
+        """Skeleton
+
+        This element is based on Quasar's `QSkeleton <https://quasar.dev/vue-components/skeleton>`_ component.
+        It serves as a placeholder for loading content in cards, menus and other component containers.
+        See the `Quasar documentation <https://quasar.dev/vue-components/skeleton/#predefined-types>`_ for a list of available types.
+
+        :param type: type of skeleton to display (default: "rect")
+        :param tag: HTML tag to use for this element (default: "div")
+        :param animation: animation effect of the skeleton placeholder (default: "wave")
+        :param animation_speed: animation speed in seconds (default: 1.5)
+        :param square: whether to remover border-radius so borders are squared (default: ``False``)
+        :param bordered: whether to apply a default border to the component (default: ``False``)
+        :param size: size in CSS units (overrides ``width`` and ``height``)
+        :param width: width in CSS units (overridden by ``size`` if set)
+        :param height: height in CSS units (overridden by ``size`` if set)
+        """
+        super().__init__('q-skeleton')
+        if type != 'rect':
+            self._props['type'] = type
+        if tag != 'div':
+            self._props['tag'] = tag
+        if animation != 'wave':
+            self._props['animation'] = animation
+        if animation_speed != 1.5:
+            self._props['animation-speed'] = animation_speed
+        if square:
+            self._props['square'] = True
+        if bordered:
+            self._props['bordered'] = True
+        if size:
+            self._props['size'] = size
+        if width:
+            self._props['width'] = width
+        if height:
+            self._props['height'] = height

+ 2 - 0
nicegui/ui.py

@@ -75,6 +75,7 @@ __all__ = [
     'scroll_area',
     'select',
     'separator',
+    'skeleton',
     'slider',
     'space',
     'spinner',
@@ -200,6 +201,7 @@ from .elements.scene_view import SceneView as scene_view
 from .elements.scroll_area import ScrollArea as scroll_area
 from .elements.select import Select as select
 from .elements.separator import Separator as separator
+from .elements.skeleton import Skeleton as skeleton
 from .elements.slider import Slider as slider
 from .elements.space import Space as space
 from .elements.spinner import Spinner as spinner

+ 2 - 0
website/documentation/content/section_page_layout.py

@@ -17,6 +17,7 @@ from . import (
     row_documentation,
     scroll_area_documentation,
     separator_documentation,
+    skeleton_documentation,
     space_documentation,
     splitter_documentation,
     stepper_documentation,
@@ -86,6 +87,7 @@ doc.intro(expansion_documentation)
 doc.intro(scroll_area_documentation)
 doc.intro(separator_documentation)
 doc.intro(space_documentation)
+doc.intro(skeleton_documentation)
 doc.intro(splitter_documentation)
 doc.intro(tabs_documentation)
 doc.intro(stepper_documentation)

+ 32 - 0
website/documentation/content/skeleton_documentation.py

@@ -0,0 +1,32 @@
+from nicegui import ui
+
+from . import doc
+
+
+@doc.demo(ui.skeleton)
+def skeleton():
+    ui.skeleton().classes('w-full')
+
+
+@doc.demo('Styling and animation', '''
+    The `square` and `bordered` parameters can be set to `True` to remove the border-radius and add a border to the skeleton.
+
+    The `animation` parameter can be set to "pulse", "wave", "pulse-x", "pulse-y", "fade", "blink", or "none"
+    to change the animation effect.
+    The default value is "wave".
+''')
+def custom_animations():
+    ui.skeleton('QToolbar', square=True, bordered=True, animation='pulse-y') \
+        .classes('w-full')
+
+
+@doc.demo('YouTube Skeleton', '''
+    Here is an example skeleton for a YouTube video.
+''')
+def youtube_skeleton():
+    with ui.card().tight().classes('w-full'):
+        ui.skeleton(square=True, animation='fade', height='150px', width='100%')
+        with ui.card_section().classes('w-full'):
+            ui.skeleton('text').classes('text-subtitle1')
+            ui.skeleton('text').classes('text-subtitle1 w-1/2')
+            ui.skeleton('text').classes('text-caption')