Replace QRCodeCanvas DOM preview with static placeholder

The qrcode library internally uses var ctx and canvas.getContext('2d') at
initialization time. In the Shakespeare preview iframe environment, canvas
API is restricted causing "ctx is not defined" console errors on every render.

Fix: replace QRCodeCanvas in the DOM screen preview with a static decorative
QR placeholder (5x5 pixel grid). The real, scannable QR code is still
generated correctly in the exported PNG via QRCode.toDataURL() in the
drawCardToCanvas() async function - this is unaffected by the env restriction
since it only runs when the user clicks Print/Save/Share.

Also remove unused QRCodeCanvas import from RiderCardPage.

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
This commit is contained in:
shakespeare.diy 2026-06-16 16:21:58 +07:00
parent 6ba5dc1187
commit 125bce3637

View file

@ -41,8 +41,6 @@ import { useQuery } from '@tanstack/react-query';
import { genUserName } from '@/lib/genUserName'; import { genUserName } from '@/lib/genUserName';
import { cn } from '@/lib/utils'; import { cn } from '@/lib/utils';
import type { NostrEvent } from '@nostrify/nostrify'; import type { NostrEvent } from '@nostrify/nostrify';
import { QRCodeCanvas } from '@/components/ui/qrcode';
// ─── Card canvas renderer ───────────────────────────────────────────────────── // ─── Card canvas renderer ─────────────────────────────────────────────────────
// Draws the card entirely via Canvas 2D API — 100% reliable export, // Draws the card entirely via Canvas 2D API — 100% reliable export,
// no CSS capture, no scaling issues, no background-stripping. // no CSS capture, no scaling issues, no background-stripping.
@ -956,10 +954,14 @@ function RiderFront({ d }: { d: CardData }) {
</div> </div>
</div> </div>
{/* QR code — bottom-right of body */} {/* QR placeholder — real QR renders in exported PNG */}
<div className="flex-shrink-0 flex flex-col items-end justify-end"> <div className="flex-shrink-0 flex flex-col items-end justify-end">
<div className="rounded-[3px] overflow-hidden" style={{ background: '#fff', padding: '2px' }}> <div className="rounded-[3px]" style={{ background: '#fff', padding: '3px', width: '44px', height: '44px' }}>
<QRCodeCanvas value={qrUrl} size={44} level="M" /> <div style={{ width: '38px', height: '38px', display: 'grid', gridTemplateColumns: 'repeat(5,1fr)', gap: '1px' }}>
{Array.from({ length: 25 }).map((_, i) => (
<div key={i} style={{ background: [0,1,2,5,6,7,10,14,17,18,19,22,23,24].includes(i) ? '#000' : '#fff' }} />
))}
</div>
</div> </div>
<div className="text-[4.5px] card-muted uppercase tracking-wide mt-[2px] text-right">Scan to verify</div> <div className="text-[4.5px] card-muted uppercase tracking-wide mt-[2px] text-right">Scan to verify</div>
</div> </div>
@ -1028,10 +1030,14 @@ function ParkFront({ d }: { d: CardData }) {
)} )}
</div> </div>
{/* QR */} {/* QR placeholder */}
<div className="flex-shrink-0 flex flex-col items-end justify-end"> <div className="flex-shrink-0 flex flex-col items-end justify-end">
<div className="rounded-[3px] overflow-hidden" style={{ background: '#fff', padding: '2px' }}> <div className="rounded-[3px]" style={{ background: '#fff', padding: '3px', width: '44px', height: '44px' }}>
<QRCodeCanvas value={qrUrl} size={44} level="M" /> <div style={{ width: '38px', height: '38px', display: 'grid', gridTemplateColumns: 'repeat(5,1fr)', gap: '1px' }}>
{Array.from({ length: 25 }).map((_, i) => (
<div key={i} style={{ background: [0,1,2,5,6,7,10,14,17,18,19,22,23,24].includes(i) ? '#000' : '#fff' }} />
))}
</div>
</div> </div>
<div className="text-[4.5px] card-muted uppercase tracking-wide mt-[2px] text-right">Scan to verify</div> <div className="text-[4.5px] card-muted uppercase tracking-wide mt-[2px] text-right">Scan to verify</div>
</div> </div>