Files
jev-match-game/src/ui/report/ShareCard.tsx
T

104 lines
3.2 KiB
TypeScript

import { useEffect, useRef } from 'react';
import { AREA_BADGE_MAP, DEFAULT_BADGE } from './badges';
import type { RelationshipArea } from '../../engine/scoring';
interface Props {
/** 勋章领域(area id);null = 证据不足,用默认称号 */
badgeArea: string | null;
areas: RelationshipArea[];
/** 玩家自取称呼(C1-01 profile.name),空串时只显示编号 */
playerName?: string;
}
/** 分享卡:canvas 生成 PNG 下载(勋章 + 六领域相处线索) */
export function ShareCard({ badgeArea, areas, playerName }: Props) {
const canvasRef = useRef<HTMLCanvasElement>(null);
useEffect(() => {
draw();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [areas, badgeArea, playerName]);
function draw(): HTMLCanvasElement {
const canvas = canvasRef.current!;
const ctx = canvas.getContext('2d')!;
const W = 640;
const H = 960;
canvas.width = W;
canvas.height = H;
const badge = badgeArea ? (AREA_BADGE_MAP[badgeArea] ?? DEFAULT_BADGE) : DEFAULT_BADGE;
ctx.fillStyle = '#14231d';
ctx.fillRect(0, 0, W, H);
ctx.strokeStyle = '#8ba58e';
ctx.lineWidth = 2;
ctx.strokeRect(32, 32, W - 64, H - 64);
ctx.textAlign = 'center';
ctx.fillStyle = '#d0dfcd';
ctx.font = '28px serif';
ctx.fillText('苍梧疑冢 · 相处线索', W / 2, 80);
ctx.font = '22px serif';
ctx.fillText(`C-2049${playerName ? `「${playerName}」` : ''}的档案`, W / 2, 118);
ctx.beginPath();
ctx.arc(W / 2, 220, 70, 0, Math.PI * 2);
ctx.strokeStyle = '#bfa47c';
ctx.lineWidth = 3;
ctx.stroke();
ctx.fillStyle = '#eed6aa';
ctx.font = 'bold 44px serif';
ctx.fillText('勋', W / 2, 236);
ctx.fillStyle = '#f1eee4';
ctx.font = 'bold 40px serif';
ctx.fillText(badge.title, W / 2, 360);
ctx.fillStyle = '#b3c6b4';
ctx.font = '22px serif';
ctx.fillText(badge.flavor, W / 2, 400);
// 六领域线索行
ctx.textAlign = 'left';
areas.forEach((a, i) => {
const y = 480 + i * 64;
const signal = a.candidates.reduce((n, c) => n + c.pointIds.length, 0);
ctx.fillStyle = '#dce7d9';
ctx.font = '22px serif';
ctx.fillText(a.label, 72, y);
ctx.fillStyle = a.status === '证据不足' ? '#7d9084' : '#a8c1a3';
ctx.font = '19px serif';
const detail =
a.status === '证据不足'
? '情境不足,暂不推断'
: signal > 0
? a.candidates.map((c) => c.label).join(' / ')
: '暂未出现明确倾向';
ctx.fillText(detail, 72, y + 28);
});
ctx.textAlign = 'center';
ctx.fillStyle = '#acc0af';
ctx.font = '18px serif';
ctx.fillText('每条线索都来自剧情实测,等待本人核对。', W / 2, H - 40);
return canvas;
}
function download() {
const canvas = draw();
const a = document.createElement('a');
a.href = canvas.toDataURL('image/png');
a.download = '苍梧疑冢-勋章分享卡.png';
a.click();
}
return (
<div className="share-card">
<canvas ref={canvasRef} className="share-canvas" width={640} height={960} />
<button className="primary" onClick={download}>
下载分享卡 PNG
</button>
</div>
);
}