"use client"; import Image from "@/components/ui/resilient-image"; import Link from "next/link"; import { ArrowUpRightIcon, SearchIcon, XIcon } from "lucide-react"; import { Fragment, useMemo, useState, type ReactNode } from "react"; import { GuideImageExport } from "@/components/public/guide-image-export"; import { ConditionTabIcon } from "@/components/public/condition-switcher"; import { ExportText } from "@/components/public/export-language"; import { ScrollableNav } from "@/components/public/scrollable-nav"; import { Button } from "@/components/ui/button"; import { Badge } from "@/components/ui/badge"; import { Card, CardAction, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; import { Input } from "@/components/ui/input"; import { Kbd } from "@/components/ui/kbd"; import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select"; import { Separator } from "@/components/ui/separator"; import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group"; import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { elementBackgroundColor } from "@/lib/catalog/element"; import { characterRarityGradientClass, rarityGradientClass } from "@/lib/catalog/rarity"; import { isCustomTravelerKey } from "@/lib/catalog/travelers"; import type { PublicGuide } from "@/lib/guides/queries"; import { teamConstellationLabel, teamRefinementLabel } from "@/lib/guides/team-tools"; import { searchTeams, sortTeamsByDps, type DpsOrder, type TeamSearchTarget, } from "@/lib/guides/team-search"; import { cn } from "@/lib/utils"; export interface TeamExportData { title: string; rotationSeconds: string | number; combo: string; members: Array<{ position: number; constellation: string; refinement: string; damage: string | number; character: { key: string; name: string; imageUrl: string; element: string | null; rarity: number | null; }; weapon: { key: string; name: string; imageUrl: string; rarity: number | null; } | null; artifact: TeamArtifact | null; secondArtifact: TeamArtifact | null; }>; } type Team = PublicGuide["teams"][number]; const teamSearchTargetLabels: Record = { all: "ทั้งหมด", team: "ชื่อทีม", character: "ตัวละคร", weapon: "อาวุธ", artifact: "อาร์ติแฟกต์", }; type TeamArtifact = { key: string; name: string; imageUrl: string; rarity: number | null; }; function ArtifactHalf({ artifact, side, eager, linked, sizes, }: { artifact: TeamArtifact; side: "left" | "right"; eager: boolean; linked: boolean; sizes: string; }) { const content = ( {linked ); const className = cn( "absolute inset-0 overflow-hidden", side === "left" ? "[clip-path:polygon(0_0,0_100%,100%_100%)]" : "[clip-path:polygon(0_0,100%_0,100%_100%)]", rarityGradientClass(artifact.rarity), ); return linked ? ( {content} ) : ( {content} ); } export function TeamArtifactIcon({ first, second, eager = false, linked = false, className, sizes, }: { first: TeamArtifact | null; second: TeamArtifact | null; eager?: boolean; linked?: boolean; className?: string; sizes: string; }) { const primary = first ?? second; const secondary = first ? second : null; if (!primary) { return
; } if (!secondary) { const content = ( <> {linked {linked ? ( ) : null} ); const artifactClassName = cn( "relative aspect-square scale-110 overflow-hidden rounded-md bg-muted", rarityGradientClass(primary.rarity), className, ); return linked ? ( {content} ) : (
{content}
); } return (
); } export function TeamExportImage({ team }: { team: TeamExportData }) { const total = team.members.reduce((sum, member) => sum + Number(member.damage), 0); const seconds = Number(team.rotationSeconds); return (

{team.title}

{team.members.map((member) => { const damage = Number(member.damage); const percent = total > 0 ? damage / total * 100 : 0; return (
{member.weapon ?
: null}
{member.character.name} {teamConstellationLabel(member.constellation)}{teamRefinementLabel(member.refinement)} {damage.toLocaleString("en-US")}
{percent.toFixed(1)}%
); })}

{team.combo}

DPS: {seconds > 0 ? (total / seconds).toLocaleString("en-US", { maximumFractionDigits: 0 }) : "0"}
By YT เกนชินไม่ใช่เกมมือถือ
); } function TeamCard({ team, action, exporting = false, }: { team: Team; action?: ReactNode; exporting?: boolean; }) { const total = team.members.reduce( (sum, member) => sum + Number(member.damage), 0, ); const seconds = Number(team.rotationSeconds); return ( {team.title} โรเทชั่น {seconds} วิ {action ? {action} : null}
{team.members.map((member) => (
{member.character.name}
{member.weapon ? ( {member.weapon.name} ) : (
)}
{teamConstellationLabel(member.constellation)} {teamRefinementLabel(member.refinement)}

{member.character.name}

{Number(member.damage).toLocaleString(undefined, { maximumFractionDigits: 2, })}

{total ? ((Number(member.damage) / total) * 100).toFixed(2) : "0.00"} %

))}

ดาเมจรวม

{total.toLocaleString()}

DPS

{seconds > 0 ? (total / seconds).toLocaleString(undefined, { maximumFractionDigits: 0, }) : "0"}

{team.combo}

); } export function TeamSearch({ groups }: { groups: PublicGuide["teamGroups"] }) { const [activeCondition, setActiveCondition] = useState("0"); const activeGroup = groups[Number(activeCondition)] ?? groups[0]; const teams = useMemo(() => activeGroup?.teams ?? [], [activeGroup]); const [query, setQuery] = useState(""); const [searchTarget, setSearchTarget] = useState("all"); const [dpsOrder, setDpsOrder] = useState(null); const search = useMemo( () => searchTeams(teams, (team) => ({ team: [team.title], character: team.members.flatMap((member) => [member.character.name, ...member.character.aliases]), weapon: team.members.flatMap((member) => member.weapon ? [member.weapon.name, ...member.weapon.aliases] : []), artifact: team.members.flatMap((member) => [member.artifact, member.secondArtifact].flatMap((artifact) => artifact ? [artifact.name, ...artifact.aliases] : [])), }), query, searchTarget), [query, searchTarget, teams], ); const filteredTeams = sortTeamsByDps(search.items, dpsOrder); return (
{groups.length > 1 ? ( {groups.map((group, index) => {index > 0 ? )} ) : null} {activeGroup?.note ?

{activeGroup.note}

: null}
{ const order = value[0] as Exclude | undefined; if (order) setDpsOrder(order); }} > Best DPS Worst DPS
{filteredTeams.length ? (
{filteredTeams.map((team) => ( } /> ))}
) : ( ไม่พบทีมที่ตรงกับคำค้นหา )}
); }