From 0d41408ce04d85aff291a134f1b02b35dedeb25c Mon Sep 17 00:00:00 2001 From: "Builder.io" Date: Sun, 19 Oct 2025 00:29:17 +0000 Subject: [PATCH] Prettier format pending files --- client/components/admin/AdminRoadmap.tsx | 44 ++- client/components/roadmap/Achievements.tsx | 95 +++++- client/components/roadmap/GalaxyMap.tsx | 50 ++- client/components/roadmap/ThemeToggle.tsx | 14 +- client/components/roadmap/Timeline.tsx | 80 ++++- client/components/roadmap/VoteWidget.tsx | 51 +++- client/global.css | 12 +- client/pages/Roadmap.tsx | 305 ++++++++++++++++--- client/pages/community/MentorProfile.tsx | 81 ++++- client/pages/community/MentorshipRequest.tsx | 4 +- 10 files changed, 616 insertions(+), 120 deletions(-) diff --git a/client/components/admin/AdminRoadmap.tsx b/client/components/admin/AdminRoadmap.tsx index 6b87ba3d..d6808634 100644 --- a/client/components/admin/AdminRoadmap.tsx +++ b/client/components/admin/AdminRoadmap.tsx @@ -1,11 +1,31 @@ -import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; +import { + Card, + CardContent, + CardDescription, + CardHeader, + CardTitle, +} from "@/components/ui/card"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; -import { CheckCircle2, ExternalLink, Flag, ListChecks, Rocket, Sparkles, Target } from "lucide-react"; +import { + CheckCircle2, + ExternalLink, + Flag, + ListChecks, + Rocket, + Sparkles, + Target, +} from "lucide-react"; -const linearProjectUrl = "https://linear.app/duo-simulators/project/aethex-roadmap-8600b796e8ad"; +const linearProjectUrl = + "https://linear.app/duo-simulators/project/aethex-roadmap-8600b796e8ad"; -const phases: { title: string; timeframe: string; items: string[]; icon: any }[] = [ +const phases: { + title: string; + timeframe: string; + items: string[]; + icon: any; +}[] = [ { title: "Access & IA", timeframe: "Now — 0–2 weeks", @@ -65,11 +85,18 @@ export default function AdminRoadmap() { - + All systems focused @@ -80,7 +107,10 @@ export default function AdminRoadmap() { {phases.map((p) => { const Icon = p.icon; return ( - +
diff --git a/client/components/roadmap/Achievements.tsx b/client/components/roadmap/Achievements.tsx index 3b79fb85..746bcfe8 100644 --- a/client/components/roadmap/Achievements.tsx +++ b/client/components/roadmap/Achievements.tsx @@ -1,32 +1,101 @@ -import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; +import { + Card, + CardContent, + CardDescription, + CardHeader, + CardTitle, +} from "@/components/ui/card"; import { Badge } from "@/components/ui/badge"; import { Trophy, Award, Crown, Compass } from "lucide-react"; -export default function Achievements({ earnedXp, phaseClaims }: { earnedXp: number; phaseClaims: Record; }) { - const badges: { id: string; label: string; unlocked: boolean; icon: any; desc: string }[] = [ - { id: "rookie", label: "Rookie Explorer", unlocked: earnedXp >= 100, icon: Compass, desc: "Earn 100+ XP" }, - { id: "seasoned", label: "Seasoned Adventurer", unlocked: earnedXp >= 300, icon: Trophy, desc: "Earn 300+ XP" }, - { id: "master", label: "Master Builder", unlocked: earnedXp >= 600, icon: Crown, desc: "Earn 600+ XP" }, - { id: "trailblazer", label: "Trailblazer", unlocked: ["now","month1","month2","month3"].every((k) => (phaseClaims[k] || 0) > 0), icon: Award, desc: "Complete a quest in every phase" }, +export default function Achievements({ + earnedXp, + phaseClaims, +}: { + earnedXp: number; + phaseClaims: Record; +}) { + const badges: { + id: string; + label: string; + unlocked: boolean; + icon: any; + desc: string; + }[] = [ + { + id: "rookie", + label: "Rookie Explorer", + unlocked: earnedXp >= 100, + icon: Compass, + desc: "Earn 100+ XP", + }, + { + id: "seasoned", + label: "Seasoned Adventurer", + unlocked: earnedXp >= 300, + icon: Trophy, + desc: "Earn 300+ XP", + }, + { + id: "master", + label: "Master Builder", + unlocked: earnedXp >= 600, + icon: Crown, + desc: "Earn 600+ XP", + }, + { + id: "trailblazer", + label: "Trailblazer", + unlocked: ["now", "month1", "month2", "month3"].every( + (k) => (phaseClaims[k] || 0) > 0, + ), + icon: Award, + desc: "Complete a quest in every phase", + }, ]; return ( Achievements - Earn badges as you progress. Displayed publicly soon. + + Earn badges as you progress. Displayed publicly soon. + {badges.map((b) => { const Icon = b.icon; return ( -
- +
+
-
{b.label}
-
{b.desc}
+
+ {b.label} +
+
+ {b.desc} +
- + {b.unlocked ? "Unlocked" : "Locked"}
diff --git a/client/components/roadmap/GalaxyMap.tsx b/client/components/roadmap/GalaxyMap.tsx index c1aa636c..6e9cd8a8 100644 --- a/client/components/roadmap/GalaxyMap.tsx +++ b/client/components/roadmap/GalaxyMap.tsx @@ -8,7 +8,13 @@ export interface PhaseSummary { percent: number; // 0..100 } -export default function GalaxyMap({ phases, onSelect }: { phases: PhaseSummary[]; onSelect?: (id: PhaseSummary["id"]) => void }) { +export default function GalaxyMap({ + phases, + onSelect, +}: { + phases: PhaseSummary[]; + onSelect?: (id: PhaseSummary["id"]) => void; +}) { const iconFor: Record = { now: Target, month1: Flame, @@ -18,8 +24,15 @@ export default function GalaxyMap({ phases, onSelect }: { phases: PhaseSummary[] return (
-
- +
+ @@ -36,18 +49,35 @@ export default function GalaxyMap({ phases, onSelect }: { phases: PhaseSummary[] {phases.map((p) => { const Icon = iconFor[p.id]; return ( -
- {p.label} + + {p.label} +
- {p.percent}% + + {p.percent}% +
-
+
+
+
+ Tap to focus this phase
-
Tap to focus this phase
); })} @@ -55,7 +85,9 @@ export default function GalaxyMap({ phases, onSelect }: { phases: PhaseSummary[]
-

Planets represent phases. Progress fills as quests are claimed.

+

+ Planets represent phases. Progress fills as quests are claimed. +

); diff --git a/client/components/roadmap/ThemeToggle.tsx b/client/components/roadmap/ThemeToggle.tsx index 4c117cf8..beca0462 100644 --- a/client/components/roadmap/ThemeToggle.tsx +++ b/client/components/roadmap/ThemeToggle.tsx @@ -5,7 +5,13 @@ export type RoadmapTheme = "space" | "fantasy" | "city" | "adventure"; const key = "aethex_roadmap_theme_v1"; -export default function ThemeToggle({ value, onChange }: { value?: RoadmapTheme; onChange?: (v: RoadmapTheme) => void }) { +export default function ThemeToggle({ + value, + onChange, +}: { + value?: RoadmapTheme; + onChange?: (v: RoadmapTheme) => void; +}) { const [theme, setTheme] = useState(value || "space"); useEffect(() => { @@ -29,7 +35,11 @@ export default function ThemeToggle({ value, onChange }: { value?: RoadmapTheme; }; return ( - set(v as RoadmapTheme)} className="w-full"> + set(v as RoadmapTheme)} + className="w-full" + > Space Fantasy diff --git a/client/components/roadmap/Timeline.tsx b/client/components/roadmap/Timeline.tsx index 671cdb9b..365edbff 100644 --- a/client/components/roadmap/Timeline.tsx +++ b/client/components/roadmap/Timeline.tsx @@ -2,7 +2,14 @@ import { useMemo, useRef } from "react"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { cn } from "@/lib/utils"; -import { CheckCircle2, Circle, Rocket, Target, Flame, Sparkles } from "lucide-react"; +import { + CheckCircle2, + Circle, + Rocket, + Target, + Flame, + Sparkles, +} from "lucide-react"; export type RoadmapPhase = "now" | "month1" | "month2" | "month3"; @@ -25,17 +32,34 @@ export default function Timeline({ }) { const containerRef = useRef(null); const phases: RoadmapPhase[] = ["now", "month1", "month2", "month3"]; - const iconFor: Record = { now: Target, month1: Flame, month2: Rocket, month3: Sparkles }; + const iconFor: Record = { + now: Target, + month1: Flame, + month2: Rocket, + month3: Sparkles, + }; const grouped = useMemo(() => { - const map: Record = { now: [], month1: [], month2: [], month3: [] }; + const map: Record = { + now: [], + month1: [], + month2: [], + month3: [], + }; for (const e of events) map[e.phase].push(e); return map; }, [events]); const scrollToPhase = (p: RoadmapPhase) => { - const el = containerRef.current?.querySelector(`[data-phase="${p}"]`); - if (el) el.scrollIntoView({ behavior: "smooth", inline: "center", block: "nearest" }); + const el = containerRef.current?.querySelector( + `[data-phase="${p}"]`, + ); + if (el) + el.scrollIntoView({ + behavior: "smooth", + inline: "center", + block: "nearest", + }); onSelectPhase?.(p); }; @@ -45,9 +69,22 @@ export default function Timeline({
{phases.map((p) => { const Icon = iconFor[p]; - const label = p === "now" ? "Now" : p === "month1" ? "Month 1" : p === "month2" ? "Month 2" : "Month 3"; + const label = + p === "now" + ? "Now" + : p === "month1" + ? "Month 1" + : p === "month2" + ? "Month 2" + : "Month 3"; return ( - ); @@ -64,9 +101,18 @@ export default function Timeline({
{/* Phase header */}
- {(() => { const Icon = iconFor[p]; return ; })()} + {(() => { + const Icon = iconFor[p]; + return ; + })()} - {p === "now" ? "Now" : p === "month1" ? "Month 1" : p === "month2" ? "Month 2" : "Month 3"} + {p === "now" + ? "Now" + : p === "month1" + ? "Month 1" + : p === "month2" + ? "Month 2" + : "Month 3"}
{/* Events for phase */} @@ -90,15 +136,23 @@ export default function Timeline({
-
{e.title}
-
Tap to {e.claimed ? "unclaim" : "claim"} • {e.xp} XP
+
+ {e.title} +
+
+ Tap to {e.claimed ? "unclaim" : "claim"} • {e.xp} XP +
- {e.xp} XP + + {e.xp} XP +
))} {grouped[p].length === 0 && ( -
No quests yet
+
+ No quests yet +
)}
diff --git a/client/components/roadmap/VoteWidget.tsx b/client/components/roadmap/VoteWidget.tsx index fa7925d1..4e7470e4 100644 --- a/client/components/roadmap/VoteWidget.tsx +++ b/client/components/roadmap/VoteWidget.tsx @@ -1,9 +1,19 @@ import { useEffect, useMemo, useState } from "react"; -import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; +import { + Card, + CardContent, + CardDescription, + CardHeader, + CardTitle, +} from "@/components/ui/card"; import { Button } from "@/components/ui/button"; import { Badge } from "@/components/ui/badge"; -export default function VoteWidget({ options }: { options: { id: string; label: string }[] }) { +export default function VoteWidget({ + options, +}: { + options: { id: string; label: string }[]; +}) { const key = "aethex_roadmap_votes_v1"; const [votes, setVotes] = useState>({}); const [choice, setChoice] = useState(null); @@ -21,7 +31,10 @@ export default function VoteWidget({ options }: { options: { id: string; label: } catch {} }, [votes]); - const total = useMemo(() => Object.values(votes).reduce((a, b) => a + b, 0), [votes]); + const total = useMemo( + () => Object.values(votes).reduce((a, b) => a + b, 0), + [votes], + ); const vote = (id: string) => { setChoice(id); @@ -37,23 +50,37 @@ export default function VoteWidget({ options }: { options: { id: string; label: What should we ship next? - Local voting preview. Public voting will sync later. + + Local voting preview. Public voting will sync later. +
{options.map((o) => { - const pct = total ? Math.round(((votes[o.id] || 0) / total) * 100) : 0; + const pct = total + ? Math.round(((votes[o.id] || 0) / total) * 100) + : 0; return ( -
+
{o.label}
-
+
{pct}% -
@@ -62,8 +89,12 @@ export default function VoteWidget({ options }: { options: { id: string; label: })}
- -
Votes are stored locally on your device.
+ +
+ Votes are stored locally on your device. +
diff --git a/client/global.css b/client/global.css index 30012252..dfdd7d3c 100644 --- a/client/global.css +++ b/client/global.css @@ -99,9 +99,15 @@ } @layer utilities { - .section-cozy { padding-block: var(--space-section-y); } - .gap-cozy { gap: var(--space-5); } - .pad-cozy { padding: var(--space-5); } + .section-cozy { + padding-block: var(--space-section-y); + } + .gap-cozy { + gap: var(--space-5); + } + .pad-cozy { + padding: var(--space-5); + } .text-gradient { @apply bg-gradient-to-r from-aethex-400 via-neon-blue to-aethex-600 bg-clip-text text-transparent; diff --git a/client/pages/Roadmap.tsx b/client/pages/Roadmap.tsx index 677432de..a733b9a9 100644 --- a/client/pages/Roadmap.tsx +++ b/client/pages/Roadmap.tsx @@ -1,10 +1,26 @@ import Layout from "@/components/Layout"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; -import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; +import { + Card, + CardContent, + CardDescription, + CardHeader, + CardTitle, +} from "@/components/ui/card"; import { cn } from "@/lib/utils"; import { useEffect, useMemo, useState } from "react"; -import { Sparkles, Lock, Gift, Rocket, Target, Flame, Eye, CheckCircle2, TimerReset } from "lucide-react"; +import { + Sparkles, + Lock, + Gift, + Rocket, + Target, + Flame, + Eye, + CheckCircle2, + TimerReset, +} from "lucide-react"; import Timeline from "@/components/roadmap/Timeline"; import GalaxyMap from "@/components/roadmap/GalaxyMap"; import Achievements from "@/components/roadmap/Achievements"; @@ -27,18 +43,90 @@ interface Peek { } const QUESTS: Quest[] = [ - { id: "realm-gating", title: "Finalize realm gating", xp: 120, phase: "now", description: "Tight access across routes with glossy redirects." }, - { id: "nav-ia", title: "Unify navigation", xp: 80, phase: "now", description: "Consistent top-level labels, fewer detours." }, - { id: "mentor-admin", title: "Mentorship admin flows", xp: 100, phase: "now", description: "Accept / reject, filters, analytics." }, - { id: "mentor-polish", title: "Mentor directory polish", xp: 120, phase: "month1", description: "Filters, profiles, and smoother requests." }, - { id: "featured-studios", title: "Featured studios persistence", xp: 90, phase: "month1", description: "Curation + partner spotlight." }, - { id: "blog-seo", title: "Blog editor + SEO", xp: 130, phase: "month1", description: "Meta/OG, list pages, Supabase sync." }, - { id: "opps-tooling", title: "Opportunities tooling", xp: 140, phase: "month2", description: "Applicant review, statuses, filters." }, - { id: "pricing-funnels", title: "Engage/pricing funnels", xp: 120, phase: "month2", description: "Plans and conversion events." }, - { id: "observability", title: "Observability + Sentry", xp: 110, phase: "month2", description: "Errors, alerts, status surfacing." }, - { id: "collab-teams", title: "Teams & projects enhancements", xp: 150, phase: "month3", description: "Membership, board UX, notifications." }, - { id: "advanced-mentoring", title: "Advanced mentoring flows", xp: 150, phase: "month3", description: "Availability, pricing, scheduling hooks." }, - { id: "public-roadmap", title: "Public roadmap page", xp: 100, phase: "month3", description: "This page—interactive and fun." }, + { + id: "realm-gating", + title: "Finalize realm gating", + xp: 120, + phase: "now", + description: "Tight access across routes with glossy redirects.", + }, + { + id: "nav-ia", + title: "Unify navigation", + xp: 80, + phase: "now", + description: "Consistent top-level labels, fewer detours.", + }, + { + id: "mentor-admin", + title: "Mentorship admin flows", + xp: 100, + phase: "now", + description: "Accept / reject, filters, analytics.", + }, + { + id: "mentor-polish", + title: "Mentor directory polish", + xp: 120, + phase: "month1", + description: "Filters, profiles, and smoother requests.", + }, + { + id: "featured-studios", + title: "Featured studios persistence", + xp: 90, + phase: "month1", + description: "Curation + partner spotlight.", + }, + { + id: "blog-seo", + title: "Blog editor + SEO", + xp: 130, + phase: "month1", + description: "Meta/OG, list pages, Supabase sync.", + }, + { + id: "opps-tooling", + title: "Opportunities tooling", + xp: 140, + phase: "month2", + description: "Applicant review, statuses, filters.", + }, + { + id: "pricing-funnels", + title: "Engage/pricing funnels", + xp: 120, + phase: "month2", + description: "Plans and conversion events.", + }, + { + id: "observability", + title: "Observability + Sentry", + xp: 110, + phase: "month2", + description: "Errors, alerts, status surfacing.", + }, + { + id: "collab-teams", + title: "Teams & projects enhancements", + xp: 150, + phase: "month3", + description: "Membership, board UX, notifications.", + }, + { + id: "advanced-mentoring", + title: "Advanced mentoring flows", + xp: 150, + phase: "month3", + description: "Availability, pricing, scheduling hooks.", + }, + { + id: "public-roadmap", + title: "Public roadmap page", + xp: 100, + phase: "month3", + description: "This page—interactive and fun.", + }, ]; const PEEKS: Peek[] = [ @@ -96,7 +184,10 @@ export default function Roadmap() { const progress = Math.min(100, Math.round((earnedXp / totalXp) * 100)); const phaseTotals = useMemo(() => { - const res: Record = {}; + const res: Record< + string, + { total: number; earned: number; count: number } + > = {}; for (const q of QUESTS) { const key = q.phase; res[key] = res[key] || { total: 0, earned: 0, count: 0 }; @@ -115,19 +206,36 @@ export default function Roadmap() { return res; }, [claimed]); - const toggleClaim = (id: string) => setClaimed((m) => ({ ...m, [id]: !m[id] })); - const toggleUnlock = (id: string) => setUnlocked((m) => ({ ...m, [id]: !m[id] })); + const toggleClaim = (id: string) => + setClaimed((m) => ({ ...m, [id]: !m[id] })); + const toggleUnlock = (id: string) => + setUnlocked((m) => ({ ...m, [id]: !m[id] })); - const PhaseIcon: Record = { now: Target, month1: Flame, month2: Rocket, month3: Sparkles }; + const PhaseIcon: Record = { + now: Target, + month1: Flame, + month2: Rocket, + month3: Sparkles, + }; return (
- Roadmap -

The AeThex Roadmap

-

Follow along, earn XP, and unlock sneak peeks. New drops roll out regularly.

+ + Roadmap + +

+ The AeThex Roadmap +

+

+ Follow along, earn XP, and unlock sneak peeks. New drops roll out + regularly. +

@@ -135,15 +243,28 @@ export default function Roadmap() {

Community XP

-
+
-

{earnedXp} / {totalXp} XP

+

+ {earnedXp} / {totalXp} XP +

- Now - Next - Later - Legendary + + Now + + + Next + + + Later + + + Legendary +
@@ -222,20 +389,38 @@ export default function Roadmap() {
{/* Sneak peeks */} -
+
- Sneak peeks + + Sneak peeks +

Dev Drops

-

Unlock previews as we get closer. Collect them all.

+

+ Unlock previews as we get closer. Collect them all. +

{PEEKS.map((p) => ( - +
{p.title} {!unlocked[p.id] && ( @@ -251,13 +436,35 @@ export default function Roadmap() { {p.title}
- {p.teaser} + + {p.teaser} + - {p.phase === "now" ? "Now" : p.phase === "month1" ? "Month 1" : p.phase === "month2" ? "Month 2" : "Month 3"} + + {p.phase === "now" + ? "Now" + : p.phase === "month1" + ? "Month 1" + : p.phase === "month2" + ? "Month 2" + : "Month 3"} +
-
- ({ id: p.id, label: p.title }))} /> + ({ id: p.id, label: p.title }))} + />
diff --git a/client/pages/community/MentorProfile.tsx b/client/pages/community/MentorProfile.tsx index 77248de8..1a97d81b 100644 --- a/client/pages/community/MentorProfile.tsx +++ b/client/pages/community/MentorProfile.tsx @@ -1,7 +1,13 @@ import Layout from "@/components/Layout"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; -import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; +import { + Card, + CardContent, + CardDescription, + CardHeader, + CardTitle, +} from "@/components/ui/card"; import { useEffect, useMemo, useState } from "react"; import { useNavigate, useParams } from "react-router-dom"; import { aethexSocialService } from "@/lib/aethex-social-service"; @@ -31,8 +37,15 @@ export default function MentorProfile() { const load = async () => { setLoading(true); try { - const rows = (await aethexSocialService.listMentors({ q: username, limit: 50 })) as MentorRow[]; - const found = rows.find((r) => (r.user_profiles?.username || "").toLowerCase() === (username || "").toLowerCase()); + const rows = (await aethexSocialService.listMentors({ + q: username, + limit: 50, + })) as MentorRow[]; + const found = rows.find( + (r) => + (r.user_profiles?.username || "").toLowerCase() === + (username || "").toLowerCase(), + ); setMentor(found || null); } catch { setMentor(null); @@ -43,25 +56,45 @@ export default function MentorProfile() { load(); }, [username]); - const displayName = useMemo(() => mentor?.user_profiles?.full_name || mentor?.user_profiles?.username || "Mentor", [mentor]); + const displayName = useMemo( + () => + mentor?.user_profiles?.full_name || + mentor?.user_profiles?.username || + "Mentor", + [mentor], + ); return (
- Mentorship -

{loading ? "Loading…" : displayName}

+ + Mentorship + +

+ {loading ? "Loading…" : displayName} +

{!loading && ( -

{mentor?.user_profiles?.bio || mentor?.bio || "Mentor profile"}

+

+ {mentor?.user_profiles?.bio || mentor?.bio || "Mentor profile"} +

)}
{loading && ( - Loading profile… + + + Loading profile… + + )} {!loading && !mentor && ( - Mentor not found. + + + Mentor not found. + + )} {!loading && mentor && ( @@ -72,10 +105,14 @@ export default function MentorProfile() { Background and focus areas - {mentor.bio &&

{mentor.bio}

} + {mentor.bio && ( +

{mentor.bio}

+ )}
{(mentor.expertise || []).map((tag) => ( - {tag} + + {tag} + ))}
@@ -88,14 +125,30 @@ export default function MentorProfile() {
-
Availability: {mentor.available ? "Accepting requests" : "Unavailable"}
+
+ Availability:{" "} + {mentor.available ? "Accepting requests" : "Unavailable"} +
{typeof mentor.hourly_rate === "number" && (
Rate: ${mentor.hourly_rate}/hr
)}
- - + +
diff --git a/client/pages/community/MentorshipRequest.tsx b/client/pages/community/MentorshipRequest.tsx index a600fa23..4e3d50a7 100644 --- a/client/pages/community/MentorshipRequest.tsx +++ b/client/pages/community/MentorshipRequest.tsx @@ -281,7 +281,9 @@ export default function MentorshipRequest() { onClick={() => { const uname = m.user_profiles?.username; if (uname) { - navigate(`/community/mentor/${encodeURIComponent(uname)}`); + navigate( + `/community/mentor/${encodeURIComponent(uname)}`, + ); } }} className="w-full"