+ {phase === "revealed" ? "⚓ Treasure Claimed" : "📦 Treasure Chest"} +
+ + {/* Chest */} +Tap to Open!
+YOUR HARD WORK HAS PAID OFF, PIRATE
+ > + )} + {phase === "shaking" && ( + <> +The chest stirs...
+⚡ ⚡ ⚡
+ > + )} + {phase === "revealed" && ( + <> +⚓ Spoils of Victory
+{r.lbl}
+{r.val}
++ tap anywhere to continue +
+ )} +📍 {node.islandName}
+{node.flavourText}
++ {node.requirement.target} {node.requirement.label} +
++ {isCompleted + ? "✅ Completed — treasure claimed!" + : isLocked + ? "🔒 Complete previous quests first" + : `${node.progress} / ${node.requirement.target} done`} +
++ 🧭 {howTo.title} +
+Quest Locked
++ Complete the previous island to sail here +
+📦 Treasure Chest
+✅ Completed — treasure claimed!
+ ) : isLocked ? ( +🔒 Locked — keep sailing
+ ) : ( ++ {progress}% complete · {node.requirement.target - node.progress}{" "} + {node.requirement.label} remaining +
+ )} +Crew Rank
+{rank.label}
+All caught up, Captain!
++ No active quests — keep sailing +
++ {arc.emoji} {arc.name} +
+{node.title}
+ {isClaimable ? ( ++ ✨ Chest ready to open! +
+ ) : ( + <> ++ {node.progress} / {node.requirement.target}{" "} + {node.requirement.label} +
+ > + )} +{message}
+ + +📌 Pick up where you left off
diff --git a/src/pages/student/QuestMap.tsx b/src/pages/student/QuestMap.tsx new file mode 100644 index 0000000..1137d05 --- /dev/null +++ b/src/pages/student/QuestMap.tsx @@ -0,0 +1,996 @@ +import { useState, useRef } from "react"; +import { Lock, CheckCircle } from "lucide-react"; +import type { QuestArc, QuestNode, NodeStatus } from "../../types/quest"; +import { useQuestStore, getQuestSummary } from "../../stores/useQuestStore"; +import { QuestNodeModal } from "../../components/QuestNodeModal"; +import { ChestOpenModal } from "../../components/ChestOpenModal"; + +// ─── Map geometry (all in SVG user-units, viewBox width = 390) ─────────────── +const VW = 390; // viewBox width — matches typical phone width +const ROW_GAP = 260; // vertical distance between island centres +const TOP_PAD = 80; // y of first island centre + +// Three column x-centres: Left=22%, Centre=50%, Right=78% +const COL_X = [ + Math.round(VW * 0.22), // 86 + Math.round(VW * 0.5), // 195 + Math.round(VW * 0.78), // 304 +]; +// Per-arc column sequences — each arc winds differently across the map. +// 0 = Left (22%), 1 = Centre (50%), 2 = Right (78%) +const ARC_COL_SEQS: Record{node.title}
++ {REQ_ICON[node.requirement.type]} + {node.progress}/{node.requirement.target}{" "} + {node.requirement.label} +
+ > + )} + {isLocked && ( ++ 🔒 {node.requirement.target} {node.requirement.label} to unlock +
+ )} + {isCompleted && ( ++ ✅ Conquered! +
+ )} + {isClaimable && ( + + )} +🏴☠️ Treasure Quests
+Chart your course across the Grand Line
+{arc.name}
+{arc.subtitle}
+