polish(card): roles/badges on their own line, QR nudged to centre

Verified both sides by rendering the public card headlessly (the studio preview
and /card/:npub use the same canvas renderer).
This commit is contained in:
SkateSpots 2026-10-02 12:06:39 +07:00
parent 3b542caade
commit 9dc7e7429d

View file

@ -161,7 +161,7 @@ async function drawStub(ctx: CanvasRenderingContext2D, data: CanvasCardData, p:
const size = 156; const size = 156;
const qx = STUB_X + (STUB_W - size) / 2; const qx = STUB_X + (STUB_W - size) / 2;
const qy = 128; const qy = 140;
roundRect(ctx, qx - 12, qy - 12, size + 24, size + 24, 14); roundRect(ctx, qx - 12, qy - 12, size + 24, size + 24, 14);
ctx.fillStyle = '#ffffff'; ctx.fillStyle = '#ffffff';
@ -191,11 +191,11 @@ async function drawRiderFront(ctx: CanvasRenderingContext2D, data: CanvasCardDat
// Name — the focal point (sized to leave the QR room). // Name — the focal point (sized to leave the QR room).
ctx.fillStyle = p.text; ctx.fillStyle = p.text;
ctx.font = 'bold 46px system-ui, sans-serif'; ctx.font = 'bold 46px system-ui, sans-serif';
ctx.fillText(fitText(ctx, data.name.toUpperCase(), TEXT_W), TEXT_X, 156); ctx.fillText(fitText(ctx, data.name.toUpperCase(), TEXT_W), TEXT_X, 148);
// One identity line: style · level · local. // One identity line: style · level · local.
const identity = [data.style, data.level, data.showLocal ? data.local : ''].filter(Boolean).join(' · '); const identity = [data.style, data.level, data.showLocal ? data.local : ''].filter(Boolean).join(' · ');
let y = 196; let y = 188;
if (identity) { if (identity) {
ctx.fillStyle = p.accent; ctx.fillStyle = p.accent;
ctx.font = 'bold 20px system-ui, sans-serif'; ctx.font = 'bold 20px system-ui, sans-serif';
@ -233,14 +233,14 @@ async function drawRiderFront(ctx: CanvasRenderingContext2D, data: CanvasCardDat
cx += circleR * 2 + 14 + ctx.measureText(nm).width + 12; cx += circleR * 2 + 14 + ctx.measureText(nm).width + 12;
}); });
// Roles + witnessed badges, on their own line just above the circles. // Roles + witnessed badges on their own line.
const chips: string[] = []; const chips: string[] = [];
if (data.showRoles) for (const r of (data.roles ?? []).slice(0, 2)) { const m = roleMeta(r); if (m) chips.push(`${m.emoji} ${m.label}`); } if (data.showRoles) for (const r of (data.roles ?? []).slice(0, 2)) { const m = roleMeta(r); if (m) chips.push(`${m.emoji} ${m.label}`); }
for (const b of (data.receivedBadges ?? []).slice(0, 3)) chips.push(`★ ${b.skill}`); for (const b of (data.receivedBadges ?? []).slice(0, 3)) chips.push(`★ ${b.skill}`);
if (chips.length > 0 && crewNames.length === 0) { if (chips.length > 0) {
ctx.fillStyle = p.accent2; ctx.fillStyle = p.accent2;
ctx.font = 'bold 15px system-ui, sans-serif'; ctx.font = 'bold 16px system-ui, sans-serif';
ctx.fillText(fitText(ctx, chips.join(' '), TEXT_W), TEXT_X, cy + 5); ctx.fillText(fitText(ctx, chips.join(' '), TEXT_W), TEXT_X, 276);
} }
if (logo) drawCover(ctx, logo, 22, 22, 58, 58, 12); if (logo) drawCover(ctx, logo, 22, 22, 58, 58, 12);