Add automatic tab centering to TabsScroller
- Clicked tabs now scroll to center of container automatically - Behavior works on all pages using TabsScroller - Removed duplicate scroll logic from Features.tsx Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -168,8 +168,22 @@ const TabsScroller = forwardRef<HTMLDivElement, TabsScrollerProps>(
|
||||
}, 150);
|
||||
};
|
||||
const handleScrollEnd = () => updateOverflow();
|
||||
|
||||
// Scroll clicked tab to center
|
||||
const handleTabClick = (event: Event) => {
|
||||
const target = event.target as HTMLElement;
|
||||
const tabButton = target.closest('.page-tab-btn, .admin-tab-btn') as HTMLElement;
|
||||
if (!tabButton) return;
|
||||
const nodeWidth = node.clientWidth;
|
||||
const buttonLeft = tabButton.offsetLeft;
|
||||
const buttonWidth = tabButton.offsetWidth;
|
||||
const scrollLeft = buttonLeft - (nodeWidth / 2) + (buttonWidth / 2);
|
||||
node.scrollTo({ left: Math.max(0, scrollLeft), behavior: 'smooth' });
|
||||
};
|
||||
|
||||
node.addEventListener('scroll', handleScroll, { passive: true });
|
||||
node.addEventListener('scrollend', handleScrollEnd, { passive: true });
|
||||
node.addEventListener('click', handleTabClick);
|
||||
let resizeObserver: ResizeObserver | null = null;
|
||||
if (typeof ResizeObserver !== 'undefined') {
|
||||
resizeObserver = new ResizeObserver(() => scheduleOverflowUpdate());
|
||||
@@ -189,6 +203,7 @@ const TabsScroller = forwardRef<HTMLDivElement, TabsScrollerProps>(
|
||||
return () => {
|
||||
node.removeEventListener('scroll', handleScroll);
|
||||
node.removeEventListener('scrollend', handleScrollEnd);
|
||||
node.removeEventListener('click', handleTabClick);
|
||||
if (scrollEndTimeoutRef.current) {
|
||||
clearTimeout(scrollEndTimeoutRef.current);
|
||||
}
|
||||
|
||||
@@ -51,7 +51,6 @@ export default function Features() {
|
||||
const [localOrder, setLocalOrder] = useState<string[]>([]);
|
||||
const [localPositions, setLocalPositions] = useState<Record<string, 'top' | 'bottom'>>({});
|
||||
const [hasOrderChanges, setHasOrderChanges] = useState(false);
|
||||
const tabsContainerRef = useRef<HTMLDivElement>(null);
|
||||
const isUserEditing = useRef(false); // Track if user is actively editing
|
||||
const initialOrderRef = useRef<string[]>([]);
|
||||
const initialPositionsRef = useRef<Record<string, 'top' | 'bottom'>>({});
|
||||
@@ -155,27 +154,10 @@ export default function Features() {
|
||||
localPositionsRef.current = localPositions;
|
||||
}, [localPositions]);
|
||||
|
||||
// Scroll active tab to center of container
|
||||
const scrollActiveTabIntoView = useCallback((tabId: string) => {
|
||||
if (tabsContainerRef.current) {
|
||||
const container = tabsContainerRef.current;
|
||||
const activeButton = container.querySelector(`[data-tab-id="${tabId}"]`) as HTMLElement;
|
||||
if (activeButton) {
|
||||
const containerWidth = container.clientWidth;
|
||||
const buttonLeft = activeButton.offsetLeft;
|
||||
const buttonWidth = activeButton.offsetWidth;
|
||||
// Calculate scroll position to center the button
|
||||
const scrollLeft = buttonLeft - (containerWidth / 2) + (buttonWidth / 2);
|
||||
container.scrollTo({ left: Math.max(0, scrollLeft), behavior: 'smooth' });
|
||||
}
|
||||
}
|
||||
}, []);
|
||||
|
||||
// Handle tab change with scroll
|
||||
// Handle tab change (centering is handled by TabsScroller)
|
||||
const handleTabChange = useCallback((tabId: TabId) => {
|
||||
setActiveTab(tabId);
|
||||
setTimeout(() => scrollActiveTabIntoView(tabId), 50);
|
||||
}, [scrollActiveTabIntoView]);
|
||||
}, []);
|
||||
// Keep saveRef updated with latest function
|
||||
useEffect(() => {
|
||||
saveRef.current = saveModulesToBackend;
|
||||
@@ -787,7 +769,7 @@ export default function Features() {
|
||||
onMenuClick={toggleMobileMenu}
|
||||
/>
|
||||
<div className="page-tabs-container">
|
||||
<TabsScroller className="page-tabs-slider" ref={tabsContainerRef} showArrows>
|
||||
<TabsScroller className="page-tabs-slider" showArrows>
|
||||
<div className="page-title-section">
|
||||
<span className="page-title-text">{t.featuresPage.title}</span>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user