Skip to main content

Documentation Index

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

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

TrickOrTreatBag is the decorative illustration companion to the bio text on the About page. It renders a cream-colored trick-or-treat bag SVG with a pumpkin-orange handle and carved face. Hovering or tapping the bag triggers an animation that pops five personality-tag pills out of the bag like candy flying into the air. The component accepts no props and manages its own hover state.

Usage

Drop <TrickOrTreatBag /> anywhere — it is fully self-contained:
import { TrickOrTreatBag } from '../components/TrickOrTreatBag';

<TrickOrTreatBag />
On the About page it sits inside a flex row alongside the bio text:
// assets/main.js — About page
<div className="flex-1 w-full">
  <TrickOrTreatBag />
</div>

Interaction

The component uses a useState boolean (isOpen) that toggles on onMouseEnter, resets on onMouseLeave, and also flips on onClick for touch support. When isOpen is true:
  • Each candy tag animates out of the bag via Framer Motion’s AnimatePresence, springing upward and fanning out at different angles.
  • The bag itself scales up slightly and wobbles with a four-keyframe rotation sequence.
  • A hint label beneath the bag switches from "Hover or tap the bag" to "Sweet!".
// Interaction handlers on the wrapper
onMouseEnter={() => setIsOpen(true)}
onMouseLeave={() => setIsOpen(false)}
onClick={() => setIsOpen(!isOpen)}

Entrance Animation

The bag wrapper receives a Framer Motion scale entrance from the parent page:
// assets/main.js — About page
<motion.div
  initial={{ scale: 0.8, opacity: 0 }}
  animate={{ scale: 1, opacity: 1 }}
  transition={{ delay: 0.4 }}
>
  <TrickOrTreatBag />
</motion.div>

Candy Tags

Five personality tags are defined as a static array inside TrickOrTreatBag.js. Each tag has its own color, rotation angle, and stagger delay:
// components/TrickOrTreatBag.js
const candies = [
  { id: 1, text: '5 years shipping React', color: '#ff7a1a', angle: -25, delay: 0.1 },
  { id: 2, text: 'Coffee-fueled',           color: '#e63946', angle: -10, delay: 0.2 },
  { id: 3, text: 'Allergic to untyped code',color: '#2a9d8f', angle:  10, delay: 0.3 },
  { id: 4, text: 'CSS Grid Enthusiast',     color: '#e9c46a', angle:  25, delay: 0.4 },
  { id: 5, text: 'Accessibility Advocate',  color: '#9b5de5', angle: -35, delay: 0.5 },
];
Each pill animates from a collapsed, transparent state at the bag opening to its final floating position:
<motion.div
  initial={{ y: 100, opacity: 0, scale: 0.5, rotate: 0 }}
  animate={{
    y: -150 - Math.abs(candy.angle) * 2,
    x: candy.angle * 4,
    opacity: 1,
    scale: 1,
    rotate: candy.angle,
  }}
  exit={{ y: 100, opacity: 0, scale: 0.5, rotate: 0 }}
  transition={{ type: 'spring', stiffness: 200, damping: 15, delay: candy.delay }}
/>
The vertical position (y) is calculated as -150 minus twice the absolute angle value, so more extreme angles fly higher out of the bag for a natural arc effect.

SVG Structure

The bag is drawn in a viewBox="0 0 200 200" coordinate space:
ShapeElementDescription
Handle<path> arcPumpkin-orange (#ff7a1a) rounded handle above the bag opening
Bag body<path> trapezoidCream-colored (#f4f1ea) body widening from top to bottom
Left crease<path>Subtle shading line (#e0dcd3) on the left fold
Right crease<path>Subtle shading line on the right fold
Left eye<polygon> triangleOrange carved-face element
Right eye<polygon> triangleOrange carved-face element
Nose<polygon> small triangleOrange carved-face element
Smile<path> arcCurved orange grin at the bottom of the face

Customization

Change the personality tags — Edit the candies array directly in components/TrickOrTreatBag.js. Each entry needs an id, text, color (any valid CSS color), angle (degrees, negative = left lean), and delay (seconds):
{ id: 6, text: 'Open Source Contributor', color: '#06b6d4', angle: 15, delay: 0.6 },
Adjust the fly-out height — The y animation value controls how high pills travel. Increase the base offset from -150 to -200 for a more dramatic launch:
y: -200 - Math.abs(candy.angle) * 2,
Swap the illustration for a photo — If you prefer a profile picture over the SVG bag, replace <TrickOrTreatBag /> in the About section of assets/main.js with a standard image tag:
<img
  src="/images/your-photo.jpg"
  alt="Profile photo"
  className="rounded-2xl w-full max-w-sm mx-auto shadow-2xl"
/>
Because TrickOrTreatBag has no props, all visual customization requires editing the component source file directly. The component intentionally avoids a props API to keep the About page markup clean.
Edit bag colors — The bag body fill (#f4f1ea) and handle stroke (#ff7a1a) are hardcoded in the SVG <path> elements. To use a different palette, search for those hex values in components/TrickOrTreatBag.js and replace them:
// Orange bag variant
<path d="M 40 80 L 160 80 L 180 190 ..." fill="#ff7a1a" />  // body
<path d="M 60 80 C 60 20, 140 20, 140 80"
  stroke="#f4f1ea" strokeWidth="8" />                        // handle

Build docs developers (and LLMs) love