Skip to content

Commit

Permalink
feature: add info drawer
Browse files Browse the repository at this point in the history
  • Loading branch information
vitormv committed Feb 25, 2024
1 parent 696fe0f commit 423cbd5
Show file tree
Hide file tree
Showing 5 changed files with 177 additions and 40 deletions.
2 changes: 1 addition & 1 deletion src/app/page.tsx
Expand Up @@ -40,7 +40,7 @@ export default function Home() {
<main
className={cn({
'relative flex h-full flex-1 flex-col items-center': true,
'gap-10 p-4 md:p-10': !funnel,
'gap-10 p-4 py-10 sm:p-10': !funnel,
})}
>
{loading && (
Expand Down
70 changes: 56 additions & 14 deletions src/components/FunnelPreview.tsx
Expand Up @@ -6,8 +6,10 @@ import { ImageBlock } from 'src/components/blocks/ImageBlock';
import { ListBlock } from 'src/components/blocks/ListBlock';
import { TextBlock } from 'src/components/blocks/TextBlock';
import { ProgressBar } from 'src/components/common/ProgressBar';
import { ChevronLeftIcon, ChevronRightIcon } from '@heroicons/react/24/outline';
import { FunnelType, PageType } from 'src/funnel.types';
import { useHorizontalSwipe } from 'src/hooks/useHorizontalSwipe';
import { cn } from 'src/utils/cn';

type Props = {
funnel: FunnelType;
Expand Down Expand Up @@ -64,24 +66,64 @@ export const FunnelPreview = ({ funnel }: Props) => {
onTouchEnd={swipeHandler.onTouchEnd}
onTouchMove={swipeHandler.onTouchMove}
>
<div
className={`relative flex w-full max-w-full flex-1 flex-col overflow-hidden md:max-w-xl`}
>
<div className="flex w-full flex-1 justify-between gap-20">
<button
type="button"
className={cn({
'fixed left-0 top-1/2 hidden': true,
hidden: funnel.pages.length < 2,
'md:block': funnel.pages.length > 1,
})}
onClick={onNavigateBackwards}
disabled={activePage === 0}
>
<ChevronLeftIcon
className={cn({
'h-20 w-20 text-primary': true,
'hover:text-primary-highlight': activePage > 0,
'cursor-default text-gray-400': activePage === 0,
})}
/>
</button>

<div
key={`page.${activePage}-${funnel.pages.length}`}
className={`h-full w-full flex-1 animate-page-appear overflow-hidden`}
className={`relative mx-auto flex w-full max-w-full flex-1 flex-col overflow-hidden md:max-w-xl`}
>
<div className="flex h-full w-full flex-1 flex-col gap-6 overflow-y-auto p-4 md:my-10">
{currentPage.blocks.map((block, i) => (
<Fragment key={block.id}>
{block.type === 'text' && <TextBlock {...block} hasAppearAnimation={i === 0} />}
{block.type === 'image' && <ImageBlock {...block} />}
{block.type === 'list' && <ListBlock {...block} />}
{block.type === 'button' && <ButtonBlock {...block} />}
</Fragment>
))}
<div
key={`page.${activePage}-${funnel.pages.length}`}
className={`h-full w-full flex-1 animate-page-appear overflow-hidden`}
>
<div className="flex h-full w-full flex-1 flex-col gap-6 overflow-y-auto p-4 md:my-10">
{currentPage.blocks.map((block, i) => (
<Fragment key={block.id}>
{block.type === 'text' && <TextBlock {...block} hasAppearAnimation={i === 0} />}
{block.type === 'image' && <ImageBlock {...block} />}
{block.type === 'list' && <ListBlock {...block} />}
{block.type === 'button' && <ButtonBlock {...block} />}
</Fragment>
))}
</div>
</div>
</div>

<button
type="button"
className={cn({
'fixed right-0 top-1/2 hidden': true,
hidden: funnel.pages.length < 2,
'md:block': funnel.pages.length > 1,
})}
onClick={onNavigateForward}
disabled={activePage >= maxPageIndex}
>
<ChevronRightIcon
className={cn({
'h-20 w-20 text-primary transition-transform active:scale-90': true,
'hover:text-primary-highlight': activePage < maxPageIndex,
'cursor-default text-gray-400': activePage >= maxPageIndex,
})}
/>
</button>
</div>

<div className="flex-0 fixed bottom-0 w-full pt-2">
Expand Down
59 changes: 59 additions & 0 deletions src/components/layout/InfoDrawer.tsx
@@ -0,0 +1,59 @@
import { Dialog, Transition } from '@headlessui/react';
import { QuestionMarkCircleIcon, XMarkIcon } from '@heroicons/react/24/outline';
import { Fragment } from 'react';

type Props = {
isOpen: boolean;
setOpen: (open: boolean) => void;
};

export const InfoDrawer = ({ isOpen, setOpen }: Props) => {
return (
<Transition.Root show={isOpen} as={Fragment}>
<Dialog as="div" className="relative z-10" onClose={setOpen} open={isOpen}>
<div className="fixed inset-0 overflow-hidden">
<div className="absolute inset-0 overflow-hidden">
<div className="pointer-events-none fixed inset-x-0 bottom-0 flex max-w-full">
<Transition.Child
as={Fragment}
enter="transform transition ease-in-out duration-300"
enterFrom="translate-y-full"
enterTo="translate-y-0"
leave="transform transition ease-in-out duration-300"
leaveFrom="translate-y-0"
leaveTo="translate-y-full"
>
<Dialog.Panel className="pointer-events-auto relative w-screen border-t-2 border-t-primary bg-white px-4 py-6 shadow-[rgba(0,0,15,0.1)_0px_-3px_10px_4px]">
<Dialog.Title className="mb-4 flex justify-between gap-4 text-base font-semibold leading-6 text-gray-900">
<div className="flex items-center gap-4 text-primary">
<QuestionMarkCircleIcon
className="inline-block h-5 w-5 align-middle"
aria-hidden="true"
/>
<span>Navigation</span>
</div>
<button
type="button"
className="inline-flex h-8 w-8 items-center justify-center rounded-lg bg-transparent text-sm text-gray-400 hover:bg-gray-200 hover:text-gray-900 dark:hover:bg-gray-600 dark:hover:text-white"
onClick={() => setOpen(false)}
>
<XMarkIcon className="inline-block h-6 w-6" aria-hidden="true" />
</button>
</Dialog.Title>

<p className="mb-6 max-w-lg text-sm text-gray-800">
<strong>On desktop</strong>, you can navigate through the funnel using the&nbsp;
<strong>keyboard arrows keys</strong>, or by clicking the arrows on either side.
</p>
<p className="mb-6 max-w-lg text-sm text-gray-800">
<strong>On mobile</strong>, you can use swipe navigation to move between pages.
</p>
</Dialog.Panel>
</Transition.Child>
</div>
</div>
</div>
</Dialog>
</Transition.Root>
);
};
46 changes: 28 additions & 18 deletions src/components/layout/Navbar.tsx
@@ -1,7 +1,8 @@
'use client';

import { Bars3Icon, XMarkIcon } from '@heroicons/react/24/outline';
import { Bars3Icon, QuestionMarkCircleIcon, XMarkIcon } from '@heroicons/react/24/outline';
import { useCallback, useState } from 'react';
import { InfoDrawer } from 'src/components/layout/InfoDrawer';
import { Sidebar } from 'src/components/layout/Sidebar';
import { FunnelType } from 'src/funnel.types';

Expand All @@ -10,11 +11,12 @@ type Props = {
};

export const Navbar = ({ onSelectFunnel }: Props) => {
const [open, setOpen] = useState(false);
const [sidebarOpen, setSidebarOpen] = useState(false);
const [infoDrawerOpen, setInfoDrawerOpen] = useState(false);

const onFunnelChosen = useCallback(
(funnel: FunnelType) => {
setOpen(false);
setSidebarOpen(false);
onSelectFunnel(funnel);
},
[onSelectFunnel],
Expand All @@ -32,21 +34,29 @@ export const Navbar = ({ onSelectFunnel }: Props) => {
</div>
</a>

<button
type="button"
className="relative inline-flex items-center justify-center rounded-md p-2 text-gray-400 hover:bg-primary hover:text-white focus:outline-none focus:ring-2 focus:ring-inset focus:ring-white"
onClick={() => setOpen(true)}
>
<span className="absolute -inset-0.5" />
<span className="sr-only">Open main menu</span>
{open ? (
<XMarkIcon className="block h-6 w-6" aria-hidden="true" />
) : (
<Bars3Icon className="block h-6 w-6" aria-hidden="true" />
)}
</button>

<Sidebar isOpen={open} setOpen={setOpen} onSelectFunnel={onFunnelChosen} />
<div>
<button
type="button"
className="relative inline-flex items-center justify-center rounded-md p-2 text-gray-400 hover:bg-primary hover:text-white focus:outline-none focus:ring-2 focus:ring-inset focus:ring-white"
onClick={() => setInfoDrawerOpen(true)}
>
<QuestionMarkCircleIcon className="block h-6 w-6" aria-hidden="true" />
</button>
<button
type="button"
className="relative inline-flex items-center justify-center rounded-md p-2 text-gray-400 hover:bg-primary hover:text-white focus:outline-none focus:ring-2 focus:ring-inset focus:ring-white"
onClick={() => setSidebarOpen(true)}
>
{sidebarOpen ? (
<XMarkIcon className="block h-6 w-6" aria-hidden="true" />
) : (
<Bars3Icon className="block h-6 w-6" aria-hidden="true" />
)}
</button>
</div>

<Sidebar isOpen={sidebarOpen} setOpen={setSidebarOpen} onSelectFunnel={onFunnelChosen} />
<InfoDrawer isOpen={infoDrawerOpen} setOpen={setInfoDrawerOpen} />
</nav>
);
};
40 changes: 33 additions & 7 deletions src/content/funnel.sheltie.json
Expand Up @@ -9,7 +9,7 @@
"id": "block1",
"type": "text",
"text": "Welcome to Shetland Sheepdogs Facts.",
"color": "#202020",
"color": "#1D2325",
"align": "center"
},
{
Expand All @@ -21,7 +21,7 @@
"id": "block3",
"type": "text",
"text": "Let's learn about these wonderful creatures:",
"color": "#202020",
"color": "#1D2325",
"align": "center"
},
{
Expand Down Expand Up @@ -49,8 +49,8 @@
"id": "block5",
"type": "button",
"text": "Next Page",
"color": "white",
"bgColor": "#0076FF"
"color": "#1D2325",
"bgColor": "#D79C75"
}
]
},
Expand All @@ -61,7 +61,14 @@
"id": "block9",
"type": "text",
"text": "Even more about Shetland Sheepdogs!",
"color": "#202020",
"color": "#1D2325",
"align": "center"
},
{
"id": "block9.5",
"type": "text",
"text": "Because we can't resist these adorable faces 😍",
"color": "#1D2325",
"align": "center"
},
{
Expand Down Expand Up @@ -94,8 +101,27 @@
"id": "block12",
"type": "button",
"text": "Next Page",
"color": "white",
"bgColor": "#0076FF"
"color": "#1D2325",
"bgColor": "#D79C75"
}
]
},
{
"id": "page3",
"blocks": [
{
"id": "block9",
"type": "text",
"text": "Thanks for taking the time to learn something new today 😄",
"color": "#1D2325",
"align": "center"
},
{
"id": "block12",
"type": "button",
"text": "Thanks for the info!",
"color": "#1D2325",
"bgColor": "#D79C75"
}
]
}
Expand Down

0 comments on commit 423cbd5

Please sign in to comment.