I can show and hide the columns comanger

This commit is contained in:
2026-01-25 11:29:18 +01:00
parent 7f3e6270a2
commit 3abfab8e97
8 changed files with 656 additions and 228 deletions

View File

@@ -9,6 +9,7 @@ panels.
**Key features:**
- Three customizable zones (left panel, main content, right panel)
- Configurable panel titles with sticky headers
- Toggle visibility with hide/show icons
- Resizable panels with drag handles
- Smooth CSS animations for show/hide transitions
@@ -108,10 +109,37 @@ The Panel component consists of three zones with optional side panels:
| Left panel | Optional collapsible panel (default: visible) |
| Main content | Always-visible central content area |
| Right panel | Optional collapsible panel (default: visible) |
| Hide icon () | Inside each panel, top right corner |
| Hide icon () | Inside each panel header, right side |
| Show icon (⋯) | In main area when panel is hidden |
| Resizer (║) | Drag handle to resize panels manually |
**Panel with title (default):**
When `show_left_title` or `show_right_title` is `True` (default), panels display a sticky header with title and hide icon:
```
┌─────────────────────────────┐
│ Title [] │ ← Header (sticky, always visible)
├─────────────────────────────┤
│ │
│ Scrollable Content │ ← Content area (scrolls independently)
│ │
└─────────────────────────────┘
```
**Panel without title:**
When `show_left_title` or `show_right_title` is `False`, panels use the legacy layout:
```
┌─────────────────────────────┐
│ [] │ ← Hide icon at top-right (absolute)
│ │
│ Content │
│ │
└─────────────────────────────┘
```
### Creating a Panel
The Panel is a `MultipleInstance`, meaning you can create multiple independent panels in your application. Create it by
@@ -196,7 +224,7 @@ panel = Panel(parent=root_instance)
### Panel Configuration
By default, both left and right panels are enabled. You can customize this with `PanelConf`:
By default, both left and right panels are enabled with titles. You can customize this with `PanelConf`:
```python
from myfasthtml.controls.Panel import PanelConf
@@ -218,6 +246,49 @@ conf = PanelConf(left=False, right=False)
panel = Panel(parent=root_instance, conf=conf)
```
**Customizing panel titles:**
```python
# Custom titles for panels
conf = PanelConf(
left=True,
right=True,
left_title="Explorer", # Custom title for left panel
right_title="Properties" # Custom title for right panel
)
panel = Panel(parent=root_instance, conf=conf)
```
**Disabling panel titles:**
When titles are disabled, panels use the legacy layout without a sticky header:
```python
# Disable titles (legacy layout)
conf = PanelConf(
left=True,
right=True,
show_left_title=False,
show_right_title=False
)
panel = Panel(parent=root_instance, conf=conf)
```
**Disabling show icons:**
You can hide the show icons (⋯) that appear when panels are hidden. This means users can only show panels programmatically:
```python
# Disable show icons (programmatic control only)
conf = PanelConf(
left=True,
right=True,
show_display_left=False, # No show icon for left panel
show_display_right=False # No show icon for right panel
)
panel = Panel(parent=root_instance, conf=conf)
```
**Note:** When a panel is disabled in configuration, it won't render at all. When a panel is hidden (via toggle), it
renders but with zero width and overflow hidden.
@@ -321,8 +392,8 @@ You can control panels programmatically using commands:
```python
# Toggle panel visibility
toggle_left = panel.commands.toggle_side("left", visible=False) # Hide left
toggle_right = panel.commands.toggle_side("right", visible=True) # Show right
toggle_left = panel.commands.set_side_visible("left", visible=False) # Hide left
toggle_right = panel.commands.set_side_visible("right", visible=True) # Show right
# Update panel width
update_left_width = panel.commands.update_side_width("left")
@@ -335,8 +406,8 @@ These commands are typically used with buttons or other interactive elements:
from myfasthtml.controls.helpers import mk
# Add buttons to toggle panels
hide_left_btn = mk.button("Hide Left", command=panel.commands.toggle_side("left", False))
show_left_btn = mk.button("Show Left", command=panel.commands.toggle_side("left", True))
hide_left_btn = mk.button("Hide Left", command=panel.commands.set_side_visible("left", False))
show_left_btn = mk.button("Show Left", command=panel.commands.set_side_visible("left", True))
# Add to your layout
panel.set_main(
@@ -364,21 +435,25 @@ panel.set_main(
The Panel uses CSS classes that you can customize:
| Class | Element |
|----------------------------|------------------------------------------|
| `mf-panel` | Root panel container |
| `mf-panel-left` | Left panel container |
| `mf-panel-right` | Right panel container |
| `mf-panel-main` | Main content area |
| `mf-panel-hide-icon` | Hide icon () inside panels |
| `mf-panel-show-icon` | Show icon (⋯) in main area |
| `mf-panel-show-icon-left` | Show icon for left panel |
| `mf-panel-show-icon-right` | Show icon for right panel |
| `mf-resizer` | Resize handle base class |
| `mf-resizer-left` | Left panel resize handle |
| `mf-resizer-right` | Right panel resize handle |
| `mf-hidden` | Applied to hidden panels |
| `no-transition` | Disables transition during manual resize |
| Class | Element |
|----------------------------|--------------------------------------------|
| `mf-panel` | Root panel container |
| `mf-panel-left` | Left panel container |
| `mf-panel-right` | Right panel container |
| `mf-panel-main` | Main content area |
| `mf-panel-with-title` | Panel using title layout (no padding-top) |
| `mf-panel-body` | Grid container for header + content |
| `mf-panel-header` | Sticky header with title and hide icon |
| `mf-panel-content` | Scrollable content area |
| `mf-panel-hide-icon` | Hide icon () inside panels |
| `mf-panel-show-icon` | Show icon (⋯) in main area |
| `mf-panel-show-icon-left` | Show icon for left panel |
| `mf-panel-show-icon-right` | Show icon for right panel |
| `mf-resizer` | Resize handle base class |
| `mf-resizer-left` | Left panel resize handle |
| `mf-resizer-right` | Right panel resize handle |
| `mf-hidden` | Applied to hidden panels |
| `no-transition` | Disables transition during manual resize |
**Example customization:**
@@ -641,13 +716,13 @@ panel.set_right(
# Create control buttons
toggle_left_btn = mk.button(
"Toggle Left Panel",
command=panel.commands.toggle_side("left", False),
command=panel.commands.set_side_visible("left", False),
cls="btn btn-sm"
)
toggle_right_btn = mk.button(
"Toggle Right Panel",
command=panel.commands.toggle_side("right", False),
command=panel.commands.set_side_visible("right", False),
cls="btn btn-sm"
)
@@ -657,8 +732,8 @@ show_all_btn = mk.button(
"show_all",
"Show all panels",
lambda: (
panel.toggle_side("left", True),
panel.toggle_side("right", True)
panel.toggle_side("left", True),
panel.toggle_side("right", True)
)
),
cls="btn btn-sm btn-primary"
@@ -668,17 +743,17 @@ show_all_btn = mk.button(
panel.set_main(
Div(
H1("Panel Controls Demo", cls="text-2xl font-bold mb-4"),
Div(
toggle_left_btn,
toggle_right_btn,
show_all_btn,
cls="space-x-2 mb-4"
),
P("Use the buttons above to toggle panels programmatically."),
P("You can also use the hide () and show (⋯) icons."),
cls="p-4"
)
)
@@ -696,10 +771,16 @@ This section contains technical details for developers working on the Panel comp
The Panel component uses `PanelConf` dataclass for configuration:
| Property | Type | Description | Default |
|----------|---------|----------------------------|---------|
| `left` | boolean | Enable/disable left panel | `True` |
| `right` | boolean | Enable/disable right panel | `True` |
| Property | Type | Description | Default |
|----------------------|---------|-------------------------------------------|-----------|
| `left` | boolean | Enable/disable left panel | `False` |
| `right` | boolean | Enable/disable right panel | `True` |
| `left_title` | string | Title displayed in left panel header | `"Left"` |
| `right_title` | string | Title displayed in right panel header | `"Right"` |
| `show_left_title` | boolean | Show title header on left panel | `True` |
| `show_right_title` | boolean | Show title header on right panel | `True` |
| `show_display_left` | boolean | Show the "show" icon when left is hidden | `True` |
| `show_display_right` | boolean | Show the "show" icon when right is hidden | `True` |
### State
@@ -735,10 +816,40 @@ codebase.
### High Level Hierarchical Structure
**With title (default, `show_*_title=True`):**
```
Div(id="{id}", cls="mf-panel")
├── Div(id="{id}_pl", cls="mf-panel-left mf-panel-with-title [mf-hidden]")
│ ├── Div(cls="mf-panel-body")
│ │ ├── Div(cls="mf-panel-header")
│ │ │ ├── Div [Title text]
│ │ │ └── Div (hide icon)
│ │ └── Div(id="{id}_cl", cls="mf-panel-content")
│ │ └── [Left content - scrollable]
│ └── Div (resizer-left)
├── Div(cls="mf-panel-main")
│ ├── Div(id="{id}_show_left", cls="hidden|mf-panel-show-icon-left")
│ ├── Div(id="{id}_m", cls="mf-panel-main")
│ │ └── [Main content]
│ └── Div(id="{id}_show_right", cls="hidden|mf-panel-show-icon-right")
├── Div(id="{id}_pr", cls="mf-panel-right mf-panel-with-title [mf-hidden]")
│ ├── Div (resizer-right)
│ └── Div(cls="mf-panel-body")
│ ├── Div(cls="mf-panel-header")
│ │ ├── Div [Title text]
│ │ └── Div (hide icon)
│ └── Div(id="{id}_cr", cls="mf-panel-content")
│ └── [Right content - scrollable]
└── Script # initResizer('{id}')
```
**Without title (legacy, `show_*_title=False`):**
```
Div(id="{id}", cls="mf-panel")
├── Div(id="{id}_pl", cls="mf-panel-left [mf-hidden]")
│ ├── Div (hide icon)
│ ├── Div (hide icon - absolute positioned)
│ ├── Div(id="{id}_cl")
│ │ └── [Left content]
│ └── Div (resizer-left)
@@ -749,7 +860,7 @@ Div(id="{id}", cls="mf-panel")
│ └── Div(id="{id}_show_right", cls="hidden|mf-panel-show-icon-right")
├── Div(id="{id}_pr", cls="mf-panel-right [mf-hidden]")
│ ├── Div (resizer-right)
│ ├── Div (hide icon)
│ ├── Div (hide icon - absolute positioned)
│ └── Div(id="{id}_cr")
│ └── [Right content]
└── Script # initResizer('{id}')
@@ -757,11 +868,12 @@ Div(id="{id}", cls="mf-panel")
**Note:**
- Left panel: hide icon, then content, then resizer (resizer on right edge)
- Right panel: resizer, then hide icon, then content (resizer on left edge)
- Hide icons are positioned at panel root level (not inside content div)
- Main content has an outer wrapper and inner content div with ID
- With title: uses grid layout (`mf-panel-body`) with sticky header and scrollable content
- Without title: hide icon is absolutely positioned at top-right with padding-top on panel
- Left panel: body/content then resizer (resizer on right edge)
- Right panel: resizer then body/content (resizer on left edge)
- `[mf-hidden]` class is conditionally applied when panel is hidden
- `mf-panel-with-title` class removes default padding-top when using title layout
### Element IDs