Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/apursley2012/sys-witch/llms.txt

Use this file to discover all available pages before exploring further.

PortalNav is the site-wide navigation component rendered at the top of every non-home page in Sys.Witch V2. It displays the SYS.WITCH logo mark alongside a list of seven portfolio sections, each paired with a custom SVG sigil icon. On desktop the bar sits as a fixed frosted-glass strip along the top of the viewport; on mobile it collapses into a full-screen overlay that slides in when the hamburger button is tapped. The navigation array is defined directly in PortalNav.js as Nd — a plain JavaScript object array. Each entry carries a path, a display label, a sigilId matching a key in data/sigils.js, and a neon color accent:
const navItems = [
  { path: "/",             label: "Portal",         sigilId: "home",         color: "purple"  },
  { path: "/about",        label: "Origin",         sigilId: "about",        color: "cyan"    },
  { path: "/projects",     label: "Conjured Works", sigilId: "projects",     color: "magenta" },
  { path: "/skills",       label: "Arcana",         sigilId: "skills",       color: "lime"    },
  { path: "/writing",      label: "Tomes",          sigilId: "writing",      color: "purple"  },
  { path: "/case-studies", label: "Ritual Reports", sigilId: "case-studies", color: "cyan"    },
  { path: "/contact",      label: "Cast Message",   sigilId: "contact",      color: "magenta" },
];
To add a new route, append an object to this array with a matching route registered in your React Router config and a valid sigil key from data/sigils.js.

Visual Appearance

On desktop (md: breakpoint and above) the <nav> renders as a fixed strip with:
  • fixed positioning, md:top-0 md:left-0 md:w-full md:h-20
  • md:bg-surface/80 md:backdrop-blur-md — 80 % opacity surface colour with a 12 px backdrop blur
  • md:border-b md:border-neon-purple/20 — a 1 px bottom border at 20 % neon-purple opacity
  • z-40 stacking context (mobile hamburger button uses z-50)
Active links are highlighted with a neon colour glow and an animated 2 px underline bar:
// Active link — colour and glow applied dynamically per-item accent
className={isActive
  ? `text-neon-${color} text-glow-${color}`
  : "text-text-secondary hover:text-text-primary"}

// Underline bar rendered inside the label span when active
<span className={`absolute -bottom-2 left-0 w-full h-[2px] bg-neon-${color} shadow-glow-${color}`} />
Each link also shows a Sigil icon at 18 px. When inactive the sigil is rendered at opacity-50; hover and active states bring it to full opacity via group-hover:opacity-100.

Logo Area

The desktop logo area renders the home sigil at 32 px alongside the SYS.WITCH wordmark:
<div className="hidden md:flex items-center gap-3 group">
  <Sigil
    id="home"
    color="purple"
    size={32}
    className="group-hover:animate-pulse-glow"
  />
  <span className="font-display text-xl tracking-widest text-glow-purple text-neon-purple">
    SYS.WITCH
  </span>
</div>
The home sigil path is "M12 2 L22 12 L12 22 L2 12 Z M12 6 L18 12 L12 18 L6 12 Z M12 10 L14 12 L12 14 L10 12 Z" — three concentric diamonds forming the portal diamond mark. On group hover it triggers the animate-pulse-glow keyframe (pulse-glow cycles brightness between 1 and 1.5 over 3 s).

Mobile Behavior

On small screens (< md) the entire nav is hidden off-screen with -translate-y-full. A fixed hamburger button (Lucide Menu icon at 28 px, z-50) appears in the top-right corner. Tapping it toggles a React useState boolean that drives the overlay class:
// Open state — full-screen overlay
"inset-0 bg-base/95 backdrop-blur-xl translate-y-0"

// Closed state — hidden above viewport
"top-0 left-0 w-full h-screen -translate-y-full md:h-auto"
The transition uses transition-all duration-500 ease-in-out. When open, the hamburger icon swaps to a Lucide X icon. Tapping any nav link calls setIsOpen(false) to dismiss the overlay.

Usage

PortalNav is rendered automatically by Layout on all non-home routes — you do not need to import it into individual pages:
// Layout.js renders PortalNav conditionally
const isHome = location.pathname === "/";

return (
  <div className="min-h-screen flex flex-col relative">
    <ParticleField />
    {!isHome && <PortalNav />}
    <main className={`flex-grow relative z-10 ${isHome ? "" : "pt-24 pb-16"}`}>
      <Outlet />
    </main>
  </div>
);
If you ever need to render PortalNav in isolation — for example in a Storybook story — import it directly:
import PortalNav from "./components/layout/PortalNav";

export default function Preview() {
  return (
    <>
      <PortalNav />
      <main className="pt-24"></main>
    </>
  );
}
1

Open PortalNav.js

Locate the navItems array (minified as Nd) near the bottom of components/layout/PortalNav.js.
2

Add or edit an entry

Each object requires path, label, sigilId, and color. color must be one of purple, cyan, magenta, or lime to match the theme token set.
3

Register a sigil

If you’re introducing a new sigil, add its SVG path data to data/sigils.js under the key that matches your new sigilId.
4

Add the route

Register the matching path in your React Router <Routes> tree inside App.jsx so the link resolves correctly.
The active-link detection uses React Router’s NavLink isActive callback, which performs an exact match by default. The Portal home link (/) will only be marked active when pathname is exactly "/".

Build docs developers (and LLMs) love