Skip to main content

Documentation Index

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

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

Every page in the portfolio follows the same four-layer pattern: a React component wrapped in a Win98Window, a route entry in the HashRouter, a desktop icon entry in the Taskbar, and a static HTML shell file for direct-URL support on GitHub Pages. Adding a new section means wiring up all four layers in order.
The project ships with compiled, minified bundles in assets/main.js and assets/main.css. Those files are production build artifacts — editing them directly is not viable. You need the original source files (the JSX components, router config, Taskbar.js, etc.) to make structural changes. After editing source, run npm run build to regenerate the bundles.
1

Create the page component

Create a new React component file in your pages directory. The component must import Win98Window and useNavigate, then return the window wrapper with your content inside.
src/pages/MyPage.jsx
import { useNavigate } from "react-router-dom";
import Win98Window from "../components/Win98Window";

export default function MyPage() {
  const navigate = useNavigate();

  return (
    <Win98Window
      title="My New Page"
      onClose={() => navigate("/")}
    >
      <div className="p-4 font-mono text-retro-black">
        <h2 className="font-pixel text-lg text-shadow-retro mb-3">
          My New Page
        </h2>
        <p className="text-sm leading-relaxed">
          Add your content here. All Tailwind retro tokens and Win98
          utility classes are available — see the Theming guide for the
          full list.
        </p>
      </div>
    </Win98Window>
  );
}
The onClose prop receives the function the window’s ✕ button calls — always navigate back to / so the user returns to the desktop when they close the window. The title string appears in the Win98 title bar. The optional icon prop accepts a React node rendered beside the title.
Use React DevTools to inspect the component tree of an existing page (like /about) while the dev server is running. You can see exactly which props Win98Window receives, what className patterns the inner content uses, and how data flows from the route into the component — handy for matching the visual style of existing pages.
2

Register the route

Open the main router configuration file (wherever your HashRouter and Routes block live) and add a <Route> entry alongside the existing routes.
src/main.jsx (router section)
import { HashRouter, Routes, Route } from "react-router-dom";
import MyPage from "./pages/MyPage";

// Inside your router JSX:
<HashRouter>
  <Routes>
    <Route path="/"             element={<Desktop />} />
    <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="/blog"         element={<Blog />} />
    <Route path="/contact"      element={<Contact />} />
    <Route path="/testimonials" element={<Testimonials />} />

    {/* Add your new route here */}
    <Route path="/my-page"      element={<MyPage />} />
  </Routes>
