Skip to content

Commit

Permalink
wallet-ext: overflow menu
Browse files Browse the repository at this point in the history
* adds overflow menu
* moves settings from navigation bar to the overflow menu
* pressing escape closes menu

note: There is a warning from react router which I think we can safely ignore, because we are using a different source for the location of the menu router from it's parent one.
  • Loading branch information
pchrysochoidis committed Jul 13, 2022
1 parent 3c65b52 commit ddd7538
Show file tree
Hide file tree
Showing 17 changed files with 256 additions and 10 deletions.
55 changes: 55 additions & 0 deletions wallet/src/ui/app/components/menu/button/MenuButton.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
@use '_variables' as v;

$btn-width: 20px;
$btn-height: 14px;
$line-height: 2px;

.button {
background: none;
outline: none;
border: none;
width: $btn-width;
height: $btn-height;
position: relative;
cursor: pointer;
padding: 0;
}

.line {
width: $btn-width;
height: $line-height;
background-color: v.use(v.$colors-menu-btn-color);
transition-property: opacity, transform, top;
transition-duration: 0.2s;
transition-timing-function: ease-in-out;
display: block;
position: absolute;
border-radius: 10px;

&.line-1 {
top: 0;
}

&.line-2 {
top: calc(50% - ($line-height / 2));
}

&.line-3 {
bottom: 0;
}
}

.open {
> .line-1 {
top: calc(50% - ($line-height / 2));
transform: rotate(45deg);
}

> .line-2 {
transform: rotate(-45deg);
}

> .line-3 {
opacity: 0;
}
}
31 changes: 31 additions & 0 deletions wallet/src/ui/app/components/menu/button/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Copyright (c) 2022, Mysten Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

import cl from 'classnames';
import { memo } from 'react';
import { Link } from 'react-router-dom';

import { useMenuIsOpen, useNextMenuUrl } from '_components/menu/hooks';

import st from './MenuButton.module.scss';

export type MenuButtonProps = {
className?: string;
};

function MenuButton({ className }: MenuButtonProps) {
const isOpen = useMenuIsOpen();
const menuUrl = useNextMenuUrl(!isOpen, '/');
return (
<Link
className={cl(st.button, { [st.open]: isOpen }, className)}
to={menuUrl}
>
<span className={cl(st.line, st.line1)} />
<span className={cl(st.line, st.line2)} />
<span className={cl(st.line, st.line3)} />
</Link>
);
}

export default memo(MenuButton);
25 changes: 25 additions & 0 deletions wallet/src/ui/app/components/menu/content/MenuContent.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
@use '_values/colors';
@use '_variables' as v;

.container {
position: absolute;
width: 100%;
height: 100%;
}

.backdrop {
position: absolute;
width: 100%;
height: 100%;
background-color: colors.$gray-100;
opacity: 0.8;
}

.content {
position: relative;
padding: 20px 25px 25px;
background-color: v.use(v.$colors-main-content-background);
border-radius: 20px;
max-height: 100%;
overflow-y: auto;
}
56 changes: 56 additions & 0 deletions wallet/src/ui/app/components/menu/content/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// Copyright (c) 2022, Mysten Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

import { useCallback } from 'react';
import { Navigate, Route, Routes, useNavigate } from 'react-router-dom';

import Settings from './settings';
import {
useMenuIsOpen,
useMenuUrl,
useNextMenuUrl,
} from '_components/menu/hooks';
import { useOnKeyboardEvent } from '_hooks';

import type { MouseEvent } from 'react';

import st from './MenuContent.module.scss';

const CLOSE_KEY_CODES: string[] = ['Escape'];

