From 0f164fadee297731a9d82fa7471ddd5a7a644df5 Mon Sep 17 00:00:00 2001 From: Simon Burmer Date: Tue, 31 Mar 2026 18:59:11 +0200 Subject: [PATCH 1/2] init --- app/member-journey/page.tsx | 194 ++++++++++++++++++++++++++++++++---- 1 file changed, 174 insertions(+), 20 deletions(-) diff --git a/app/member-journey/page.tsx b/app/member-journey/page.tsx index e874430..0315917 100644 --- a/app/member-journey/page.tsx +++ b/app/member-journey/page.tsx @@ -246,6 +246,7 @@ const memberStories: MemberStory[] = [ export default function MemberJourneyPage() { const [loading, setLoading] = useState(true) + const [activeDeptId, setActiveDeptId] = useState(departments[0].id) const [eventImageIndex, setEventImageIndex] = useState(0) const [currentEventIndex, setCurrentEventIndex] = useState(0) const timelineSliderRef = useRef(null) @@ -406,7 +407,7 @@ export default function MemberJourneyPage() { JOURNEY } - description="Become a member and spend two active semesters contributing to the community" + description="Become a member and spend at least two active semesters contributing to the community" >
@@ -512,30 +513,178 @@ export default function MemberJourneyPage() {

-
- {departments.map((dept) => ( -
-
-
-
- {dept.icon} -
-

{dept.name}

-

{dept.description}

+ {/* Desktop: arc layout */} + {(() => { + // Half-ellipse: center=(300,380), rx=220, ry=380 + // Arc from (80,380) through (300,0) to (520,380) + const cx = 300, cy = 380, rx = 220, ry = 380 + const toRad = (deg: number) => (deg * Math.PI) / 180 + // 5 dots evenly spread across the arc (150° → 30°) + const angles = [150, 115, 90, 65, 30] + const dots = departments.map((dept, i) => { + const a = toRad(angles[i]) + return { + dept, + x: cx + rx * Math.cos(a), + y: cy - ry * Math.sin(a), + angle: angles[i], + } + }) + const activeDept = departments.find(d => d.id === activeDeptId) + + return ( + <> + {/* Desktop */} +
+ {/* Arc */} +
+ + {/* Full dashed arc */} + + + {/* Highlighted arc up to active dot */} + {activeDeptId && (() => { + const idx = departments.findIndex(d => d.id === activeDeptId) + const endAngle = toRad(angles[idx]) + const ex = cx + rx * Math.cos(endAngle) + const ey = cy - ry * Math.sin(endAngle) + // Arc from left edge (0, cy) to the active dot — always < 180° so large-arc=0 + return ( + + ) + })()} + + {/* Dots + labels */} + {dots.map(({ dept, x, y, angle }) => { + const isActive = activeDeptId === dept.id + // Label side: left of arc → anchor end, top → middle, right → start + const labelAnchor = angle > 110 ? 'end' : angle < 70 ? 'start' : 'middle' + const labelX = angle > 110 ? x - 28 : angle < 70 ? x + 28 : x + const labelY = angle > 110 ? y + 6 : angle < 70 ? y + 6 : y - 26 + + return ( + setActiveDeptId(dept.id)} + className="cursor-pointer" + style={{ transition: 'all 0.3s' }} + > + {/* Glow ring */} + {isActive && ( + + )} + {/* Dot */} + + {/* Inner dot when active */} + {isActive && } + {/* Label */} + + {dept.name.toUpperCase()} + + + ) + })} +
-
-

Responsibilities

- {dept.responsibilities.map((resp, i) => ( -
-
- {resp} + + {/* Detail panel */} +
+ {activeDept && ( +
+
+ {activeDept.icon} +
+

{activeDept.name.toUpperCase()}

+

{activeDept.description}

+
+

Responsibilities

+
+ {activeDept.responsibilities.map((resp, i) => ( +
+
+ {resp} +
+ ))} +
+
+ )} +
+
+ + {/* Mobile: icon strip + card */} +
+
+ {departments.map((dept) => ( + ))}
+ {activeDept && ( +
+

{activeDept.name.toUpperCase()}

+

{activeDept.description}

+
+

Responsibilities

+ {activeDept.responsibilities.map((resp, i) => ( +
+
+ {resp} +
+ ))} +
+
+ )}
-
- ))} -
+ + ) + })()} {/* ═══ INTERNAL EVENTS ═══ */} @@ -817,6 +966,11 @@ export default function MemberJourneyPage() { } .tabular-nums { font-variant-numeric: tabular-nums; } + + @keyframes fadeInPanel { + from { opacity: 0; transform: translateY(8px); } + to { opacity: 1; transform: translateY(0); } + } `} ) From 3025d132544bb03887c60619e92921b408dfd76c Mon Sep 17 00:00:00 2001 From: Simon Burmer Date: Wed, 1 Apr 2026 01:46:09 +0200 Subject: [PATCH 2/2] feat: replace departments grid with interactive arc navigation - Half-circle arc (pink) on the right side of the section - Five clickable dots along the arc, one per department - Active dot animates with glow ring and inner highlight - Selected department info fades in on the left panel - Mobile fallback with icon strip + expandable card --- app/member-journey/page.tsx | 129 +++++++++++++++--------------------- 1 file changed, 52 insertions(+), 77 deletions(-) diff --git a/app/member-journey/page.tsx b/app/member-journey/page.tsx index 0315917..4ae42af 100644 --- a/app/member-journey/page.tsx +++ b/app/member-journey/page.tsx @@ -515,19 +515,21 @@ export default function MemberJourneyPage() { {/* Desktop: arc layout */} {(() => { - // Half-ellipse: center=(300,380), rx=220, ry=380 - // Arc from (80,380) through (300,0) to (520,380) - const cx = 300, cy = 380, rx = 220, ry = 380 + // Left-side half-circle "(" : center=(300,300), r=300 + // Arc from (300,0) at top, curving LEFT through (0,300), to (300,600) at bottom + const cx = 300, cy = 300, r = 300 const toRad = (deg: number) => (deg * Math.PI) / 180 - // 5 dots evenly spread across the arc (150° → 30°) - const angles = [150, 115, 90, 65, 30] + // Standard-math angles (CCW from +x): 108°→top-left … 252°→bottom-left + const angles = [108, 144, 180, 216, 252] + // Per-dot label vertical nudge (positive = lower, negative = higher) + const labelYOffsets = [18, 6, 6, 6, -8] const dots = departments.map((dept, i) => { const a = toRad(angles[i]) return { dept, - x: cx + rx * Math.cos(a), - y: cy - ry * Math.sin(a), - angle: angles[i], + x: cx + r * Math.cos(a), + y: cy - r * Math.sin(a), + labelYOffset: labelYOffsets[i], } }) const activeDept = departments.find(d => d.id === activeDeptId) @@ -535,50 +537,54 @@ export default function MemberJourneyPage() { return ( <> {/* Desktop */} -
- {/* Arc */} +
+ {/* Detail panel — left */} +
+ {activeDept && ( +
+
+ {activeDept.icon} +
+

{activeDept.name.toUpperCase()}

+

{activeDept.description}

+
+

Responsibilities

+
+ {activeDept.responsibilities.map((resp, i) => ( +
+
+ {resp} +
+ ))} +
+
+
+ )} +
+ + {/* Arc — right */}
- {/* Full dashed arc */} + {/* Always-pink arc: (300,0) CCW through (0,300) to (300,600) */} - {/* Highlighted arc up to active dot */} - {activeDeptId && (() => { - const idx = departments.findIndex(d => d.id === activeDeptId) - const endAngle = toRad(angles[idx]) - const ex = cx + rx * Math.cos(endAngle) - const ey = cy - ry * Math.sin(endAngle) - // Arc from left edge (0, cy) to the active dot — always < 180° so large-arc=0 - return ( - - ) - })()} - {/* Dots + labels */} - {dots.map(({ dept, x, y, angle }) => { + {dots.map(({ dept, x, y, labelYOffset }) => { const isActive = activeDeptId === dept.id - // Label side: left of arc → anchor end, top → middle, right → start - const labelAnchor = angle > 110 ? 'end' : angle < 70 ? 'start' : 'middle' - const labelX = angle > 110 ? x - 28 : angle < 70 ? x + 28 : x - const labelY = angle > 110 ? y + 6 : angle < 70 ? y + 6 : y - 26 - return ( - {/* Glow ring */} {isActive && ( )} - {/* Dot */} - {/* Inner dot when active */} {isActive && } - {/* Label */} + {/* Label — to the right of dot, toward the opening */} {dept.name.toUpperCase()} @@ -620,34 +623,6 @@ export default function MemberJourneyPage() { })}
- - {/* Detail panel */} -
- {activeDept && ( -
-
- {activeDept.icon} -
-

{activeDept.name.toUpperCase()}

-

{activeDept.description}

-
-

Responsibilities

-
- {activeDept.responsibilities.map((resp, i) => ( -
-
- {resp} -
- ))} -
-
-
- )} -
{/* Mobile: icon strip + card */}