design: fixing system menu and nav, various design tweaks

This commit is contained in:
Hunter Miller 2021-09-02 14:48:11 -05:00
parent 797ae776e0
commit dea33d9019
11 changed files with 118 additions and 108 deletions

View File

@ -121,13 +121,13 @@ export const AppInfo: FC<AppInfoProps> = ({ docket, vat, className }) => {
</DocketHeader>
{vat ? (
<>
<hr className="-mx-5 sm:-mx-8" />
<hr className="-mx-5 sm:-mx-8 border-gray-50" />
<VatMeta vat={vat} />
</>
) : null}
{'chad' in docket ? null : (
<>
<hr className="-mx-5 sm:-mx-8" />
<hr className="-mx-5 sm:-mx-8 border-gray-50" />
<TreatyMeta treaty={docket} />
</>
)}

View File

@ -200,7 +200,7 @@ export const Leap = React.forwardRef(({ menu, dropdown, navOpen, className }: Le
<form
className={classNames(
'flex items-center h-full w-full px-2 rounded-full bg-white default-ring focus-within:ring-2',
navOpen && menu !== 'search' && 'opacity-80',
navOpen && menu !== 'search' && 'opacity-60',
!navOpen ? 'bg-gray-50' : '',
className
)}
@ -220,7 +220,7 @@ export const Leap = React.forwardRef(({ menu, dropdown, navOpen, className }: Le
type="text"
ref={inputRef}
placeholder={selection ? '' : 'Search Landscape'}
className="flex-1 w-full px-2 h4 rounded-full bg-transparent outline-none"
className="flex-1 w-full h-full px-2 h4 rounded-full bg-transparent outline-none"
value={rawInput}
onClick={toggleSearch}
onFocus={onFocus}
@ -234,7 +234,7 @@ export const Leap = React.forwardRef(({ menu, dropdown, navOpen, className }: Le
{navOpen && (
<Link
to="/"
className="absolute top-1/2 right-2 flex-none circle-button w-8 h-8 text-gray-400 bg-gray-100 default-ring -translate-y-1/2"
className="absolute top-1/2 right-2 flex-none circle-button w-8 h-8 text-gray-400 bg-gray-50 default-ring -translate-y-1/2"
onClick={() => select(null)}
>
<Cross className="w-3 h-3 fill-current" />

View File

@ -2,7 +2,7 @@ import { DialogContent } from '@radix-ui/react-dialog';
import * as Portal from '@radix-ui/react-portal';
import classNames from 'classnames';
import React, { FunctionComponent, useCallback, useEffect, useRef, useState } from 'react';
import { Route, Switch, useHistory } from 'react-router-dom';
import { Route, Switch, useHistory, useRouteMatch } from 'react-router-dom';
import create from 'zustand';
import { Dialog } from '../components/Dialog';
import { Help } from './Help';
@ -88,7 +88,7 @@ export const Nav: FunctionComponent<NavProps> = ({ menu }) => {
const inputRef = useRef<HTMLInputElement>(null);
const navRef = useRef<HTMLDivElement>(null);
const dialogNavRef = useRef<HTMLDivElement>(null);
const [systemMenuOpen, setSystemMenuOpen] = useState(false);
const systemMenuOpen = useRouteMatch('/system-menu');
const [dialogContentOpen, setDialogContentOpen] = useState(false);
const select = useLeapStore((state) => state.select);
@ -123,16 +123,6 @@ export const Nav: FunctionComponent<NavProps> = ({ menu }) => {
}
}, []);
const disableCloseWhenDropdownOpen = useCallback(
(e: Event, cb?: () => void) => {
if (systemMenuOpen) {
e.preventDefault();
cb && cb();
}
},
[systemMenuOpen]
);
return (
<>
{/* Using portal so that we can retain the same nav items both in the dialog and in the base header */}
@ -141,8 +131,7 @@ export const Nav: FunctionComponent<NavProps> = ({ menu }) => {
className="flex justify-center w-full space-x-2"
>
<SystemMenu
open={systemMenuOpen}
setOpen={setSystemMenuOpen}
open={!!systemMenuOpen}
menu={menuState}
navOpen={isOpen}
className={classNames('relative z-50 flex-none', eitherOpen ? 'bg-white' : 'bg-gray-50')}
@ -153,7 +142,7 @@ export const Nav: FunctionComponent<NavProps> = ({ menu }) => {
<div
ref={navRef}
className={classNames(
'w-full max-w-3xl my-6 px-4 text-gray-400 font-semibold',
'w-full max-w-[712px] mx-auto my-6 text-gray-400 font-semibold',
dialogContentOpen && 'h-12'
)}
role="combobox"
@ -164,18 +153,19 @@ export const Nav: FunctionComponent<NavProps> = ({ menu }) => {
<Dialog open={isOpen} onOpenChange={onDialogClose}>
<DialogContent
onOpenAutoFocus={onOpen}
onEscapeKeyDown={(e) => disableCloseWhenDropdownOpen(e, () => setSystemMenuOpen(false))}
onInteractOutside={disableCloseWhenDropdownOpen}
className="fixed bottom-0 sm:top-0 sm:bottom-auto scroll-left-50 flex flex-col scroll-full-width max-w-3xl px-4 sm:pb-4 text-gray-400 -translate-x-1/2 outline-none"
className="fixed bottom-0 sm:top-0 sm:bottom-auto scroll-left-50 flex flex-col scroll-full-width max-w-[882px] px-4 sm:pb-4 text-gray-400 -translate-x-1/2 outline-none"
role="combobox"
aria-controls="leap-items"
aria-owns="leap-items"
aria-expanded={isOpen}
>
<header ref={dialogNavRef} className="my-6 order-last sm:order-none" />
<header
ref={dialogNavRef}
className="max-w-[712px] w-full mx-auto mt-6 mb-3 order-last sm:order-none"
/>
<div
id="leap-items"
className="grid grid-rows-[fit-content(100vh)] bg-white rounded-3xl overflow-hidden default-ring focus-visible:ring-2"
className="grid grid-rows-[fit-content(calc(100vh-6.25rem))] bg-white rounded-3xl overflow-hidden default-ring focus-visible:ring-2"
tabIndex={0}
role="listbox"
>

View File

@ -39,7 +39,7 @@ export const NotificationsLink = ({ navOpen, menu }: NotificationsLinkProps) =>
className={classNames(
'relative z-50 flex-none circle-button h4 default-ring',
navOpen && 'text-opacity-60',
navOpen && menu !== 'notifications' && 'opacity-80',
navOpen && menu !== 'notifications' && 'opacity-60',
state === 'empty' && !navOpen && 'text-gray-400 bg-gray-50',
state === 'empty' && navOpen && 'text-gray-400 bg-white',
state === 'unread' && 'bg-blue-400 text-white',

View File

@ -2,7 +2,7 @@ import * as DropdownMenu from '@radix-ui/react-dropdown-menu';
import classNames from 'classnames';
import clipboardCopy from 'clipboard-copy';
import React, { HTMLAttributes, useCallback, useState } from 'react';
import { Link } from 'react-router-dom';
import { Link, Route, useHistory } from 'react-router-dom';
import { Vat } from '@urbit/api/hood';
import { Adjust } from '../components/icons/Adjust';
import { useVat } from '../state/kiln';
@ -10,9 +10,8 @@ import { disableDefault, handleDropdownLink } from '../state/util';
import { MenuState } from './Nav';
type SystemMenuProps = HTMLAttributes<HTMLButtonElement> & {
open: boolean;
setOpen: (open: boolean) => void;
menu: MenuState;
open: boolean;
navOpen: boolean;
};
@ -21,7 +20,8 @@ function getHash(vat: Vat): string {
return parts[parts.length - 1];
}
export const SystemMenu = ({ open, setOpen, className, menu, navOpen }: SystemMenuProps) => {
export const SystemMenu = ({ className, menu, open, navOpen }: SystemMenuProps) => {
const { push } = useHistory();
const [copied, setCopied] = useState(false);
const garden = useVat('garden');
const hash = getHash(garden);
@ -37,72 +37,98 @@ export const SystemMenu = ({ open, setOpen, className, menu, navOpen }: SystemMe
}, 1250);
}, []);
const preventFlash = useCallback((e) => {
const target = e.target as HTMLElement;
if (target.id !== 'system-menu-overlay') {
e.preventDefault();
}
}, []);
return (
<>
<DropdownMenu.Root open={open} onOpenChange={(isOpen) => setOpen(isOpen)}>
<DropdownMenu.Trigger
className={classNames(
'circle-button default-ring',
open && 'text-gray-300',
navOpen && menu !== 'system-preferences' && menu !== 'help-and-support' && 'opacity-80',
className
)}
<div className="z-40">
<DropdownMenu.Root
modal={false}
open={open}
onOpenChange={(isOpen) => setTimeout(() => !isOpen && push('/'), 15)}
>
<Adjust className="w-6 h-6 fill-current" />
<span className="sr-only">System Menu</span>
</DropdownMenu.Trigger>
<DropdownMenu.Content
onCloseAutoFocus={disableDefault}
sideOffset={12}
className="dropdown min-w-64 p-4 font-semibold text-gray-500 bg-white"
>
<DropdownMenu.Group>
<DropdownMenu.Item
as={Link}
to="/leap/system-preferences"
className="flex items-center p-2 mb-2 space-x-2 focus:bg-blue-200 focus:outline-none rounded"
onSelect={handleDropdownLink(setOpen)}
<DropdownMenu.Trigger
as={Link}
to="/system-menu"
className={classNames(
'circle-button default-ring',
open && 'text-gray-300',
navOpen &&
menu !== 'system-preferences' &&
menu !== 'help-and-support' &&
'opacity-60',
className
)}
>
<Adjust className="w-6 h-6 fill-current" />
<span className="sr-only">System Menu</span>
</DropdownMenu.Trigger>
<Route path="/system-menu">
<DropdownMenu.Content
portalled={false}
onCloseAutoFocus={disableDefault}
onInteractOutside={preventFlash}
onFocusOutside={preventFlash}
onPointerDownOutside={preventFlash}
sideOffset={12}
className="dropdown relative z-40 min-w-64 p-4 font-semibold text-gray-500 bg-white"
>
<span className="w-5 h-5 bg-gray-100 rounded-full" />
<span className="h4">System Preferences</span>
</DropdownMenu.Item>
<DropdownMenu.Item
as={Link}
to="/leap/help-and-support"
className="flex items-center p-2 mb-2 space-x-2 focus:bg-blue-200 focus:outline-none rounded"
onSelect={handleDropdownLink(setOpen)}
>
<span className="w-5 h-5 bg-gray-100 rounded-full" />
<span className="h4">Help and Support</span>
</DropdownMenu.Item>
<DropdownMenu.Item
as={Link}
to="/app/garden"
className="flex items-center p-2 mb-2 space-x-2 focus:bg-blue-200 focus:outline-none rounded"
onSelect={handleDropdownLink(setOpen)}
>
<span className="w-5 h-5 bg-gray-100 rounded-full" />
<span className="h4">About Landscape</span>
</DropdownMenu.Item>
<DropdownMenu.Item
as="button"
className="inline-flex items-center py-2 px-3 m-2 h4 text-black bg-gray-100 rounded focus:bg-blue-200 focus:outline-none"
onSelect={copyHash}
>
<span className="sr-only">Base Hash</span>
<code>
{!copied && <span aria-label={hash.split('').join('-')}>{hash}</span>}
{copied && 'copied!'}
</code>
</DropdownMenu.Item>
</DropdownMenu.Group>
</DropdownMenu.Content>
</DropdownMenu.Root>
{!navOpen && open && (
<div className="fixed z-30 right-0 bottom-0 w-screen h-screen bg-black opacity-30" />
)}
<DropdownMenu.Group>
<DropdownMenu.Item
as={Link}
to="/leap/system-preferences"
className="flex items-center p-2 mb-2 space-x-2 focus:bg-blue-200 focus:outline-none rounded"
onSelect={handleDropdownLink()}
>
<span className="w-5 h-5 bg-gray-100 rounded-full" />
<span className="h4">System Preferences</span>
</DropdownMenu.Item>
<DropdownMenu.Item
as={Link}
to="/leap/help-and-support"
className="flex items-center p-2 mb-2 space-x-2 focus:bg-blue-200 focus:outline-none rounded"
onSelect={handleDropdownLink()}
>
<span className="w-5 h-5 bg-gray-100 rounded-full" />
<span className="h4">Help and Support</span>
</DropdownMenu.Item>
<DropdownMenu.Item
as={Link}
to="/app/garden"
className="flex items-center p-2 mb-2 space-x-2 focus:bg-blue-200 focus:outline-none rounded"
onSelect={handleDropdownLink()}
>
<span className="w-5 h-5 bg-gray-100 rounded-full" />
<span className="h4">About Landscape</span>
</DropdownMenu.Item>
<DropdownMenu.Item
as="button"
className="inline-flex items-center py-2 px-3 m-2 h4 text-black bg-gray-100 rounded focus:bg-blue-200 focus:outline-none"
onSelect={copyHash}
>
<span className="sr-only">Base Hash</span>
<code>
{!copied && <span aria-label={hash.split('').join('-')}>{hash}</span>}
{copied && 'copied!'}
</code>
</DropdownMenu.Item>
</DropdownMenu.Group>
</DropdownMenu.Content>
</Route>
</DropdownMenu.Root>
</div>
<Route path="/system-menu">
<div
id="system-menu-overlay"
className="fixed z-30 right-0 bottom-0 w-screen h-screen bg-black opacity-30"
/>
</Route>
</>
);
};

View File

@ -23,7 +23,7 @@ export const SystemPreferences = ({ match }: RouteComponentProps<{ submenu: stri
return (
<div className="flex h-[600px] max-h-full">
<aside className="flex-none min-w-60 border-r-2 border-gray-50">
<div className="p-5">
<div className="p-8">
<input className="input h4 default-ring bg-gray-50" placeholder="Search Preferences" />
</div>
<nav className="border-b-2 border-gray-50">
@ -32,7 +32,7 @@ export const SystemPreferences = ({ match }: RouteComponentProps<{ submenu: stri
<Link
to={`${match.url}/notifications`}
className={classNames(
'flex items-center px-5 py-3 hover:text-black hover:bg-gray-50',
'flex items-center px-8 py-3 hover:text-black hover:bg-gray-50',
matchSub('notifications') && 'text-black bg-gray-50'
)}
>
@ -44,7 +44,7 @@ export const SystemPreferences = ({ match }: RouteComponentProps<{ submenu: stri
<Link
to={`${match.url}/system-updates`}
className={classNames(
'flex items-center px-5 py-3 hover:text-black hover:bg-gray-50',
'flex items-center px-8 py-3 hover:text-black hover:bg-gray-50',
matchSub('system-updates') && 'text-black bg-gray-50'
)}
>
@ -55,7 +55,7 @@ export const SystemPreferences = ({ match }: RouteComponentProps<{ submenu: stri
</ul>
</nav>
</aside>
<section className="flex-1 px-5 py-7 text-black">
<section className="flex-1 p-8 text-black">
<Switch>
<Route path={`${match.url}/system-updates`} component={SystemUpdatePrefs} />
<Route path={[`${match.url}/notifications`, match.url]} component={NotificationPrefs} />

View File

@ -115,7 +115,7 @@ export const Home = () => {
size="small"
/>
)}
<hr className="-mx-4 my-6 md:-mx-8 md:my-9" />
<hr className="-mx-4 my-6 md:-mx-8 md:my-9 border-t-2 border-gray-50" />
<h2 id="recent-devs" className="mb-4 h4 text-gray-500">
Recent Developers
</h2>

View File

@ -28,7 +28,7 @@ export const Grid: FunctionComponent<GridProps> = ({ match }) => {
return (
<div className="flex flex-col">
<header className="fixed sm:sticky bottom-0 sm:bottom-auto sm:top-0 left-0 z-30 flex justify-center w-full bg-white">
<header className="fixed sm:sticky bottom-0 sm:bottom-auto sm:top-0 left-0 z-30 flex justify-center w-full px-4 bg-white">
<Nav menu={match.params.menu} />
</header>

View File

@ -101,7 +101,7 @@ const useDocketState = create<DocketState>((set, get) => ({
}
if (useMockData) {
set((state) => addCharge(state, desk, { ...treaty, chad: { install: null } }));
await new Promise<void>((res) => setTimeout(() => res(), 5000));
await new Promise<void>((res) => setTimeout(() => res(), 10000));
set((state) => addCharge(state, desk, { ...treaty, chad: { glob: null } }));
}

View File

@ -19,10 +19,10 @@ export function disableDefault<T extends Event>(e: T): void {
}
// hack until radix-ui fixes this behavior
export function handleDropdownLink(setOpen: (open: boolean) => void): (e: Event) => void {
export function handleDropdownLink(setOpen?: (open: boolean) => void): (e: Event) => void {
return (e: Event) => {
e.stopPropagation();
e.preventDefault();
setTimeout(() => setOpen(false), 15);
setTimeout(() => setOpen?.(false), 15);
};
}

View File

@ -61,9 +61,6 @@ export const TileMenu = ({ desk, active, menuColor, lightText, className }: Tile
</DropdownMenu.Trigger>
<DropdownMenu.Content
align="start"
alignOffset={-32}
sideOffset={4}
onCloseAutoFocus={disableDefault}
className={classNames(
'dropdown py-2 font-semibold',
@ -88,10 +85,7 @@ export const TileMenu = ({ desk, active, menuColor, lightText, className }: Tile
Remove App
</Item>
</DropdownMenu.Group>
<DropdownMenu.Arrow
className="w-4 h-[10px] fill-current -translate-x-10"
style={{ color: menuColor }}
/>
<DropdownMenu.Arrow className="w-4 h-[10px] fill-current" style={{ color: menuColor }} />
</DropdownMenu.Content>
</DropdownMenu.Root>
);