Rich card data

This commit is contained in:
2026-10-19 16:47:27 -04:00
parent f26e38b096
commit 6155e8b3ed
31 changed files with 633 additions and 25 deletions
+7 -3
View File
@@ -2,6 +2,8 @@ import { ArrowUpRight, BookOpen, Globe2, Shield, Sparkles, Swords } from 'lucide
import { rarity, stats, type Article } from '../shared/protocol.ts';
import type { TestnetBlock } from '../shared/testnet.ts';
import { STARTER_ARTICLES } from '../shared/catalog.ts';
import { useEnrichment } from './useEnrichment.ts';
import { CardInsights, EnrichmentScores } from './CardInsights.tsx';
// hash is the RandomX proof hash for game stats; block.tokenId is NFT identity.
export type CardData = { article: Article; hash: string; block?: TestnetBlock };
@@ -19,15 +21,17 @@ export function Card({ card, onClick }: { card: CardData; onClick?: () => void }
const { article, hash } = card;
const tier = rarity(hash);
const s = stats(hash);
return <button className={`wiki-card ${tier.toLowerCase()}`} onClick={onClick} tabIndex={onClick ? 0 : -1} aria-label={`View ${article.title} ${tier} card`}>
const {data:enrichment,error}=useEnrichment(article.pageId);
return <><button className={`wiki-card ${tier.toLowerCase()}`} onClick={onClick} tabIndex={onClick ? 0 : -1} aria-label={`View ${article.title} ${tier} card`}>
<div className="card-top"><span><Sparkles size={11} /> {tier}</span><span>W / {String(article.pageId).slice(-4)}</span></div>
<div className={`card-art art-${article.category.toLowerCase()}`}>
{article.image ? <img src={article.image} alt={article.title} loading="lazy" referrerPolicy="no-referrer" onError={e => { e.currentTarget.style.display = 'none'; }} /> : <Globe2 size={64} />}
<span className="card-category">{article.category}</span>
</div>
<div className="card-content"><div className="card-title"><h3>{article.title}</h3><ArrowUpRight size={16} /></div><p>{article.extract}</p>
<div className="card-stats"><span><Swords size={12} />{s.power}</span><span><Shield size={12} />{s.defense}</span><span><BookOpen size={12} />{s.knowledge}</span></div>
<div className="card-stats" aria-label="Immutable proof-derived game stats"><span title="Power · proof-derived"><Swords size={12} />{s.power}</span><span title="Defense · proof-derived"><Shield size={12} />{s.defense}</span><span title="Knowledge · proof-derived"><BookOpen size={12} />{s.knowledge}</span></div>
<div className="card-enrichment">{enrichment?<><div className="card-readership"><span>LIVE WIKIPEDIA</span><span>{enrichment.pageviews.status==='available'?`${new Intl.NumberFormat('en',{notation:'compact',maximumFractionDigits:1}).format(enrichment.pageviews.months.at(-1)!.views)} views / month`:'Views unavailable'}</span></div><EnrichmentScores data={enrichment}/></>:<span className="card-enrichment-status">{error?'Live metadata unavailable':'Loading article insights…'}</span>}</div>
</div>
<div className="card-bottom"><span>WIKIPEDIA · #{article.pageId}</span><span>{card.block ? `BLOCK ${card.block.height}` : 'PREVIEW'}</span></div>
</button>;
</button>{!onClick&&<CardInsights pageId={article.pageId}/>}</>;
}