3.7 KiB
3.7 KiB
Tabs Widget Proposal
Overview
A new Tabs Widget that allows organizing content into multiple switchable tabs. Each tab will contain its own nested layout, capable of holding multiple widgets, similar to the LayoutContainerWidget.
Data Structure
The widget will maintain a list of tabs, where each tab holds a reference to a unique "Virtual Page ID" essentially acting as a container for other widgets.
interface TabDefinition {
id: string; // Unique identifier for the tab
label: string; // Display text
layoutId: string; // The 'pageId' used for the nested GenericCanvas
icon?: string; // Optional icon name
}
interface TabsWidgetProps {
tabs: TabDefinition[];
activeTabId: string;
orientation: 'horizontal' | 'vertical';
tabBarPosition: 'top' | 'bottom' | 'left' | 'right';
className?: string; // Container classes
tabBarClassName?: string; // Tab bar specific classes
contentClassName?: string; // Content area classes
}
Implementation Strategy
1. Widget Registration (registerWidgets.ts)
Register a new TabsWidget with a custom configuration schema.
- Tabs Management: A dedicated property editor (array of objects) to add/remove/reorder tabs and rename them.
- Orientation/Position: Selectors for tab bar placement.
- Styling: Tailwind CSS class pickers for container, tab bar, and content area.
2. Component Structure (TabsWidget.tsx)
The component will render:
- Tab Bar: A list of buttons/tabs.
- Content Area: renders a
GenericCanvasfor the currently active tab.
// simplified pseudo-code
const TabsWidget = ({ tabs, activeTabId, ...props }) => {
const [currentTabId, setCurrentTabId] = useState(activeTabId || tabs[0]?.id);
const currentTab = tabs.find(t => t.id === currentTabId);
return (
<div className="flex flex-col ...">
<TabBar
tabs={tabs}
activeId={currentTabId}
onSelect={setCurrentTabId}
/>
<div className="flex-1 relative">
{currentTab && (
<GenericCanvas
key={currentTab.layoutId} // Key ensures remount/proper context switch
pageId={currentTab.layoutId}
isEditMode={isEditMode}
/>
)}
</div>
</div>
);
}
3. Widget Properties Interface (WidgetPropertiesForm.tsx)
We need a new field type: 'array-objects' or specifically 'tabs-editor' to manage the list of tabs.
- Add Tab: Generates a new
layoutId(e.g.,tabs-<widgetId>-<timestamp>) and adds to the list. - Edit Tab: Change label/icon.
- Remove Tab: Removes from list (and ideally cleans up the layout, though we might leave orphans for safety initially).
- Reorder: Drag-and-drop reordering.
UX & Styling
- Tailwind Support: Fully transparent styling via props.
- Default Styles: Clean, modern tab look (border-b active state).
- Edit Mode: When in edit mode, the
GenericCanvasinside the active tab should allow dropping widgets just like the main canvas.
Nested Layout Handling
By reusing GenericCanvas, we automatically get:
- Drag & Drop support.
- Widget resizing within the tab.
- Persistence (provided the backend
layoutstable orpage_layoutssupports these virtual IDs).
Dependencies
GenericCanvas: For rendering the nested content.dnd-kit(or similar): For reordering tabs in the property panel.lucide-react: For tab icons.
Roadmap
- Scaffold: Create
TabsWidget.tsxand register it. - Properties: Update
WidgetPropertiesFormto support managing a list of tabs. - Integration: Verify nested drag-and-drop works correctly within
GenericCanvas.