First set of upgrades for the Panel component

This commit is contained in:
2025-12-20 11:52:44 +01:00
parent 1347f12618
commit 81a80a47b6
6 changed files with 1634 additions and 177 deletions

View File

@@ -5,23 +5,37 @@ from fasthtml.components import Div
from fasthtml.xtend import Script
from myfasthtml.controls.BaseCommands import BaseCommands
from myfasthtml.controls.helpers import mk
from myfasthtml.core.commands import Command
from myfasthtml.core.dbmanager import DbObject
from myfasthtml.core.instances import MultipleInstance
from myfasthtml.icons.fluent_p1 import more_horizontal20_regular
from myfasthtml.icons.fluent_p2 import subtract20_regular
@dataclass
class PanelConf:
left: bool = False
left: bool = True
right: bool = True
class PanelState(DbObject):
def __init__(self, owner, name=None):
super().__init__(owner, name=name)
with self.initializing():
self.left_visible: bool = True
self.right_visible: bool = True
self.left_width: int = 250
self.right_width: int = 250
class Commands(BaseCommands):
def toggle_side(self, side: Literal["left", "right"]):
def toggle_side(self, side: Literal["left", "right"], visible: bool = None):
return Command("TogglePanelSide",
f"Toggle {side} side panel",
self._owner,
self._owner.toggle_side,
args=[side])
args=[side, visible]).htmx(target=f"#{self._id}_panel_{side}")
def update_side_width(self, side: Literal["left", "right"]):
"""
@@ -37,7 +51,7 @@ class Commands(BaseCommands):
f"Update {side} side panel width",
self._owner,
self._owner.update_side_width,
args=[side])
args=[side]).htmx(target=f"#{self._id}_panel_{side}")
class Panel(MultipleInstance):
@@ -54,15 +68,26 @@ class Panel(MultipleInstance):
super().__init__(parent, _id=_id)
self.conf = conf or PanelConf()
self.commands = Commands(self)
self._state = PanelState(self)
self._main = None
self._right = None
self._left = None
def update_side_width(self, side, width):
pass
if side == "left":
self._state.left_width = width
else:
self._state.right_width = width
return self._mk_panel(side)
def toggle_side(self, side):
pass
def toggle_side(self, side, visible):
if side == "left":
self._state.left_visible = visible
else:
self._state.right_visible = visible
return self._mk_panel(side), self._mk_show_icon(side)
def set_main(self, main):
self._main = main
@@ -76,35 +101,82 @@ class Panel(MultipleInstance):
self._left = left
return Div(self._left, id=f"{self._id}_l")
def _mk_right(self):
if not self.conf.right:
def _mk_panel(self, side: Literal["left", "right"]):
enabled = self.conf.left if side == "left" else self.conf.right
if not enabled:
return None
visible = self._state.left_visible if side == "left" else self._state.right_visible
content = self._right if side == "right" else self._left
resizer = Div(
cls="mf-resizer mf-resizer-right",
data_command_id=self.commands.update_side_width("right").id,
data_side="right"
cls=f"mf-resizer mf-resizer-{side}",
data_command_id=self.commands.update_side_width(side).id,
data_side=side
)
return Div(resizer, Div(self._right, id=f"{self._id}_r"), cls="mf-panel-right")
hide_icon = mk.icon(
subtract20_regular,
size=20,
command=self.commands.toggle_side(side, False),
cls="mf-panel-hide-icon"
)
panel_cls = f"mf-panel-{side}"
if not visible:
panel_cls += " mf-hidden"
# Left panel: content then resizer (resizer on the right)
# Right panel: resizer then content (resizer on the left)
if side == "left":
return Div(
Div(hide_icon, content, id=f"{self._id}_content_{side}"),
resizer,
cls=panel_cls,
id=f"{self._id}_panel_{side}"
)
else:
return Div(
resizer,
Div(hide_icon, content, id=f"{self._id}_content_{side}"),
cls=panel_cls,
id=f"{self._id}_panel_{side}"
)
def _mk_left(self):
if not self.conf.left:
def _mk_show_icon(self, side: Literal["left", "right"]):
"""
Create show icon for a panel side if it's hidden.
Args:
side: Which panel side ("left" or "right")
Returns:
Div with icon if panel is hidden, None otherwise
"""
enabled = self.conf.left if side == "left" else self.conf.right
if not enabled:
return None
resizer = Div(
cls="mf-resizer mf-resizer-left",
data_command_id=self.commands.update_side_width("left").id,
data_side="left"
)
is_visible = self._state.left_visible if side == "left" else self._state.right_visible
icon_cls = "hidden" if is_visible else f"mf-panel-show-icon mf-panel-show-icon-{side}"
return Div(Div(self._left, id=f"{self._id}_l"), resizer, cls="mf-panel-left")
return mk.icon(
more_horizontal20_regular,
command=self.commands.toggle_side(side, True),
cls=icon_cls,
id=f"{self._id}_show_{side}"
)
def render(self):
return Div(
self._mk_left(),
Div(self._main, cls="mf-panel-main"),
self._mk_right(),
self._mk_panel("left"),
Div(
self._mk_show_icon("left"),
self._main,
self._mk_show_icon("right"),
cls="mf-panel-main"
),
self._mk_panel("right"),
Script(f"initResizer('{self._id}');"),
cls="mf-panel",
id=self._id,