Skip to main content

Documentation Index

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

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

Digital Domain is a single-page application that uses React Router v6’s BrowserRouter to manage navigation entirely on the client. All 11 routes share a single Layout shell component that renders the sticky Win98-style header, the scanlines overlay, and the AnimatePresence-wrapped <Outlet> for page transitions. Navigation never triggers a full page reload — the browser URL updates and React Router swaps the active page component in place.

Route Table

PathComponentDescription
/HomeWelcome marquee ticker, Notepad-style intro window, webring links
/aboutAboutBio inside a Win98 window, RPG-style animated stat bars, Polaroid photos
/projectsProjectsThree draggable project windows on a free-form desktop canvas
/skillsSkillsFull Win98 desktop simulation with icons, openable windows, and a taskbar
/workWorkTypewriter animation rendering CAREER.TXT inside a Notepad window
/case-studiesCaseStudiesWindows Explorer file browser listing case study .doc files
/case-studies/:slugCaseStudyDetailWordPad-style document view for an individual case study
/blogBlogFilterable list of blog posts styled as Win98 table layouts
/blog/:slugBlogPostIndividual blog post with mood, currently-listening metadata
/contactContactRetro contact form inside a Send_Message.exe window
/testimonialsGuestbookInteractive guestbook with live-added entries and random emoji avatars

Router Setup

The entire application is bootstrapped in assets/main.js. The root App component (Ee in the minified bundle) wraps everything in a BrowserRouter, then declares a single top-level Route for "/" whose element is <Layout>. Every page is a nested child route rendered into Layout’s <Outlet>.
import {
  BrowserRouter,
  Routes,
  Route,
} from "react-router-dom";

function App() {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/" element={<Layout />}>
          <Route index element={<Home />} />
          <Route path="about" element={<About />} />
          <Route path="projects" element={<Projects />} />
          <Route path="skills" element={<Skills />} />
          <Route path="work" element={<Work />} />
          <Route path="case-studies" element={<CaseStudies />} />
          <Route path="case-studies/:slug" element={<CaseStudyDetail />} />
          <Route path="blog" element={<Blog />} />
          <Route path="blog/:slug" element={<BlogPost />} />
          <Route path="contact" element={<Contact />} />
          <Route path="testimonials" element={<Guestbook />} />
        </Route>
      </Routes>
    </BrowserRouter>
  );
}

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<App />);
Child routes use bare path segments (e.g. "about", "blog/:slug") rather than absolute paths. React Router v6 concatenates them onto the parent "/" automatically, so the resolved URL for the About page is /about, not //about.
The Layout component defines a navLinks array that drives the sticky header navigation bar. Each entry maps a URL path to a display label. The active route is highlighted by comparing navLinks[i].path against useLocation().pathname.
const navLinks = [
  { path: "/",             label: "Home"         },
  { path: "/about",        label: "About Me"     },
  { path: "/projects",     label: "Projects"     },
  { path: "/skills",       label: "Skills"       },
  { path: "/work",         label: "Work"         },
  { path: "/case-studies", label: "Case Studies" },
  { path: "/blog",         label: "Blog"         },
  { path: "/testimonials", label: "Guestbook"    },
  { path: "/contact",      label: "Contact"      },
];
navLinks is mapped to a row of <BeveledButton> components inside <nav>. The active button receives the active prop, which applies the shadow-win-btn-active box-shadow to give it the “pressed” Win98 look:
<nav className="flex flex-wrap gap-2">
  {navLinks.map((link) => (
    <NavLink to={link.path} key={link.path} className="focus:outline-none">
      <BeveledButton active={location.pathname === link.path}>
        <span className="hover:underline decoration-2 underline-offset-2">
          {link.label}
        </span>
      </BeveledButton>
    </NavLink>
  ))}
</nav>
There are 11 routes in the router tree but only 9 entries in navLinks. The /case-studies/:slug and /blog/:slug detail pages are accessible via their list views and are intentionally omitted from the top-level navigation.

Dynamic Routes with useParams()

Two routes use a :slug URL parameter to load individual content items:
  • /case-studies/:slugCaseStudyDetail
  • /blog/:slugBlogPost
Both components call useParams() to retrieve the slug and use it as the document heading (with hyphens replaced by spaces):
import { useParams } from "react-router-dom";

function CaseStudyDetail() {
  const { slug } = useParams();

  return (
    <div className="max-w-3xl mx-auto pb-20">
      <Window title={`${slug}.doc - WordPad`}>
        <div className="p-8 bg-white font-comic space-y-6">
          <h1 className="font-vt323 text-4xl text-center text-retro-purple uppercase">
            {slug?.replace(/-/g, " ")}
          </h1>
          {/* ... */}
        </div>
      </Window>
    </div>
  );
}
function BlogPost() {
  const { slug } = useParams();

  return (
    <div className="max-w-3xl mx-auto">
      <table className="w-full bg-white border-4 border-win-gray shadow-win-out">
        <tbody>
          <tr>
            <td className="bg-titlebar text-white font-comic font-bold p-4 text-2xl">
              {slug?.replace(/-/g, " ").toUpperCase()}
            </td>
          </tr>
          {/* ... */}
        </tbody>
      </table>
    </div>
  );
}
The slugs for the case studies are defined in a static caseStudies array (rebranding-techcorp, scaling-databases, accessibility-overhaul). Blog post slugs (why-tables-are-better, css-is-a-fad, my-new-winamp-skin) are likewise statically declared — there is no external CMS or API.

Static Deployment Caveat

Digital Domain is deployed as a static site (GitHub Pages). Because BrowserRouter uses the HTML5 History API, navigating directly to a deep link like https://example.github.io/digital-domain/about will result in a 404 from the server — the web host has no file at that path.The repository includes a .nojekyll file to prevent Jekyll processing, but you must also configure a 404 fallback. Common solutions for GitHub Pages include:
  • Adding a 404.html that redirects to index.html and restores the path via sessionStorage.
  • Switching to HashRouter so all routing state lives in the URL hash (e.g. /#/about), which the static host never intercepts.

Build docs developers (and LLMs) love