--- import FilterGroup from "@gk/ui/components/FilterGroup.astro"; import Icon from "@gk/ui/components/Icon.astro"; import PageShell from "@gk/ui/components/PageShell.astro"; import Star from "@gk/ui/components/Star.astro"; import StarChartArt from "@gk/ui/components/StarChartArt.astro"; import StatusPill from "@gk/ui/components/StatusPill.astro"; import PageHero from "../components/PageHero.astro"; import NowStrip, { type NowItem } from "../components/world/NowStrip.astro"; import WorldSection from "../components/world/WorldSection.astro"; import type { Note } from "../lib/content.ts"; import { plural, site } from "../lib/page.ts"; import { slugify } from "@gk/schema"; import { byOrder, deckUrl, makePhotos, sentence, stancePill, systemPill, systemStates } from "../lib/world.ts"; const s = await site(); const text = s.pageText("/tabletop"); const intro = s.render(text?.body); const stateRank = (st: string) => systemStates.indexOf(st as (typeof systemStates)[number]); const systems = byOrder(s.all("tabletop-system")).sort((a, b) => stateRank(a.data.state) - stateRank(b.data.state)); const states = systemStates.filter((st) => systems.some((x) => x.data.state === st)); const campaigns = [...s.all("campaign")].sort((a, b) => a.title.localeCompare(b.title)); const atTable = campaigns.filter((c) => c.data.status === "active" || c.data.status === "playtest"); const pastCampaigns = campaigns.filter((c) => !atTable.includes(c)); const games = byOrder(s.all("card-game")); const allDecks = [...s.all("deck")].sort((a, b) => a.title.localeCompare(b.title)); const isFav = (d: Note<"deck">) => !!d.data.favorite; const decks = allDecks.some(isFav) ? allDecks.filter(isFav) : allDecks; const gameOf = (d: Note<"deck">) => s.link(d.data.game); const deckGroup = (d: Note<"deck">) => [shortGame(gameOf(d).title), d.data.format].filter(Boolean).join(" "); const deckGroups = [...new Set(decks.map(deckGroup))]; /** "Magic: The Gathering" reads as MTG in kickers, as the design does. */ function shortGame(title: string) { return /^magic/i.test(title) ? "MTG" : title; } /** A status that points at a deck makes it the deck of the moment. */ const deckStatus = s.statuses().find((st) => s.byName(st.data.subject)?.type === "deck"); const deckOfMoment = deckStatus ? (s.byName(deckStatus.data.subject) as Note<"deck">) : undefined; const nowItems: NowItem[] = atTable.map((c) => { const system = c.data.system ? s.link(c.data.system) : null; const label = c.data.status === "playtest" ? "Playtest" : [system?.title, c.data.platform && `on ${c.data.platform}`].filter(Boolean).join(" · "); return { id: c.slug, label: label || "Campaign", title: c.title, note: [c.data.schedule, c.data.blurb].filter(Boolean).join(" · ") || undefined, }; }); if (deckOfMoment) { nowItems.push({ label: ["Deck of the moment", deckGroup(deckOfMoment)].filter(Boolean).join(" · "), title: deckOfMoment.title, note: deckStatus?.data.note ?? deckOfMoment.data.take, href: `#${deckOfMoment.slug}`, }); } const archidekt = s.settings()?.socials.find((x) => /archidekt/i.test(x.label)); const shelfCount = s.all("board-game").length; const workshopImg = s.all("make").flatMap((m) => makePhotos(m))[0]; --- {nowItems.length > 0 && } {intro &&
} { systems.length > 0 && ( {states.length > 1 && ( ({ label: sentence(st), value: st }))]} /> )}
    {systems.map((x) => { const runs = campaigns.filter((c) => s.byName(c.data.system)?.path === x.path); return (
  • {x.title}

    {sentence(x.data.state)}

    {x.data.blurb}

    {runs.length > 0 && (

    {runs.map((c, i) => ( <> {i > 0 && " · "} {c.title} ))}

    )}
  • ); })}
{pastCampaigns.length > 0 && (

Earlier campaigns

    {pastCampaigns.map((c) => (
  • {c.title} {sentence(c.data.status)} {c.data.blurb && {c.data.blurb}}
  • ))}
)}
) } { decks.length > 0 && ( {archidekt && ( All my Magic decks on Archidekt )} {deckGroups.length > 1 && ( ({ label: g, value: g }))]} /> )}
    {decks.map((d) => { const url = deckUrl(d); const game = gameOf(d); return (
  • {[shortGame(game.title), d.data.format].filter(Boolean).join(" · ")}

    {url ? ( {d.title} ) : ( d.title )} {isFav(d) && }

    {deckOfMoment?.path === d.path && Playing now}
    {d.data.take &&

    {d.data.take}

    } {url && ( {d.data.archidektId ? "On Archidekt" : "Deck list"} )}
  • ); })}
) } { games.length > 0 && (
    {games.map((g) => { const n = s.all("deck").filter((d) => s.byName(d.data.game)?.path === g.path).length; return (
  • {g.title}

    {g.data.stance}
    {g.data.blurb &&

    {g.data.blurb}

    } {n > 0 &&

    {plural(n, "deck")} here

    }
  • ); })}
) }