Browse Source

Merge pull request #676 from abulka/splitter

ui.splitter element
Rodja Trappe 2 năm trước cách đây
mục cha
commit
e5f6777fa4

+ 37 - 0
nicegui/elements/splitter.py

@@ -0,0 +1,37 @@
+from typing import Callable, Optional, Tuple
+
+from .mixins.value_element import ValueElement
+
+
+class Splitter(ValueElement):
+    def __init__(self, *,
+                 horizontal: Optional[bool] = False,
+                 reverse: Optional[bool] = False,
+                 limits: Optional[Tuple[float, float]] = (0, 100),
+                 value: Optional[float] = 50,
+                 on_change: Optional[Callable] = None) -> None:
+        """Splitter
+
+        The `ui.splitter` element divides the screen space into resizable sections, 
+        allowing for flexible and responsive layouts in your applications.
+
+        Based on Quasar's Splitter component:
+        `Splitter <https://quasar.dev/vue-components/splitter>`_
+
+        It provides three customizable slots: ``before``, ``after``, and ``separator``, which can be
+        used to embed other elements within the splitter.
+
+        :param horizontal: Whether to split horizontally instead of vertically
+        :param limits: Two numbers representing the minimum and maximum split size of the two panels
+        :param value: Size of the first panel (or second if using reverse)
+        :param reverse: Whether to apply the model size to the second panel instead of the first
+        :param on_change: callback which is invoked when the user releases the splitter
+        """
+        super().__init__(tag='q-splitter', value=value, on_value_change=on_change, throttle=0.05)
+        self._props['horizontal'] = horizontal
+        self._props['limits'] = limits
+        self._props['reverse'] = reverse
+
+        self.before = self.add_slot('before')
+        self.after = self.add_slot('after')
+        self.separator = self.add_slot('separator')

+ 1 - 0
nicegui/ui.py

@@ -46,6 +46,7 @@ from .elements.select import Select as select
 from .elements.separator import Separator as separator
 from .elements.slider import Slider as slider
 from .elements.spinner import Spinner as spinner
+from .elements.splitter import Splitter as splitter
 from .elements.switch import Switch as switch
 from .elements.table import Table as table
 from .elements.tabs import Tab as tab

+ 18 - 0
tests/test_splitter.py

@@ -0,0 +1,18 @@
+from nicegui import ui
+
+from .screen import Screen
+
+
+def test_splitter(screen: Screen):
+    with ui.splitter() as splitter:
+        with splitter.before:
+            ui.label('Left hand side.')
+        with splitter.after:
+            ui.label('Right hand side.')
+    ui.label().bind_text_from(splitter, 'value')
+
+    screen.open('/')
+    screen.should_contain('Left hand side.')
+    screen.should_contain('Right hand side.')
+    screen.should_contain('50')
+    # TODO: programmatically move splitter

+ 1 - 0
website/documentation.py

@@ -163,6 +163,7 @@ def create_full() -> None:
         ui.button('Clear', on_click=container.clear)
 
     load_demo(ui.expansion)
+    load_demo(ui.splitter)
 
     @text_demo('Tabs', '''
         The elements `ui.tabs`, `ui.tab`, `ui.tab_panels`, and `ui.tab_panel` resemble

+ 42 - 0
website/more_documentation/splitter_documentation.py

@@ -0,0 +1,42 @@
+from nicegui import ui
+
+from ..documentation_tools import text_demo
+
+
+def main_demo() -> None:
+    with ui.splitter() as splitter:
+        with splitter.before:
+            ui.label('This is some content on the left hand side.')
+        with splitter.after:
+            ui.label('This is some content on the right hand side.')\
+                .classes('ml-2')
+
+
+def more() -> None:
+    @text_demo('Advanced usage', '''
+        This demo shows all the slots and parameters including a tooltip, a custom separator, and a callback.
+    ''')
+    def advanced_usage() -> None:
+        with ui.splitter(horizontal=False, reverse=False, value=60,
+                         on_change=lambda e: ui.notify(e.value)) as splitter:
+            ui.tooltip('This is the default slot.').classes('bg-green')
+            with splitter.before:
+                ui.label('This is the left hand side.')
+            with splitter.after:
+                ui.label('This is the right hand side.') \
+                    .classes('ml-2')
+            with splitter.separator:
+                ui.icon('lightbulb').classes('text-green')
+
+        ui.number('Split value', format='%.1f').bind_value(splitter)
+
+    @text_demo('Image fun', '''
+        This demo shows how to use the splitter to display images side by side.
+    ''')
+    def image_fun() -> None:
+        with ui.splitter().classes('w-72 h-48') \
+                .props('before-class=overflow-hidden after-class=overflow-hidden') as splitter:
+            with splitter.before:
+                ui.image('https://cdn.quasar.dev/img/parallax1.jpg').classes('w-72 absolute-top-left')
+            with splitter.after:
+                ui.image('https://cdn.quasar.dev/img/parallax1-bw.jpg').classes('w-72 absolute-top-right')