Add persistent navbar with SSH Keys link

Refactor App.tsx to use Layout + Outlet pattern with sticky navbar
containing: Dashboard | Machines | Sync Pairs | Jobs | SSH Keys | Settings.
Clean up redundant button row from Dashboard and inline SSH Keys links.
This commit is contained in:
2026-07-07 20:40:24 -04:00
parent bfa006f4ab
commit 93c22e844e
4 changed files with 59 additions and 28 deletions
+58 -8
View File
@@ -1,4 +1,4 @@
import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom';
import { BrowserRouter, Routes, Route, Navigate, NavLink, Outlet } from 'react-router-dom';
import { useState, useEffect } from 'react';
import Login from './pages/Login';
import Dashboard from './pages/Dashboard';
@@ -20,18 +20,68 @@ function ProtectedRoute({ children }: { children: JSX.Element }) {
return authed ? children : <Navigate to="/login" />;
}
function NavBar() {
const navItems = [
{ to: '/', label: 'Dashboard' },
{ to: '/machines', label: 'Machines' },
{ to: '/sync-pairs', label: 'Sync Pairs' },
{ to: '/jobs', label: 'Jobs' },
{ to: '/ssh-keys', label: 'SSH Keys' },
{ to: '/settings', label: 'Settings' },
];
return (
<nav className="sticky top-0 z-50 bg-gray-900 border-b border-gray-700">
<div className="max-w-7xl mx-auto px-4">
<div className="flex items-center h-14 gap-1">
<span className="text-white font-bold text-lg mr-4">SyncServer</span>
{navItems.map(item => (
<NavLink
key={item.to}
to={item.to}
end={item.to === '/'}
className={({ isActive }) =>
`px-3 py-1.5 rounded text-sm font-medium transition-colors ${
isActive
? 'text-white bg-gray-800'
: 'text-gray-400 hover:text-white hover:bg-gray-800'
}`
}
>
{item.label}
</NavLink>
))}
</div>
</div>
</nav>
);
}
function Layout() {
return (
<div className="min-h-screen bg-gray-900">
<NavBar />
<main>
<Outlet />
</main>
</div>
);
}
export default function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/login" element={<Login />} />
<Route path="/" element={<ProtectedRoute><Dashboard /></ProtectedRoute>} />
<Route path="/machines" element={<ProtectedRoute><Machines /></ProtectedRoute>} />
<Route path="/sync-pairs" element={<ProtectedRoute><SyncPairs /></ProtectedRoute>} />
<Route path="/jobs" element={<ProtectedRoute><JobHistory /></ProtectedRoute>} />
<Route path="/jobs/:id" element={<ProtectedRoute><JobDetail /></ProtectedRoute>} />
<Route path="/settings" element={<ProtectedRoute><Settings /></ProtectedRoute>} />
<Route path="/ssh-keys" element={<ProtectedRoute><SSHKeys /></ProtectedRoute>} />
<Route element={<ProtectedRoute><Layout /></ProtectedRoute>}>
<Route path="/" element={<Dashboard />} />
<Route path="/machines" element={<Machines />} />
<Route path="/sync-pairs" element={<SyncPairs />} />
<Route path="/jobs" element={<JobHistory />} />
<Route path="/jobs/:id" element={<JobDetail />} />
<Route path="/ssh-keys" element={<SSHKeys />} />
<Route path="/settings" element={<Settings />} />
</Route>
<Route path="*" element={<Navigate to="/" />} />
</Routes>
</BrowserRouter>