Documentation Index
Fetch the complete documentation index at: https://mintlify.com/apursley2012/space-mission/llms.txt
Use this file to discover all available pages before exploring further.
The Navigation component is the persistent top-of-screen header in Space Mission. It sits in a fixed position with z-50 so it always floats above every page, the starfield background, and any animated content. On desktop it presents a horizontal HUD control panel — status readout on the left, nine nav links across the center/right — while on mobile it collapses to a hamburger button that opens a Framer Motion animated drawer.
Desktop Layout
The bar is divided into two visible regions on wide screens:
Left — HUD Status Panel. A two-ring pulsing beacon (the inner dot using animate-pulse, the outer ring using animate-ping-slow) sits next to the text NAV_SYS_ONLINE, with the current useLocation().pathname rendered beneath it in a monospace font. This panel is purely informational and gives the UI its mission-control feel.
Center/Right — Nav Links. Nine <NavLink> elements from React Router are spread horizontally. React Router’s NavLink automatically receives an isActive prop that the component uses to apply active styling and trigger the Framer Motion underline indicator.
import { NavLink, useLocation } from 'react-router-dom';
// Status panel example
const { pathname } = useLocation();
<div className="flex items-center gap-3 font-mono text-xs text-space-turquoise">
<div className="relative flex items-center justify-center w-4 h-4">
<div className="absolute w-2 h-2 bg-space-turquoise rounded-full animate-pulse" />
<div className="absolute w-4 h-4 border border-space-turquoise rounded-full animate-ping-slow opacity-50" />
</div>
<div className="flex flex-col">
<span className="tracking-widest">NAV_SYS_ONLINE</span>
<span className="text-space-white/50">{pathname}</span>
</div>
</div>
Nav Routes
All nine routes are defined in the Uo array inside the component. Each object maps a path to a mission-control label displayed in the nav bar:
| Path | Label |
|---|
/ | SYS_CORE |
/about | ORIGIN |
/projects | STAR_MAP |
/skills | CONSTELLATIONS |
/work | LOGS |
/case-studies | ARCHIVE |
/blog | TRANSMISSIONS |
/testimonials | SIGNALS |
/contact | COMMS |
Active Indicator
The active nav link is highlighted by a Framer Motion shared-layout background element using layoutId='nav-active'. When the route changes, Framer Motion detects that a new <NavLink> now owns the layoutId and smoothly spring-animates the background pill from its old position to the new one — no manual transition code required.
import { motion } from 'framer-motion';
import { NavLink } from 'react-router-dom';
{routes.map(({ path, label }) => (
<NavLink key={path} to={path} className="relative px-4 py-2 font-mono text-xs tracking-wider overflow-hidden group">
{({ isActive }) => (
<>
<span className={`relative z-10 ${isActive ? 'text-space-navy font-bold' : 'text-space-white/70 group-hover:text-space-turquoise'}`}>
{label}
</span>
{isActive && (
<motion.div
layoutId="nav-active"
className="absolute inset-0 bg-space-turquoise z-0"
transition={{ type: 'spring', stiffness: 300, damping: 30 }}
/>
)}
</>
)}
</NavLink>
))}
layoutId must be unique across the entire React tree. The value 'nav-active' is already reserved by Navigation — do not reuse this string in other components.
Mobile Navigation
On small viewports the center links are hidden (hidden md:flex) and a hamburger Menu icon button appears on the right side of the bar (md:hidden). Tapping it toggles a Framer Motion motion.div drawer that animates in from above. Each route item in the drawer is prefixed with a crosshair icon and closes the drawer automatically when tapped.
import { motion } from 'framer-motion';
import { Menu, X, Crosshair } from 'lucide-react';
// Hamburger toggle button (md:hidden)
<button
className="md:hidden hud-border p-2 rounded-sm text-space-turquoise"
onClick={() => setIsOpen(!isOpen)}
>
{isOpen ? <X size={20} /> : <Menu size={20} />}
</button>
// Drawer — conditionally rendered, animates in with motion.div
{isOpen && (
<motion.div
initial={{ opacity: 0, y: -20 }}
animate={{ opacity: 1, y: 0 }}
className="md:hidden absolute top-16 left-4 right-4 hud-border rounded-sm p-4 flex flex-col gap-2 pointer-events-auto"
>
{routes.map(({ path, label }) => (
<NavLink key={path} to={path} onClick={() => setIsOpen(false)}
className={({ isActive }) =>
`font-mono text-sm p-3 border border-transparent flex items-center gap-3
${isActive
? 'bg-space-turquoise/10 border-space-turquoise text-space-turquoise'
: 'text-space-white/70 hover:bg-space-white/5 hover:border-space-white/20'}`
}
>
<Crosshair size={14} className="opacity-50" />
{label}
</NavLink>
))}
</motion.div>
)}
The drawer closes when any link is clicked because the onClick callback calls setIsOpen(false). If you add a new route you do not need to wire this up separately — it inherits the same handler from the routes.map. Note that the drawer uses a plain conditional render rather than AnimatePresence, so there is no exit animation when it closes.
Adding a New Nav Item
To add a route to the navigation, insert a new object into the Uo array in Navigation.js:
// Inside Navigation.js — the Uo routes array
const Uo = [
{ path: '/', label: 'SYS_CORE' },
{ path: '/about', label: 'ORIGIN' },
{ path: '/projects', label: 'STAR_MAP' },
{ path: '/skills', label: 'CONSTELLATIONS'},
{ path: '/work', label: 'LOGS' },
{ path: '/case-studies',label: 'ARCHIVE' },
{ path: '/blog', label: 'TRANSMISSIONS' },
{ path: '/testimonials',label: 'SIGNALS' },
{ path: '/contact', label: 'COMMS' },
// ✅ Add your new route here:
{ path: '/awards', label: 'HONOURS' },
];
Then create the matching page component and register it in your router:
// src/pages/Awards.jsx
import { PageTransition } from '../components/PageTransition';
const AwardsPage = () => (
<PageTransition>
<div className="max-w-6xl mx-auto">
<h1 className="font-mono text-space-teal">HONOURS</h1>
{/* page content */}
</div>
</PageTransition>
);
export default AwardsPage;
// In your router configuration
import AwardsPage from './pages/Awards';
<Route path="/awards" element={<AwardsPage />} />
The React Router path string. Must begin with / and be unique across all routes.
The mission-control display label shown in the nav bar. Convention is UPPER_SNAKE_CASE.
Customization
Changing a label. Labels are purely display strings — edit the label value in Uo without touching any other file.
Changing the status text. The NAV_SYS_ONLINE string is hardcoded in the JSX of the status panel. Replace it with any string; for example you could make it dynamic based on an online/offline event listener.
Adjusting the spring. The layoutId='nav-active' indicator uses a spring transition. Tune stiffness and damping to control how snappy or floaty the slide feels:
transition={{ type: 'spring', stiffness: 300, damping: 30 }}
// Snappier: stiffness: 600, damping: 40
// Floatier: stiffness: 120, damping: 15