Add subtle transitions to sidebars (#344)
This commit is contained in:
@ -1,10 +1,11 @@
|
|||||||
import { Popover } from '@headlessui/react'
|
import { Popover, Transition } from '@headlessui/react'
|
||||||
import { ActionButton } from './ActionButton'
|
import { ActionButton } from './ActionButton'
|
||||||
import { faHome } from '@fortawesome/free-solid-svg-icons'
|
import { faHome } from '@fortawesome/free-solid-svg-icons'
|
||||||
import { ProjectWithEntryPointMetadata, paths } from '../Router'
|
import { ProjectWithEntryPointMetadata, paths } from '../Router'
|
||||||
import { isTauri } from '../lib/isTauri'
|
import { isTauri } from '../lib/isTauri'
|
||||||
import { Link } from 'react-router-dom'
|
import { Link } from 'react-router-dom'
|
||||||
import { ExportButton } from './ExportButton'
|
import { ExportButton } from './ExportButton'
|
||||||
|
import { Fragment } from 'react'
|
||||||
|
|
||||||
const ProjectSidebarMenu = ({
|
const ProjectSidebarMenu = ({
|
||||||
project,
|
project,
|
||||||
@ -34,7 +35,7 @@ const ProjectSidebarMenu = ({
|
|||||||
) : (
|
) : (
|
||||||
<Popover className="relative">
|
<Popover className="relative">
|
||||||
<Popover.Button
|
<Popover.Button
|
||||||
className="border-0 px-1 pr-2 pl-0 flex items-center gap-4 focus:outline-none focus:ring-2 focus:ring-energy-50"
|
className="border-0 p-0.5 pr-2 flex items-center gap-4 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-energy-50"
|
||||||
data-testid="project-sidebar-toggle"
|
data-testid="project-sidebar-toggle"
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
@ -46,54 +47,77 @@ const ProjectSidebarMenu = ({
|
|||||||
{isTauri() && project?.name ? project.name : 'KittyCAD Modeling App'}
|
{isTauri() && project?.name ? project.name : 'KittyCAD Modeling App'}
|
||||||
</span>
|
</span>
|
||||||
</Popover.Button>
|
</Popover.Button>
|
||||||
<Popover.Overlay className="fixed z-20 inset-0 bg-chalkboard-110/50" />
|
<Transition
|
||||||
|
enter="duration-200 ease-out"
|
||||||
|
enterFrom="opacity-0"
|
||||||
|
enterTo="opacity-100"
|
||||||
|
leave="duration-100 ease-in"
|
||||||
|
leaveFrom="opacity-100"
|
||||||
|
leaveTo="opacity-0"
|
||||||
|
as={Fragment}
|
||||||
|
>
|
||||||
|
<Popover.Overlay className="fixed z-20 inset-0 bg-chalkboard-110/50" />
|
||||||
|
</Transition>
|
||||||
|
|
||||||
<Popover.Panel className="fixed inset-0 right-auto z-30 w-64 bg-chalkboard-10 dark:bg-chalkboard-100 border border-energy-100 shadow-md rounded-r-lg overflow-hidden">
|
<Transition
|
||||||
<div className="flex items-center gap-4 px-4 py-3 bg-energy-100">
|
enter="duration-100 ease-out"
|
||||||
<img
|
enterFrom="opacity-0 -translate-x-1/4"
|
||||||
src="/kitt-8bit-winking.svg"
|
enterTo="opacity-100 translate-x-0"
|
||||||
alt="KittyCAD App"
|
leave="duration-75 ease-in"
|
||||||
className="h-9 w-auto"
|
leaveFrom="opacity-100 translate-x-0"
|
||||||
/>
|
leaveTo="opacity-0 -translate-x-4"
|
||||||
|
as={Fragment}
|
||||||
|
>
|
||||||
|
<Popover.Panel className="fixed inset-0 right-auto z-30 w-64 bg-chalkboard-10 dark:bg-chalkboard-100 border border-energy-100 dark:border-energy-100/50 shadow-md rounded-r-lg overflow-hidden">
|
||||||
|
<div className="flex items-center gap-4 px-4 py-3 bg-energy-100">
|
||||||
|
<img
|
||||||
|
src="/kitt-8bit-winking.svg"
|
||||||
|
alt="KittyCAD App"
|
||||||
|
className="h-9 w-auto"
|
||||||
|
/>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<p
|
<p
|
||||||
className="m-0 text-energy-10 text-mono"
|
className="m-0 text-energy-10 text-mono"
|
||||||
data-testid="projectName"
|
data-testid="projectName"
|
||||||
>
|
>
|
||||||
{project?.name ? project.name : 'KittyCAD Modeling App'}
|
{project?.name ? project.name : 'KittyCAD Modeling App'}
|
||||||
</p>
|
|
||||||
{project?.entrypoint_metadata && (
|
|
||||||
<p className="m-0 text-energy-40 text-xs" data-testid="createdAt">
|
|
||||||
Created{' '}
|
|
||||||
{project?.entrypoint_metadata.createdAt.toLocaleDateString()}
|
|
||||||
</p>
|
</p>
|
||||||
|
{project?.entrypoint_metadata && (
|
||||||
|
<p
|
||||||
|
className="m-0 text-energy-40 text-xs"
|
||||||
|
data-testid="createdAt"
|
||||||
|
>
|
||||||
|
Created{' '}
|
||||||
|
{project?.entrypoint_metadata.createdAt.toLocaleDateString()}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="p-4 flex flex-col gap-2">
|
||||||
|
<ExportButton
|
||||||
|
className={{
|
||||||
|
button:
|
||||||
|
'border-transparent dark:border-transparent dark:hover:border-energy-60',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Export Model
|
||||||
|
</ExportButton>
|
||||||
|
{isTauri() && (
|
||||||
|
<ActionButton
|
||||||
|
Element="link"
|
||||||
|
to={paths.HOME}
|
||||||
|
icon={{
|
||||||
|
icon: faHome,
|
||||||
|
}}
|
||||||
|
className="border-transparent dark:border-transparent dark:hover:border-energy-60"
|
||||||
|
>
|
||||||
|
Go to Home
|
||||||
|
</ActionButton>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</Popover.Panel>
|
||||||
<div className="p-4 flex flex-col gap-2">
|
</Transition>
|
||||||
<ExportButton
|
|
||||||
className={{
|
|
||||||
button:
|
|
||||||
'border-transparent dark:border-transparent dark:hover:border-energy-60',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Export Model
|
|
||||||
</ExportButton>
|
|
||||||
{isTauri() && (
|
|
||||||
<ActionButton
|
|
||||||
Element="link"
|
|
||||||
to={paths.HOME}
|
|
||||||
icon={{
|
|
||||||
icon: faHome,
|
|
||||||
}}
|
|
||||||
className="border-transparent dark:border-transparent dark:hover:border-energy-60"
|
|
||||||
>
|
|
||||||
Go to Home
|
|
||||||
</ActionButton>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</Popover.Panel>
|
|
||||||
</Popover>
|
</Popover>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import { Popover } from '@headlessui/react'
|
import { Popover, Transition } from '@headlessui/react'
|
||||||
import { ActionButton } from './ActionButton'
|
import { ActionButton } from './ActionButton'
|
||||||
import { faBars, faGear, faSignOutAlt } from '@fortawesome/free-solid-svg-icons'
|
import { faBars, faGear, faSignOutAlt } from '@fortawesome/free-solid-svg-icons'
|
||||||
import { faGithub } from '@fortawesome/free-brands-svg-icons'
|
import { faGithub } from '@fortawesome/free-brands-svg-icons'
|
||||||
import { useNavigate } from 'react-router-dom'
|
import { useNavigate } from 'react-router-dom'
|
||||||
import { useState } from 'react'
|
import { Fragment, useState } from 'react'
|
||||||
import { paths } from '../Router'
|
import { paths } from '../Router'
|
||||||
import makeUrlPathRelative from '../lib/makeUrlPathRelative'
|
import makeUrlPathRelative from '../lib/makeUrlPathRelative'
|
||||||
import { Models } from '@kittycad/lib'
|
import { Models } from '@kittycad/lib'
|
||||||
@ -61,82 +61,102 @@ const UserSidebarMenu = ({ user }: { user?: User }) => {
|
|||||||
Menu
|
Menu
|
||||||
</ActionButton>
|
</ActionButton>
|
||||||
)}
|
)}
|
||||||
<Popover.Overlay className="fixed z-20 inset-0 bg-chalkboard-110/50" />
|
<Transition
|
||||||
|
enter="duration-200 ease-out"
|
||||||
|
enterFrom="opacity-0"
|
||||||
|
enterTo="opacity-100"
|
||||||
|
leave="duration-100 ease-in"
|
||||||
|
leaveFrom="opacity-100"
|
||||||
|
leaveTo="opacity-0"
|
||||||
|
as={Fragment}
|
||||||
|
>
|
||||||
|
<Popover.Overlay className="fixed z-20 inset-0 bg-chalkboard-110/50" />
|
||||||
|
</Transition>
|
||||||
|
|
||||||
<Popover.Panel className="fixed inset-0 left-auto z-30 w-64 bg-chalkboard-10 dark:bg-chalkboard-100 border border-liquid-100 shadow-md rounded-l-lg overflow-hidden">
|
<Transition
|
||||||
{({ close }) => (
|
enter="duration-100 ease-out"
|
||||||
<>
|
enterFrom="opacity-0 translate-x-1/4"
|
||||||
{user && (
|
enterTo="opacity-100 translate-x-0"
|
||||||
<div className="flex items-center gap-4 px-4 py-3 bg-liquid-100">
|
leave="duration-75 ease-in"
|
||||||
{user.image && !imageLoadFailed && (
|
leaveFrom="opacity-100 translate-x-0"
|
||||||
<div className="rounded-full shadow-inner overflow-hidden">
|
leaveTo="opacity-0 translate-x-4"
|
||||||
<img
|
as={Fragment}
|
||||||
src={user.image}
|
>
|
||||||
alt={user.name || ''}
|
<Popover.Panel className="fixed inset-0 left-auto z-30 w-64 bg-chalkboard-10 dark:bg-chalkboard-100 border border-liquid-100 dark:border-liquid-100/50 shadow-md rounded-l-lg overflow-hidden">
|
||||||
className="h-8 w-8"
|
{({ close }) => (
|
||||||
referrerPolicy="no-referrer"
|
<>
|
||||||
onError={() => setImageLoadFailed(true)}
|
{user && (
|
||||||
/>
|
<div className="flex items-center gap-4 px-4 py-3 bg-liquid-100">
|
||||||
</div>
|
{user.image && !imageLoadFailed && (
|
||||||
)}
|
<div className="rounded-full shadow-inner overflow-hidden">
|
||||||
|
<img
|
||||||
<div>
|
src={user.image}
|
||||||
<p
|
alt={user.name || ''}
|
||||||
className="m-0 text-liquid-10 text-mono"
|
className="h-8 w-8"
|
||||||
data-testid="username"
|
referrerPolicy="no-referrer"
|
||||||
>
|
onError={() => setImageLoadFailed(true)}
|
||||||
{displayedName || ''}
|
/>
|
||||||
</p>
|
</div>
|
||||||
{displayedName !== user.email && (
|
|
||||||
<p
|
|
||||||
className="m-0 text-liquid-40 text-xs"
|
|
||||||
data-testid="email"
|
|
||||||
>
|
|
||||||
{user.email}
|
|
||||||
</p>
|
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<p
|
||||||
|
className="m-0 text-liquid-10 text-mono"
|
||||||
|
data-testid="username"
|
||||||
|
>
|
||||||
|
{displayedName || ''}
|
||||||
|
</p>
|
||||||
|
{displayedName !== user.email && (
|
||||||
|
<p
|
||||||
|
className="m-0 text-liquid-40 text-xs"
|
||||||
|
data-testid="email"
|
||||||
|
>
|
||||||
|
{user.email}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
)}
|
||||||
|
<div className="p-4 flex flex-col gap-2">
|
||||||
|
<ActionButton
|
||||||
|
Element="button"
|
||||||
|
icon={{ icon: faGear }}
|
||||||
|
className="border-transparent dark:border-transparent dark:hover:border-liquid-60"
|
||||||
|
onClick={() => {
|
||||||
|
// since /settings is a nested route the sidebar doesn't close
|
||||||
|
// automatically when navigating to it
|
||||||
|
close()
|
||||||
|
navigate(makeUrlPathRelative(paths.SETTINGS))
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Settings
|
||||||
|
</ActionButton>
|
||||||
|
<ActionButton
|
||||||
|
Element="link"
|
||||||
|
to="https://github.com/KittyCAD/modeling-app/discussions"
|
||||||
|
icon={{ icon: faGithub }}
|
||||||
|
className="border-transparent dark:border-transparent dark:hover:border-liquid-60"
|
||||||
|
>
|
||||||
|
Request a feature
|
||||||
|
</ActionButton>
|
||||||
|
<ActionButton
|
||||||
|
Element="button"
|
||||||
|
onClick={() => send('Log out')}
|
||||||
|
icon={{
|
||||||
|
icon: faSignOutAlt,
|
||||||
|
bgClassName: 'bg-destroy-80',
|
||||||
|
iconClassName:
|
||||||
|
'text-destroy-20 group-hover:text-destroy-10 hover:text-destroy-10',
|
||||||
|
}}
|
||||||
|
className="border-transparent dark:border-transparent hover:border-destroy-40 dark:hover:border-destroy-60"
|
||||||
|
>
|
||||||
|
Sign out
|
||||||
|
</ActionButton>
|
||||||
</div>
|
</div>
|
||||||
)}
|
</>
|
||||||
<div className="p-4 flex flex-col gap-2">
|
)}
|
||||||
<ActionButton
|
</Popover.Panel>
|
||||||
Element="button"
|
</Transition>
|
||||||
icon={{ icon: faGear }}
|
|
||||||
className="border-transparent dark:border-transparent dark:hover:border-liquid-60"
|
|
||||||
onClick={() => {
|
|
||||||
// since /settings is a nested route the sidebar doesn't close
|
|
||||||
// automatically when navigating to it
|
|
||||||
close()
|
|
||||||
navigate(makeUrlPathRelative(paths.SETTINGS))
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Settings
|
|
||||||
</ActionButton>
|
|
||||||
<ActionButton
|
|
||||||
Element="link"
|
|
||||||
to="https://github.com/KittyCAD/modeling-app/discussions"
|
|
||||||
icon={{ icon: faGithub }}
|
|
||||||
className="border-transparent dark:border-transparent dark:hover:border-liquid-60"
|
|
||||||
>
|
|
||||||
Request a feature
|
|
||||||
</ActionButton>
|
|
||||||
<ActionButton
|
|
||||||
Element="button"
|
|
||||||
onClick={() => send('Log out')}
|
|
||||||
icon={{
|
|
||||||
icon: faSignOutAlt,
|
|
||||||
bgClassName: 'bg-destroy-80',
|
|
||||||
iconClassName:
|
|
||||||
'text-destroy-20 group-hover:text-destroy-10 hover:text-destroy-10',
|
|
||||||
}}
|
|
||||||
className="border-transparent dark:border-transparent hover:border-destroy-40 dark:hover:border-destroy-60"
|
|
||||||
>
|
|
||||||
Sign out
|
|
||||||
</ActionButton>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</Popover.Panel>
|
|
||||||
</Popover>
|
</Popover>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user