Skip to content

Commit

Permalink
Improve items popover positioning (#446)
Browse files Browse the repository at this point in the history
Closes #131

Signed-off-by: Cintia Sanchez Garcia <[email protected]>
  • Loading branch information
cynthia-sg authored Jan 15, 2024
1 parent 4760382 commit b45f358
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 22 deletions.
5 changes: 3 additions & 2 deletions web/src/layout/common/zoomModal/ZoomModal.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@

.wrapper {
background-color: var(--bs-white);
/* Tooltip height + Subcategory title height + Featured card height */
min-height: calc(262px + 35px + 68px * 2);
max-height: 90%;
width: 90%;
}

.catTitle {
Expand All @@ -24,6 +24,7 @@
.content {
background-color: var(--bs-gray-100);
padding: 0.6rem;
max-height: calc(100% - 35px);
}

.grid {
Expand Down
35 changes: 26 additions & 9 deletions web/src/layout/common/zoomModal/index.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { createElementSize } from '@solid-primitives/resize-observer';
import isNull from 'lodash/isNull';
import isUndefined from 'lodash/isUndefined';
import { Accessor, createEffect, createSignal, For, Show, untrack } from 'solid-js';
import { Accessor, createEffect, createSignal, For, on, Show, untrack } from 'solid-js';

import { ZOOM_LEVELS } from '../../../data';
import { BaseItem, Item } from '../../../types';
Expand All @@ -24,9 +24,12 @@ const ZoomModal = () => {
const fullDataReady = useFullDataReady();
const updateActiveSection = useSetVisibleZoom();
const [container, setContainer] = createSignal<HTMLDivElement>();
const [itemsWrapper, setItemsWrapper] = createSignal<HTMLDivElement>();
const [modal, setModal] = createSignal<HTMLDivElement>();
const [gridContainer, setGridContainer] = createSignal<HTMLDivElement>();
const [items, setItems] = createSignal<Item[] | undefined | null>();
const [containerWidth, setContainerWidth] = createSignal<string>('');
const [overflowGrid, setOverflowGrid] = createSignal<boolean>(false);
const size = createElementSize(container);

createEffect(() => {
Expand Down Expand Up @@ -66,6 +69,18 @@ const ZoomModal = () => {
untrack(containerWidth);
});

createEffect(
on(itemsWrapper, () => {
if (!isUndefined(itemsWrapper())) {
if (itemsWrapper()!.clientHeight < itemsWrapper()!.scrollHeight) {
setOverflowGrid(true);
} else {
setOverflowGrid(false);
}
}
})
);

return (
<Show when={!isUndefined(visibleZoomSection())}>
<FullScreenModal
Expand All @@ -82,12 +97,8 @@ const ZoomModal = () => {
</div>
}
>
<div class="d-flex flex-column p-5 h-100">
<div
ref={setModal}
class={`d-flex flex-row m-auto ${styles.wrapper}`}
style={{ width: containerWidth() !== '' ? containerWidth() : '100%', 'max-width': '100%' }}
>
<div class="d-flex flex-column align-items-center justify-content-center p-4 p-xl-5 h-100">
<div ref={setModal} class={`d-flex flex-row m-auto ${styles.wrapper}`}>
<div
class={`text-white border border-3 border-white fw-semibold p-2 py-5 ${styles.catTitle}`}
style={{ 'background-color': visibleZoomSection()!.bgColor }}
Expand All @@ -97,7 +108,7 @@ const ZoomModal = () => {
</div>
</div>

<div class="d-flex flex-column align-items-stretch w-100">
<div ref={setGridContainer} class="d-flex flex-column align-items-stretch w-100">
<div class={'col-12 d-flex flex-column border border-3 border-white border-start-0 border-bottom-0'}>
<div
class={`d-flex align-items-center text-white justify-content-center text-center px-2 w-100 fw-semibold ${styles.subcatTitle}`}
Expand All @@ -106,7 +117,12 @@ const ZoomModal = () => {
<div class="text-truncate">{visibleZoomSection()!.subcategory}</div>
</div>
</div>
<div class={`h-100 overflow-auto ${styles.content}`}>
{/* overflow-auto only necessary when items exceeds height */}
<div
ref={setItemsWrapper}
class={`h-100 ${styles.content}`}
classList={{ 'overflow-auto': overflowGrid() }}
>
<div class={styles.grid}>
<For each={sortItemsByOrderValue(items()!)}>
{(item: BaseItem | Item) => {
Expand All @@ -115,6 +131,7 @@ const ZoomModal = () => {
item={item}
borderColor={visibleZoomSection()!.bgColor}
showMoreInfo={false}
container={gridContainer()}
activeDropdown
/>
);
Expand Down
22 changes: 20 additions & 2 deletions web/src/layout/explore/grid/GridItem.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -110,9 +110,9 @@
min-width: 200px;
font-size: 0.85rem;
margin-top: calc(var(--card-size-height) + 0.5rem);
min-height: 10rem;
min-height: 210px;
border-color: var(--bs-gray-600);
box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.5) !important;
box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.25) !important;
z-index: 1020;
}

Expand All @@ -132,6 +132,16 @@
right: calc(var(--card-size-width) * -1);
}

.topAligned {
top: auto;
bottom: 10px;
box-shadow: 0 -0.15rem 1rem rgba(0, 0, 0, 0.25) !important;
}

.bottomAligned {
top: 0;
}

.card:global(.bigCard) .rightAligned {
right: calc(var(--card-size-width) * 2 * -1);
}
Expand All @@ -146,6 +156,14 @@
height: 0;
}

.topAligned .arrow {
top: auto;
bottom: -0.5rem;
border-width: 0.5rem 0.5rem 0;
border-bottom-color: transparent;
border-top-color: var(--bs-gray-700);
}

.centerAligned .arrow {
left: calc(50% - 0.5rem);
}
Expand Down
38 changes: 29 additions & 9 deletions web/src/layout/explore/grid/GridItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import isUndefined from 'lodash/isUndefined';
import { createEffect, createSignal, on, onCleanup, Show } from 'solid-js';

import { BaseItem, Item } from '../../../types';
import getItemDescription from '../../../utils/getItemDescription';
import itemsDataGetter from '../../../utils/itemsDataGetter';
import Image from '../../common/Image';
import Loading from '../../common/Loading';
Expand All @@ -16,10 +17,13 @@ interface Props {
showMoreInfo: boolean;
activeDropdown: boolean;
enableLazyLoad?: boolean;
container?: HTMLDivElement;
}

const DEFAULT_DROPDOWN_WIDTH = 450;
const DEFAULT_MARGIN = 30;
const DEFAULT_HEADER = 72;
const DEFAULT_DROPDOWN_HEIGHT = 213 + 10; // Height + arrow with gap
const DEFAULT_MARGIN = 35;

const GridItem = (props: Props) => {
let ref;
Expand All @@ -30,9 +34,13 @@ const GridItem = (props: Props) => {
const [onLinkHover, setOnLinkHover] = createSignal(false);
const [onDropdownHover, setOnDropdownHover] = createSignal(false);
const [tooltipAlignment, setTooltipAlignment] = createSignal<'right' | 'left' | 'center'>('center');
const [tooltipVerticalAlignment, setTooltipVerticalAlignment] = createSignal<'top' | 'bottom'>('bottom');
const [dropdownTimeout, setDropdownTimeout] = createSignal<number>();
const [elWidth, setElWidth] = createSignal<number>(0);
const [item, setItem] = createSignal<Item | undefined>();
const description = () => getItemDescription(props.item);
const containerWidth = () => (!isUndefined(props.container) ? props.container.clientWidth : window.innerWidth);
const containerHeight = () => (!isUndefined(props.container) ? props.container.clientHeight : window.innerHeight);

createEffect(
on(fullDataReady, () => {
Expand All @@ -44,19 +52,30 @@ const GridItem = (props: Props) => {

const calculateTooltipPosition = () => {
if (!isUndefined(wrapper())) {
const windowWidth = window.innerWidth;
const bounding = wrapper()!.getBoundingClientRect();
setElWidth(bounding.width);
const overflowTooltip = (DEFAULT_DROPDOWN_WIDTH - elWidth()) / 2;
const overflowTooltip = (DEFAULT_DROPDOWN_WIDTH - bounding.width) / 2;
const margin = !isUndefined(props.container) ? props.container?.getBoundingClientRect().x : DEFAULT_MARGIN;
const marginTop = !isUndefined(props.container)
? props.container.getBoundingClientRect().y + DEFAULT_MARGIN
: DEFAULT_HEADER;
const dropdownHeight = description().length > 68 ? DEFAULT_DROPDOWN_HEIGHT + 17 : DEFAULT_DROPDOWN_HEIGHT;
// Horizontal positioning
if (
DEFAULT_MARGIN + bounding.right + overflowTooltip < windowWidth &&
bounding.left - overflowTooltip - DEFAULT_MARGIN > 0
margin + bounding.right + overflowTooltip < containerWidth() &&
bounding.left - overflowTooltip - margin > 0
) {
setTooltipAlignment('center');
} else if (windowWidth - bounding.right - DEFAULT_MARGIN < DEFAULT_DROPDOWN_WIDTH - bounding.width) {
setTooltipAlignment('right');
} else {
} else if (containerWidth() + margin - bounding.x > DEFAULT_DROPDOWN_WIDTH) {
setTooltipAlignment('left');
} else {
setTooltipAlignment('right');
}
// Vertical positioning
if (containerHeight() - bounding.bottom > dropdownHeight) {
setTooltipVerticalAlignment('bottom');
} else if (bounding.top - marginTop > dropdownHeight) {
setTooltipVerticalAlignment('top');
}
}
};
Expand Down Expand Up @@ -148,9 +167,10 @@ const GridItem = (props: Props) => {
role="complementary"
class={`dropdown-menu rounded-0 p-3 popover show ${styles.dropdown} ${
styles[`${tooltipAlignment()}Aligned`]
}`}
} ${styles[`${tooltipVerticalAlignment()}Aligned`]}`}
style={{
'min-width': `${DEFAULT_DROPDOWN_WIDTH}px`,
'max-width': !isUndefined(props.container) && props.container.clientWidth < 750 ? '300px' : 'auto',
left: tooltipAlignment() === 'center' ? `${-(DEFAULT_DROPDOWN_WIDTH - elWidth()) / 2}px` : 'auto',
}}
onMouseEnter={() => {
Expand Down

0 comments on commit b45f358

Please sign in to comment.