function MenuContent() {
const isOpen = useMenuIsOpen();
const menuUrl = useMenuUrl();
const menuHomeUrl = useNextMenuUrl(true, '/settings');
const closeMenuUrl = useNextMenuUrl(false);
const navigate = useNavigate();
const handleOnCloseMenu = useCallback(
(e: KeyboardEvent | MouseEvent<HTMLDivElement>) => {
if (isOpen) {
e.preventDefault();
navigate(closeMenuUrl);
}
},
[isOpen, navigate, closeMenuUrl]
);
useOnKeyboardEvent('keydown', CLOSE_KEY_CODES, handleOnCloseMenu, isOpen);
if (!isOpen) {
return null;
}
return (
<div className={st.container}>
<div className={st.backdrop} onClick={handleOnCloseMenu} />
<div className={st.content}>
<Routes location={menuUrl || ''}>
<Route path="settings" element={<Settings />} />
<Route
path="*"
element={<Navigate to={menuHomeUrl} replace={true} />}
/>
</Routes>
</div>
</div>
);
}

export default MenuContent;
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import type { SerializedError } from '@reduxjs/toolkit';

import st from './SettingsPage.module.scss';

function SettingsPage() {
function Settings() {
const [logoutInProgress, setLogoutInProgress] = useState(false);
const [mintInProgress, setMintInProgress] = useState(false);
const [mintStatus, setMintStatus] = useState<boolean | null>(null);
Expand Down Expand Up @@ -114,4 +114,4 @@ function SettingsPage() {
);
}

export default SettingsPage;
export default Settings;
40 changes: 40 additions & 0 deletions wallet/src/ui/app/components/menu/hooks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Copyright (c) 2022, Mysten Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

import { useMemo } from 'react';
import { useLocation, useSearchParams } from 'react-router-dom';

const MENU_PARAM = 'menu';

export function useMenuUrl() {
const [searchParams] = useSearchParams();
if (searchParams.has(MENU_PARAM)) {
return searchParams.get(MENU_PARAM) || '/';
}
return false;
}

export function useMenuIsOpen() {
const [searchParams] = useSearchParams();
return searchParams.has(MENU_PARAM);
}

/**
* Get the URL that contains the background page and the menu location
*
* @param isOpen Indicates if the menu will be open
* @param nextMenuLocation The location within the menu
*/
export function useNextMenuUrl(isOpen: boolean, nextMenuLocation = '/') {
const [searchParams] = useSearchParams();
const { pathname } = useLocation();
return useMemo(() => {
if (isOpen) {
searchParams.set(MENU_PARAM, nextMenuLocation);
} else {
searchParams.delete(MENU_PARAM);
}
const search = searchParams.toString();
return `${pathname}${search ? '?' : ''}${search}`;
}, [isOpen, nextMenuLocation, searchParams, pathname]);
}
5 changes: 5 additions & 0 deletions wallet/src/ui/app/components/menu/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// Copyright (c) 2022, Mysten Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

export { default as MenuButton } from './button';
export { default as MenuContent } from './content';
4 changes: 0 additions & 4 deletions wallet/src/ui/app/components/navigation/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,6 @@ function Navigation({ className }: NavigationProps) {
<Icon className={st.icon} icon={SuiIcons.History} />
<span className={st.title}>Activity</span>
</NavLink>
<NavLink to="./settings" className={makeLinkCls} title="Settings">
<Icon className={st.icon} icon={SuiIcons.Apps} />
<span className={st.title}>Settings</span>
</NavLink>
</nav>
);
}
Expand Down
1 change: 1 addition & 0 deletions wallet/src/ui/app/hooks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ export { default as useMediaUrl } from './useMediaUrl';
export { default as useSuiObjectFields } from './useSuiObjectFields';
export { default as useNumberDelimiters } from './useNumberDelimiters';
export { default as useOnClickOutside } from './useOnClickOutside';
export { default as useOnKeyboardEvent } from './useOnKeyboardEvent';
29 changes: 29 additions & 0 deletions wallet/src/ui/app/hooks/useOnKeyboardEvent.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Copyright (c) 2022, Mysten Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

import { useEffect } from 'react';

function useOnKeyboardEvent<K extends 'keydown' | 'keyup' | 'keypress'>(
eventType: K,
keys: string[],
handler: (e: KeyboardEvent) => void,
enabled = true
) {
useEffect(() => {
if (enabled) {
const listener = (e: KeyboardEvent) => {
if (keys.includes(e.key)) {
handler(e);
}
};

document.addEventListener(eventType, listener);

return () => {
document.removeEventListener(eventType, listener);
};
}
}, [eventType, keys, handler, enabled]);
}

