Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix two active navigation pills #524

Merged
merged 9 commits into from
Aug 16, 2023
22 changes: 18 additions & 4 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -197,15 +197,22 @@ const Routing = () => {
<Routes>
<Route path="*" element={<Layout />}>
<Route index element={<Navigate to="overview" />} />
{pages.map(renderPageComponent)}
{pages.map((page) => renderPageComponent(page))}
r-czajkowski marked this conversation as resolved.
Show resolved Hide resolved
<Route path="*" element={<Navigate to="overview" />} />
</Route>
</Routes>
)
}

const renderPageComponent = (PageComponent: PageComponent) => {
const renderPageComponent = (
PageComponent: PageComponent,
/** @see PageComponent type */
parentPathBase: string = ""
r-czajkowski marked this conversation as resolved.
Show resolved Hide resolved
) => {
if (!PageComponent.route.isPageEnabled) return null
const updatedParentPathBase = PageComponent.route.path
? `${parentPathBase}/${PageComponent.route.path}`
: parentPathBase

return (
<Fragment key={PageComponent.route.path}>
Expand All @@ -217,9 +224,16 @@ const renderPageComponent = (PageComponent: PageComponent) => {
)}
<Route
path={PageComponent.route.path}
element={<PageComponent {...PageComponent.route} />}
element={
<PageComponent
{...PageComponent.route}
parentPathBase={updatedParentPathBase}
/>
}
>
{PageComponent.route.pages?.map(renderPageComponent)}
{PageComponent.route.pages?.map((page) =>
renderPageComponent(page, updatedParentPathBase)
)}
</Route>
</Fragment>
)
Expand Down
88 changes: 80 additions & 8 deletions src/components/SubNavigationPills/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,33 @@ import {
Stack,
useColorModeValue,
} from "@threshold-network/components"
import { useMatch, useResolvedPath } from "react-router-dom"
import { matchPath, resolvePath } from "react-router-dom"
import { RouteProps } from "../../types"
import Link from "../Link"

interface Props {
interface SubNavigationPillsProps {
links: RouteProps[]
/** @see PageComponent type */
parentPathBase: string
r-czajkowski marked this conversation as resolved.
Show resolved Hide resolved
}

const SubNavigationPills: FC<Props> = ({ links }) => {
interface PathMatchResult {
index: number
path: string
pathOverride?: string
resolvedPath: string
match: any
}
interface NavPill extends RouteProps {
isActive?: boolean
}

const SubNavigationPills: FC<SubNavigationPillsProps> = ({
links,
parentPathBase,
}) => {
const linksWithTitle = links.filter((link) => !!link.title)
const activePillIndex = getActivePillIndex(linksWithTitle, parentPathBase)
const wrapperBorderColor = useColorModeValue("gray.100", "gray.700")

return (
Expand All @@ -38,16 +55,17 @@ const SubNavigationPills: FC<Props> = ({ links }) => {
height="28px"
as="ul"
>
{linksWithTitle.map(renderPill)}
{linksWithTitle.map((linkWithTitle, index) => {
const isActive = index === activePillIndex
return renderPill(linkWithTitle, isActive)
})}
</HStack>
</Box>
</>
)
}

const NavPill: FC<RouteProps> = ({ path, pathOverride, title }) => {
const resolved = useResolvedPath(pathOverride || path)
const isActive = useMatch({ path: resolved.pathname, end: true })
const NavPill: FC<NavPill> = ({ path, title, isActive = false }) => {
const activeColor = useColorModeValue("brand.500", "gray.100")
const underlineColor = useColorModeValue("brand.500", "white")

Expand Down Expand Up @@ -81,6 +99,60 @@ const NavPill: FC<RouteProps> = ({ path, pathOverride, title }) => {
)
}

const renderPill = (pill: RouteProps) => <NavPill key={pill.path} {...pill} />
const renderPill = (pill: RouteProps, isActive = false) => (
<NavPill key={pill.path} isActive={isActive} {...pill} />
)

const getPathMatches = (pills: RouteProps[], parentPathBase: string = "") => {
const pathMatches: PathMatchResult[] = []
for (let i = 0; i < pills.length; i++) {
const { path, pathOverride } = pills[i]
const location = window.location.pathname
// This is a workaround for preview links. We have to remove the branch name
// from the pathname
const currentPathname =
location.includes(parentPathBase) &&
location.indexOf(parentPathBase) !== 0
? location.substring(location.indexOf(parentPathBase), location.length)
: location
const resolved = resolvePath(
pathOverride
? `${parentPathBase}/${pathOverride}`
: `${parentPathBase}/${path}`
)
const match = matchPath(
{ path: resolved.pathname, end: true },
currentPathname
)
pathMatches.push({
index: i,
path,
pathOverride,
resolvedPath: resolved.pathname,
match,
})
}
return pathMatches
}

const getActivePillIndex = (pills: RouteProps[], parentPathBase: string) => {
const pathMatches = getPathMatches(pills, parentPathBase)
const matchedPaths = pathMatches.filter((_) => {
return !!_.match
})
if (matchedPaths.length === 0) return undefined
if (matchedPaths.length === 1) return matchedPaths[0].index

const matchedElementWithLongestPathnameBase = matchedPaths.reduce(
(maxElement, currentElement) => {
return currentElement.match.pathnameBase.length >
maxElement.match.pathnameBase.length
? currentElement
: maxElement
}
)

return matchedElementWithLongestPathnameBase.index
}

export default SubNavigationPills
8 changes: 7 additions & 1 deletion src/pages/Feedback/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,13 @@ import Settings from "./Settings"
import { featureFlags } from "../../constants"

const FeedbackPage: PageComponent = (props) => {
return <PageLayout title={props.title} pages={props.pages} />
return (
<PageLayout
title={props.title}
pages={props.pages}
parentPathBase={props.parentPathBase}
/>
)
}

FeedbackPage.route = {
Expand Down
7 changes: 6 additions & 1 deletion src/pages/PageLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,15 @@ import useDocumentTitle from "../hooks/useDocumentTitle"
export interface PageLayoutProps extends ContainerProps {
pages?: PageComponent[]
title?: string
/** @see PageComponent type */
parentPathBase: string
}

const PageLayout: FC<PageLayoutProps> = ({
pages,
title,
children,
parentPathBase,
...restProps
}) => {
useDocumentTitle(`Threshold - ${title}`)
Expand All @@ -23,7 +26,9 @@ const PageLayout: FC<PageLayoutProps> = ({

return (
<>
{links.length > 0 && <SubNavigationPills links={links} />}
{links.length > 0 && (
<SubNavigationPills links={links} parentPathBase={parentPathBase} />
)}
<Container
maxW={{ base: "2xl", xl: "6xl" }}
mt="6.25rem"
Expand Down
9 changes: 8 additions & 1 deletion src/pages/Staking/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,12 @@ const StakingPage: PageComponent = (props) => {
} = useAppSelector((state) => state.account)

return (
<PageLayout pages={props.pages} title={props.title} maxW={"100%"}>
<PageLayout
pages={props.pages}
title={props.title}
maxW={"100%"}
parentPathBase={props.parentPathBase}
>
<HStack
alignItems={{ base: "flex-end", lg: "flex-start" }}
w={"100%"}
Expand Down Expand Up @@ -186,6 +191,7 @@ const MainStakingPage: PageComponent = (props) => {
pages={props.pages}
title={props.title}
maxW={{ base: "2xl", lg: "4xl", xl: "6xl" }}
parentPathBase={props.parentPathBase}
/>
)
}
Expand All @@ -212,6 +218,7 @@ Auth.route = {
StakingPage.route = {
path: "",
index: false,
pathOverride: "*",
title: "Staking",
isPageEnabled: true,
}
Expand Down
8 changes: 7 additions & 1 deletion src/pages/Upgrade/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,13 @@ import PageLayout from "../PageLayout"
import { PageComponent } from "../../types"

const UpgradePage: PageComponent = (props) => {
return <PageLayout title={props.title} pages={props.pages} />
return (
<PageLayout
title={props.title}
pages={props.pages}
parentPathBase={props.parentPathBase}
/>
)
}

UpgradePage.route = {
Expand Down
4 changes: 2 additions & 2 deletions src/pages/tBTC/Bridge/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useEffect } from "react"
import { Grid, Box, Skeleton, Stack } from "@threshold-network/components"
import { Grid, Box } from "@threshold-network/components"
import { PageComponent } from "../../../types"
import { TbtcBalanceCard } from "./TbtcBalanceCard"
import { MintUnmintNav } from "./MintUnmintNav"
Expand Down Expand Up @@ -70,7 +70,7 @@ const TBTCBridge: PageComponent = (props) => {
TBTCBridge.route = {
path: "",
index: false,
pathOverride: "/tBTC/*",
pathOverride: "*",
pages: [MintPage, UnmintPage],
title: "Bridge",
isPageEnabled: true,
Expand Down
8 changes: 7 additions & 1 deletion src/pages/tBTC/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,13 @@ import { featureFlags } from "../../constants"
import { ExplorerPage } from "./Explorer"

const MainTBTCPage: PageComponent = (props) => {
return <PageLayout title={props.title} pages={props.pages} />
return (
<PageLayout
title={props.title}
pages={props.pages}
parentPathBase={props.parentPathBase}
/>
)
}

MainTBTCPage.route = {
Expand Down
9 changes: 8 additions & 1 deletion src/types/page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,11 @@ export type RouteProps = {
isPageEnabled: boolean
}

export type PageComponent = FC<RouteProps> & { route: RouteProps }
export type PageComponent = FC<
RouteProps & {
// Paths combined from all Route parents of the current Route
parentPathBase: string
r-czajkowski marked this conversation as resolved.
Show resolved Hide resolved
}
> & {
route: RouteProps
}
Loading