From 7136b01be4dae69a4e53b42b241bbe1916129273 Mon Sep 17 00:00:00 2001 From: dwindown Date: Thu, 20 Nov 2025 21:00:30 +0700 Subject: [PATCH] fix: Vertical tabs visibility and add mobile horizontal tabs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixed two critical issues with VerticalTabForm: Issue #1: All sections showing at once - Problem: className override was removing original classes - Fix: Preserve originalClassName and append 'hidden' when inactive - Now only active section is visible - Inactive sections get 'hidden' class added Issue #2: No horizontal tabs on mobile - Added mobile horizontal tabs (lg:hidden) - Scrollable tab bar with overflow-x-auto - Active tab highlighted with bg-primary - Icons + labels for each tab - Separate mobile content area Changes to VerticalTabForm.tsx: 1. Fixed className merging logic - Get originalClassName from child.props - Active: use originalClassName as-is - Inactive: append ' hidden' to originalClassName - Prevents className override issue 2. Added mobile layout - Horizontal tabs at top (lg:hidden) - Flex with gap-2, overflow-x-auto - flex-shrink-0 prevents tab squishing - Active state: bg-primary text-primary-foreground - Inactive state: bg-muted text-muted-foreground 3. Desktop layout (hidden lg:flex) - Vertical sidebar (w-56) - Content area (flex-1) - Scroll spy for desktop only 4. Mobile content area (lg:hidden) - No scroll spy (simpler) - Direct tab switching - Same visibility logic (hidden class) Result: ✅ Only active section visible (desktop + mobile) ✅ Mobile has horizontal tabs ✅ Desktop has vertical sidebar ✅ Proper responsive behavior ✅ Tab switching works correctly --- admin-spa/src/components/VerticalTabForm.tsx | 69 ++++++++++++++++---- 1 file changed, 55 insertions(+), 14 deletions(-) diff --git a/admin-spa/src/components/VerticalTabForm.tsx b/admin-spa/src/components/VerticalTabForm.tsx index a632ebc..ff73297 100644 --- a/admin-spa/src/components/VerticalTabForm.tsx +++ b/admin-spa/src/components/VerticalTabForm.tsx @@ -66,20 +66,20 @@ export function VerticalTabForm({ tabs, children, className }: VerticalTabFormPr }; return ( -
- {/* Vertical Tabs Sidebar */} -
-
+
+ {/* Mobile: Horizontal Tabs */} +
+
{tabs.map((tab) => (
- {/* Content Area */} -
+ {/* Desktop: Vertical Layout */} +
+ {/* Vertical Tabs Sidebar */} +
+
+ {tabs.map((tab) => ( + + ))} +
+
+ + {/* Content Area - Desktop */} +
+ {React.Children.map(children, (child) => { + if (React.isValidElement(child) && child.props['data-section-id']) { + const sectionId = child.props['data-section-id']; + const isActive = sectionId === activeTab; + const originalClassName = child.props.className || ''; + return React.cloneElement(child as React.ReactElement, { + ref: (el: HTMLElement) => registerSection(sectionId, el), + className: isActive ? originalClassName : `${originalClassName} hidden`.trim(), + }); + } + return child; + })} +
+
+ + {/* Mobile: Content Area */} +
{React.Children.map(children, (child) => { if (React.isValidElement(child) && child.props['data-section-id']) { const sectionId = child.props['data-section-id']; const isActive = sectionId === activeTab; + const originalClassName = child.props.className || ''; return React.cloneElement(child as React.ReactElement, { - ref: (el: HTMLElement) => registerSection(sectionId, el), - className: isActive ? '' : 'hidden', + className: isActive ? originalClassName : `${originalClassName} hidden`.trim(), }); } return child;