export default useOnKeyboardEvent;
2 changes: 0 additions & 2 deletions wallet/src/ui/app/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import { useAppDispatch, useAppSelector } from '_hooks';
import { DappTxApprovalPage } from '_pages/dapp-tx-approval';
import HomePage, {
NftsPage,
SettingsPage,
StakePage,
TokensPage,
TransactionDetailsPage,
Expand Down Expand Up @@ -49,7 +48,6 @@ const App = () => {
<Route path="tokens" element={<TokensPage />} />
<Route path="nfts" element={<NftsPage />} />
<Route path="transactions" element={<TransactionsPage />} />
<Route path="settings" element={<SettingsPage />} />
<Route path="send" element={<TransferCoinPage />} />
<Route path="send-nft" element={<TransferNFTPage />} />
<Route path="stake" element={<StakePage />} />
Expand Down
6 changes: 5 additions & 1 deletion wallet/src/ui/app/pages/home/Home.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,14 @@
flex-flow: row nowrap;
align-items: center;
padding: 0 15px;
justify-content: center;
justify-content: space-between;
min-height: 52px;
}

.menu-button {
justify-self: flex-end;
}

.content {
display: flex;
flex-flow: column nowrap;
Expand Down
5 changes: 4 additions & 1 deletion wallet/src/ui/app/pages/home/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { of, filter, switchMap, from, defer, repeat } from 'rxjs';

import Loading from '_components/loading';
import Logo from '_components/logo';
import { MenuButton, MenuContent } from '_components/menu';
import Navigation from '_components/navigation';
import { useInitializedGuard, useAppDispatch } from '_hooks';
import PageLayout from '_pages/layout';
Expand Down Expand Up @@ -38,13 +39,16 @@ const HomePage = () => {
<Loading loading={guardChecking}>
<div className={st.container}>
<div className={st.header}>
<span />
<Logo className={st.logo} txt={true} />
<MenuButton className={st.menuButton} />
</div>
<div className={st.content}>
<main className={st.main}>
<Outlet />
</main>
<Navigation />
<MenuContent />
</div>
</div>
</Loading>
Expand All @@ -54,7 +58,6 @@ const HomePage = () => {

export default HomePage;
export { default as NftsPage } from './nfts';
export { default as SettingsPage } from './settings';
export { default as StakePage } from './stake';
export { default as TokensPage } from './tokens';
export { default as TransactionDetailsPage } from './transaction-details';
Expand Down
1 change: 1 addition & 0 deletions wallet/src/ui/styles/themes/dark.scss
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,5 @@ $values: (
c-var.$nav-item-highlighted-color: c-val.$white,
c-var.$nav-item-icon-highlighted-color: c-val.$sui-blue,
c-var.$nav-item-icon-highlighted-gradient-color: none,
c-var.$menu-btn-color: c-val.$white,
);
1 change: 1 addition & 0 deletions wallet/src/ui/styles/themes/light.scss
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,5 @@ $values: (
c-var.$nav-item-icon-highlighted-color: transparent,
c-var.$nav-item-icon-highlighted-gradient-color:
linear-gradient(135deg, #589aea 0%, #4c75a6 100%),
c-var.$menu-btn-color: c-val.$gray-70,
);
1 change: 1 addition & 0 deletions wallet/src/ui/styles/variables/colors.scss
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ $nav-item-color: '--colors-nav-item-color';
$nav-item-highlighted-color: '--colors-nav-item-highlighted-color';
$nav-item-icon-highlighted-color: '--colors-nav-item-icon-highlighted-color';
$nav-item-icon-highlighted-gradient-color: '--colors-nav-item-icon-highlighted-gradient-color';
$menu-btn-color: '--colors-menu-btn-color';

0 comments on commit ddd7538

Please sign in to comment.