Skip to main content

Documentation Index

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

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

Y2K Webring uses hash-based routing so the entire site can be served from any static file host without server configuration. Every URL takes the form /pages/About.html#/about — the part after # is interpreted by React Router in the browser, while the server only ever sees the path before it. This means no .htaccess rules, no Nginx try_files, and no Netlify _redirects file is required.

Route Table

The seven application routes are defined in the Pd nav array inside components/layout/LeftNav.js. Each entry specifies the hash path, the display label rendered in the sidebar, and the lucide-react icon used beside it.
PathLabelIcon
/Home.exesparkles
/aboutAbout_Meuser
/projectsOpen_Projectsfolder-open
/skillsCharms_&_Abilitieszap
/writingArchive.logbook-open
/case-studiesCase_Filesfile-text
/contactSign_Guestbookmessage-square
The Pd array drives both the navigation sidebar rendering and, via React Router v6, the actual route matching. Changing a path in this array changes both the sidebar link and the URL the route responds to.

Hash Redirect Script

Each pre-rendered HTML file contains an inline <script> block that executes before the React bundle loads. Its job is to detect when a visitor arrives at a URL that has no hash fragment and immediately redirect them to the hash-prefixed equivalent.
(function () {
  if (!window.location.hash || window.location.hash === "#") {
    window.location.replace(
      window.location.pathname +
      window.location.search +
      "#/"
    );
  }
})();
For example, in pages/About.html the script contains a hardcoded "#/about" target, so a visitor who navigates directly to /pages/About.html is immediately redirected to /pages/About.html#/about before React mounts. Each HTML file also sets a window.__STATIC_PAGE_ROUTE__ variable (e.g. "/about") as a metadata hint for the app, while the actual redirect target is baked in as a literal string in each file’s inline script.
window.location.replace() is used instead of window.location.href = so the redirect does not add an extra entry to the browser’s history stack. The visitor’s Back button still takes them where they expect.

Page Transition Bar

PageTransitionBar (components/layout/PageTransitionBar.js) is the Framer Motion wrapper that AppLayout places around all page children. It provides two visual effects on every route change:
  1. Progress bar — A 1px-tall magenta bar (bg-y2k-magenta) fixed to the top of the viewport scales from scaleX: 0 to scaleX: 1 over 300 ms, then fades out.
  2. Page fade-in — The incoming page content animates from opacity: 0, y: 10 to opacity: 1, y: 0 with a 100 ms delay, giving a subtle “load” feel.
Both animations are driven by useLocation().pathname — when the pathname changes, a useState flag triggers the bar, and the Framer Motion key prop on the page wrapper forces a re-mount with fresh animation state.
// PageTransitionBar.js (reconstructed from source)
const PageTransitionBar = ({ children }) => {
  const location = useLocation();
  const [isTransitioning, setIsTransitioning] = useState(false);

  useEffect(() => {
    setIsTransitioning(true);
    const timer = setTimeout(() => setIsTransitioning(false), 300);
    return () => clearTimeout(timer);
  }, [location.pathname]);

  return (
    <>
      <AnimatePresence>
        {isTransitioning && (
          <motion.div
            initial={{ scaleX: 0 }}
            animate={{ scaleX: 1 }}
            exit={{ opacity: 0 }}
            transition={{ duration: 0.3, ease: "easeInOut" }}
            className="fixed top-0 left-0 right-0 h-1 bg-y2k-magenta z-50 origin-left"
          />
        )}
      </AnimatePresence>
      <motion.div
        key={location.pathname}
        initial={{ opacity: 0, y: 10 }}
        animate={{ opacity: 1, y: 0 }}
        transition={{ duration: 0.3, delay: 0.1 }}
        className="flex-1 w-full"
      >
        {children}
      </motion.div>
    </>
  );
};

Adding a New Route

1

Add an entry to the nav array in LeftNav.js

Open components/layout/LeftNav.js and find the Pd array. Append a new object with your chosen path, display label, and a lucide-react icon component:
{
  path: "/credits",
  label: "Credits.txt",
  icon: StarIcon, // import from lucide-react
}
2

Create the page component

In the source project, add a new file for your page’s React component (e.g. Credits.jsx). Export only the page body — AppLayout is applied by the router, not by individual page components.
3

Register the route in the React Router config

In your source project’s router configuration (wherever <HashRouter> and the <Routes> tree are defined), add a <Route> entry that maps your new path to your new page component:
<Route path="/credits" element={<CreditsPage />} />
4

Create the pre-rendered HTML file in /pages/

Copy an existing file such as pages/About.html to pages/Credits.html. Update two values inside the copy:
  • The <title> tag: <title>Credits | y2k-webring</title>
  • The inline script’s window.__STATIC_PAGE_ROUTE__ assignment and the hash fallback path:
<script>
  window.__STATIC_PAGE_ROUTE__ = "/credits";

  (function () {
    if (!window.location.hash || window.location.hash === "#") {
      window.location.replace(
        window.location.pathname +
        window.location.search +
        "#/credits"
      );
    }
  })();
</script>
Keep route paths in Pd and the pre-rendered HTML filenames in sync. A mismatch between the hash redirect target and the registered React Router path is the most common source of blank-page bugs when adding new routes.

Build docs developers (and LLMs) love