Documentation Index
Fetch the complete documentation index at: https://mintlify.com/blairxu13/persona3-website/llms.txt
Use this file to discover all available pages before exploring further.
P3Menu is the central navigation component of the portfolio, rendering a vertical list of five menu items styled after the iconic Persona 3 UI. Each item slides in on mount with a staggered CSS transition, responds to keyboard arrow keys and Enter, and displays a radial glow, a triangular shadow pop, and a bright label highlight whenever it becomes active. The component accepts a single callback prop so the parent can respond to navigation events without coupling to React Router directly.
Props
Called when the user selects a menu item — either by pressing Enter on the currently active item or by clicking a row directly. The
page string passed to the callback corresponds to the page field of the selected item in the ITEMS array and should match a registered React Router route path.ITEMS Array
The menu is driven by a staticITEMS array defined at the top of P3Menu.jsx. Each element controls the label text, target page, and all per-item typographic transform values that give the menu its hand-crafted, slanted look.
Item shape:
Keyboard Controls
P3Menu attaches a keydown listener to window inside a useEffect so the user can navigate the menu without a mouse. The listener is cleaned up on unmount and re-registered whenever active changes.
| Key | Action |
|---|---|
ArrowUp | Moves the active index up by one (minimum index: 0) |
ArrowDown | Moves the active index down by one (maximum: last item) |
Enter | Calls onNavigate with the page of the active item |
CSS Class Reference
The visual identity of the menu is expressed entirely through CSS classes toggled by component state. Below is a description of each key class.| Class | Description |
|---|---|
.p3-row | Base class for each menu item. Starts at opacity: 0 and transform: translateX(36px). Transitions to opacity: 1 and translateX(0) when the .mounted class is added to the container after the 1000 ms delay. Each row receives a staggered transition-delay of i * 80ms. |
.p3-row.active | Applied to the currently selected row. Enables the .p3-glow, .p3-shadow-tri, .p3-highlight, and .p3-label-bright sub-elements and switches the label to its red highlight colour. |
.p3-label-dark | Default label colour — cyan #3ce2ff. Changes to a deep red #6b0010 when the row is active and brightens to #00d9ff on hover. |
.p3-glow | A radial gradient element that appears behind the active row, creating a soft bloom effect around the label. |
.p3-shadow-tri | A pink triangle element rendered behind the active label. It plays the p3-shadow-pop keyframe animation each time a new item is activated (see The Shadow Pop Animation). |
.p3-hint | A keyboard hint element anchored to the bottom-right corner of the menu. It is invisible until the .mounted class is applied, then fades in alongside the menu rows. |
.p3-name-tag | A watermark element containing the text "jade's / persona", rotated 18 degrees and positioned in the top-left corner of the menu. |
Mount Animation
WhenP3Menu first renders, all .p3-row elements are invisible and offset 36 px to the right via their base CSS. After a 1000 ms delay — giving any preceding page transition time to complete — the component sets mounted to true:
mounted adds the .mounted class to the menu container, which triggers the CSS transition on every .p3-row simultaneously. Because each row has a different transition-delay (i * 80ms), the items slide in one after another from top to bottom, producing a staggered cascade effect without any JavaScript animation library.
The Shadow Pop Animation
Each time a new item is activated — whether by keyboard or click — the component incrementsanimKey:
animKey is passed as the React key prop on the .p3-shadow-tri element. Changing key causes React to unmount and remount the element, which restarts its CSS animation from scratch. This guarantees the triangular pop plays in full every time the active item changes, even if the same item is selected twice in a row.
The animation itself is defined by the p3-shadow-pop keyframe:
cubic-bezier(0.34, 1.56, 0.64, 1) — an overshoot curve that gives the triangle a satisfying elastic snap as it expands.
Adding a Menu Item
To extend the menu with a new entry, append an object to theITEMS array in P3Menu.jsx. Choose fontSize, offsetX, offsetY, skew, and skewY values that fit visually with the surrounding items.
Register the route
Add a matching
<Route path="contact" element={<Contact />} /> in your router configuration. See Routing for details.Create the page component
Build the page component and, if desired, a custom
PageTransition variant for it. See PageTransition and Page Transitions.Customising Menu Items
Detailed guide to adjusting labels, font sizes, and skew values for each row.
Routing
How React Router v7 route paths map to the page strings used in ITEMS.