Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/apursley2012/choose-your-destiny/llms.txt

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

The portfolio’s component library is intentionally small and composable. Four primitives — NeonCard, NeonButton, TerminalLine, and BlinkingCursor — produce every interactive surface, label, and status indicator in the project. Each is color-aware through a single color prop that maps to the five neon custom properties, so swapping a section’s accent is a one-prop change rather than a class-string audit. All four components live in components/UIComponents.js and are tree-shaken by Vite’s rollup build under short single-letter aliases.

NeonCard

NeonCard is the primary container primitive. It renders a dark panel (bg-dark-panel) with a 1px border-dark-lighter border, absolute-positioned corner accent decorators in the active neon color, and a glow-* box shadow. When hover is enabled the card lifts 4px on :hover and deepens its glow, making it suitable for clickable project tiles or selectable stage entries.

Props

PropTypeDefaultDescription
colorstring"cyan"Neon accent color. Accepts "cyan", "magenta", "purple", "lime", or "orange".
classNamestring""Extra Tailwind classes appended to the wrapper div.
hoverbooleanfalseWhen true, adds hover:glow-* and hover:-translate-y-1 for a lift-and-brighten interaction.
onClickfunctionundefinedClick handler. When provided, a Framer Motion whileTap={{ scale: 0.98 }} press effect is also applied.
childrenReactNodeContent rendered inside a relative z-10 wrapper, above the corner decorators.

Corner Decorators

Four 8×8px absolute-positioned divs sit at each corner of the card. Each one has two borders (border-t-2 border-l-2, etc.) in the active border-neon-{color} shade, recreating the crosshair-corner aesthetic common to JRPG and retro HUD designs.
// NeonCard — source structure (UIComponents.js)
const NeonCard = ({ children, color = "cyan", className = "", hover = false, onClick }) => {
  const base    = "bg-dark-panel border border-dark-lighter p-6 relative overflow-hidden transition-all duration-300";
  const glow    = `glow-${color}`;
  const hoverFx = hover ? `hover:${glow} hover:-translate-y-1 cursor-pointer` : glow;

  return (
    <motion.div className={`${base} ${hoverFx} ${className}`} onClick={onClick} whileTap={onClick ? { scale: 0.98 } : {}}>
      {/* Corner accents */}
      <div className={`absolute top-0 left-0    w-2 h-2 border-t-2 border-l-2 border-neon-${color}`} />
      <div className={`absolute top-0 right-0   w-2 h-2 border-t-2 border-r-2 border-neon-${color}`} />
      <div className={`absolute bottom-0 left-0  w-2 h-2 border-b-2 border-l-2 border-neon-${color}`} />
      <div className={`absolute bottom-0 right-0 w-2 h-2 border-b-2 border-r-2 border-neon-${color}`} />

      <div className="relative z-10">{children}</div>
    </motion.div>
  );
};

Usage Examples

import { NeonCard } from "./components/UIComponents";

// A static informational card in the Projects section accent (purple)
<NeonCard color="purple">
  <h3 className="font-arcade text-neon-purple text-sm mb-2">
    Project Alpha
  </h3>
  <p className="font-sans text-gray-300 text-sm leading-relaxed">
    A full-stack event platform built with Next.js and Supabase.
  </p>
</NeonCard>

When to use

Use NeonCard as the wrapper for any discrete content block: project tiles, skill category panels, blog post previews, or contact form containers. Pair hover={true} whenever the card is clickable. For non-interactive decorative panels pass hover={false} (the default) to avoid misleading pointer affordances.

NeonButton

NeonButton renders a terminal-style <button> that pairs a 2px border-neon-{color} outline with an offset box-shadow (4px 4px 0px var(--neon-{color})), producing a hard-edged “pixel shadow” common in retro game UI. The active state collapses the shadow (active:shadow-none) and shifts the element down (active:translate-y-1) to simulate a physical key press.

Props

PropTypeDefaultDescription
colorstring"cyan"Neon accent. Accepts "cyan", "magenta", "purple", "lime", or "orange".
childrenReactNodeButton label text or icon content.
classNamestring""Additional classes merged into the button’s className.
typestring"button"HTML button type attribute — use "submit" inside forms.
disabledbooleanfalseWhen true, disables the button — the browser applies the native disabled state (dimmed appearance and no interaction) via the spread ...rest attribute.
...restobjectAll other props (e.g. onClick, aria-label, data-*) are spread onto the <button> element.

Button Typography

