mirror of
https://github.com/natankeddem/bale.git
synced 2026-04-23 06:50:41 +00:00
265 lines
7.6 KiB
Python
265 lines
7.6 KiB
Python
from typing import Any, Callable, Dict, List, Literal, Optional, Union
|
|
from nicegui import ui, app, Tailwind
|
|
from nicegui.elements.spinner import SpinnerTypes
|
|
from nicegui.tailwind_types.height import Height
|
|
from nicegui.tailwind_types.width import Width
|
|
from nicegui.elements.mixins.validation_element import ValidationElement
|
|
from nicegui.events import GenericEventArguments, handle_event
|
|
from snapper.interfaces import cli
|
|
import logging
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
orange = "#f59e0b"
|
|
dark = "#171717"
|
|
ui.card.default_style("max-width: none")
|
|
ui.card.default_props("flat bordered")
|
|
ui.input.default_props("outlined dense hide-bottom-space")
|
|
ui.button.default_props("outline dense")
|
|
ui.select.default_props("outlined dense dense-options")
|
|
ui.checkbox.default_props("dense")
|
|
|
|
|
|
class ErrorAggregator:
|
|
def __init__(self, *elements: ValidationElement) -> None:
|
|
self.elements: list[ValidationElement] = list(elements)
|
|
self.enable: bool = True
|
|
|
|
def clear(self):
|
|
self.elements.clear()
|
|
|
|
def append(self, element: ValidationElement):
|
|
self.elements.append(element)
|
|
|
|
def remove(self, element: ValidationElement):
|
|
self.elements.remove(element)
|
|
|
|
@property
|
|
def no_errors(self) -> bool:
|
|
validators = all(validation(element.value) for element in self.elements for validation in element.validation.values())
|
|
return self.enable and validators
|
|
|
|
|
|
class WColumn(ui.column):
|
|
def __init__(self) -> None:
|
|
super().__init__()
|
|
self.tailwind.width("full").align_items("center")
|
|
|
|
|
|
class DBody(ui.column):
|
|
def __init__(self, height: Height = "[480px]", width: Width = "[240px]") -> None:
|
|
super().__init__()
|
|
self.tailwind.align_items("center").justify_content("between")
|
|
self.tailwind.height(height).width(width)
|
|
|
|
|
|
class WRow(ui.row):
|
|
def __init__(self) -> None:
|
|
super().__init__()
|
|
self.tailwind.width("full").align_items("center").justify_content("center")
|
|
|
|
|
|
class Card(ui.card):
|
|
def __init__(self) -> None:
|
|
super().__init__()
|
|
self.tailwind.border_color(f"[{orange}]")
|
|
|
|
|
|
class DInput(ui.input):
|
|
def __init__(
|
|
self,
|
|
label: str | None = None,
|
|
*,
|
|
placeholder: str | None = None,
|
|
value: str = " ",
|
|
password: bool = False,
|
|
password_toggle_button: bool = False,
|
|
on_change: Callable[..., Any] | None = None,
|
|
autocomplete: List[str] | None = None,
|
|
validation: Callable[..., Any] = bool,
|
|
) -> None:
|
|
super().__init__(
|
|
label,
|
|
placeholder=placeholder,
|
|
value=value,
|
|
password=password,
|
|
password_toggle_button=password_toggle_button,
|
|
on_change=on_change,
|
|
autocomplete=autocomplete,
|
|
validation={"": validation},
|
|
)
|
|
self.tailwind.width("full")
|
|
if value == " ":
|
|
self.value = ""
|
|
|
|
|
|
class FInput(ui.input):
|
|
def __init__(
|
|
self,
|
|
label: str | None = None,
|
|
*,
|
|
placeholder: str | None = None,
|
|
value: str = " ",
|
|
password: bool = False,
|
|
password_toggle_button: bool = False,
|
|
on_change: Callable[..., Any] | None = None,
|
|
autocomplete: List[str] | None = None,
|
|
validation: Callable[..., Any] = bool,
|
|
read_only: bool = False,
|
|
) -> None:
|
|
super().__init__(
|
|
label,
|
|
placeholder=placeholder,
|
|
value=value,
|
|
password=password,
|
|
password_toggle_button=password_toggle_button,
|
|
on_change=on_change,
|
|
autocomplete=autocomplete,
|
|
validation={} if read_only else {"": validation},
|
|
)
|
|
self.tailwind.width("64")
|
|
if value == " ":
|
|
self.value = ""
|
|
if read_only:
|
|
self.props("readonly")
|
|
|
|
|
|
class DSelect(ui.select):
|
|
def __init__(
|
|
self,
|
|
options: List | Dict,
|
|
*,
|
|
label: str | None = None,
|
|
value: Any = None,
|
|
on_change: Callable[..., Any] | None = None,
|
|
with_input: bool = False,
|
|
multiple: bool = False,
|
|
clearable: bool = False,
|
|
) -> None:
|
|
super().__init__(
|
|
options, label=label, value=value, on_change=on_change, with_input=with_input, multiple=multiple, clearable=clearable
|
|
)
|
|
self.tailwind.width("full").max_height("[40px]")
|
|
|
|
|
|
class FSelect(ui.select):
|
|
def __init__(
|
|
self,
|
|
options: List | Dict,
|
|
*,
|
|
label: str | None = None,
|
|
value: Any = None,
|
|
on_change: Callable[..., Any] | None = None,
|
|
with_input: bool = False,
|
|
multiple: bool = False,
|
|
clearable: bool = False,
|
|
) -> None:
|
|
super().__init__(
|
|
options, label=label, value=value, on_change=on_change, with_input=with_input, multiple=multiple, clearable=clearable
|
|
)
|
|
self.tailwind.width("64")
|
|
|
|
|
|
class DButton(ui.button):
|
|
def __init__(
|
|
self,
|
|
text: str = "",
|
|
*,
|
|
on_click: Callable[..., Any] | None = None,
|
|
color: Optional[str] = "primary",
|
|
icon: str | None = None,
|
|
) -> None:
|
|
super().__init__(text, on_click=on_click, color=color, icon=icon)
|
|
self.props("size=md")
|
|
self.tailwind.padding("px-2.5").padding("py-1")
|
|
|
|
|
|
class DCheckbox(ui.checkbox):
|
|
def __init__(self, text: str = "", *, value: bool = False, on_change: Callable[..., Any] | None = None) -> None:
|
|
super().__init__(text, value=value, on_change=on_change)
|
|
self.tailwind.width("full").text_color("secondary")
|
|
|
|
|
|
class IButton(ui.button):
|
|
def __init__(
|
|
self,
|
|
text: str = "",
|
|
*,
|
|
on_click: Callable[..., Any] | None = None,
|
|
color: Optional[str] = "primary",
|
|
icon: str | None = None,
|
|
) -> None:
|
|
super().__init__(text, on_click=on_click, color=color, icon=icon)
|
|
self.props("size=sm")
|
|
|
|
|
|
class SmButton(ui.button):
|
|
def __init__(
|
|
self,
|
|
text: str = "",
|
|
*,
|
|
on_click: Callable[..., Any] | None = None,
|
|
color: Optional[str] = "primary",
|
|
icon: str | None = None,
|
|
) -> None:
|
|
super().__init__(text, on_click=on_click, color=color, icon=icon)
|
|
self.props("size=sm")
|
|
self.tailwind.width("16")
|
|
|
|
|
|
class LgButton(ui.button):
|
|
def __init__(
|
|
self,
|
|
text: str = "",
|
|
*,
|
|
on_click: Callable[..., Any] | None = None,
|
|
color: Optional[str] = "primary",
|
|
icon: str | None = None,
|
|
) -> None:
|
|
super().__init__(text, on_click=on_click, color=color, icon=icon)
|
|
self.props("size=md")
|
|
|
|
|
|
class Spinner(ui.spinner):
|
|
def __init__(
|
|
self,
|
|
type: SpinnerTypes | None = "bars",
|
|
*,
|
|
size: str = "lg",
|
|
color: str | None = "primary",
|
|
thickness: float = 5,
|
|
master: ui.spinner | None = None,
|
|
) -> None:
|
|
super().__init__(type, size=size, color=color, thickness=thickness)
|
|
self.visible = False
|
|
if master is not None:
|
|
self.bind_visibility_from(master, "visible")
|
|
|
|
|
|
def notify(
|
|
message: Any,
|
|
*,
|
|
type: Optional[
|
|
Literal[ # pylint: disable=redefined-builtin
|
|
"positive",
|
|
"negative",
|
|
"warning",
|
|
"info",
|
|
"ongoing",
|
|
]
|
|
] = None,
|
|
multi_line: bool = False,
|
|
) -> None:
|
|
if multi_line:
|
|
ui.notify(
|
|
message=message,
|
|
position="bottom-left",
|
|
multi_line=True,
|
|
close_button=True,
|
|
classes="multi-line-notification",
|
|
type=type,
|
|
timeout=20000,
|
|
)
|
|
else:
|
|
ui.notify(message=message, position="bottom-left", type=type)
|