Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,16 @@ import PikiLogoCart from '@/assets/images/piki-logo-cart.svg';
import type { RankedProductT } from '../../../_common/_types/tournament';
import ReceiptPaper from '../ReceiptPaper';

/** 종이 폭은 고정하고 zoom 으로 내용만 키운다 — 렌더 폭이 줄어 결과 폭은 동일하다 */
/** 좁은 폭으로 레이아웃한 뒤 zoom 으로 확대해 최종 폭을 만든다 */
const RECEIPT_PAPER_WIDTH_PX = 370;
const RECEIPT_ZOOM = 1.42;
const RECEIPT_RENDER_WIDTH_PX = RECEIPT_PAPER_WIDTH_PX / RECEIPT_ZOOM;

const RECEIPT_BOX_HEIGHT_PX = 748;
/** 이 높이를 넘길 때만 배율을 낮춘다 */
const RECEIPT_MAX_HEIGHT_PX = 737;

/** ReceiptPaper 하단 물결(h-4.5). absolute 라 종이 높이에 안 잡힌다 */
const RECEIPT_ZIGZAG_HEIGHT_PX = 18;

type ReceiptShareCaptureLayerProps = {
tournamentId: number;
Expand All @@ -23,34 +27,49 @@ const ReceiptShareCaptureLayer = forwardRef<HTMLDivElement, ReceiptShareCaptureL
function ReceiptShareCaptureLayer({ tournamentId, tournamentName, result, date }, ref) {
const paperRef = useRef<HTMLDivElement>(null);
const zoomRef = useRef<HTMLDivElement>(null);
const logoAreaRef = useRef<HTMLDivElement>(null);

/** 내용이 넘치면 zoom 을 낮춘다. 종이 폭이 좁아지지 않게 렌더 폭도 함께 보정한다. */
/**
* 배율을 낮추면 레이아웃 폭이 넓어져 긴 상품명의 줄바꿈이 달라지고, 그러면 높이가 다시
* 변한다. 한 번만 계산하면 이 되먹임 때문에 결과가 어긋나므로 값이 안정될 때까지 반복한다.
* 줄바꿈은 계단식이라 두 값을 오갈 수 있어, 그중 상한을 넘지 않는 최대 배율을 고른다.
*/
useLayoutEffect(() => {
const paper = paperRef.current;
const zoomWrap = zoomRef.current;
if (!paper || !zoomWrap) return;

/** 이전 축소가 남아 있으면 높이를 잘못 재므로 기준값으로 되돌리고 측정 */
zoomWrap.style.zoom = String(RECEIPT_ZOOM);
zoomWrap.style.width = `${RECEIPT_RENDER_WIDTH_PX}px`;
const paperHeight = paper.scrollHeight;
if (!paperHeight) return;
let best = 0;
let candidate = RECEIPT_ZOOM;

for (let i = 0; i < 6; i += 1) {
zoomWrap.style.zoom = String(candidate);
zoomWrap.style.width = `${RECEIPT_PAPER_WIDTH_PX / candidate}px`;

const height = paper.scrollHeight * candidate;
if (!height) return;

if (height <= RECEIPT_MAX_HEIGHT_PX) best = Math.max(best, candidate);

const fitZoom = Math.min(RECEIPT_ZOOM, RECEIPT_BOX_HEIGHT_PX / paperHeight);
const next = Math.min(RECEIPT_ZOOM, (candidate * RECEIPT_MAX_HEIGHT_PX) / height);
if (Math.abs(next - candidate) < 0.002) break;
candidate = next;
}

const fitZoom = best || candidate;
zoomWrap.style.zoom = String(fitZoom);
zoomWrap.style.width = `${RECEIPT_PAPER_WIDTH_PX / fitZoom}px`;

/** 물결 높이를 여백으로 되돌려야 로고가 물결 끝 기준으로 가운데 온다 */
if (logoAreaRef.current) {
logoAreaRef.current.style.paddingTop = `${RECEIPT_ZIGZAG_HEIGHT_PX * fitZoom}px`;
}
}, [result, tournamentName, date]);

return (
<div aria-hidden className="pointer-events-none fixed top-0 -left-250">
<div
ref={ref}
className="flex h-240 w-135 flex-col items-center justify-center gap-6 bg-sky-blue-200 py-12"
>
<div
className="flex w-92.5 items-center justify-center pt-8.5 pb-6.5"
style={{ height: RECEIPT_BOX_HEIGHT_PX }}
>
<div ref={ref} className="flex h-240 w-135 flex-col items-center bg-sky-blue-200 pt-27.75">
<div className="flex w-92.5 items-center justify-center">
<div ref={zoomRef} style={{ zoom: RECEIPT_ZOOM, width: RECEIPT_RENDER_WIDTH_PX }}>
<div ref={paperRef}>
<ReceiptPaper
Expand All @@ -62,7 +81,11 @@ const ReceiptShareCaptureLayer = forwardRef<HTMLDivElement, ReceiptShareCaptureL
</div>
</div>
</div>
<PikiLogoCart aria-hidden className="h-8 w-11 shrink-0 text-white" />

{/* 종이 아래 남는 공간의 한가운데에 로고를 둔다 */}
<div ref={logoAreaRef} className="flex flex-1 items-center justify-center">
<PikiLogoCart aria-hidden className="h-8 w-11 shrink-0 text-white" />
</div>
</div>
</div>
);
Expand Down
Loading