33import type { CSSProperties } from "react" ;
44import Reveal from "@/components/Reveal" ;
55import Window from "./Window" ;
6- import { nfts } from "../_data" ;
6+ import type { Nft } from "../_data" ;
77import { useLanguage } from "@/lib/useLanguage" ;
88import { criptoDict } from "../_i18n" ;
99
10- export default function Nfts ( ) {
10+ type NftsProps = {
11+ items : Nft [ ] ;
12+ isLive : boolean ;
13+ } ;
14+
15+ export default function Nfts ( { items, isLive } : NftsProps ) {
1116 const { lang } = useLanguage ( ) ;
1217 const t = criptoDict [ lang ] . nfts ;
1318
@@ -19,61 +24,20 @@ export default function Nfts() {
1924 < div className = "max-w-[1160px] mx-auto px-5 py-20" >
2025 < Reveal className = "flex flex-wrap items-end justify-between gap-4 mb-12" >
2126 < div >
22- < p className = "c-label mb-3 !text-[var(--c-white)]/60" >
23- { t . label }
24- </ p >
25- < h2 className = "c-display text-[clamp(30px,5vw,58px)]" >
26- { t . title }
27- </ h2 >
27+ < p className = "c-label mb-3 !text-[var(--c-white)]/60" > { t . label } </ p >
28+ < h2 className = "c-display text-[clamp(30px,5vw,58px)]" > { t . title } </ h2 >
2829 </ div >
2930 < span className = "c-tag !border-[var(--c-white)]/40 !bg-transparent !text-[var(--c-white)]/70" >
30- { t . sampleTag }
31+ { isLive ? t . liveTag : t . sampleTag }
3132 </ span >
3233 </ Reveal >
3334
3435 < div className = "grid grid-cols-2 lg:grid-cols-4 gap-5" >
35- { nfts . map ( ( nft , i ) => {
36- const bright = nft . bg === "--c-lime" ;
37- return (
38- < Reveal key = { nft . name } delay = { i * 0.06 } >
39- < div className = "nft-card border-2 border-[var(--c-white)] bg-[var(--c-paper)] text-[var(--c-ink)] shadow-[5px_5px_0_var(--c-white)]" >
40- < div
41- className = "relative aspect-square overflow-hidden border-b-2 border-[var(--c-ink)]"
42- style = { { background : `var(${ nft . bg } )` } as CSSProperties }
43- >
44- < div
45- className = "halftone absolute inset-0 opacity-30"
46- style = { { [ "--dot" as string ] : "var(--c-ink)" } }
47- />
48- < span
49- className = { `absolute inset-0 grid place-items-center c-display text-[clamp(30px,7vw,56px)] ${
50- bright
51- ? "text-[var(--c-on-bright)] opacity-80"
52- : "text-[var(--c-white)] mix-blend-overlay"
53- } `}
54- >
55- #{ nft . tokenId }
56- </ span >
57- < span
58- className = { `absolute top-2 left-2 c-mono text-[9px] tracking-[0.12em] ${
59- bright ? "text-[var(--c-on-bright)]" : "text-[var(--c-white)]"
60- } `}
61- >
62- { nft . collection . toUpperCase ( ) }
63- </ span >
64- </ div >
65- < div className = "p-3 flex items-center justify-between" >
66- < span className = "c-mono text-[11px] font-semibold truncate" >
67- { nft . name }
68- </ span >
69- < span className = "c-mono text-[11px] text-[var(--c-ink-soft)]" >
70- ↗
71- </ span >
72- </ div >
73- </ div >
36+ { items . map ( ( nft , i ) => (
37+ < Reveal key = { `${ nft . chain ?? "x" } -${ nft . collection } -${ nft . tokenId } -${ i } ` } delay = { i * 0.06 } >
38+ < NftCard nft = { nft } />
7439 </ Reveal >
75- ) ;
76- } ) }
40+ ) ) }
7741 </ div >
7842
7943 < Reveal delay = { 0.1 } className = "mt-10" >
@@ -83,13 +47,89 @@ export default function Nfts() {
8347 bodyClassName = "p-5 bg-[var(--c-paper)] text-[var(--c-ink)]"
8448 >
8549 < p className = "c-mono text-[12px] leading-[1.7]" >
86- { t . notePre }
50+ { isLive ? t . liveNotePre : t . notePre }
8751 < b > { t . noteBold } </ b >
88- { t . notePost }
52+ { isLive ? t . liveNotePost : t . notePost }
8953 </ p >
9054 </ Window >
9155 </ Reveal >
9256 </ div >
9357 </ section >
9458 ) ;
9559}
60+
61+ function NftCard ( { nft } : { nft : Nft } ) {
62+ const bright = nft . bg === "--c-lime" ;
63+
64+ const card = (
65+ < div className = "nft-card h-full border-2 border-[var(--c-white)] bg-[var(--c-paper)] text-[var(--c-ink)] shadow-[5px_5px_0_var(--c-white)]" >
66+ < div
67+ className = "relative aspect-square overflow-hidden border-b-2 border-[var(--c-ink)]"
68+ style = {
69+ nft . image
70+ ? undefined
71+ : ( { background : `var(${ nft . bg } )` } as CSSProperties )
72+ }
73+ >
74+ { nft . image ? (
75+ // NFT art comes from arbitrary CDNs / IPFS gateways, so next/image
76+ // (which needs an allowlist of hosts) isn't practical here.
77+ // eslint-disable-next-line @next/next/no-img-element
78+ < img
79+ src = { nft . image }
80+ alt = { nft . name }
81+ loading = "lazy"
82+ className = "absolute inset-0 h-full w-full object-cover transition-transform duration-300 group-hover:scale-[1.04]"
83+ />
84+ ) : (
85+ < >
86+ < div
87+ className = "halftone absolute inset-0 opacity-30"
88+ style = { { [ "--dot" as string ] : "var(--c-ink)" } }
89+ />
90+ < span
91+ className = { `absolute inset-0 grid place-items-center c-display text-[clamp(30px,7vw,56px)] ${
92+ bright
93+ ? "text-[var(--c-on-bright)] opacity-80"
94+ : "text-[var(--c-white)] mix-blend-overlay"
95+ } `}
96+ >
97+ #{ nft . tokenId }
98+ </ span >
99+ </ >
100+ ) }
101+ < span
102+ className = {
103+ nft . image
104+ ? "absolute top-2 left-2 c-mono text-[9px] tracking-[0.12em] px-1.5 py-0.5 bg-[var(--c-ink)] text-[var(--c-white)]"
105+ : `absolute top-2 left-2 c-mono text-[9px] tracking-[0.12em] ${
106+ bright ? "text-[var(--c-on-bright)]" : "text-[var(--c-white)]"
107+ } `
108+ }
109+ >
110+ { nft . collection . toUpperCase ( ) }
111+ </ span >
112+ </ div >
113+ < div className = "p-3 flex items-center justify-between gap-2" >
114+ < span className = "c-mono text-[11px] font-semibold truncate" >
115+ { nft . name }
116+ </ span >
117+ < span className = "c-mono text-[11px] text-[var(--c-ink-soft)]" > ↗</ span >
118+ </ div >
119+ </ div >
120+ ) ;
121+
122+ if ( ! nft . href ) return card ;
123+
124+ return (
125+ < a
126+ href = { nft . href }
127+ target = "_blank"
128+ rel = "noopener noreferrer"
129+ className = "group block h-full"
130+ aria-label = { `${ nft . name } — view on OpenSea` }
131+ >
132+ { card }
133+ </ a >
134+ ) ;
135+ }
0 commit comments