The Craft implements client-side navigation entirely through React Router v6. All routes are declared inDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/apursley2012/the-craft/llms.txt
Use this file to discover all available pages before exploring further.
assets/main.js, nested under a single parent layout route, and backed by React.lazy imports so that each page’s JavaScript chunk is only fetched when that route is first visited. A custom 404 component catches any path that does not match the defined routes and keeps the grimoire aesthetic intact.
Route Map
Every navigable path in the application is listed below. The parent route (/) renders the Layout shell, and all child routes render their page component into the <Outlet /> inside that shell.
| Path | Component | Notes |
|---|---|---|
/ | Home | Index route — renders at the root path |
/about | About | Practitioner bio page |
/projects | Projects | Portfolio work and side projects |
/skills | Skills | Arcane arts / technology skills |
/work | Work | Coven records — employment history |
/case-studies | CaseStudies | Tome of Workings deep-dives |
/blog | Blog | Whispers — blog posts |
/contact | Contact | Summoning — contact form |
/testimonials | Testimonials | Client and colleague testimonials |
/* | NotFound | Custom 404 — “This page was hexed out of existence.” |
Lazy Loading Pattern
Every page component is wrapped inReact.lazy with a dynamic import(). This keeps the initial bundle small: the JavaScript for /projects, for example, is only downloaded the first time a visitor navigates to that path.
React.Suspense shows a full-screen fallback component — an animated sigil icon with the text “Consulting the spirits…” rendered in the font-cursive (Pinyon Script) typeface.
The Suspense fallback renders against
bg-midnight with the sigil pulsing via the .animate-pulse-glow utility class. In practice the fallback is rarely visible because Vite’s module preload injection pre-fetches linked chunks while the browser is idle.Layout Nesting
The full router tree demonstrates how theLayout shell wraps every page:
Layout component renders MoonPhaseNav and CursorTrail once — they are persistent across all navigation events. Only the <Outlet /> content changes as the user moves between routes.
MoonPhaseNav Route Array
components/MoonPhaseNav.js maintains its own routes array that drives both the navigation links and the moon phase SVG rendered beside each link. Each entry has three fields:
| Field | Type | Description |
|---|---|---|
path | string | The URL path this nav item links to |
name | string | The grimoire-flavoured display label |
phase | string | Moon phase key that selects the correct SVG illustration |
The
testimonials route does not appear in MoonPhaseNav — it is accessible by URL but intentionally excluded from the primary navigation. To surface it in the nav, add an entry to this array (see below).Adding a New Route
Create the page file
Add a new file in
assets/, for example assets/Rituals.js. Export a named component that matches the filename:Add the Route element
Inside the
<Route path="/" element={<Layout />}> block in assets/main.js, add a child route: