import { useMemo, useState } from 'react'
import { Link, useParams } from 'react-router-dom'
import PublicLayout from '../../components/PublicLayout.jsx'
import PageHeader from '../../components/PageHeader.jsx'
import { Loading, ErrorState, EmptyState } from '../../components/PageState.jsx'
import { useAsync } from '../../lib/useAsync.js'
import { api } from '../../api/client.js'
// One creature: where it spawns, and what spawns alongside it.
//
// `places` is the point of the page — the aggregate that turns 62 raw
// coordinates into "Shrines, Isamu-Jima, Yew". The individual spawners are
// available underneath for the reader who actually wants a coordinate, but they
// are secondary and collapsed by default.
const num = (v) => (Number.isFinite(v) ? v.toLocaleString() : '—')
// Spawn delays are stored in seconds. A raw "1200" tells the reader nothing.
function delay(min, max) {
const fmt = (s) => (s >= 60 ? `${Math.round(s / 60)}m` : `${s}s`)
if (!Number.isFinite(min) || !Number.isFinite(max)) return null
if (min === max) return fmt(min)
return `${fmt(min)}–${fmt(max)}`
}
function Panel({ title, right, children }) {
return (
{title}
{right}
No placed spawners.
} return (| Place | Facet | Coords | Max | Respawn |
|---|---|---|---|---|
| {s.label} | {s.facet} | {s.x}, {s.y} | {num(s.maxCount)} | {delay(s.minDelay, s.maxDelay) || '—'} |
Only the largest spawners are listed.
)}← Spawn atlas
{loading &&