Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update mobile menu items and variant selector #38

Merged
merged 1 commit into from
Feb 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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