diff --git a/apps/explorer/src/app/components/header/header.tsx b/apps/explorer/src/app/components/header/header.tsx
index 01bd98747..b21e84696 100644
--- a/apps/explorer/src/app/components/header/header.tsx
+++ b/apps/explorer/src/app/components/header/header.tsx
@@ -62,14 +62,14 @@ export const Header = () => {
>
}
- onResize={(width, ref) => {
+ onResize={(width, el) => {
if (width < 1157) {
// switch to magnifying glass trigger when widht < 1157
- ref.current?.classList.remove('nav-search-full');
- ref.current?.classList.add('nav-search-compact');
+ el.classList.remove('nav-search-full');
+ el.classList.add('nav-search-compact');
} else {
- ref.current?.classList.remove('nav-search-compact');
- ref.current?.classList.add('nav-search-full');
+ el.classList.remove('nav-search-compact');
+ el.classList.add('nav-search-full');
}
}}
>
diff --git a/apps/explorer/src/app/components/nav/index.tsx b/apps/explorer/src/app/components/nav/index.tsx
deleted file mode 100644
index 38d674589..000000000
--- a/apps/explorer/src/app/components/nav/index.tsx
+++ /dev/null
@@ -1 +0,0 @@
-export * from './nav';
diff --git a/apps/explorer/src/app/components/nav/nav.tsx b/apps/explorer/src/app/components/nav/nav.tsx
deleted file mode 100644
index f54724894..000000000
--- a/apps/explorer/src/app/components/nav/nav.tsx
+++ /dev/null
@@ -1,181 +0,0 @@
-import { NavLink, useLocation } from 'react-router-dom';
-import type { Navigable } from '../../routes/router-config';
-import routerConfig from '../../routes/router-config';
-import classnames from 'classnames';
-import { create } from 'zustand';
-import {
- useCallback,
- useEffect,
- useLayoutEffect,
- useMemo,
- useRef,
-} from 'react';
-import { Icon } from '@vegaprotocol/ui-toolkit';
-import first from 'lodash/first';
-import last from 'lodash/last';
-import { BREAKPOINT_MD } from '../../config/breakpoints';
-
-type NavStore = {
- open: boolean;
- toggle: () => void;
- hide: () => void;
-};
-
-export const useNavStore = create()((set, get) => ({
- open: false,
- toggle: () => set({ open: !get().open }),
- hide: () => set({ open: false }),
-}));
-
-const NavLinks = ({ links }: { links: Navigable[] }) => {
- const navLinks = links.map((r) => (
-
-
- classnames(
- 'block mb-2 px-2',
- 'text-lg hover:bg-vega-pink dark:hover:bg-vega-yellow hover:text-white dark:hover:text-black',
- {
- 'bg-vega-pink text-white dark:bg-vega-yellow dark:text-black':
- isActive,
- }
- )
- }
- >
- {r.text}
-
-
- ));
-
- return ;
-};
-
-export const Nav = () => {
- const [open, hide] = useNavStore((state) => [state.open, state.hide]);
- const location = useLocation();
-
- const navRef = useRef(null);
- const btnRef = useRef(null);
-
- const focusable = useMemo(
- () =>
- navRef.current
- ? [
- ...(navRef.current.querySelectorAll(
- 'a, button'
- ) as NodeListOf),
- ]
- : [],
- // eslint-disable-next-line react-hooks/exhaustive-deps
- [navRef.current] // do not remove `navRef.current` from deps
- );
-
- const closeNav = useCallback(() => {
- hide();
- console.log(focusable);
- focusable.forEach((fe) =>
- fe.setAttribute(
- 'tabindex',
- window.innerWidth > BREAKPOINT_MD ? '0' : '-1'
- )
- );
- }, [focusable, hide]);
-
- // close navigation when location changes
- useEffect(() => {
- closeNav();
- }, [closeNav, location]);
-
- useLayoutEffect(() => {
- if (open) {
- focusable.forEach((fe) => fe.setAttribute('tabindex', '0'));
- }
-
- document.body.style.overflow = open ? 'hidden' : '';
- const offset =
- document.querySelector('header')?.getBoundingClientRect().top || 0;
- if (navRef.current) {
- navRef.current.style.height = `calc(100vh - ${offset}px)`;
- }
-
- // focus current by default
- if (navRef.current && open) {
- (navRef.current.querySelector('a[aria-current]') as HTMLElement)?.focus();
- }
-
- const closeOnEsc = (e: KeyboardEvent) => {
- if (e.key === 'Escape') {
- closeNav();
- }
- };
-
- // tabbing loop
- const focusLast = (e: FocusEvent) => {
- e.preventDefault();
- const isNavElement =
- e.relatedTarget && navRef.current?.contains(e.relatedTarget as Node);
- if (!isNavElement && open) {
- last(focusable)?.focus();
- }
- };
- const focusFirst = (e: FocusEvent) => {
- e.preventDefault();
- const isNavElement =
- e.relatedTarget && navRef.current?.contains(e.relatedTarget as Node);
- if (!isNavElement && open) {
- first(focusable)?.focus();
- }
- };
-
- const resetOnDesktop = () => {
- focusable.forEach((fe) =>
- fe.setAttribute(
- 'tabindex',
- window.innerWidth > BREAKPOINT_MD ? '0' : '-1'
- )
- );
- };
-
- window.addEventListener('resize', resetOnDesktop);
-
- first(focusable)?.addEventListener('focusout', focusLast);
- last(focusable)?.addEventListener('focusout', focusFirst);
-
- document.addEventListener('keydown', closeOnEsc);
- return () => {
- window.removeEventListener('resize', resetOnDesktop);
- document.removeEventListener('keydown', closeOnEsc);
- first(focusable)?.removeEventListener('focusout', focusLast);
- last(focusable)?.removeEventListener('focusout', focusFirst);
- };
- }, [closeNav, focusable, open]);
-
- return (
-
- );
-};
diff --git a/apps/trading/components/navbar/navbar.tsx b/apps/trading/components/navbar/navbar.tsx
index bc65bcaae..98c87c88d 100644
--- a/apps/trading/components/navbar/navbar.tsx
+++ b/apps/trading/components/navbar/navbar.tsx
@@ -1,6 +1,4 @@
-import { useState } from 'react';
-import classNames from 'classnames';
-import { NavLink, Link } from 'react-router-dom';
+import type { ComponentProps } from 'react';
import {
DApp,
NetworkSwitcher,
@@ -11,32 +9,22 @@ import { t } from '@vegaprotocol/i18n';
import { useGlobalStore } from '../../stores';
import { VegaWalletConnectButton } from '../vega-wallet-connect-button';
import {
- Drawer,
- getNavLinkClassNames,
- getActiveNavLinkClassNames,
- Nav,
- NewTab,
ThemeSwitcher,
+ Navigation,
+ NavigationList,
+ NavigationItem,
+ NavigationLink,
+ ExternalLink,
+ Icon,
+ NavigationBreakpoint,
} from '@vegaprotocol/ui-toolkit';
-import { Vega } from '../icons/vega';
-import type { HTMLAttributeAnchorTarget } from 'react';
+
import { Links, Routes } from '../../pages/client-router';
-type NavbarTheme = 'inherit' | 'dark' | 'yellow';
-interface NavbarProps {
- navbarTheme?: NavbarTheme;
-}
-
-const LinkList = ({
- navbarTheme,
- className = 'flex',
- dataTestId = 'navbar-links',
- onNavigate,
+export const Navbar = ({
+ theme = 'system',
}: {
- navbarTheme: NavbarTheme;
- className?: string;
- dataTestId?: string;
- onNavigate?: () => void;
+ theme: ComponentProps['theme'];
}) => {
const tokenLink = useLinks(DApp.Token);
const { marketId } = useGlobalStore((store) => ({
@@ -46,178 +34,47 @@ const LinkList = ({
? Links[Routes.MARKET](marketId)
: Links[Routes.MARKET]();
return (
-
- );
-};
-
-const MobileMenuBar = ({ navbarTheme }: { navbarTheme: NavbarTheme }) => {
- const [drawerOpen, setDrawerOpen] = useState(false);
- const [container, setContainer] = useState(null);
-
- const menuButton = (
-
- );
-
- return (
-
-
-
-
-
-
setDrawerOpen(false)}
- />
-
-
-
-
- );
-};
-
-export const Navbar = ({ navbarTheme = 'inherit' }: NavbarProps) => {
- const titleContent = (
-
-
-
- );
- return (
-
- );
-};
-
-interface AppNavLinkProps {
- name: string;
- path: string;
- navbarTheme: NavbarTheme;
- testId?: string;
- target?: HTMLAttributeAnchorTarget;
- end?: boolean;
- onClick?: () => void;
-}
-
-const AppNavLink = ({
- name,
- path,
- navbarTheme,
- target,
- testId = name,
- end,
- onClick,
-}: AppNavLinkProps) => {
- const borderClasses = classNames(
- 'absolute h-[2px] md:h-1 w-full bottom-[-1px] left-0',
- {
- 'bg-black dark:bg-vega-yellow': navbarTheme !== 'yellow',
- 'bg-black dark:bg-vega-yellow md:dark:bg-black': navbarTheme === 'yellow',
- }
- );
- return (
-
- {({ isActive }) => {
- return (
- <>
- {name}
- {isActive && }
- >
- );
- }}
-
+
+
+
+
+
+
+
+
+ {t('Markets')}
+
+
+
+ {t('Trading')}
+
+
+
+ {t('Portfolio')}
+
+
+
+
+
+ {t('Governance')}{' '}
+
+
+
+
+
+
);
};
diff --git a/apps/trading/components/vega-wallet-connect-button/vega-wallet-connect-button.tsx b/apps/trading/components/vega-wallet-connect-button/vega-wallet-connect-button.tsx
index a83a59479..342c55c86 100644
--- a/apps/trading/components/vega-wallet-connect-button/vega-wallet-connect-button.tsx
+++ b/apps/trading/components/vega-wallet-connect-button/vega-wallet-connect-button.tsx
@@ -54,7 +54,7 @@ const MobileWalletButton = ({
? 'hidden'
: isYellow
? 'fill-black'
- : 'fill-white';
+ : 'fill-black dark:fill-white';
const [container, setContainer] = useState(null);
const walletButton = (
diff --git a/apps/trading/pages/_app.page.tsx b/apps/trading/pages/_app.page.tsx
index 013ce58a4..c1905d8c1 100644
--- a/apps/trading/pages/_app.page.tsx
+++ b/apps/trading/pages/_app.page.tsx
@@ -1,6 +1,5 @@
import Head from 'next/head';
import type { AppProps } from 'next/app';
-import { Navbar } from '../components/navbar';
import { t } from '@vegaprotocol/i18n';
import {
useEagerConnect as useVegaEagerConnect,
@@ -33,6 +32,7 @@ import { ViewingBanner } from '../components/viewing-banner';
import { Banner } from '../components/banner';
import classNames from 'classnames';
import { AppLoader, DynamicLoader } from '../components/app-loader';
+import { Navbar } from '../components/navbar';
const DEFAULT_TITLE = t('Welcome to Vega trading!');
@@ -83,9 +83,7 @@ function AppBody({ Component }: AppProps) {
-
+
diff --git a/libs/ui-toolkit/src/components/navigation/navigation.tsx b/libs/ui-toolkit/src/components/navigation/navigation.tsx
index 1cc07cd8b..4849b0850 100644
--- a/libs/ui-toolkit/src/components/navigation/navigation.tsx
+++ b/libs/ui-toolkit/src/components/navigation/navigation.tsx
@@ -1,12 +1,11 @@
import classNames from 'classnames';
-import type { ComponentProps, ReactNode, RefObject } from 'react';
-import type { MutableRefObject } from 'react';
+import type { ComponentProps, ReactNode } from 'react';
+import { useLayoutEffect } from 'react';
import { createContext } from 'react';
import { useContext } from 'react';
import { useRef } from 'react';
import { VegaLogo } from '../vega-logo';
import * as NavigationMenu from '@radix-ui/react-navigation-menu';
-import { useResizeObserver } from '@vegaprotocol/react-helpers';
import { Icon } from '../icon';
import { Drawer, DrawerContext, useDrawer } from '../drawer';
import type { Link } from 'react-router-dom';
@@ -38,7 +37,8 @@ type NavigationProps = {
* Size variants breakpoints
*/
breakpoints?: [number, number];
- onResize?: (width: number, ref: RefObject) => void;
+ fullWidth?: boolean;
+ onResize?: (width: number, navigationElement: HTMLElement) => void;
};
export enum NavigationBreakpoint {
@@ -310,6 +310,44 @@ export const NavigationContext = createContext<{
theme: NavigationProps['theme'];
}>({ theme: 'system' });
+const setSizeVariantClasses = (
+ breakpoints: [number, number],
+ currentWidth: number,
+ target: HTMLElement
+) => {
+ if (
+ currentWidth <= breakpoints[0] &&
+ !target.classList.contains(NavigationBreakpoint.Small)
+ ) {
+ target.classList.remove(
+ NavigationBreakpoint.Full,
+ NavigationBreakpoint.Narrow
+ );
+ target.classList.add(NavigationBreakpoint.Small);
+ }
+ if (
+ currentWidth > breakpoints[0] &&
+ currentWidth <= breakpoints[1] &&
+ !target.classList.contains(NavigationBreakpoint.Narrow)
+ ) {
+ target.classList.remove(
+ NavigationBreakpoint.Full,
+ NavigationBreakpoint.Small
+ );
+ target.classList.add(NavigationBreakpoint.Narrow);
+ }
+ if (
+ currentWidth > breakpoints[1] &&
+ !target.classList.contains(NavigationBreakpoint.Full)
+ ) {
+ target.classList.remove(
+ NavigationBreakpoint.Narrow,
+ NavigationBreakpoint.Small
+ );
+ target.classList.add(NavigationBreakpoint.Full);
+ }
+};
+
export const Navigation = ({
appName,
homeLink = '/',
@@ -319,47 +357,28 @@ export const Navigation = ({
breakpoints = [478, 1000],
onResize,
}: NavigationProps) => {
- const navigationRef = useRef(
- null
- ) as MutableRefObject;
+ const navigationRef = useRef(null);
const actionsRef = useRef(null);
- useResizeObserver(navigationRef.current, (entries) => {
- if (entries.length === 0 || !navigationRef.current) return;
- const w = entries[0].borderBoxSize[0].inlineSize;
- if (onResize) onResize(w, navigationRef);
- if (
- w <= breakpoints[0] &&
- !navigationRef.current.classList.contains(NavigationBreakpoint.Small)
- ) {
- navigationRef.current.classList.remove(
- NavigationBreakpoint.Full,
- NavigationBreakpoint.Narrow
- );
- navigationRef.current.classList.add(NavigationBreakpoint.Small);
- }
- if (
- w > breakpoints[0] &&
- w <= breakpoints[1] &&
- !navigationRef.current.classList.contains(NavigationBreakpoint.Narrow)
- ) {
- navigationRef.current.classList.remove(
- NavigationBreakpoint.Full,
- NavigationBreakpoint.Small
- );
- navigationRef.current.classList.add(NavigationBreakpoint.Narrow);
- }
- if (
- w > breakpoints[1] &&
- !navigationRef.current.classList.contains(NavigationBreakpoint.Full)
- ) {
- navigationRef.current.classList.remove(
- NavigationBreakpoint.Narrow,
- NavigationBreakpoint.Small
- );
- navigationRef.current.classList.add(NavigationBreakpoint.Full);
- }
- });
+ useLayoutEffect(() => {
+ if (!navigationRef.current) return;
+ const target = navigationRef.current;
+ const currentWidth = Math.min(
+ target.getBoundingClientRect().width,
+ window.innerWidth
+ );
+ setSizeVariantClasses(breakpoints, currentWidth, target);
+
+ const handler = () => {
+ const currentWidth = target.getBoundingClientRect().width;
+ setSizeVariantClasses(breakpoints, currentWidth, target);
+ onResize?.(currentWidth, target);
+ };
+ window.addEventListener('resize', handler);
+ return () => {
+ window.removeEventListener('resize', handler);
+ };
+ }, [breakpoints, onResize]);
const [drawerOpen, setDrawerOpen] = useDrawer((state) => [
state.drawerOpen,
@@ -368,9 +387,13 @@ export const Navigation = ({
const drawerTrigger = (
);