The three layout components in Spell Index require no props — each manages its own state and wires itself directly to the router. They are intended to be mounted once at the application root and remain persistent across every route change.Documentation Index
Fetch the complete documentation index at: https://mintlify.com/apursley2012/spell-index/llms.txt
Use this file to discover all available pages before exploring further.
Navigation
TheNavigation component renders a persistent site-wide nav. On lg breakpoints and above it displays as a fixed left sidebar (w-64); on smaller screens it collapses entirely and a hamburger button opens a full-screen animated mobile drawer instead.
Route array
All nine routes are hardcoded insideNavigation.js. Each entry has a path, a thematic label displayed in Cinzel font, and a sub subtitle shown in smaller uppercase tracking:
Active state indicator
The current route is detected with React Router’suseLocation. When a route is active, its label renders in amber (text-amber) instead of the default parchment. A 4 × 4 px amber dot (w-1 h-1 rounded-full) appears to the left of the active link and animates between routes using Framer Motion’s layoutId="nav-indicator" — this causes the dot to smoothly slide from the old link to the new one rather than blinking in place.
Desktop sidebar
backdrop-blur-mdkeeps the sidebar legible over the particle background.- The scrollable route list uses a custom scrollbar class (
custom-scrollbar) to preserve the dark aesthetic.
Mobile drawer
On screens smaller thanlg, the sidebar is hidden (hidden lg:flex). A floating hamburger button (fixed top-4 right-4 z-50) opens the drawer by setting local isOpen state to true.
The drawer itself is conditionally rendered inside Framer Motion’s AnimatePresence and slides in from the right:
initial/animate stagger so links fade-slide up in sequence. Clicking any link calls setIsOpen(false) to dismiss the drawer.
Usage
Navigation relies on React Router’s useLocation hook. It must be rendered inside a <BrowserRouter> (or equivalent) context, or it will throw a hook error.Footer
TheFooter component renders a 192 px tall bar (h-48) pinned below the main content area with a top border (border-t border-ink). It has three visual layers:
- Dot grid — a CSS
background-imageradial-gradient pattern at 24 × 24 px spacing, 50 % opacity. - Credit text — centered
font-cinzellines: “Manifested with TypeScript and questionable life choices.” and the current year (new Date().getFullYear()). - Mouse-tracking cat — a small teal SVG cat icon (
w-8 h-8) that spring-animates itsleftposition to follow the horizontal cursor position within the footer. The position is tracked via anonMouseMovehandler that calculates(clientX - rect.left) / rect.width * 100as a percentage.
PageTransition
PageTransition is a thin wrapper component that accepts React children and applies a unified enter/exit animation to every page. It uses the current location.pathname as its Framer Motion key so that a new animation fires on every route change.
Transition behaviour
| Phase | opacity | filter | y offset |
|---|---|---|---|
| Enter | 0 → 1 | blur(10px) → blur(0) | 20px → 0 |
| Exit | 1 → 0 | blur(0) → blur(10px) | 0 → -20px |
[0.22, 1, 0.36, 1] (a fast-in slow-out curve) gives the entrance a premium feel. Duration is 0.8s.
Usage
Wrap each page component withPageTransition inside your route definitions:
PageTransition must be a child of Framer Motion’s <AnimatePresence> to enable exit animations. The root App component wraps all routes in <AnimatePresence mode="wait"> to ensure only one page is mounted at a time during transitions.