[WEB-5556] chore: tab navigation and sidebar improvements (#8218)
This commit is contained in:
parent
ec478a8979
commit
e650b19933
3 changed files with 40 additions and 16 deletions
|
|
@ -115,7 +115,7 @@ export const TabNavigationRoot: FC<TTabNavigationRootProps> = observer((props) =
|
|||
const hiddenNavigationItems = allNavigationItems.filter((item) => tabPreferences.hiddenTabs.includes(item.key));
|
||||
|
||||
// Responsive tab layout hook
|
||||
const { visibleItems, overflowItems, hasOverflow, containerRef, itemRefs } = useResponsiveTabLayout({
|
||||
const { visibleItems, overflowItems, hasOverflow, itemRefs, containerRef } = useResponsiveTabLayout({
|
||||
visibleNavigationItems,
|
||||
hiddenNavigationItems,
|
||||
isActive,
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
import { useEffect, useMemo, useRef, useState } from "react";
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||
import type { TNavigationItem } from "./tab-navigation-root";
|
||||
|
||||
export type TResponsiveTabLayout = {
|
||||
visibleItems: TNavigationItem[];
|
||||
overflowItems: TNavigationItem[];
|
||||
hasOverflow: boolean;
|
||||
containerRef: React.RefObject<HTMLDivElement>;
|
||||
itemRefs: React.MutableRefObject<(HTMLDivElement | null)[]>;
|
||||
containerRef: (node: HTMLDivElement | null) => void;
|
||||
};
|
||||
|
||||
type UseResponsiveTabLayoutProps = {
|
||||
|
|
@ -30,9 +30,9 @@ export const useResponsiveTabLayout = ({
|
|||
hiddenNavigationItems,
|
||||
isActive,
|
||||
}: UseResponsiveTabLayoutProps): TResponsiveTabLayout => {
|
||||
// Refs for measuring space and items
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
// Refs for measuring items
|
||||
const itemRefs = useRef<(HTMLDivElement | null)[]>([]);
|
||||
const resizeObserverRef = useRef<ResizeObserver | null>(null);
|
||||
|
||||
// State for responsive behavior
|
||||
const [containerWidth, setContainerWidth] = useState<number>(0);
|
||||
|
|
@ -42,24 +42,44 @@ export const useResponsiveTabLayout = ({
|
|||
const gap = 4; // gap-1 = 4px
|
||||
const overflowButtonWidth = 40;
|
||||
|
||||
const container = containerRef?.current;
|
||||
// Callback ref that sets up ResizeObserver when element is attached
|
||||
const containerRef = useCallback((node: HTMLDivElement | null) => {
|
||||
// Clean up previous observer if it exists
|
||||
if (resizeObserverRef.current) {
|
||||
resizeObserverRef.current.disconnect();
|
||||
resizeObserverRef.current = null;
|
||||
}
|
||||
|
||||
// ResizeObserver to measure container width
|
||||
useEffect(() => {
|
||||
if (!container) return;
|
||||
// If node is null (unmounting), just clean up
|
||||
if (!node) {
|
||||
setContainerWidth(0);
|
||||
return;
|
||||
}
|
||||
|
||||
// Set initial width immediately
|
||||
setContainerWidth(node.offsetWidth);
|
||||
|
||||
// Create and set up new ResizeObserver
|
||||
const resizeObserver = new ResizeObserver((entries) => {
|
||||
for (const entry of entries) {
|
||||
setContainerWidth(entry.contentRect.width);
|
||||
}
|
||||
});
|
||||
|
||||
resizeObserver.observe(container);
|
||||
resizeObserverRef.current = resizeObserver;
|
||||
resizeObserver.observe(node);
|
||||
}, []); // Empty deps - callback function remains stable
|
||||
|
||||
return () => {
|
||||
resizeObserver.disconnect();
|
||||
};
|
||||
}, [container]);
|
||||
// Cleanup effect to disconnect observer on component unmount
|
||||
useEffect(
|
||||
() => () => {
|
||||
if (resizeObserverRef.current) {
|
||||
resizeObserverRef.current.disconnect();
|
||||
resizeObserverRef.current = null;
|
||||
}
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
// Calculate how many items can fit
|
||||
useEffect(() => {
|
||||
|
|
@ -137,7 +157,7 @@ export const useResponsiveTabLayout = ({
|
|||
visibleItems,
|
||||
overflowItems,
|
||||
hasOverflow,
|
||||
containerRef,
|
||||
itemRefs,
|
||||
containerRef,
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -69,8 +69,8 @@ export const SidebarProjectsListItem = observer(function SidebarProjectsListItem
|
|||
const { isMobile } = usePlatformOS();
|
||||
const { allowPermissions } = useUserPermissions();
|
||||
const { getIsProjectListOpen, toggleProjectListOpen } = useCommandPalette();
|
||||
const { toggleAnySidebarDropdown } = useAppTheme();
|
||||
const { preferences: projectPreferences } = useProjectNavigationPreferences();
|
||||
const { isExtendedProjectSidebarOpened, toggleExtendedProjectSidebar, toggleAnySidebarDropdown } = useAppTheme();
|
||||
|
||||
// states
|
||||
const [leaveProjectModalOpen, setLeaveProjectModal] = useState(false);
|
||||
|
|
@ -259,6 +259,10 @@ export const SidebarProjectsListItem = observer(function SidebarProjectsListItem
|
|||
} else {
|
||||
router.push(defaultTabUrl);
|
||||
}
|
||||
// close the extended sidebar if it is open
|
||||
if (isExtendedProjectSidebarOpened) {
|
||||
toggleExtendedProjectSidebar(false);
|
||||
}
|
||||
};
|
||||
|
||||
const isAccordionMode = projectPreferences.navigationMode === "accordion";
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue