From 9c980f06f9432e6f641e7b089d899efb70aa8136 Mon Sep 17 00:00:00 2001 From: Uriel Date: Thu, 27 Jul 2023 09:41:47 -0300 Subject: [PATCH] Make manual proportion list grow if there is space (#784) Co-authored-by: lucas lelievre --- gui/src/components/MainLayout.tsx | 2 +- .../body-proportions/BodyProportions.tsx | 104 +++++++++++------- gui/src/hooks/timeout.ts | 11 ++ gui/tailwind.config.ts | 1 + 4 files changed, 77 insertions(+), 41 deletions(-) diff --git a/gui/src/components/MainLayout.tsx b/gui/src/components/MainLayout.tsx index f421ac3b8..b20568d4e 100644 --- a/gui/src/components/MainLayout.tsx +++ b/gui/src/components/MainLayout.tsx @@ -77,7 +77,7 @@ export function MainLayoutRoute({ >
diff --git a/gui/src/components/onboarding/pages/body-proportions/BodyProportions.tsx b/gui/src/components/onboarding/pages/body-proportions/BodyProportions.tsx index 3a6d099aa..b56a7bd58 100644 --- a/gui/src/components/onboarding/pages/body-proportions/BodyProportions.tsx +++ b/gui/src/components/onboarding/pages/body-proportions/BodyProportions.tsx @@ -6,7 +6,6 @@ import { useEffect, useRef, UIEvent, - MouseEvent, useMemo, } from 'react'; import { @@ -17,6 +16,8 @@ import { import { useLocaleConfig } from '../../../../i18n/config'; import { Typography } from '../../../commons/Typography'; import { ArrowDownIcon, ArrowUpIcon } from '../../../commons/icon/ArrowIcons'; +import { useBreakpoint } from '../../../../hooks/breakpoint'; +import { debounce } from '../../../../hooks/timeout'; function IncrementButton({ children, @@ -52,8 +53,14 @@ export function BodyProportions({ const { bodyParts, dispatch, state, setRatioMode } = useManualProportions(); const { l10n } = useLocalization(); const { currentLocales } = useLocaleConfig(); + const { isTall } = useBreakpoint('tall'); - const srcollerRef = useRef(null); + const offsetItems = isTall ? 2 : 1; + const itemsToDisplay = offsetItems * 2 + 1; + const itemHeight = 80; + const scrollHeight = itemHeight * itemsToDisplay; + + const scrollerRef = useRef(null); const cmFormat = Intl.NumberFormat(currentLocales, { style: 'unit', @@ -78,41 +85,48 @@ export function BodyProportions({ }, [type]); useEffect(() => { - if (srcollerRef.current && bodyParts.length > 0) { - moveToIndex(1); + if (scrollerRef.current && bodyParts.length > 0) { + selectId(bodyParts[offsetItems].label); } - }, [srcollerRef, bodyParts.length]); + }, [scrollerRef, bodyParts.length]); const handleUIEvent = (e: UIEvent) => { const target = e.target as HTMLDivElement; - - const itemHeight = target.offsetHeight / 3; - + const itemHeight = target.offsetHeight / itemsToDisplay; const atSnappingPoint = target.scrollTop % itemHeight === 0; + const index = Math.round(target.scrollTop / itemHeight); + const elem = scrollerRef.current?.childNodes[ + index + offsetItems + ] as HTMLDivElement; + + elem.scrollIntoView({ behavior: 'smooth', block: 'center' }); if (atSnappingPoint) { - const index = target.scrollTop / itemHeight; - const elem = srcollerRef.current?.childNodes[index + 1] as HTMLDivElement; + const elem = scrollerRef.current?.childNodes[ + index + offsetItems + ] as HTMLDivElement; const id = elem.getAttribute('itemid'); + if (id) selectNew(id); } }; - const clickPart = (id: string) => (e: MouseEvent) => { - const target = e.target as HTMLDivElement; - target.scrollIntoView({ behavior: 'smooth', block: 'center' }); + const moveToId = (id: string) => { + if (!scrollerRef.current) return; + const index = bodyParts.findIndex(({ label }) => label === id); + scrollerRef.current.scrollTo({ + top: index * itemHeight, + behavior: 'smooth', + }); + }; + + const clickPart = (id: string) => () => { + moveToId(id); selectNew(id); }; - const moveToIndex = (index: number, smooth = true) => { - // We add one because of the offset placeholder - const elem = srcollerRef.current?.childNodes[index + 1] as HTMLDivElement; - elem?.scrollIntoView({ - behavior: smooth ? 'smooth' : 'auto', - block: 'center', - }); - - const id = elem.getAttribute('itemid'); + const selectId = (id: string) => { + moveToId(id); if (id) selectNew(id); }; @@ -170,15 +184,12 @@ export function BodyProportions({ }, [state]); const move = (action: 'next' | 'prev') => { - const elem = srcollerRef.current?.querySelector( + const elem = scrollerRef.current?.querySelector( `div[itemid=${state.currentLabel}]` ); - const moveId = (id: string, elem: HTMLDivElement) => { - elem?.scrollIntoView({ - behavior: 'smooth', - block: 'center', - }); + const moveId = (id: string) => { + moveToId(id); selectNew(id); }; @@ -186,14 +197,14 @@ export function BodyProportions({ const prevElem = elem?.previousSibling as HTMLDivElement; const prevId = prevElem.getAttribute('itemid'); if (!prevId) return; - moveId(prevId, prevElem); + moveId(prevId); } if (action === 'next') { const nextElem = elem?.nextSibling as HTMLDivElement; const nextId = nextElem.getAttribute('itemid'); if (!nextId) return; - moveId(nextId, nextElem); + moveId(nextId); } }; @@ -264,7 +275,7 @@ export function BodyProportions({ className={classNames( 'h-12 w-32 rounded-lg bg-background-60 flex flex-col justify-center', 'items-center fill-background-10', - srcollerRef?.current?.scrollTop ?? 0 > 0 + scrollerRef?.current?.scrollTop ?? 0 > 0 ? 'opacity-100 active:bg-accent-background-30' : 'opacity-50' )} @@ -273,11 +284,17 @@ export function BodyProportions({
-
+ {Array.from({ length: offsetItems }).map((_, index) => ( +
+ ))} {bodyParts.map((part) => { const { label, value: originalValue, type, ...props } = part; const value = @@ -292,7 +309,8 @@ export function BodyProportions({ key={label} itemID={label} onClick={clickPart(label)} - className="snap-start h-20 flex-col flex justify-center" + style={{ height: itemHeight }} + className="flex-col flex justify-center" >
); })} -
+ {Array.from({ length: offsetItems }).map((_, index) => ( +
+ ))}
void, deps: any[], delay: numbe // eslint-disable-next-line react-hooks/exhaustive-deps }, [...(deps || []), delay]); }; + +export const debounce = any>(func: F, waitFor: number) => { + let timeout = 0; + + const debounced = (...args: any) => { + window.clearTimeout(timeout); + timeout = window.setTimeout(() => func(...args), waitFor); + }; + + return debounced as (...args: Parameters) => ReturnType; +}; diff --git a/gui/tailwind.config.ts b/gui/tailwind.config.ts index 143a68c01..cb6efaedc 100644 --- a/gui/tailwind.config.ts +++ b/gui/tailwind.config.ts @@ -163,6 +163,7 @@ const config = { 'md-max': { raw: 'not (min-width: 1100px)' }, lg: '1300px', xl: '1600px', + tall: { raw: '(min-height: 800px)'} }, extend: { colors: {