diff --git a/package-lock.json b/package-lock.json
index c3e139a..4029398 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -12,6 +12,7 @@
"lucide-react": "^1.17.0",
"react": "^19.2.6",
"react-dom": "^19.2.6",
+ "react-router-dom": "^7.18.0",
"recharts": "^3.8.1",
"tailwindcss": "^4.3.0"
},
@@ -1697,6 +1698,19 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/cookie": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.1.1.tgz",
+ "integrity": "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
+ }
+ },
"node_modules/cross-spawn": {
"version": "7.0.6",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
@@ -2977,6 +2991,44 @@
}
}
},
+ "node_modules/react-router": {
+ "version": "7.18.0",
+ "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.18.0.tgz",
+ "integrity": "sha512-pTTGt8J+ji1NOmYnjzT+bAJy/1zD+Jp4ziO6cL7T3ZLvXKtusO7BpFqlRXitqpcPVqllsIXFHRMt+2/k3Xn6HQ==",
+ "license": "MIT",
+ "dependencies": {
+ "cookie": "^1.0.1",
+ "set-cookie-parser": "^2.6.0"
+ },
+ "engines": {
+ "node": ">=20.0.0"
+ },
+ "peerDependencies": {
+ "react": ">=18",
+ "react-dom": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/react-router-dom": {
+ "version": "7.18.0",
+ "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.18.0.tgz",
+ "integrity": "sha512-Fi0yY6kgtKae/Th2xibdWK0KSdYZ4B53Gyf6wRtomOKWgpNm7H7+DyfDhncdz9FKbpS+1jmDhg3F4WoGJ+yFOA==",
+ "license": "MIT",
+ "dependencies": {
+ "react-router": "7.18.0"
+ },
+ "engines": {
+ "node": ">=20.0.0"
+ },
+ "peerDependencies": {
+ "react": ">=18",
+ "react-dom": ">=18"
+ }
+ },
"node_modules/recharts": {
"version": "3.8.1",
"resolved": "https://registry.npmjs.org/recharts/-/recharts-3.8.1.tgz",
@@ -3077,6 +3129,12 @@
"semver": "bin/semver.js"
}
},
+ "node_modules/set-cookie-parser": {
+ "version": "2.7.2",
+ "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.2.tgz",
+ "integrity": "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==",
+ "license": "MIT"
+ },
"node_modules/shebang-command": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
diff --git a/package.json b/package.json
index fd16521..897023b 100644
--- a/package.json
+++ b/package.json
@@ -14,6 +14,7 @@
"lucide-react": "^1.17.0",
"react": "^19.2.6",
"react-dom": "^19.2.6",
+ "react-router-dom": "^7.18.0",
"recharts": "^3.8.1",
"tailwindcss": "^4.3.0"
},
diff --git a/src/App.tsx b/src/App.tsx
index bb9bdef..4b92cca 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -1,9 +1,9 @@
import { useState } from 'react'
+import { Routes, Route } from 'react-router-dom'
import Sidebar from './components/Sidebar'
import TopBar from './components/TopBar'
-import StatusCards from './components/StatusCards'
-import MiddleRow from './components/MiddleRow'
-import BottomRow from './components/BottomRow'
+import Glance from './pages/Glance'
+import Infrastructure from './pages/Infrastructure'
function App() {
const [sidebarCollapsed, setSidebarCollapsed] = useState(false)
@@ -26,47 +26,10 @@ function App() {
className="flex w-full flex-col overflow-hidden"
style={{ height: 'calc(100vh - 56px)', scrollbarWidth: 'none', padding: '16px 24px 24px 24px', gap: '20px' }}
>
- {/* Hero + KPI overlap — KPI bottom aligns with banner bottom */}
-
-

{
- const target = e.currentTarget
- target.style.display = 'none'
- target.parentElement!.classList.add('bg-card')
- }}
- />
- {/* Side vignette so the rectangular image blends into the page edges */}
-
- {/* KPI cards positioned so their bottom edge aligns with banner bottom */}
-
-
-
-
-
- {/* Middle Row — stretches to fill available vertical space */}
-
-
-
-
- {/* Bottom Row — anchored to the bottom */}
-
-
-
+
+ } />
+ } />
+
diff --git a/src/components/Sidebar.tsx b/src/components/Sidebar.tsx
index c8fd688..de748cb 100644
--- a/src/components/Sidebar.tsx
+++ b/src/components/Sidebar.tsx
@@ -1,3 +1,4 @@
+import { useLocation, Link } from 'react-router-dom'
import {
LayoutGrid,
Server,
@@ -15,16 +16,17 @@ interface SidebarProps {
}
const navItems = [
- { icon: LayoutGrid, label: 'Glance', route: '/', active: true },
- { icon: Server, label: 'Infrastructure', route: '/infrastructure', active: false },
- { icon: Globe, label: 'Network', route: '/network', active: false },
- { icon: Bookmark, label: 'BookNest', route: '/booknest', active: false },
- { icon: Terminal, label: 'Terminal', route: '/terminal', active: false },
- { icon: Settings, label: 'Settings', route: '/settings', active: false },
+ { icon: LayoutGrid, label: 'Glance', route: '/' },
+ { icon: Server, label: 'Infrastructure', route: '/infrastructure' },
+ { icon: Globe, label: 'Network', route: '/network' },
+ { icon: Bookmark, label: 'BookNest', route: '/booknest' },
+ { icon: Terminal, label: 'Terminal', route: '/terminal' },
+ { icon: Settings, label: 'Settings', route: '/settings' },
]
export default function Sidebar({ collapsed, onToggle }: SidebarProps) {
const width = collapsed ? 64 : 200
+ const location = useLocation()
return (