mirror of
https://github.com/GitbookIO/gitbook.git
synced 2026-09-24 19:32:07 +00:00
Section groups visual bug fix (#2821)
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'gitbook': patch
|
||||
---
|
||||
|
||||
Visual fix for section group in Safari
|
||||
@@ -22,26 +22,30 @@ export function SiteSectionTabs(props: { sections: SectionsList }) {
|
||||
} = props;
|
||||
const [value, setValue] = React.useState<string | null>();
|
||||
const [offset, setOffset] = React.useState<number | null>(null);
|
||||
const scrollableViewRef = React.useRef<HTMLDivElement>(null);
|
||||
|
||||
const onNodeUpdate = (
|
||||
trigger: HTMLButtonElement | null,
|
||||
itemValue: string,
|
||||
size: number = 0,
|
||||
) => {
|
||||
const windowWidth = window.innerWidth;
|
||||
const windowWidth = document.documentElement.clientWidth;
|
||||
if (windowWidth < 768) {
|
||||
// if the screen is small don't offset the menu
|
||||
setOffset(0);
|
||||
} else if (trigger && value === itemValue) {
|
||||
const padding = 16;
|
||||
const viewportWidth =
|
||||
size < MIN_ITEMS_FOR_COLS ? VIEWPORT_ITEM_WIDTH : VIEWPORT_ITEM_WIDTH * 2;
|
||||
const halfViewportWidth = viewportWidth / 2;
|
||||
const viewportFreeZone = 10 /* buffer */ + 8 /* padding */ + halfViewportWidth;
|
||||
const triggerOffsetRight = trigger.offsetLeft + trigger.offsetWidth / 2;
|
||||
size < MIN_ITEMS_FOR_COLS
|
||||
? VIEWPORT_ITEM_WIDTH + padding
|
||||
: VIEWPORT_ITEM_WIDTH * 2 + padding;
|
||||
const scrollLeft = scrollableViewRef.current?.scrollLeft ?? 0;
|
||||
const triggerOffset = trigger.offsetLeft - scrollLeft; // offset of the trigger from the left edge including scrolling
|
||||
const bufferLeft = 2; // offset the menu viewport should not pass on the left side of window
|
||||
const bufferRight = windowWidth - (16 + viewportWidth); // offset the menu viewport should not pass on the right side of the window
|
||||
setOffset(
|
||||
Math.min(
|
||||
Math.max(viewportFreeZone, Math.round(triggerOffsetRight)),
|
||||
windowWidth - viewportFreeZone,
|
||||
),
|
||||
// constrain to within the window with some buffer on the left and right we don't want the menu to enter
|
||||
Math.min(bufferRight, Math.max(bufferLeft, Math.round(triggerOffset))),
|
||||
);
|
||||
} else if (!value) {
|
||||
setOffset(null);
|
||||
@@ -55,6 +59,7 @@ export function SiteSectionTabs(props: { sections: SectionsList }) {
|
||||
className="w-full relative z-10 flex flex-nowrap items-center max-w-screen-2xl mx-auto page-full-width:max-w-full"
|
||||
>
|
||||
<div
|
||||
ref={scrollableViewRef}
|
||||
className="w-full hide-scroll overflow-x-scroll overflow-y-hidden pb-4 -mb-4" /* Positive padding / negative margin allows the navigation menu indicator to show in a scroll view */
|
||||
>
|
||||
<NavigationMenu.List className="center m-0 flex list-none bg-transparent px-1 sm:px-3 md:px-5 gap-2">
|
||||
@@ -112,7 +117,7 @@ export function SiteSectionTabs(props: { sections: SectionsList }) {
|
||||
);
|
||||
})}
|
||||
<NavigationMenu.Indicator
|
||||
className="top-full z-0 flex h-3 items-end justify-center motion-safe:transition-[width,_transform] data-[state=hidden]:motion-safe:animate-fadeOut data-[state=visible]:motion-safe:animate-fadeIn"
|
||||
className="top-full z-0 flex h-3 items-end justify-center duration-150 motion-safe:transition-[width,_transform] data-[state=hidden]:motion-safe:animate-fadeOut data-[state=visible]:motion-safe:animate-fadeIn"
|
||||
aria-hidden
|
||||
>
|
||||
<div className="bg-tint shadow-1xs shadow-dark/1 dark:shadow-dark/4 relative top-[70%] size-3 rotate-[225deg] rounded-tl-sm" />
|
||||
@@ -120,18 +125,17 @@ export function SiteSectionTabs(props: { sections: SectionsList }) {
|
||||
</NavigationMenu.List>
|
||||
</div>
|
||||
<div
|
||||
className="absolute mx-4 top-full flex transition-transform duration-200 ease-in-out"
|
||||
className="absolute top-full flex transition-transform duration-200 ease-in-out"
|
||||
style={{
|
||||
display: offset === null ? 'none' : undefined,
|
||||
transform: offset ? `translateX(${offset}px)` : undefined,
|
||||
}}
|
||||
>
|
||||
<NavigationMenu.Viewport
|
||||
className="bg-tint rounded straight-corners:rounded-none shadow-1xs shadow-dark/1 dark:shadow-dark/4 relative mt-3 w-[calc(100vw_-_2rem)] md:w-[var(--radix-navigation-menu-viewport-width)] h-[var(--radix-navigation-menu-viewport-height)] origin-[top_center] overflow-hidden motion-safe:transition-[width,_height,_transform] duration-300 data-[state=closed]:motion-safe:animate-scaleOut data-[state=open]:motion-safe:animate-scaleIn"
|
||||
className="bg-tint rounded straight-corners:rounded-none shadow-1xs shadow-dark/1 dark:shadow-dark/4 relative mt-3 ml-4 md:mx-0 w-[calc(100vw_-_2rem)] md:w-[var(--radix-navigation-menu-viewport-width)] h-[var(--radix-navigation-menu-viewport-height)] origin-[top_center] overflow-hidden motion-safe:transition-[width,_height,_transform] duration-250 data-[state=closed]:duration-150 data-[state=closed]:motion-safe:animate-scaleOut data-[state=open]:motion-safe:animate-scaleIn"
|
||||
style={{
|
||||
translate: offset
|
||||
? '-50% 0'
|
||||
: undefined /* don't move this to a Tailwind class as Radix renders viewport incorrectly for a few frames */,
|
||||
translate:
|
||||
undefined /* don't move this to a Tailwind class as Radix renders viewport incorrectly for a few frames */,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
@@ -254,7 +258,7 @@ function SectionGroupTile(props: { section: SiteSection; isActive: boolean }) {
|
||||
{icon ? <SectionIcon isActive={false} icon={icon as IconName} /> : null}
|
||||
<span className="truncate min-w-0">{title}</span>
|
||||
</div>
|
||||
<p className="text-tint-subtle min-h-[2lh]">{section.description}</p>
|
||||
<p className="text-tint-subtle">{section.description}</p>
|
||||
</Link>
|
||||
</li>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user