@php
/**
* One printed table-card side (front or back). Each element is optional and — where noted — placed on
* the shared 3x3 grid the TV editor uses:
* • a full-bleed background image
* • the restaurant's own logo (anchored)
* • a featured-product overlay (anchored)
* • the table's own scan-to-order QR (anchored), with the table number + zone above it and,
* optionally, the restaurant logo dropped into its centre
* • a footer line (a disclaimer + an optional "powered by" credit)
*
* Rendered identically by the design editor preview and by the print sheet; only the per-table bits
* differ (the QR target and the number/zone). The QR itself is drawn client-side into [data-qr], so
* this partial never touches the existing scan-code logic — it only places the code.
*
* @var array $side One side of the QrCard config.
* @var array $card The whole card config (theme/accent/bgColor/orientation/poweredBy).
* @var array|null $product Resolved featured dish ['name','desc','price'] or null.
* @var string $qrPath Scan path to encode on this side ('' = draw no QR).
* @var array $logo The restaurant's brand mark ['src'=>'','initials'=>'','color'=>''].
* @var array $table This table's identity ['label'=>'','zone'=>''] (per-table; a sample in preview).
*/
$side = $side ?? [];
$card = $card ?? [];
$product = $product ?? null;
$qrPath = (string) ($qrPath ?? '');
$logo = $logo ?? [];
$table = $table ?? [];
$placeholder = (bool) ($placeholder ?? false); // preview/template mode: show a "background image" slot
$theme = ($card['theme'] ?? 'light') === 'dark' ? 'dark' : 'light';
$orient = ($card['orientation'] ?? 'portrait') === 'landscape' ? 'landscape' : 'portrait';
$accent = preg_match('/^#[0-9a-fA-F]{6}$/', (string) ($card['accent'] ?? '')) ? $card['accent'] : '#e11d2a';
$bgColor = (string) ($card['bgColor'] ?? '');
$bgImg = ($side['background'] ?? '') !== '' ? media($side['background']) : '';
$hasBg = $bgImg !== '';
$fontStack = \App\Services\Receipt::fontStack((string) ($card['font'] ?? 'sans'));
// The card's aspect ratio matches the chosen paper so it fills the printed sheet exactly.
$paper = \App\Models\QrCard::PAPERS[$card['paper'] ?? 'a5'] ?? \App\Models\QrCard::PAPERS['a5'];
$ar = $orient === 'landscape' ? ($paper['h'] . ' / ' . $paper['w']) : ($paper['w'] . ' / ' . $paper['h']);
// Per-corner radius (0–10 → cqmin), so each corner can round independently or stay a straight 90° cut.
$rad = static fn ($n) => round(max(0, min(10, (int) $n)) * 0.8, 2) . 'cqmin';
$borderRad = $rad($card['cornerTl'] ?? 3) . ' ' . $rad($card['cornerTr'] ?? 3) . ' ' . $rad($card['cornerBr'] ?? 3) . ' ' . $rad($card['cornerBl'] ?? 3);
$styleVars = '--qrc-accent:' . e($accent) . ';--qrc-font:' . $fontStack . ';aspect-ratio:' . $ar . ';border-radius:' . $borderRad . ';';
if ($bgColor !== '') { $styleVars .= '--qrc-bg:' . e($bgColor) . ';'; }
/** One element's offset-nudge style vars (cqw/cqh of the card). */
$off = static fn (string $x, string $y) => '--qrc-ox:' . (int) ($side[$x] ?? 0) . 'cqw;--qrc-oy:' . (int) ($side[$y] ?? 0) . 'cqh;';
$showLogo = !empty($side['logo']);
// A design can CARRY a QR without yet having anything to encode: a platform payment-card template (the
// pay link is stripped as tenant data), or a vendor's card before they paste their link. Drawing nothing
// hid the element entirely, so the author could not see where the code sits or how big it is. Instead the
// slot renders as an OUTLINE at its true size — the same language the printable menu uses.
$qrWanted = !empty($side['qr']);
$showQr = $qrWanted && $qrPath !== '';
$qrOutline = $qrWanted && $qrPath === '';
$tLabel = (string) ($table['label'] ?? '');
$tZone = (string) ($table['zone'] ?? '');
$showTable = !empty($side['showTable']) && ($tLabel !== '' || $tZone !== '');
$footer = mb_substr(trim((string) ($side['footer'] ?? '')), 0, 120);
$powered = !empty($card['poweredBy']);
$hasContent = $hasBg || $showLogo || $product || $showQr || $qrOutline || $footer !== '' || $powered || trim((string) ($side['title'] ?? '')) !== '';
// 0–10 size sliders → the scale ranges the stylesheet expects.
$prodScale = round(0.7 + (max(0, min(10, (int) ($side['productSize'] ?? 5))) / 10) * 1.3, 3); // 0.7–2.0
// QR size uses the printable menu's vocabulary (small | medium | large) so one word means one thing
// across every design surface. Legacy 0-10 slider values are bucketed by QrCard::qrSize().
$qrScale = ['small' => 0.75, 'medium' => 1.1, 'large' => 1.5][\App\Models\QrCard::qrSize($side['qrSize'] ?? null)];
$logoScale = round(0.6 + (max(0, min(10, (int) ($side['logoSize'] ?? 4))) / 10) * 1.6, 3); // 0.6–2.2
$titleScale = round(0.6 + (max(0, min(10, (int) ($side['titleSize'] ?? 6))) / 10) * 1.6, 3); // 0.6–2.2
$title = mb_substr(trim((string) ($side['title'] ?? '')), 0, 40);
$caption = mb_substr(trim((string) ($side['qrCaption'] ?? '')), 0, 60);
// The code's surround and its ink. Both are re-cleaned here rather than trusted, because this partial
// also renders a preview built straight from a GET payload. An ink that misses the contrast floor comes
// back empty, so the code draws in the product's default near-black instead of an unscannable tint.
$qrFrame = in_array($side['qrFrame'] ?? '', \App\Models\QrCard::QR_FRAMES, true) ? (string) $side['qrFrame'] : 'plate';
$qrInk = \App\Models\QrCard::cleanInk((string) ($side['qrInk'] ?? ''));
// Error correction, in the order the budget is spent: a centre logo punches a hole in the code (H), and
// a gradient is at its palest somewhere along the sweep, so buy the redundancy back there too (Q). A
// flat ink has one contrast value everywhere and needs no more than the default M.
$qrEc = !empty($side['qrLogo']) ? 'H' : (str_contains($qrInk, ',') ? 'Q' : 'M');
// A table card has no single code to draw while it is being designed, so the QR renders as an outline
// (see $qrOutline below). Hand the ink's two stops down as vars so that outline can still show which
// colours were chosen — otherwise the ink is invisible on the one surface where it is being picked.
$inkStops = $qrInk !== '' ? array_pad(explode(',', $qrInk), 2, '') : [];
$inkVars = $inkStops ? '--qrc-ink-a:' . e($inkStops[0]) . ';--qrc-ink-b:' . e($inkStops[1] !== '' ? $inkStops[1] : $inkStops[0]) . ';' : '';
/** The restaurant mark as an when it has a logo, else its branded initials monogram. */
$brandMark = static function (string $cls) use ($logo, $__env) {
$src = (string) ($logo['src'] ?? '');
if ($src !== '') {
return '
';
}
return '' . e((string) ($logo['initials'] ?? '')) . '';
};
@endphp