</HashRouter>
Because the project uses a HashRouter, all navigation happens via the URL hash (e.g. /#/my-page), which means no server-side routing configuration is needed for development. The hash segment never reaches the web server.
3

Add a desktop icon

Open Taskbar.js (or the file that defines the desktop icons array) and append a new entry to the array. Each entry is a plain object with a name string displayed below the icon, a path matching the route you just registered, and an icon React node.
src/components/Taskbar.js (desktop icons array)
import { Star } from "lucide-react"; // or any lucide icon

const desktopIcons = [
  { name: "About Moi",               path: "/about",        icon: <User className="text-retro-magenta" /> },
  { name: "Stuff I Built",           path: "/projects",     icon: <Monitor className="text-retro-turquoise" /> },
  { name: "My L33t Skillz",          path: "/skills",       icon: <Terminal className="text-retro-black" /> },
  { name: "~*~ Where I've Been ~*~", path: "/work",         icon: <Briefcase className="text-retro-black" /> },
  { name: "Deep Dives",              path: "/case-studies", icon: <FileText className="text-retro-navy" /> },
  { name: "My Webrings & Writings",  path: "/blog",         icon: <BookOpen className="text-retro-teal" /> },
  { name: "Sign My Guestbook",       path: "/contact",      icon: <Mail className="text-retro-magenta" /> },
  { name: "Kind Words",              path: "/testimonials", icon: <MessageSquare className="text-retro-turquoise" /> },

  // Add your new icon here
  { name: "My New Page",             path: "/my-page",      icon: <Star className="text-retro-navy" /> },
];
Pick an icon color from the retro token set that fits the section’s personality — text-retro-magenta for personal content, text-retro-turquoise for work/projects, text-retro-teal for writing, text-retro-navy for anything formal.
4

Add a Start menu entry

The Start menu flyout is also driven by an array in Taskbar.js. Each item is a plain object with name, path, and icon fields. A divider between groups is represented by a single { divider: true } entry. Add a matching item for the new page:
src/components/Taskbar.js (Start menu items array)
const startMenuItems = [
  { name: "About Moi",              path: "/about",        icon: <User size={16} className="text-retro-navy" /> },
  { name: "Stuff I Built",          path: "/projects",     icon: <Monitor size={16} className="text-retro-navy" /> },
  { name: "My L33t Skillz",         path: "/skills",       icon: <Terminal size={16} className="text-retro-navy" /> },
  // ... existing entries ...

  { divider: true }, // optional visual separator

  // Add your new menu item here
  { name: "My New Page",            path: "/my-page",      icon: <Star size={16} className="text-retro-navy" /> },
];
Start menu icons should use size={16} and text-retro-navy to match the uniform navy-on-silver style of the existing menu items. Divider items must contain only { divider: true } — no other fields.
5

Create the static HTML shell

GitHub Pages serves static files, so every route needs an HTML entry point that bootstraps the React app and signals which route to activate. Copy the existing pages/About.html file to a new file named pages/MyPage.html and update the route value.
pages/MyPage.html
<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" type="image/svg+xml" href="/vite.svg" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>My New Page | windows-98</title>
    <script type="module" crossorigin src="../assets/main.js"></script>
    <link rel="modulepreload" crossorigin href="../assets/jsx-runtime.js">
    <link rel="modulepreload" crossorigin href="../assets/index.js">
    <link rel="modulepreload" crossorigin href="../assets/proxy.js">
    <link rel="modulepreload" crossorigin href="../assets/index2.js">
    <link rel="modulepreload" crossorigin href="./components/CustomCursor.js">
    <link rel="modulepreload" crossorigin href="./components/VisitorCounter.js">
    <link rel="modulepreload" crossorigin href="../assets/createLucideIcon.js">
    <link rel="modulepreload" crossorigin href="./components/Taskbar.js">
    <link rel="modulepreload" crossorigin href="./components/DesktopIcon.js">
    <link rel="modulepreload" crossorigin href="./components/Win98Window.js">
    <link rel="stylesheet" crossorigin href="../assets/main.css">
    <script>
  window.__STATIC_PAGE_ROUTE__ = "/my-page";
  if (!window.location.hash || window.location.hash === "#/" || window.location.hash === "#") {
    window.location.hash = "/my-page";
  }
</script>
  </head>
  <body>
    <div id="root"></div>
  </body>
</html>
The window.__STATIC_PAGE_ROUTE__ assignment is read by the router bootstrap code before React mounts. The if block ensures that users who land directly on yoursite.com/pages/MyPage.html (via a shared link or bookmark) are redirected to the correct hash route instead of seeing the bare desktop. Only update the route string — keep the surrounding modulepreload links identical to About.html.
6

Rebuild

With all four layers in place, compile the updated source into production bundles:
npm run build
The Vite build outputs fresh assets/main.js and assets/main.css files. If you are working locally with the dev server (npm run dev), Vite’s hot module replacement will pick up component and route changes without a manual rebuild — but you still need a production build before deploying to GitHub Pages.

Editing existing content

Beyond adding new pages, several common content areas are driven by plain JavaScript arrays in the source. Finding and editing these arrays is the fastest way to update the portfolio’s text content.

Blog posts

The blog page renders from a posts data array in the source. Each entry is a plain object with date, title, and content fields:
Blog posts array
const blogPosts = [
  {
    date:    "11/05/2023",
    title:   "Why I still use tables for layout (jk)",
    content: "Your post body text here.",
  },
  {
    date:    "09/12/2023",
    title:   "My new mechanical keyboard",
    content: "Your post body text here.",
  },
  // Add a new post by appending an object here
  {
    date:    "MM/DD/YYYY",
    title:   "Your post title",
    content: "Your post body text.",
  },
];
Add entries to the top of the array to have them appear first. Remove an entry to pull it from the blog listing entirely.

Guestbook seed data

The guestbook initializes with default entries from a seed array. These are the messages that appear before any real visitor submissions are stored in localStorage.
Guestbook seed array
const guestbookSeed = [
  {
    name:    "CoolDude99",
    date:    "10/12/1999",
    message: "Awesome site! Added u to my webring.",
  },
  {
    name:    "xX_Angel_Xx",
    date:    "04/05/2001",
    message: "luv the colors <3 plz sign my guestbook back!",
  },
  {
    name:    "WebMaster_Dan",
    date:    "11/20/2003",
    message: "Your HTML is very clean. Good use of tables.",
  },
];
Edit the name, date, and message fields to replace the placeholder seed messages with your own. Use dates in MM/DD/YYYY format to match the retro aesthetic.

Work history cards

The Work page renders from a work history data array in the source. Each object represents one job card with fields for company name, role, years, and a description string. Locate the array near the Work component definition and update the values:
Work history array
const workHistory = [
  {
    company: "Acme Corp",
    role:    "Senior Front-End Engineer",
    years:   "2021 – Present",
    desc:    "Built and maintained design systems for high-traffic marketing pages.",
  },
  {
    company: "Initech",
    role:    "UI Developer",
    years:   "2018 – 2021",
    desc:    "Developed internal tooling dashboards using React and D3.",
  },
  // Add, remove, or reorder entries here
];
Each card in the Work window maps directly to one array entry, so the order of entries controls the display order in the window.

Win98Window Component

Deep-dive into the Win98Window props, title bar behavior, and drag constraints.

Theming

Swap color tokens, fonts, and CRT effects to personalize the portfolio’s visual style.

Build docs developers (and LLMs) love