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.

The Skills page is the most fully realised desktop simulation in Digital Domain. It renders a teal #008080 Windows 98 desktop complete with clickable file icons, openable skill windows, a bottom taskbar with a Start button, animated task buttons for each open window, and a static system clock. The entire interaction model — double-click to open, click title bar X to close, click taskbar button to focus — faithfully mirrors the Win98 user experience.

Desktop Container

The outermost container sets up the desktop canvas:
<div className="h-[80vh] bg-[#008080] relative overflow-hidden border-4 border-win-gray shadow-win-in flex flex-col">
  <div className="flex-1 p-4 flex flex-col gap-6 items-start">
    {/* Desktop icons */}
  </div>
  {/* Open windows */}
  {/* Taskbar */}
</div>
Visual appearance: The classic Windows 98 teal desktop (#008080) fills 80vh. The outer border uses border-4 border-win-gray shadow-win-in to give the sunken inset appearance. Icons are arranged top-to-bottom on the left side via flex flex-col gap-6 items-start. The taskbar is pinned to the bottom by the flexbox column layout.

Skill Icons

Four desktop icons are defined in a top-level constant array (y in the compiled source):
const skills = [
  {
    id: "frontend",
    label: "Frontend.exe",
    icon: LayoutTemplate,   // from lucide-react
    content: "React, Vue, Tailwind CSS, Framer Motion. Making things look pretty and move smoothly.",
  },
  {
    id: "backend",
    label: "Backend.bat",
    icon: Terminal,
    content: "Node.js, Python, Go. The invisible gears that make the machine actually work.",
  },
  {
    id: "database",
    label: "Databases.db",
    icon: Database,
    content: "PostgreSQL, MongoDB, Redis. Storing your data safely since 2010.",
  },
  {
    id: "languages",
    label: "Languages.txt",
    icon: CodeXml,
    content: "TypeScript, JavaScript, Python, SQL. I speak to computers so you don't have to.",
  },
];
Each icon renders as a div with onDoubleClick to open its associated window:
<div
  onDoubleClick={() => openWindow(skill.id)}
  className="flex flex-col items-center gap-1 w-24 cursor-pointer group"
>
  <div className="w-12 h-12 bg-transparent group-hover:bg-blue-500/30 flex items-center justify-center rounded">
    <skill.icon size={32} className="text-white drop-shadow-md" />
  </div>
  <span className="text-white font-comic text-sm text-center bg-transparent group-hover:bg-blue-600 px-1">
    {skill.label}
  </span>
</div>
Visual appearance: Icons are 48×48px (w-12 h-12) white Lucide SVGs with a drop-shadow-md for depth. Labels are white font-comic text-sm text centred below. On hover, the icon background becomes a translucent blue (group-hover:bg-blue-500/30) and the label gets a solid blue highlight (group-hover:bg-blue-600) — exactly matching the Win98 selected icon style.
A single click does nothing. Icons must be double-clicked to open their associated skill window, replicating authentic Windows desktop behaviour.

Window Open/Close State

Two useState hooks manage the desktop state:
const [openWindows, setOpenWindows] = useState([]);   // array of open window IDs
const [focusedId, setFocusedId]     = useState(null); // currently focused window ID
Opening a window — the openWindow function adds the ID if it is not already in the array:
const openWindow = (id) => {
  if (!openWindows.includes(id)) {
    setOpenWindows([...openWindows, id]);
  }
  setFocusedId(id);
};
Closing a window — the closeWindow function removes the ID from the array and clears focus if the closed window was focused:
const closeWindow = (id) => {
  setOpenWindows(openWindows.filter((w) => w !== id));
  if (focusedId === id) setFocusedId(null);
};
Each Window component receives onClose={() => closeWindow(skill.id)} and onFocus={() => setFocusedId(skill.id)} props, along with staggered defaultPosition values:
{skills.map((skill, index) =>
  openWindows.includes(skill.id) ? (
    <Window
      key={skill.id}
      title={skill.label}
      icon={<skill.icon size={14} />}
      defaultPosition={{ x: 100 + index * 30, y: 50 + index * 30 }}
      defaultSize={{ width: 300, height: 200 }}
      zIndex={focusedId === skill.id ? 50 : 10}
      onFocus={() => setFocusedId(skill.id)}
      onClose={() => closeWindow(skill.id)}
    >
      <div className="p-4 font-comic text-lg">{skill.content}</div>
    </Window>
  ) : null
)}
Visual appearance: Each skill window’s content area is a simple p-4 font-comic text-lg paragraph listing the technologies. Windows are 300×200px. The stagger formula { x: 100 + i*30, y: 50 + i*30 } cascades windows diagonally so they do not perfectly overlap on first open.

Taskbar

The taskbar is pinned to the bottom of the flex-column desktop container:
<div className="h-10 bg-win-gray shadow-win-out flex items-center px-1 gap-2 z-50">
  {/* Start button */}
  {/* Separator */}
  {/* Task buttons (AnimatePresence) */}
  {/* System clock */}
</div>

Start Button

<button className="bg-win-gray shadow-win-btn active:shadow-win-btn-active px-2 py-1 font-bold flex items-center gap-2 h-8">
  <img src="https://win98icons.alexmeub.com/icons/png/windows-0.png" alt="Start" className="w-4 h-4" />
  Start
</button>
The Windows logo image is sourced from the publicly available win98icons.alexmeub.com icon set. The button uses shadow-win-btn at rest and shadow-win-btn-active on :active for the pressed-in bevel effect. The Start button is decorative — it does not open a Start menu.

Task Buttons (AnimatePresence)

Open windows appear in the taskbar via AnimatePresence, which animates their entrance and exit:
<AnimatePresence>
  {openWindows.map((id) => {
    const skill = skills.find((s) => s.id === id);
    const isFocused = focusedId === id;
    return (
      <motion.button
        key={id}
        initial={{ opacity: 0, width: 0 }}
        animate={{ opacity: 1, width: "auto" }}
        exit={{ opacity: 0, width: 0 }}
        onClick={() => setFocusedId(id)}
        className={`
          px-2 py-1 text-sm font-comic flex items-center gap-2 min-w-[120px] max-w-[150px] truncate h-8
          ${isFocused ? "shadow-win-btn-active bg-gray-300" : "shadow-win-btn bg-win-gray"}
        `}
      >
        <skill.icon size={14} />
        <span className="truncate">{skill.label}</span>
      </motion.button>
    );
  })}
</AnimatePresence>
Visual appearance: Task buttons animate in by expanding from zero width (width: 0) to their natural width (width: "auto") while fading in from opacity: 0. On exit (window closed), they collapse back to zero width and fade out. The focused window’s task button uses the sunken bevel (shadow-win-btn-active bg-gray-300); unfocused buttons use the raised bevel (shadow-win-btn bg-win-gray).

System Clock

The tray clock at the right of the taskbar renders the current local time, refreshed on page render:
<div className="shadow-win-in px-2 py-1 text-xs font-comic h-8 flex items-center bg-win-gray">
  {new Date().toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" })}
</div>
The clock reads the time once on render using new Date(). It does not update live — there is no setInterval or useState driving it. It will show the time at which the component was last rendered.

Component Dependencies

ComponentSourceUsage
Window (p)components/Window.jsSkill detail windows
AnimatePresence (E)framer-motionTaskbar button entrance/exit animation
motion.buttonframer-motionAnimated taskbar task buttons
LayoutTemplate (Lucide)lucide-reactFrontend.exe icon
Terminal (Lucide)lucide-reactBackend.bat icon
Database (Lucide)lucide-reactDatabases.db icon
CodeXml (Lucide)lucide-reactLanguages.txt icon
useStateReact 18Open windows array + focused ID

Build docs developers (and LLMs) love