123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278 |
- from typing import Literal, Optional
- from .context import context
- from .element import Element
- from .elements.mixins.value_element import ValueElement
- from .functions.html import add_body_html
- from .logging import log
- DrawerSides = Literal['left', 'right']
- PageStickyPositions = Literal[
- 'top-right',
- 'top-left',
- 'bottom-right',
- 'bottom-left',
- 'top',
- 'right',
- 'bottom',
- 'left',
- ]
- class Header(ValueElement):
- def __init__(self, *,
- value: bool = True,
- fixed: bool = True,
- bordered: bool = False,
- elevated: bool = False,
- wrap: bool = True,
- add_scroll_padding: bool = True,
- ) -> None:
- """Header
- This element is based on Quasar's `QHeader <https://quasar.dev/layout/header-and-footer#qheader-api>`_ component.
- Note: The header is automatically placed above other layout elements in the DOM to improve accessibility.
- To change the order, use the `move` method.
- :param value: whether the header is already opened (default: `True`)
- :param fixed: whether the header should be fixed to the top of the page (default: `True`)
- :param bordered: whether the header should have a border (default: `False`)
- :param elevated: whether the header should have a shadow (default: `False`)
- :param wrap: whether the header should wrap its content (default: `True`)
- :param add_scroll_padding: whether to automatically prevent link targets from being hidden behind the header (default: `True`)
- """
- _check_current_slot(self)
- with context.client.layout:
- super().__init__(tag='q-header', value=value, on_value_change=None)
- self._classes.append('nicegui-header')
- self._props['bordered'] = bordered
- self._props['elevated'] = elevated
- if wrap:
- self._classes.append('wrap')
- code = list(self.client.layout._props['view'])
- code[1] = 'H' if fixed else 'h'
- self.client.layout._props['view'] = ''.join(code)
- self.move(target_index=0)
- if add_scroll_padding:
- add_body_html(f'''
- <script>
- window.onload = () => {{
- const header = getElement({self.id}).$el;
- new ResizeObserver(() => {{
- document.documentElement.style.scrollPaddingTop = `${{header.offsetHeight}}px`;
- }}).observe(header);
- }};
- </script>
- ''')
- def toggle(self):
- """Toggle the header"""
- self.value = not self.value
- def show(self):
- """Show the header"""
- self.value = True
- def hide(self):
- """Hide the header"""
- self.value = False
- class Drawer(Element):
- def __init__(self,
- side: DrawerSides, *,
- value: Optional[bool] = None,
- fixed: bool = True,
- bordered: bool = False,
- elevated: bool = False,
- top_corner: bool = False,
- bottom_corner: bool = False) -> None:
- """Drawer
- This element is based on Quasar's `QDrawer <https://quasar.dev/layout/drawer>`_ component.
- Note: Depending on the side, the drawer is automatically placed above or below the main page container in the DOM to improve accessibility.
- To change the order, use the `move` method.
- :param side: side of the page where the drawer should be placed (`left` or `right`)
- :param value: whether the drawer is already opened (default: `None`, i.e. if layout width is above threshold)
- :param fixed: whether the drawer is fixed or scrolls with the content (default: `True`)
- :param bordered: whether the drawer should have a border (default: `False`)
- :param elevated: whether the drawer should have a shadow (default: `False`)
- :param top_corner: whether the drawer expands into the top corner (default: `False`)
- :param bottom_corner: whether the drawer expands into the bottom corner (default: `False`)
- """
- _check_current_slot(self)
- with context.client.layout:
- super().__init__('q-drawer')
- if value is None:
- self._props['show-if-above'] = True
- else:
- self._props['model-value'] = value
- self._props['side'] = side
- self._props['bordered'] = bordered
- self._props['elevated'] = elevated
- self._classes.append('nicegui-drawer')
- code = list(self.client.layout._props['view'])
- code[0 if side == 'left' else 2] = side[0].lower() if top_corner else 'h'
- code[4 if side == 'left' else 6] = side[0].upper() if fixed else side[0].lower()
- code[8 if side == 'left' else 10] = side[0].lower() if bottom_corner else 'f'
- self.client.layout._props['view'] = ''.join(code)
- page_container_index = self.client.layout.default_slot.children.index(self.client.page_container)
- self.move(target_index=page_container_index if side == 'left' else page_container_index + 1)
- def toggle(self) -> None:
- """Toggle the drawer"""
- self.run_method('toggle')
- def show(self) -> None:
- """Show the drawer"""
- self.run_method('show')
- def hide(self) -> None:
- """Hide the drawer"""
- self.run_method('hide')
- class LeftDrawer(Drawer):
- def __init__(self, *,
- value: Optional[bool] = None,
- fixed: bool = True,
- bordered: bool = False,
- elevated: bool = False,
- top_corner: bool = False,
- bottom_corner: bool = False) -> None:
- """Left drawer
- This element is based on Quasar's `QDrawer <https://quasar.dev/layout/drawer>`_ component.
- Note: The left drawer is automatically placed above the main page container in the DOM to improve accessibility.
- To change the order, use the `move` method.
- :param value: whether the drawer is already opened (default: `None`, i.e. if layout width is above threshold)
- :param fixed: whether the drawer is fixed or scrolls with the content (default: `True`)
- :param bordered: whether the drawer should have a border (default: `False`)
- :param elevated: whether the drawer should have a shadow (default: `False`)
- :param top_corner: whether the drawer expands into the top corner (default: `False`)
- :param bottom_corner: whether the drawer expands into the bottom corner (default: `False`)
- """
- super().__init__('left',
- value=value,
- fixed=fixed,
- bordered=bordered,
- elevated=elevated,
- top_corner=top_corner,
- bottom_corner=bottom_corner)
- class RightDrawer(Drawer):
- def __init__(self, *,
- value: Optional[bool] = None,
- fixed: bool = True,
- bordered: bool = False,
- elevated: bool = False,
- top_corner: bool = False,
- bottom_corner: bool = False) -> None:
- """Right drawer
- This element is based on Quasar's `QDrawer <https://quasar.dev/layout/drawer>`_ component.
- Note: The right drawer is automatically placed below the main page container in the DOM to improve accessibility.
- To change the order, use the `move` method.
- :param value: whether the drawer is already opened (default: `None`, i.e. if layout width is above threshold)
- :param fixed: whether the drawer is fixed or scrolls with the content (default: `True`)
- :param bordered: whether the drawer should have a border (default: `False`)
- :param elevated: whether the drawer should have a shadow (default: `False`)
- :param top_corner: whether the drawer expands into the top corner (default: `False`)
- :param bottom_corner: whether the drawer expands into the bottom corner (default: `False`)
- """
- super().__init__('right',
- value=value,
- fixed=fixed,
- bordered=bordered,
- elevated=elevated,
- top_corner=top_corner,
- bottom_corner=bottom_corner)
- class Footer(ValueElement):
- def __init__(self, *,
- value: bool = True,
- fixed: bool = True,
- bordered: bool = False,
- elevated: bool = False,
- wrap: bool = True,
- ) -> None:
- """Footer
- This element is based on Quasar's `QFooter <https://quasar.dev/layout/header-and-footer#qfooter-api>`_ component.
- Note: The footer is automatically placed below other layout elements in the DOM to improve accessibility.
- To change the order, use the `move` method.
- :param value: whether the footer is already opened (default: `True`)
- :param fixed: whether the footer is fixed or scrolls with the content (default: `True`)
- :param bordered: whether the footer should have a border (default: `False`)
- :param elevated: whether the footer should have a shadow (default: `False`)
- :param wrap: whether the footer should wrap its content (default: `True`)
- """
- _check_current_slot(self)
- with context.client.layout:
- super().__init__(tag='q-footer', value=value, on_value_change=None)
- self.classes('nicegui-footer')
- self._props['bordered'] = bordered
- self._props['elevated'] = elevated
- if wrap:
- self._classes.append('wrap')
- code = list(self.client.layout._props['view'])
- code[9] = 'F' if fixed else 'f'
- self.client.layout._props['view'] = ''.join(code)
- self.move(target_index=-1)
- def toggle(self) -> None:
- """Toggle the footer"""
- self.value = not self.value
- def show(self) -> None:
- """Show the footer"""
- self.value = True
- def hide(self) -> None:
- """Hide the footer"""
- self.value = False
- class PageSticky(Element):
- def __init__(self, position: PageStickyPositions = 'bottom-right', x_offset: float = 0, y_offset: float = 0) -> None:
- """Page sticky
- A sticky element that is always visible at the bottom of the page.
- :param position: position of the sticky element (default: `'bottom-right'`)
- :param x_offset: horizontal offset of the sticky element (default: `0`)
- :param y_offset: vertical offset of the sticky element (default: `0`)
- """
- super().__init__('q-page-sticky')
- self._props['position'] = position
- self._props['offset'] = [x_offset, y_offset]
- def _check_current_slot(element: Element) -> None:
- parent = context.slot.parent
- if parent != parent.client.content:
- log.warning(f'Found top level layout element "{element.__class__.__name__}" inside element "{parent.__class__.__name__}". '
- 'Top level layout elements should not be nested but must be direct children of the page content. '
- 'This will be raising an exception in NiceGUI 1.5') # DEPRECATED
|