Buttons use font-terminal (VT323), text-xl, uppercase, and tracking-wider. This intentionally avoids font-arcade for buttons — Press Start 2P at interactive sizes would be illegible. VT323 reads clearly at large sizes while keeping the terminal aesthetic.
// NeonButton — source structure (UIComponents.js)
const NeonButton = ({ color = "cyan", children, className = "", ...rest }) => (
  <button
    className={`
      relative px-6 py-3 font-terminal text-xl uppercase tracking-wider font-bold
      bg-dark-panel border-2 border-neon-${color} text-neon-${color}
      transition-all duration-150 active:translate-y-1 active:shadow-none
      hover:bg-neon-${color}/10 hover:text-white hover:shadow-[0_0_15px_var(--neon-${color})]
      ${className}
    `}
    style={{ boxShadow: `4px 4px 0px var(--neon-${color})` }}
    {...rest}
  >
    {children}
  </button>
);

Usage Examples

import { NeonButton } from "./components/UIComponents";

<NeonButton color="cyan" onClick={() => navigate("/projects")}>
  View Projects
</NeonButton>

When to use

Use NeonButton for all primary CTA actions: form submissions, navigation triggers, and modal confirmations. The pixel-shadow variant matches the arcade brand. For secondary or ghost-style actions, apply bg-transparent via the className prop rather than switching to a plain <button>.

TerminalLine

TerminalLine is a single-line read-only terminal output row. It renders a flex container with a neon-lime prefix symbol on the left (defaulting to >) and the line’s content on the right in font-terminal text-xl text-gray-300. It is used throughout the About and Contact sections for status messages, log entries, and narrative exposition.

Props

PropTypeDefaultDescription
childrenReactNodeThe text or elements displayed as the line’s content.
classNamestring""Extra classes on the outer flex container.
prefixstring">"The prefix symbol shown in neon-lime on the left. Override with $, //, or >> for variety.
// TerminalLine — source structure (UIComponents.js)
const TerminalLine = ({ children, className = "", prefix = ">" }) => (
  <div className={`font-terminal text-xl text-gray-300 flex items-start gap-2 ${className}`}>
    <span className="text-neon-lime shrink-0">{prefix}</span>
    <span>{children}</span>
  </div>
);

Usage Examples

import { TerminalLine } from "./components/UIComponents";

<TerminalLine>System boot complete. All modules nominal.</TerminalLine>
<TerminalLine>Loading profile data...</TerminalLine>
<TerminalLine prefix="$">whoami — apursley</TerminalLine>

When to use

Use TerminalLine for any UI text that should read as machine output rather than human prose — status messages, data readouts, navigation breadcrumbs, and step-by-step boot sequences. Wrap multiple lines in a space-y-2 container to produce a scrolling log effect.

BlinkingCursor

BlinkingCursor renders a single 3×5 (w-3 h-5) neon-lime rectangle using the .blinking-cursor CSS class, which drives a 1s step-end opacity animation. The result is a sharp, non-interpolated blink identical to a physical terminal cursor. It is an inline-block element positioned with align-middle, so it sits correctly inline with any font-terminal text.

No props

BlinkingCursor accepts no props. Its color, size, and blink rate are fixed to the design system values.
// BlinkingCursor — source structure (UIComponents.js)
const BlinkingCursor = () => (
  <span className="inline-block w-3 h-5 bg-neon-lime ml-1 align-middle blinking-cursor" />
);
The CSS animation behind it:
.blinking-cursor {
  animation: blink 1s step-end infinite;
}

@keyframes blink {
  0%, 100% { opacity: 1; }
  50%       { opacity: 0; }
}
step-end is the critical detail. It makes the cursor switch states instantaneously at the 50% mark rather than fading, reproducing the binary on/off rhythm of a real CRT terminal.

Usage Examples

import { BlinkingCursor } from "./components/UIComponents";

<p className="font-terminal text-xl text-gray-300">
  READY<BlinkingCursor />
</p>

When to use

Place BlinkingCursor at the end of the last visible TerminalLine whenever the UI should suggest that the terminal is live and awaiting input. Avoid using more than one cursor on screen simultaneously — two blinking elements compete for attention and dilute the effect.

Component Combinations

The four primitives are designed to compose naturally. The most common pattern in the project is a NeonCard containing one or more TerminalLine rows, with a BlinkingCursor on the final line and a NeonButton below it as a CTA.
import { NeonCard, NeonButton, TerminalLine, BlinkingCursor } from "./components/UIComponents";

<NeonCard color="cyan" className="max-w-md">
  <TerminalLine prefix="//">  CONTACT TERMINAL</TerminalLine>
  <TerminalLine>All channels open.</TerminalLine>
  <TerminalLine>
    Ready to receive<BlinkingCursor />
  </TerminalLine>

  <NeonButton color="cyan" className="mt-6 w-full" onClick={openForm}>
    Open Comms
  </NeonButton>
</NeonCard>

Build docs developers (and LLMs) love