Skip to content

Commit

Permalink
Merge pull request #38 from thomasKn/thomas/fv-246-mobile-menu-item-w…
Browse files Browse the repository at this point in the history
…idth

Update mobile menu items and variant selector
  • Loading branch information
thomasKn authored Feb 6, 2024
2 parents 9200b6b + cba3a09 commit 6b2758e
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 28 deletions.
70 changes: 50 additions & 20 deletions app/components/layout/NavigationProgressBar.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,38 @@
import {useNavigation} from '@remix-run/react';
import {useNProgress} from '@tanem/react-nprogress';
import {AnimatePresence, m} from 'framer-motion';
import {useEffect, useState} from 'react';

export function NavigationProgressBar() {
const navigation = useNavigation();
const isLoading = navigation.state !== 'idle';
const [isLoading, setIsLoading] = useState(false);
const {animationDuration, isFinished, progress} = useNProgress({
isAnimating: isLoading,
});
const delay = 300;

// Delay the progress bar apparing to avoid flickering when the page loads quickly
useEffect(() => {
const timeout = setTimeout(() => {
setIsLoading(navigation.state !== 'idle');
}, delay);

return () => clearTimeout(timeout);
}, [navigation.state]);

return (
<Container animationDuration={animationDuration} isFinished={isFinished}>
<Bar animationDuration={animationDuration} progress={progress} />
</Container>
);
}

function Container(props: {
animationDuration: number;
children: React.ReactNode;
isFinished: boolean;
}) {
const {animationDuration, children, isFinished} = props;

return (
<AnimatePresence>
Expand All @@ -17,30 +42,35 @@ export function NavigationProgressBar() {
exit={{opacity: 0}}
initial={{opacity: 0}}
transition={{
delay: 0.15,
duration: animationDuration / 1000,
}}
>
<m.div
animate={{
marginLeft: `${(-1 + progress) * 100}%`,
transition: {
duration: animationDuration / 1000,
ease: 'linear',
},
}}
className="fixed left-0 top-0 z-[1042] h-[3px] w-full rounded-r-full bg-primary"
>
<div
className="absolute right-0 block h-full w-[100px] translate-y-[-4px] rotate-3 opacity-100"
style={{
boxShadow:
'0 0 10px rgb(var(--primary)), 0 0 5px rgb(var(--primary))',
}}
/>
</m.div>
{children}
</m.div>
)}
</AnimatePresence>
);
}

function Bar(props: {animationDuration: number; progress: number}) {
const {animationDuration, progress} = props;
const marginLeft = `${(-1 + progress) * 100}%`;

return (
<m.div
className="fixed left-0 top-0 z-[1041] h-[3px] w-full rounded-r-full bg-primary"
style={{
marginLeft,
transition: `margin-left ${animationDuration}ms linear`,
}}
>
<div
className="absolute right-0 block h-full w-[100px] translate-y-[-4px] rotate-3 opacity-100"
style={{
boxShadow:
'0 0 10px rgb(var(--primary)), 0 0 5px rgb(var(--primary))',
}}
/>
</m.div>
);
}
31 changes: 23 additions & 8 deletions app/components/navigation/MobileNavigation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ import {
DrawerTrigger,
} from '../ui/Drawer';

const mobileMenuLinkClass = cn(
'flex rounded-md px-3 py-2 items-center gap-2 w-full transition-colors hover:bg-accent hover:text-accent-foreground',
);

export function MobileNavigation(props: {data?: NavigationProps}) {
const [open, setOpen] = useState(false);
const device = useDevice();
Expand All @@ -41,9 +45,11 @@ export function MobileNavigation(props: {data?: NavigationProps}) {
props.data?.map((item) => (
<li key={item._key}>
{item._type === 'internalLink' && (
<div onClick={handleClose}>
<SanityInternalLink data={item} />
</div>
<SanityInternalLink
className={mobileMenuLinkClass}
data={item}
onClick={handleClose}
/>
)}
{item._type === 'externalLink' && (
<div onClick={handleClose}>
Expand Down Expand Up @@ -77,7 +83,7 @@ function MobileNavigationContent(props: {
onOpenAutoFocus={(e) => e.preventDefault()}
>
<nav className="mt-4 flex h-full flex-col gap-0 p-6">
<ul className="flex flex-1 flex-col gap-4 overflow-x-hidden overflow-y-scroll pb-6 text-xl font-medium">
<ul className="flex flex-1 flex-col gap-2 overflow-x-hidden overflow-y-scroll pb-6 text-xl font-medium">
{props.children}
</ul>
</nav>
Expand Down Expand Up @@ -107,7 +113,7 @@ function MobileNavigationNested(props: {
onOpenChange={setOpen}
open={open}
>
<DrawerTrigger className="flex items-center gap-2">
<DrawerTrigger className={mobileMenuLinkClass}>
{data.name}
<span>
<IconChevron className="size-5" direction="right" />
Expand All @@ -122,11 +128,18 @@ function MobileNavigationNested(props: {
{childLinks &&
childLinks.length > 0 &&
childLinks.map((child) => (
<li key={child._key} onClick={handleClose}>
<li key={child._key}>
{child._type === 'internalLink' ? (
<SanityInternalLink data={child} />
<SanityInternalLink
className={mobileMenuLinkClass}
data={child}
onClick={handleClose}
/>
) : child._type === 'externalLink' ? (
<SanityExternalLink data={child} />
<SanityExternalLink
className={mobileMenuLinkClass}
data={child}
/>
) : null}
</li>
))}
Expand All @@ -135,13 +148,15 @@ function MobileNavigationNested(props: {
) : data.link && data.name && (!childLinks || childLinks.length === 0) ? (
// Render internal link if no child links
<SanityInternalLink
className={mobileMenuLinkClass}
data={{
_key: data._key,
_type: 'internalLink',
anchor: null,
link: data.link,
name: data.name,
}}
onClick={handleClose}
>
{data.name}
</SanityInternalLink>
Expand Down
1 change: 1 addition & 0 deletions app/components/product/VariantSelector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@ function Pills(props: {
)}
<m.span
className="inline-flex h-8 select-none items-center justify-center whitespace-nowrap px-3 py-1.5"
tabIndex={-1}
whileTap={{scale: 0.9}}
>
{value}
Expand Down
3 changes: 3 additions & 0 deletions app/components/sanity/link/SanityInternalLink.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import type {LinkProps} from '@remix-run/react';
import type {TypeFromSelection} from 'groqd';

import {Link} from '@remix-run/react';
Expand All @@ -14,6 +15,7 @@ export function SanityInternalLink(props: {
children?: React.ReactNode;
className?: string;
data?: SanityInternalLinkProps;
onClick?: () => void;
}) {
const locale = useLocale();
const {children, className, data} = props;
Expand Down Expand Up @@ -53,6 +55,7 @@ export function SanityInternalLink(props: {
'focus-visible:rounded-md focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2',
className,
])}
onClick={props.onClick}
prefetch="intent"
to={url}
>
Expand Down

0 comments on commit 6b2758e

Please sign in to comment.