diff --git a/src/components/layout/docs-layout-client.tsx b/src/components/layout/docs-layout-client.tsx
index e5b03574..409b22eb 100644
--- a/src/components/layout/docs-layout-client.tsx
+++ b/src/components/layout/docs-layout-client.tsx
@@ -1,6 +1,8 @@
"use client";
+import { usePathname } from "next/navigation";
import type { ReactNode } from "react";
+import { useMemo } from "react";
import { baseOptions } from "@/app/layout.config";
import {
ArbitrumIcon,
@@ -21,6 +23,79 @@ interface DocsLayoutClientProps {
export function DocsLayoutClient({ children }: DocsLayoutClientProps) {
const currentTree = useNavigationTree();
+ const pathname = usePathname();
+
+ // Determine if shared paths should be included in Stellar tab based on sessionStorage
+ const tabs = useMemo(() => {
+ const isSharedPath =
+ pathname.startsWith("/monitor") || pathname.startsWith("/relayer");
+ const lastEcosystem =
+ typeof window !== "undefined"
+ ? sessionStorage.getItem("lastEcosystem")
+ : null;
+
+ // Include shared paths in Stellar tab only if coming from Stellar context
+ const stellarUrls =
+ isSharedPath && lastEcosystem === "stellar"
+ ? new Set(["/stellar-contracts", "/monitor", "/relayer"])
+ : new Set(["/stellar-contracts"]);
+
+ return [
+ {
+ title: "Ethereum & EVM",
+ url: "/contracts",
+ icon: ,
+ urls: new Set([
+ "/contracts",
+ "/community-contracts",
+ "/upgrades-plugins",
+ "/wizard",
+ "/relayer",
+ "/monitor",
+ "/ui-builder",
+ "/upgrades",
+ "/defender",
+ "/tools",
+ ]),
+ },
+ {
+ title: "Arbitrum Stylus",
+ url: "/contracts-stylus",
+ icon: ,
+ },
+ {
+ title: "Starknet",
+ url: "/contracts-cairo",
+ icon: ,
+ },
+ {
+ title: "Stellar",
+ url: "/stellar-contracts",
+ icon: ,
+ urls: stellarUrls,
+ },
+ {
+ title: "Midnight",
+ url: "/contracts-compact",
+ icon: ,
+ },
+ {
+ title: "Polkadot",
+ url: "/substrate-runtimes",
+ icon: ,
+ },
+ {
+ title: "Uniswap Hooks",
+ url: "/uniswap-hooks",
+ icon: ,
+ },
+ {
+ title: "Zama FHEVM",
+ url: "/confidential-contracts",
+ icon: ,
+ },
+ ];
+ }, [pathname]);
return (
,
- urls: new Set([
- "/contracts",
- "/community-contracts",
- "/upgrades-plugins",
- "/wizard",
- "/relayer",
- "/monitor",
- "/ui-builder",
- "/upgrades",
- "/defender",
- "/tools",
- ]),
- },
- {
- title: "Arbitrum Stylus",
- url: "/contracts-stylus",
- icon: ,
- },
- {
- title: "Starknet",
- url: "/contracts-cairo",
- icon: ,
- },
- {
- title: "Stellar",
- url: "/stellar-contracts",
- icon: ,
- },
- {
- title: "Midnight",
- url: "/contracts-compact",
- icon: ,
- },
- {
- title: "Polkadot",
- url: "/substrate-runtimes",
- icon: ,
- },
- {
- title: "Uniswap Hooks",
- url: "/uniswap-hooks",
- icon: ,
- },
- {
- title: "Zama FHEVM",
- url: "/confidential-contracts",
- icon: ,
- },
- ],
+ tabs,
}}
>
{children}
diff --git a/src/hooks/use-navigation-tree.ts b/src/hooks/use-navigation-tree.ts
index 2dfda17d..2f0a0e3f 100644
--- a/src/hooks/use-navigation-tree.ts
+++ b/src/hooks/use-navigation-tree.ts
@@ -1,6 +1,7 @@
"use client";
import { usePathname } from "next/navigation";
+import { useEffect } from "react";
import {
arbitrumStylusTree,
ethereumEvmTree,
@@ -15,6 +16,26 @@ import {
export function useNavigationTree() {
const pathname = usePathname();
+ // Track ecosystem changes in sessionStorage
+ useEffect(() => {
+ if (typeof window === "undefined") return;
+
+ if (pathname.startsWith("/stellar-contracts")) {
+ sessionStorage.setItem("lastEcosystem", "stellar");
+ } else if (
+ pathname.startsWith("/contracts") ||
+ pathname.startsWith("/community-contracts") ||
+ pathname.startsWith("/upgrades-plugins") ||
+ pathname.startsWith("/wizard") ||
+ pathname.startsWith("/ui-builder") ||
+ pathname.startsWith("/upgrades") ||
+ pathname.startsWith("/defender") ||
+ pathname.startsWith("/tools")
+ ) {
+ sessionStorage.setItem("lastEcosystem", "ethereum");
+ }
+ }, [pathname]);
+
// Determine which navigation tree to use based on the current path
if (pathname.startsWith("/contracts-stylus")) {
return arbitrumStylusTree;
@@ -34,5 +55,23 @@ export function useNavigationTree() {
return ethereumEvmTree;
}
+ // For shared paths like /monitor and /relayer, check sessionStorage to see
+ // which ecosystem was last active, defaulting to ethereumEvmTree
+ if (typeof window !== "undefined") {
+ const lastEcosystem = sessionStorage.getItem("lastEcosystem");
+
+ if (pathname.startsWith("/monitor") || pathname.startsWith("/relayer")) {
+ switch (lastEcosystem) {
+ case "stellar":
+ return stellarTree;
+ case "ethereum":
+ return ethereumEvmTree;
+ default:
+ return ethereumEvmTree;
+ }
+ }
+ }
+
+ // Default to ethereumEvmTree for other paths
return ethereumEvmTree;
}
diff --git a/src/navigation/ethereum-evm.json b/src/navigation/ethereum-evm.json
index 1c2078c8..7bc278aa 100644
--- a/src/navigation/ethereum-evm.json
+++ b/src/navigation/ethereum-evm.json
@@ -785,7 +785,7 @@
},
{
"type": "separator",
- "name": "Tools"
+ "name": "Open Source Tools"
},
{
"type": "folder",
@@ -837,11 +837,6 @@
"name": "Solana Integration",
"url": "/relayer/solana"
},
- {
- "type": "page",
- "name": "Stellar Integration",
- "url": "/relayer/stellar"
- },
{
"type": "folder",
"name": "API Reference",
@@ -1085,6 +1080,11 @@
{
"type": "folder",
"name": "Monitor",
+ "index": {
+ "type": "page",
+ "name": "Overview",
+ "url": "/monitor"
+ },
"children": [
{
"type": "page",
diff --git a/src/navigation/stellar.json b/src/navigation/stellar.json
index 0db75ee8..9b3bea6d 100644
--- a/src/navigation/stellar.json
+++ b/src/navigation/stellar.json
@@ -257,5 +257,351 @@
]
}
]
+ },
+ {
+ "type": "separator",
+ "name": "Open Source Tools"
+ },
+ {
+ "type": "folder",
+ "name": "Relayer",
+ "children": [
+ {
+ "type": "page",
+ "name": "Overview",
+ "url": "/relayer"
+ },
+ {
+ "type": "page",
+ "name": "Quickstart",
+ "url": "/relayer/quickstart"
+ },
+ {
+ "type": "folder",
+ "name": "Configuration",
+ "index": {
+ "type": "page",
+ "name": "Overview",
+ "url": "/relayer/configuration"
+ },
+ "children": [
+ {
+ "type": "page",
+ "name": "Signers",
+ "url": "/relayer/configuration/signers"
+ },
+ {
+ "type": "page",
+ "name": "Network Configuration",
+ "url": "/relayer/network_configuration"
+ },
+ {
+ "type": "page",
+ "name": "Storage Configuration",
+ "url": "/relayer/configuration/storage"
+ }
+ ]
+ },
+ {
+ "type": "page",
+ "name": "Stellar Integration",
+ "url": "/relayer/stellar"
+ },
+ {
+ "type": "folder",
+ "name": "API Reference",
+ "index": {
+ "type": "page",
+ "name": "Overview",
+ "url": "/relayer/api"
+ },
+ "children": [
+ {
+ "type": "folder",
+ "name": "Relayers",
+ "children": [
+ {
+ "type": "page",
+ "name": "List Relayers",
+ "url": "/relayer/api/listRelayers"
+ },
+ {
+ "type": "page",
+ "name": "Create Relayer",
+ "url": "/relayer/api/createRelayer"
+ },
+ {
+ "type": "page",
+ "name": "Get Relayer",
+ "url": "/relayer/api/getRelayer"
+ },
+ {
+ "type": "page",
+ "name": "Delete Relayer",
+ "url": "/relayer/api/deleteRelayer"
+ },
+ {
+ "type": "page",
+ "name": "Update Relayer",
+ "url": "/relayer/api/updateRelayer"
+ },
+ {
+ "type": "page",
+ "name": "Get Relayer Balance",
+ "url": "/relayer/api/getRelayerBalance"
+ },
+ {
+ "type": "page",
+ "name": "RPC",
+ "url": "/relayer/api/rpc"
+ },
+ {
+ "type": "page",
+ "name": "Sign",
+ "url": "/relayer/api/sign"
+ },
+ {
+ "type": "page",
+ "name": "Sign Transaction",
+ "url": "/relayer/api/signTransaction"
+ },
+ {
+ "type": "page",
+ "name": "Sign Typed Data",
+ "url": "/relayer/api/signTypedData"
+ },
+ {
+ "type": "page",
+ "name": "Get Relayer Status",
+ "url": "/relayer/api/getRelayerStatus"
+ },
+ {
+ "type": "page",
+ "name": "Send Transaction",
+ "url": "/relayer/api/sendTransaction"
+ },
+ {
+ "type": "page",
+ "name": "List Transactions",
+ "url": "/relayer/api/listTransactions"
+ },
+ {
+ "type": "page",
+ "name": "Get Transaction by Nonce",
+ "url": "/relayer/api/getTransactionByNonce"
+ },
+ {
+ "type": "page",
+ "name": "Delete Pending Transactions",
+ "url": "/relayer/api/deletePendingTransactions"
+ },
+ {
+ "type": "page",
+ "name": "Get Transaction by ID",
+ "url": "/relayer/api/getTransactionById"
+ },
+ {
+ "type": "page",
+ "name": "Replace Transaction",
+ "url": "/relayer/api/replaceTransaction"
+ },
+ {
+ "type": "page",
+ "name": "Cancel Transaction",
+ "url": "/relayer/api/cancelTransaction"
+ }
+ ]
+ },
+ {
+ "type": "folder",
+ "name": "Plugins",
+ "children": [
+ {
+ "type": "page",
+ "name": "Call Plugin",
+ "url": "/relayer/api/callPlugin"
+ }
+ ]
+ },
+ {
+ "type": "folder",
+ "name": "Notifications",
+ "children": [
+ {
+ "type": "page",
+ "name": "List Notifications",
+ "url": "/relayer/api/listNotifications"
+ },
+ {
+ "type": "page",
+ "name": "Create Notification",
+ "url": "/relayer/api/createNotification"
+ },
+ {
+ "type": "page",
+ "name": "Get Notification",
+ "url": "/relayer/api/getNotification"
+ },
+ {
+ "type": "page",
+ "name": "Delete Notification",
+ "url": "/relayer/api/deleteNotification"
+ },
+ {
+ "type": "page",
+ "name": "Update Notification",
+ "url": "/relayer/api/updateNotification"
+ }
+ ]
+ },
+ {
+ "type": "folder",
+ "name": "Signers",
+ "children": [
+ {
+ "type": "page",
+ "name": "List Signers",
+ "url": "/relayer/api/listSigners"
+ },
+ {
+ "type": "page",
+ "name": "Create Signer",
+ "url": "/relayer/api/createSigner"
+ },
+ {
+ "type": "page",
+ "name": "Get Signer",
+ "url": "/relayer/api/getSigner"
+ },
+ {
+ "type": "page",
+ "name": "Delete Signer",
+ "url": "/relayer/api/deleteSigner"
+ },
+ {
+ "type": "page",
+ "name": "Update Signer",
+ "url": "/relayer/api/updateSigner"
+ }
+ ]
+ },
+ {
+ "type": "folder",
+ "name": "Metrics",
+ "children": [
+ {
+ "type": "page",
+ "name": "Scrape Metrics",
+ "url": "/relayer/api/scrape_metrics"
+ },
+ {
+ "type": "page",
+ "name": "List Metrics",
+ "url": "/relayer/api/list_metrics"
+ },
+ {
+ "type": "page",
+ "name": "Metric Detail",
+ "url": "/relayer/api/metric_detail"
+ }
+ ]
+ },
+ {
+ "type": "folder",
+ "name": "Health",
+ "children": [
+ {
+ "type": "page",
+ "name": "Health",
+ "url": "/relayer/api/health"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "type": "page",
+ "name": "Project Structure",
+ "url": "/relayer/structure"
+ },
+ {
+ "type": "page",
+ "name": "Project Roadmap",
+ "url": "/relayer/roadmap"
+ },
+ {
+ "type": "page",
+ "name": "Plugins",
+ "url": "/relayer/plugins"
+ },
+ {
+ "type": "page",
+ "name": "Changelog",
+ "url": "/relayer/changelog"
+ },
+ {
+ "type": "page",
+ "name": "Rust Book",
+ "url": "https://docs-v1-1--openzeppelin-relayer.netlify.app/openzeppelin_relayer/",
+ "external": true
+ }
+ ]
+ },
+ {
+ "type": "folder",
+ "name": "Monitor",
+ "children": [
+ {
+ "type": "page",
+ "name": "Quickstart",
+ "url": "/monitor/quickstart"
+ },
+ {
+ "type": "page",
+ "name": "Architecture Guide",
+ "url": "/monitor/architecture"
+ },
+ {
+ "type": "page",
+ "name": "Project Structure",
+ "url": "/monitor/project-structure"
+ },
+ {
+ "type": "page",
+ "name": "RPC Client",
+ "url": "/monitor/rpc"
+ },
+ {
+ "type": "page",
+ "name": "Custom scripts",
+ "url": "/monitor/scripts"
+ },
+ {
+ "type": "page",
+ "name": "Error Handling",
+ "url": "/monitor/error"
+ },
+ {
+ "type": "page",
+ "name": "Testing",
+ "url": "/monitor/testing"
+ },
+ {
+ "type": "page",
+ "name": "Contribution guidelines",
+ "url": "/monitor/contribution"
+ },
+ {
+ "type": "page",
+ "name": "Changelog",
+ "url": "/monitor/changelog"
+ },
+ {
+ "type": "page",
+ "name": "Technical Rust Documentation",
+ "url": "https://docs-v1-0--openzeppelin-monitor.netlify.app/openzeppelin_monitor/",
+ "external": true
+ }
+ ]
}
]