mirror of
https://github.com/ilyakooo0/urbit.git
synced 2024-11-10 10:05:09 +03:00
design: fixing system menu and nav, various design tweaks
This commit is contained in:
parent
797ae776e0
commit
dea33d9019
@ -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} />
|
||||
</>
|
||||
)}
|
||||
|
@ -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" />
|
||||
|
@ -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"
|
||||
>
|
||||
|
@ -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',
|
||||
|
@ -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>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
@ -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} />
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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 } }));
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
};
|
||||
}
|
||||
|
@ -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>
|
||||
);
|
||||
|
Loading…
Reference in New Issue
Block a user