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
17 changes: 15 additions & 2 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,11 @@ const Routing = () => {

const renderPageComponent = (PageComponent: PageComponent) => {
if (!PageComponent.route.isPageEnabled) return null
const { parentPathBase: parentPathBaseFromRoute } = PageComponent.route
const parentPathBase = parentPathBaseFromRoute || ""
const updatedParentPathBase = PageComponent.route.path
? `${parentPathBase}/${PageComponent.route.path}`
: parentPathBase

return (
<Fragment key={PageComponent.route.path}>
Expand All @@ -217,9 +222,17 @@ 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) => {
page.route.parentPathBase = updatedParentPathBase
return renderPageComponent(page)
})}
</Route>
</Fragment>
)
Expand Down
94 changes: 86 additions & 8 deletions src/components/SubNavigationPills/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,29 @@ import {
Stack,
useColorModeValue,
} from "@threshold-network/components"
import { useMatch, useResolvedPath } from "react-router-dom"
import { matchPath, resolvePath, useLocation } from "react-router-dom"
import { RouteProps } from "../../types"
import Link from "../Link"

interface Props {
interface SubNavigationPillsProps {
links: RouteProps[]
}

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 }) => {
r-czajkowski marked this conversation as resolved.
Show resolved Hide resolved
const { pathname } = useLocation()
const linksWithTitle = links.filter((link) => !!link.title)
const activePillIndex = getActivePillIndex(linksWithTitle, pathname)
const wrapperBorderColor = useColorModeValue("gray.100", "gray.700")

return (
Expand All @@ -38,16 +51,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 +95,70 @@ 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[], locationPathname: string) => {
const pathMatches: PathMatchResult[] = []
for (let i = 0; i < pills.length; i++) {
const { path, pathOverride, parentPathBase } = pills[i]
// This is a workaround for preview links. We have to remove the branch name
// from the pathname so first we check if `parentPathBase` is not an
// undefined. If it is then it means that this is the main page without any
// additional paths so we can just use an empty string here. If it's not
// undefined then we have to remove all the characters (if there are any)
// that are before the occurrence of the `parentPathBase`. If this is a
// preview then those removed characters should be a name of the branch. In
// other cases there should not be any character before the occurrence of
// the `parentPathBase` so nothing happens.
const currentPathname = parentPathBase
? locationPathname.includes(parentPathBase) &&
locationPathname.indexOf(parentPathBase) !== 0
? locationPathname.substring(
locationPathname.indexOf(parentPathBase),
locationPathname.length
)
: locationPathname
: ""
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[], locationPathname: string) => {
const pathMatches = getPathMatches(pills, locationPathname)
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
1 change: 1 addition & 0 deletions src/pages/Staking/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,7 @@ Auth.route = {
StakingPage.route = {
path: "",
index: false,
pathOverride: "*",
title: "Staking",
isPageEnabled: true,
}
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
6 changes: 5 additions & 1 deletion src/types/page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ export type RouteProps = {
pages?: PageComponent[]
hideFromMenu?: boolean
isPageEnabled: boolean
// Paths combined from all Route parents of the current Route
parentPathBase?: string
}

export type PageComponent = FC<RouteProps> & { route: RouteProps }
export type PageComponent = FC<RouteProps> & {
route: RouteProps
}
Loading