This commit is contained in:
Greg Kilmer
2026-07-06 22:35:23 -04:00
parent 6c50217bc6
commit 64f33c1ef5
10 changed files with 581 additions and 0 deletions
+115
View File
@@ -0,0 +1,115 @@
---
/**
* DeckCard.astro
* ---------------------------------------------------------------------------
* Card for a single Magic: The Gathering deck pulled live from Archidekt. Shows
* the deck's featured card art (or a placeholder slab), the deck name as a link
* to its Archidekt page, a row of mana-color pips sized by color presence, and
* a meta line (card count, format, last-updated).
*
* Data shape matches ArchidektDeck in src/lib/archidekt.ts.
*/
import Icon from '@components/Icon.astro';
interface Props {
name: string;
href: string;
featured?: string;
colors?: { W: number; U: number; B: number; R: number; G: number };
size?: number;
formatLabel?: string;
updatedAt?: string;
}
const { name, href, featured, colors, size, formatLabel, updatedAt } = Astro.props;
// MTG mana colors. Used for the presence pips; a color shows only if count > 0.
const MANA: Array<[key: 'W' | 'U' | 'B' | 'R' | 'G', hex: string]> = [
['W', '#f8f4e8'],
['U', '#3b7bd4'],
['B', '#2b2b2b'],
['R', '#d44b3b'],
['G', '#3f9d52'],
];
const present = colors ? MANA.filter(([k]) => (colors[k] ?? 0) > 0) : [];
// Friendly relative-ish date (e.g. "Jul 2026"). Falls back gracefully.
const updated = updatedAt ? new Date(updatedAt).toLocaleDateString('en-US', {
month: 'short',
year: 'numeric',
}) : '';
---
<a
href={href}
target="_blank"
rel="noopener noreferrer"
class="card card-interactive group flex h-full flex-col gap-0 overflow-hidden p-0"
>
<div class="relative aspect-[4/3] w-full overflow-hidden">
{
featured ? (
<img
src={featured}
alt={`${name} featured card`}
loading="lazy"
decoding="async"
class="h-full w-full object-cover transition-transform duration-700 group-hover:scale-105"
/>
) : (
<div
class="flex h-full w-full items-center justify-center"
style="background: color-mix(in srgb, var(--color-secondary) 16%, transparent);"
aria-hidden="true"
>
<Icon
name="cards-playing"
class="h-12 w-12 opacity-50"
style="color: var(--color-text-muted);"
/>
</div>
)
}
{/* Legibility gradient at the bottom for the meta row. */}
<div
aria-hidden="true"
class="absolute inset-x-0 bottom-0 h-1/3"
style="background: linear-gradient(to top, rgba(0,0,0,0.55), transparent);"
></div>
{
/* Mana color pips, top-left over the art. */
present.length > 0 && (
<div class="absolute left-3 top-3 flex gap-1.5">
{present.map(([key, hex]) => (
<span
class="h-3 w-3 rounded-full border border-black/30"
style={`background:${hex};`}
title={`${key} mana`}
aria-hidden="true"
/>
))}
</div>
)
}
</div>
<div class="flex flex-col gap-2 p-4">
<h3
class="font-sans text-base leading-tight underline-offset-4 group-hover:underline"
style="color: var(--color-text);"
>
{name}
</h3>
<div
class="flex flex-wrap items-center gap-2 font-mono text-[0.65rem] uppercase tracking-[0.16em]"
style="color: var(--color-text-muted);"
>
{formatLabel && <span>{formatLabel}</span>}
{formatLabel && (size || updated) && <span aria-hidden="true">·</span>}
{size ? <span>{size} cards</span> : null}
{updated && (size ? <span aria-hidden="true">·</span> : null)}
{updated && <span>{updated}</span>}
</div>
</div>
</a>