Skip to content

Commit bf323aa

Browse files
authored
Merge pull request #116 from OpenZeppelin/docs-improvements
fix: Fixing navigation
2 parents 91cf862 + f753e70 commit bf323aa

File tree

4 files changed

+98
-9
lines changed

4 files changed

+98
-9
lines changed

src/app/page.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ import {
2828
ZamaIcon,
2929
} from "@/components/icons";
3030
import { DefenderIcon } from "@/components/icons/defender-icon";
31+
import { latestStable as monitorLatestStable } from "../../content/monitor/latest-versions";
32+
import { latestStable as relayerLatestStable } from "../../content/relayer/latest-versions";
3133
import { baseOptions } from "./layout.config";
3234

3335
export default function HomePage() {
@@ -137,15 +139,15 @@ export default function HomePage() {
137139
{/* Dual Heroes: Monitor and Relayer */}
138140
<div className="grid grid-cols-1 lg:grid-cols-2 gap-4 sm:gap-6 mb-4 sm:mb-6">
139141
<FeatureCard
140-
href="/relayer"
142+
href={`/relayer/${relayerLatestStable}`}
141143
icon={<RelayersIcon className="h-6 w-6 sm:h-8 sm:w-8" />}
142144
title="Relayer"
143145
description="Automate onchain transactions to schedule jobs, batch calls, and relay gasless meta transactions within your self-hosted infrastructure."
144146
glowColor="tools"
145147
/>
146148

147149
<FeatureCard
148-
href="/monitor/1.1.x"
150+
href={`/monitor/${monitorLatestStable}`}
149151
icon={<MonitorIcon className="h-6 w-6 sm:h-8 sm:w-8" />}
150152
title="Monitor"
151153
description="Monitor onchain activity in real time to watch critical events, detect anomalies, trigger alerts on your preferred channels, and set automated responses with Relayer."

src/components/sidebar.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,7 @@ export function SidebarFooter(props: ComponentProps<"div">) {
236236

237237
export function SidebarViewport(props: ScrollAreaProps) {
238238
return (
239-
<ScrollArea {...props} className={cn("h-full", props.className)}>
239+
<ScrollArea {...props} className={cn("flex-1 min-h-0", props.className)}>
240240
<ScrollViewport
241241
className="p-4 overscroll-contain"
242242
style={

src/components/ui/scroll-area.tsx

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ const ScrollArea = React.forwardRef<
88
>(({ className, children, ...props }, ref) => (
99
<ScrollAreaPrimitive.Root
1010
ref={ref}
11-
type="scroll"
11+
type="always"
1212
className={cn("overflow-hidden", className)}
1313
{...props}
1414
>
@@ -43,14 +43,16 @@ const ScrollBar = React.forwardRef<
4343
ref={ref}
4444
orientation={orientation}
4545
className={cn(
46-
"flex select-none data-[state=hidden]:animate-fd-fade-out",
47-
orientation === "vertical" && "h-full w-1.5",
48-
orientation === "horizontal" && "h-1.5 flex-col",
46+
"flex select-none touch-none p-0.5 transition-colors",
47+
orientation === "vertical" &&
48+
"h-full w-2.5 border-l border-l-transparent",
49+
orientation === "horizontal" &&
50+
"h-2.5 flex-col border-t border-t-transparent",
4951
className,
5052
)}
5153
{...props}
5254
>
53-
<ScrollAreaPrimitive.ScrollAreaThumb className="relative flex-1 rounded-full bg-fd-border" />
55+
<ScrollAreaPrimitive.ScrollAreaThumb className="relative flex-1 rounded-full bg-fd-muted-foreground/40 hover:bg-fd-muted-foreground/60 transition-colors" />
5456
</ScrollAreaPrimitive.Scrollbar>
5557
));
5658
ScrollBar.displayName = ScrollAreaPrimitive.Scrollbar.displayName;

src/lib/is-active.ts

Lines changed: 86 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,59 @@ function normalize(url: string) {
55
return url;
66
}
77

8+
// Products that have versioned paths like /product/X.Y.x/...
9+
const VERSIONED_PRODUCTS = ["/relayer", "/monitor"];
10+
11+
// Version pattern: matches patterns like "1.3.x", "1.0.x", "2.1.x"
12+
const VERSION_PATTERN = /^(\d+\.\d+\.x)$/;
13+
14+
interface ParsedPath {
15+
base: string;
16+
version: string | null; // null means development/unversioned
17+
subpath: string;
18+
}
19+
20+
/**
21+
* Parses a path for versioned products.
22+
* For "/relayer/1.3.x/quickstart" returns { base: "/relayer", version: "1.3.x", subpath: "/quickstart" }
23+
* For "/relayer/quickstart" (development) returns { base: "/relayer", version: null, subpath: "/quickstart" }
24+
* For "/relayer" (development root) returns { base: "/relayer", version: null, subpath: "" }
25+
* For non-product paths, returns null.
26+
*/
27+
function parseProductPath(path: string): ParsedPath | null {
28+
const normalizedPath = normalize(path);
29+
30+
for (const product of VERSIONED_PRODUCTS) {
31+
if (normalizedPath === product) {
32+
// Exact match to product root (development version)
33+
return { base: product, version: null, subpath: "" };
34+
}
35+
36+
if (normalizedPath.startsWith(`${product}/`)) {
37+
const remainder = normalizedPath.slice(product.length + 1); // +1 for the slash
38+
const segments = remainder.split("/");
39+
const firstSegment = segments[0];
40+
41+
if (firstSegment && VERSION_PATTERN.test(firstSegment)) {
42+
// Versioned path: /relayer/1.3.x or /relayer/1.3.x/quickstart
43+
return {
44+
base: product,
45+
version: firstSegment,
46+
subpath: segments.length > 1 ? `/${segments.slice(1).join("/")}` : "",
47+
};
48+
}
49+
// Development path with subpath: /relayer/quickstart
50+
return {
51+
base: product,
52+
version: null,
53+
subpath: `/${remainder}`,
54+
};
55+
}
56+
}
57+
58+
return null;
59+
}
60+
861
export function isActive(
962
url: string,
1063
pathname: string,
@@ -13,7 +66,39 @@ export function isActive(
1366
url = normalize(url);
1467
pathname = normalize(pathname);
1568

16-
return url === pathname || (nested && pathname.startsWith(`${url}/`));
69+
// Standard exact match or nested match
70+
if (url === pathname || (nested && pathname.startsWith(`${url}/`))) {
71+
return true;
72+
}
73+
74+
// Check for versioned/development path matching
75+
const urlParsed = parseProductPath(url);
76+
const pathnameParsed = parseProductPath(pathname);
77+
78+
if (urlParsed && pathnameParsed) {
79+
// Both are paths for the same product
80+
if (urlParsed.base === pathnameParsed.base) {
81+
// Same subpath means it's the same "page" just different version
82+
if (urlParsed.subpath === pathnameParsed.subpath) {
83+
return true;
84+
}
85+
86+
// Check if pathname is nested under url's subpath
87+
if (
88+
nested &&
89+
pathnameParsed.subpath.startsWith(`${urlParsed.subpath}/`)
90+
) {
91+
return true;
92+
}
93+
94+
// Handle root match: /relayer/1.3.x should match any /relayer/* when nested
95+
if (nested && urlParsed.subpath === "") {
96+
return true;
97+
}
98+
}
99+
}
100+
101+
return false;
17102
}
18103

19104
export function isTabActive(tab: SidebarTab, pathname: string) {

0 commit comments

Comments
 (0)