Skip to content

Commit

Permalink
Fix Nav sidebar collapse behaviour to allow only one expanded menu at…
Browse files Browse the repository at this point in the history
… a time, Refactor Nav structure (#568)

* Bump api-solang to latest version

* Show button to view nabla transaction on explorer

* Change margin of buttons

* Enable Nabla on Pendulum (only for testing, to be removed)

* remove unnecessary code

* improve nav responsiveness when multiple collapse groups appear

* fix button class

* change swap footer text

* change collapse behaviour to open only one at the time

* extract NavItem to a separate file, implement safer url check

* extract NavCollapseMenu to a separate file, change nav item active logic

* change Nav component structure

* remove unnecessary Promise constructor, no-async-promise-executor

* remove unused Nav component

* disable ForexAMM for Pendulum

---------

Co-authored-by: Marcel Ebert <[email protected]>
  • Loading branch information
Sharqiewicz and ebma authored Sep 30, 2024
1 parent 3944ce6 commit 54f0113
Show file tree
Hide file tree
Showing 6 changed files with 185 additions and 158 deletions.
129 changes: 0 additions & 129 deletions src/components/Layout/Nav.tsx

This file was deleted.

39 changes: 39 additions & 0 deletions src/components/Layout/Nav/NavCollapseMenu/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
export const NavCollapseMenu = ({
link,
disabled,
button,
children,
ariaControls,
activeSelection,
onClick,
}: {
link: string;
disabled?: boolean;
button: JSX.Element | null;
children: JSX.Element | null;
ariaControls?: string;
activeSelection?: string | null;
onClick: (link: string | null) => void;
}) => {
const isItemActive = !!activeSelection && activeSelection === link;

const handleOnClick = () => {
onClick(isItemActive ? null : link);
};

return (
<section className={`collapse ${disabled ? 'disabled' : 'collapse-arrow'} ${isItemActive ? 'collapse-open' : ''} `}>
<button
type="button"
className={`nav-item collapse-btn collapse-title ${isItemActive ? 'active' : ''}`}
aria-controls={ariaControls}
aria-disabled={disabled}
aria-expanded={isItemActive}
onClick={handleOnClick}
>
{button}
</button>
<div className="collapse-content p-0">{children}</div>
</section>
);
};
43 changes: 43 additions & 0 deletions src/components/Layout/Nav/NavItem/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { NavLink } from 'react-router-dom';
import { LinkItem } from '../../links';

const isExternalLink = (link: string) => {
try {
const parsedUrl = new URL(link);
return ['http:', 'https:'].includes(parsedUrl.protocol);
} catch {
return false;
}
};

export const NavItem = ({
item,
onClick,
isSubNavItem = false,
}: {
item: LinkItem;
onClick?: () => void;
isSubNavItem?: boolean;
}) => {
const { link, prefix, suffix, title, props, hidden } = item;
if (hidden) return null;
const isExternal = isExternalLink(link);

const linkUi = (
<>
{prefix}
<span>{title}</span>
{suffix}
</>
);
const cls = `nav-item font-outfit ${props?.className?.() || ''} ${isSubNavItem ? 'text-sm' : ''}`;
return isExternal ? (
<a href={link} {...props} className={cls} onClick={onClick}>
{linkUi}
</a>
) : (
<NavLink to={link} {...props} onClick={onClick} className={cls}>
{linkUi}
</NavLink>
);
};
80 changes: 80 additions & 0 deletions src/components/Layout/Nav/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import { memo, useEffect, useMemo, useState } from 'preact/compat';
import { useLocation } from 'react-router-dom';
import { useGlobalState } from '../../../GlobalStateProvider';
import { NavCollapseButtonContent } from '../NavCollapseButtonContent';
import { createLinks, LinkItem } from '../links';
import { NavItem } from './NavItem';
import { NavCollapseMenu } from './NavCollapseMenu';

const getActiveLink = (pathname: string): string | null => {
const [path] = pathname.split('?');
const paths = path.split('/').filter(Boolean);
return paths.length > 1 ? `/${paths[1]}` : null;
};

export type NavProps = {
onClick?: () => void;
};

const Nav = memo(({ onClick }: NavProps) => {
const state = useGlobalState();

const [isPlaying, setIsPlaying] = useState(false);
const [links, setLinks] = useState<LinkItem[]>([]);

const { pathname } = useLocation();
const activeLink = useMemo(() => getActiveLink(pathname), [pathname]);
const [activeSelection, setActiveSelection] = useState<null | string>(activeLink);

const handleMouseEnter = () => {
setIsPlaying(true);
};

useEffect(() => {
const [defaultLinks, loadedLinksPromise] = createLinks(state.tenantName);
setLinks(defaultLinks);

loadedLinksPromise.then(setLinks).catch((error) => console.error("Couldn't load links", error));
}, [state.tenantName]);

return (
<nav>
{links.map((item, i) => {
if (item.hidden) return;

return item.submenu ? (
<div onMouseEnter={handleMouseEnter} className="my-2.5">
<NavCollapseMenu
key={i}
disabled={item.disabled}
ariaControls="submenu"
button={<NavCollapseButtonContent item={item} isPlaying={isPlaying} />}
activeSelection={activeSelection}
link={item.link}
onClick={setActiveSelection}
>
<ul className="submenu" id={`submenu-${i}`}>
{item.submenu.map((subItem, j) => (
<li key={`${i}-${j}`} className="ml-[3px]">
<NavItem item={subItem} onClick={onClick} isSubNavItem={true} />
</li>
))}
</ul>
</NavCollapseMenu>
</div>
) : (
<NavItem
key={i}
item={item}
onClick={() => {
setActiveSelection(item.link);
onClick && onClick();
}}
/>
);
})}
</nav>
);
});

export default Nav;
43 changes: 21 additions & 22 deletions src/components/Layout/links.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -169,26 +169,25 @@ export function createLinks(tenantName: TenantName): [LinkItem[], Promise<LinkIt
alchemyPayLinkItem,
];

return [
links,
new Promise(async (resolve) => {
const alchemyPayLink = await config.alchemyPay.encodeUrlWithRedirection(
config.alchemyPay.prodUrl,
window.location.href,
);

resolve([
dashboardLinkItem,
zenlinkAmmLinkItem,
spacewalkLinkItem,
nablaLinkItem,
stakingLinkItem,
governanceLinkItem,
{
...alchemyPayLinkItem,
link: alchemyPayLink,
},
]);
}),
];
const getLinks = async () => {
const alchemyPayLink = await config.alchemyPay.encodeUrlWithRedirection(
config.alchemyPay.prodUrl,
window.location.href,
);

return [
dashboardLinkItem,
zenlinkAmmLinkItem,
spacewalkLinkItem,
nablaLinkItem,
stakingLinkItem,
governanceLinkItem,
{
...alchemyPayLinkItem,
link: alchemyPayLink,
},
];
};

return [links, getLinks()];
}
9 changes: 2 additions & 7 deletions src/config/apps/nabla.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,11 @@ export type NablaConfig = AppConfigBase &
>;

export const nablaConfig: NablaConfig = {
tenants: [TenantName.Foucoco, TenantName.Pendulum],
environment: ['staging', 'development', 'production'],
tenants: [TenantName.Foucoco],
environment: ['staging', 'development'],
foucoco: {
indexerUrl: 'https://pendulum.squids.live/foucoco-squid/graphql',
router: '6mYwT4yRrrMK978NszqBvxkvXjYnsmKfs2BkYGJGiR4XY9Sc',
oracle: '6kqj1tnYUGY3L93YFArXKF2E4tpQ2tUJ4DARwkAjZEyDoof6',
},
pendulum: {
indexerUrl: 'https://pendulum.squids.live/pendulum-squid/graphql',
router: '6buMJsFCbXpHRyacKTjBn3Jss241b2aA7CZf9tKzKHMJWpcJ',
oracle: '6f9uHwN2r5w82Bjrywc4wmZYb6TN64bZH5Ev87qmJ675uFvq',
},
};

0 comments on commit 54f0113

Please sign in to comment.