import Image from "next/image"; import { CheckIcon, XIcon } from "lucide-react"; import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from "@/components/ui/accordion"; import { Badge } from "@/components/ui/badge"; import { Card, CardContent } from "@/components/ui/card"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { LunarisText } from "@/components/public/lunaris-text"; import { parseLunarisText } from "@/lib/catalog/lunaris"; import { elementIconFilter } from "@/lib/catalog/element"; import { rarityGradientClass } from "@/lib/catalog/rarity"; import type { getActiveCatalog } from "@/lib/guides/queries"; import type { getStygianSchedule } from "@/lib/stygian/repository"; import { cn } from "@/lib/utils"; type Schedule = NonNullable>>; type Catalog = NonNullable>>; type Item = Schedule["recommendations"][number]["items"][number]; function RecommendedMechanic({ mechanic, type }: { mechanic: string; type: string }) { const parts = mechanic.split(/(\{SPRITE_PRESET#\d+\})/gu); return ( {parts.map((part, index) => { const preset = /^\{SPRITE_PRESET#(\d+)\}$/u.exec(part)?.[1]; if (preset) return ; return part ? : null; })} {type === "Disadvantage" ? ); } function recommendation(item: Item, catalog: Catalog) { if (item.kind === "element" && item.element) { const source = catalog.characters.find((character) => character.element === item.element && character.elementIconUrl); return { name: item.element, imageUrl: source?.elementIconUrl ?? null, badge: "Element", rarity: null }; } if (item.kind === "character") { const character = catalog.characters.find((candidate) => candidate.key === item.catalogKey); const weapon = catalog.weapons.find((candidate) => candidate.key === item.weaponKey); const artifact = catalog.artifacts.find((candidate) => candidate.key === item.artifactKey); return { name: character?.name ?? item.catalogKey ?? "Unknown", imageUrl: character?.imageUrl ?? null, badge: item.constellationLevel === null ? "Character" : `C${item.constellationLevel}`, rarity: character?.rarity ?? null, weapon, artifact, refinement: item.refinement, }; } const collection = item.kind === "weapon" ? catalog.weapons : catalog.artifacts; const value = collection.find((candidate) => candidate.key === item.catalogKey); return { name: value?.name ?? item.catalogKey ?? "Unknown", imageUrl: value?.imageUrl ?? null, badge: item.kind, rarity: value?.rarity ?? null }; } function RecommendationIcon({ item, catalog, teamLayout = false }: { item: Item; catalog: Catalog; teamLayout?: boolean }) { const value = recommendation(item, catalog); if (item.kind === "character") { const hasEquipment = Boolean(value.weapon || value.artifact); return (
{value.imageUrl ? {value.name} : null}
{hasEquipment ?
{value.weapon ?
{value.weapon.name}
: null} {value.artifact ?
{value.artifact.name}
: null}
: null}
{teamLayout ? item.constellationLevel !== null || value.weapon && value.refinement ?
{item.constellationLevel !== null ? C{item.constellationLevel} : null} {value.weapon && value.refinement ? R{value.refinement} : null}
: null : {value.name}}
); } return (
{value.imageUrl ? {value.name} : null}
{value.name}
); } function BossCard({ schedule, level, position, catalog }: { schedule: Schedule; level: 105 | 110; position: number; catalog: Catalog }) { const boss = schedule.bosses.find((candidate) => candidate.level === level && candidate.position === position); if (!boss) return null; const groups = schedule.recommendations.filter((group) => group.level === level && group.bossPosition === position); const teams = groups.filter((group) => group.kind === "team"); const units = groups.filter((group) => group.kind === "unit").flatMap((group) => group.items); return (

{boss.name}

Level {level} · HP {Math.round(boss.hp).toLocaleString("en-US")}

Boss overview {boss.mechanics.map((mechanic, index) => ( {mechanic.name} ))}

Recommended team

{teams.length ? teams.map((team) => (
{team.items.slice(0, 4).map((item) => )} {Array.from({ length: Math.max(0, 4 - team.items.length) }, (_, index) => )) :

No team recommendations yet.

}

Recommended unit

{units.length ?
{units.map((item) => )}
:

No unit recommendations yet.

}
); } export function StygianGuide({ schedule, catalog }: { schedule: Schedule; catalog: Catalog }) { return ( Level 105 Level 110 {([105, 110] as const).map((level) => ( {[0, 1, 2].map((position) => { const boss = schedule.bosses.find((candidate) => candidate.level === level && candidate.position === position); const label = boss?.name ?? `Boss ${position + 1}`; const positionLabel = ["บน", "กลาง", "ล่าง"][position]; return {boss ? : {position + 1}} {positionLabel} {boss?.recommendedMechanics.some(Boolean) ? {boss.recommendedMechanics.map((mechanic, index) => mechanic ? : null)} : null} ; })} {[0, 1, 2].map((position) => )} ))} ); }