Skip to content

Commit

Permalink
feat(app-preview): add logic for mobile sidebar and update ui (#182)
Browse files Browse the repository at this point in the history
  • Loading branch information
lordelogos authored and shellscape committed Apr 20, 2024
1 parent adc87df commit d8bb796
Show file tree
Hide file tree
Showing 4 changed files with 110 additions and 54 deletions.
117 changes: 78 additions & 39 deletions apps/preview/app/src/components/nav.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Cross2Icon, QuestionMarkCircledIcon } from '@radix-ui/react-icons';
import { Cross2Icon, QuestionMarkCircledIcon, HamburgerMenuIcon } from '@radix-ui/react-icons';
import * as Popover from '@radix-ui/react-popover';
import * as ToggleGroup from '@radix-ui/react-toggle-group';
import classnames from 'classnames';
Expand All @@ -12,50 +12,89 @@ import { NavButton } from './nav-button';
interface NavProps extends React.ComponentPropsWithoutRef<'header'> {
activeView?: Views;
markup?: string;
openNav: () => void;
setActiveView?: (view: Views) => void;
title: string;
}

export const Nav = React.forwardRef<React.ElementRef<'header'>, Readonly<NavProps>>(
({ className, title, markup, activeView, setActiveView, ...props }, forwardedRef) => (
<header
ref={forwardedRef}
className={classnames(
'bg-dark-bg flex relative items-center px-6 justify-between h-[70px] border-b border-dark-bg-border',
className
)}
{...props}
>
<div className={`items-center overflow-hidden hidden lg:flex`}>
<h2 className="text-base font-bold truncate text">{title}</h2>
</div>
({ className, title, markup, activeView, setActiveView, openNav, ...props }, forwardedRef) => (
<>
<header
ref={forwardedRef}
className={classnames(
'bg-dark-bg flex relative items-center px-6 justify-between h-[70px] border-b border-dark-bg-border',
className
)}
{...props}
>
<div className="flex items-center gap-4">
<button
onClick={openNav}
className="inlne-block lg:hidden w-5 h-5"
aria-label="Toggle nav menu"
>
<HamburgerMenuIcon className="h-5 w-5" />
</button>
{!!title && (
<div className={`items-center overflow-hidden hidden lg:flex`}>
<h2 className="text-base font-bold truncate text">{title}</h2>
</div>
)}
</div>

<div>
<Popover.Root>
<Popover.Trigger asChild>
<button
className="align-top h-[20px] w-[20px] pt-[9px] mr-4"
aria-label="Preview Information"
>
<QuestionMarkCircledIcon className="h-[20px] w-[20px]" />
</button>
</Popover.Trigger>
<Popover.Portal>
<Popover.Content className="note" sideOffset={5}>
<div className="pt-4 text-xs">
The Desktop and Mobile views are <em>an approximation</em> of what your email
template will looke like on various devices. It should not be considered a source of
truth, but rather a guide for styling and layout. Always send a test email to your
target email clients for Quality Control, before sending emails in production.
</div>
<Popover.Close className="note-close" aria-label="Close">
<Cross2Icon />
</Popover.Close>
<Popover.Arrow className="note-arrow" />
</Popover.Content>
</Popover.Portal>
</Popover.Root>
{!!title && (
<div className="flex flex-row items-center gap-4">
<Popover.Root>
<Popover.Trigger asChild>
<button className="h-5 w-5" aria-label="Preview Information">
<QuestionMarkCircledIcon className="h-5 w-5" />
</button>
</Popover.Trigger>
<Popover.Portal>
<Popover.Content className="note" sideOffset={5}>
<div className="pt-4 text-xs">
The Desktop and Mobile views are <em>an approximation</em> of what your email
template will looke like on various devices. It should not be considered a
source of truth, but rather a guide for styling and layout. Always send a test
email to your target email clients for Quality Control, before sending emails in
production.
</div>
<Popover.Close className="note-close" aria-label="Close">
<Cross2Icon />
</Popover.Close>
<Popover.Arrow className="note-arrow" />
</Popover.Content>
</Popover.Portal>
</Popover.Root>

<LayoutGroup id="topbar">
{setActiveView && (
<ToggleGroup.Root
className="hidden sm:inline-block items-center bg-darker-bg border border-dark-bg-border rounded overflow-hidden"
type="single"
value={activeView}
aria-label="View mode"
onValueChange={(value) => {
if (value) setActiveView(value as Views);
}}
>
<NavButton
activeView={activeView}
addClassNames="px-1 py-1 sm:px-3 sm:py-2"
label={Views.Desktop}
/>
<NavButton activeView={activeView} label={Views.Mobile} />
<NavButton activeView={activeView} label={Views.Jsx} />
<NavButton activeView={activeView} label={Views.Html} />
<NavButton activeView={activeView} label={Views.Plain} />
</ToggleGroup.Root>
)}
</LayoutGroup>
</div>
)}
</header>
<div className="bg-dark-bg h-[70px] flex sm:hidden items-center justify-center">
<LayoutGroup id="topbar">
{setActiveView && (
<ToggleGroup.Root
Expand All @@ -80,7 +119,7 @@ export const Nav = React.forwardRef<React.ElementRef<'header'>, Readonly<NavProp
)}
</LayoutGroup>
</div>
</header>
</>
)
);

Expand Down
2 changes: 1 addition & 1 deletion apps/preview/app/src/components/send.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ export const Send: React.FC<SendProps> = ({ markup }) => {
<div className="rounded bg-darker-bg absolute top-[20px] right-[20px] w-7 h-7 animate-[ping_1s_cubic-bezier(0,0,0.2,1)_2]" />
<Popover.Trigger asChild>
<IconButton
className="bg-darker-bg p-1 rounded focus:text-dark-bg-text ease-in-out transition duration-200 focus:outline-none focus:ring-2 focus:ring-gray-8 hover:text-dark-bg-text absolute top-[20px] right-[20px] hidden md:block"
className="bg-darker-bg p-1 rounded focus:text-dark-bg-text ease-in-out transition duration-200 focus:outline-none focus:ring-2 focus:ring-gray-8 hover:text-dark-bg-text absolute top-[20px] right-[20px]"
title="Send preview email"
>
<IconPaperAirplane />
Expand Down
20 changes: 10 additions & 10 deletions apps/preview/app/src/components/shell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,13 @@ interface ShellProps extends RootProps {

export const Shell = React.forwardRef<ShellElement, Readonly<ShellProps>>(
({ title, templateParts, children, html, activeView, setActiveView }, forwardedRef) => {
const [showNav] = React.useState(false);
const [showNav, setShowNav] = React.useState(false);
return (
<div className="flex flex-col h-screen overflow-x-hidden">
<div ref={forwardedRef} className="flex justify-between h-full">
<Sidebar
className={classNames('w-screen max-w-full md:max-w-[275px]', {
closeNav={() => setShowNav(false)}
className={classNames('w-screen max-w-full lg:max-w-[275px]', {
'translate-x-[-100%] lg:translate-x-0 absolute lg:relative': !showNav,
'translate-x-0': showNav
})}
Expand All @@ -36,14 +37,13 @@ export const Shell = React.forwardRef<ShellElement, Readonly<ShellProps>>(
'w-screen lg:w-[calc(100%_-_275px)]': !showNav
})}
>
{title && (
<Nav
title={title}
activeView={activeView}
setActiveView={setActiveView}
markup={html}
/>
)}
<Nav
title={title}
activeView={activeView}
setActiveView={setActiveView}
markup={html}
openNav={() => setShowNav(true)}
/>
<div className="relative h-[calc(100vh_-_70px)] overflow-auto">
<div className="mx-auto">{children}</div>
</div>
Expand Down
25 changes: 21 additions & 4 deletions apps/preview/app/src/components/sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import classnames from 'classnames';
import * as React from 'react';
import { Link, useLocation } from 'react-router-dom';

import { Cross1Icon } from '@radix-ui/react-icons';

import type { TemplatePart } from '../types';

import { Logo } from './logo';
Expand All @@ -11,11 +13,13 @@ type SidebarElement = React.ElementRef<'aside'>;
type RootProps = React.ComponentPropsWithoutRef<'aside'>;

interface SidebarProps extends RootProps {
closeNav: () => void;
templateParts: TemplatePart[];
title?: string;
}

interface SidebarSectionProps {
closeNav: () => void;
currentPageTitle: string;
isSubSection?: boolean;
templateParts: TemplatePart[];
Expand Down Expand Up @@ -80,7 +84,8 @@ const FileName = () => (
</svg>
);

const SidebarSection = ({
export const SidebarSection = ({
closeNav,
templateParts,
currentPageTitle,
isSubSection,
Expand Down Expand Up @@ -140,6 +145,7 @@ const SidebarSection = ({
return isParent ? (
<div className="pl-4" key={item.name}>
<SidebarSection
closeNav={closeNav}
templateParts={item.children}
currentPageTitle={currentPageTitle}
title={item.name}
Expand All @@ -156,6 +162,7 @@ const SidebarSection = ({
}
key={item.name}
to={`/${item.path}`}
onClick={closeNav}
>
<span
className={classnames(
Expand Down Expand Up @@ -187,11 +194,21 @@ const SidebarSection = ({
};

export const Sidebar = React.forwardRef<SidebarElement, Readonly<SidebarProps>>(
({ className, templateParts, title, ...props }, forwardedRef) => (
({ className, templateParts, closeNav, title, ...props }, forwardedRef) => (
<aside ref={forwardedRef} className={className} {...props}>
<nav className="h-full p-6 w-screen md:w-full md:min-w-[275px] md:max-w-[275px] flex flex-col gap-4 border-r border-dark-bg-border">
<Logo />
<nav className="h-full p-6 w-screen lg:w-full lg:min-w-[275px] lg:max-w-[275px] flex flex-col gap-4 border-r border-dark-bg-border">
<div className="flex items-center justify-between">
<Logo />
<button
onClick={closeNav}
className="inlne-block lg:hidden w-5 h-5"
aria-label="Toggle nav menu"
>
<Cross1Icon className="w-5 h-5" />
</button>
</div>
<SidebarSection
closeNav={closeNav}
templateParts={templateParts}
currentPageTitle={title}
title="Email Templates"
Expand Down

0 comments on commit d8bb796

Please sign in to comment.