Skip to content

Commit aaab157

Browse files
authored
Section groups visual bug fix (#2821)
1 parent 9943276 commit aaab157

File tree

2 files changed

+25
-16
lines changed

2 files changed

+25
-16
lines changed

.changeset/quick-cougars-mate.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'gitbook': patch
3+
---
4+
5+
Visual fix for section group in Safari

packages/gitbook/src/components/SiteSections/SiteSectionTabs.tsx

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -22,26 +22,30 @@ export function SiteSectionTabs(props: { sections: SectionsList }) {
2222
} = props;
2323
const [value, setValue] = React.useState<string | null>();
2424
const [offset, setOffset] = React.useState<number | null>(null);
25+
const scrollableViewRef = React.useRef<HTMLDivElement>(null);
2526

2627
const onNodeUpdate = (
2728
trigger: HTMLButtonElement | null,
2829
itemValue: string,
2930
size: number = 0,
3031
) => {
31-
const windowWidth = window.innerWidth;
32+
const windowWidth = document.documentElement.clientWidth;
3233
if (windowWidth < 768) {
34+
// if the screen is small don't offset the menu
3335
setOffset(0);
3436
} else if (trigger && value === itemValue) {
37+
const padding = 16;
3538
const viewportWidth =
36-
size < MIN_ITEMS_FOR_COLS ? VIEWPORT_ITEM_WIDTH : VIEWPORT_ITEM_WIDTH * 2;
37-
const halfViewportWidth = viewportWidth / 2;
38-
const viewportFreeZone = 10 /* buffer */ + 8 /* padding */ + halfViewportWidth;
39-
const triggerOffsetRight = trigger.offsetLeft + trigger.offsetWidth / 2;
39+
size < MIN_ITEMS_FOR_COLS
40+
? VIEWPORT_ITEM_WIDTH + padding
41+
: VIEWPORT_ITEM_WIDTH * 2 + padding;
42+
const scrollLeft = scrollableViewRef.current?.scrollLeft ?? 0;
43+
const triggerOffset = trigger.offsetLeft - scrollLeft; // offset of the trigger from the left edge including scrolling
44+
const bufferLeft = 2; // offset the menu viewport should not pass on the left side of window
45+
const bufferRight = windowWidth - (16 + viewportWidth); // offset the menu viewport should not pass on the right side of the window
4046
setOffset(
41-
Math.min(
42-
Math.max(viewportFreeZone, Math.round(triggerOffsetRight)),
43-
windowWidth - viewportFreeZone,
44-
),
47+
// constrain to within the window with some buffer on the left and right we don't want the menu to enter
48+
Math.min(bufferRight, Math.max(bufferLeft, Math.round(triggerOffset))),
4549
);
4650
} else if (!value) {
4751
setOffset(null);
@@ -55,6 +59,7 @@ export function SiteSectionTabs(props: { sections: SectionsList }) {
5559
className="w-full relative z-10 flex flex-nowrap items-center max-w-screen-2xl mx-auto page-full-width:max-w-full"
5660
>
5761
<div
62+
ref={scrollableViewRef}
5863
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 */
5964
>
6065
<NavigationMenu.List className="center m-0 flex list-none bg-transparent px-1 sm:px-3 md:px-5 gap-2">
@@ -112,26 +117,25 @@ export function SiteSectionTabs(props: { sections: SectionsList }) {
112117
);
113118
})}
114119
<NavigationMenu.Indicator
115-
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"
120+
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"
116121
aria-hidden
117122
>
118123
<div className="bg-tint shadow-1xs shadow-dark/1 dark:shadow-dark/4 relative top-[70%] size-3 rotate-[225deg] rounded-tl-sm" />
119124
</NavigationMenu.Indicator>
120125
</NavigationMenu.List>
121126
</div>
122127
<div
123-
className="absolute mx-4 top-full flex transition-transform duration-200 ease-in-out"
128+
className="absolute top-full flex transition-transform duration-200 ease-in-out"
124129
style={{
125130
display: offset === null ? 'none' : undefined,
126131
transform: offset ? `translateX(${offset}px)` : undefined,
127132
}}
128133
>
129134
<NavigationMenu.Viewport
130-
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"
135+
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"
131136
style={{
132-
translate: offset
133-
? '-50% 0'
134-
: undefined /* don't move this to a Tailwind class as Radix renders viewport incorrectly for a few frames */,
137+
translate:
138+
undefined /* don't move this to a Tailwind class as Radix renders viewport incorrectly for a few frames */,
135139
}}
136140
/>
137141
</div>
@@ -254,7 +258,7 @@ function SectionGroupTile(props: { section: SiteSection; isActive: boolean }) {
254258
{icon ? <SectionIcon isActive={false} icon={icon as IconName} /> : null}
255259
<span className="truncate min-w-0">{title}</span>
256260
</div>
257-
<p className="text-tint-subtle min-h-[2lh]">{section.description}</p>
261+
<p className="text-tint-subtle">{section.description}</p>
258262
</Link>
259263
</li>
260264
);

0 commit comments

Comments
 (0)