@php /** * A TV menu board, rendered full-screen from a restaurant's live menu. * Standalone document (no site chrome) — this is what a wall screen shows. * * The board is a row of COLUMNS (1–4). Each resolved column is one of: * menu → heading + item list (per-column images / numbers / descriptions) * image → a cover image * video → an uploaded clip or a YouTube embed * feature → hero product card(s) * * @var array $restaurant the restaurant row * @var array $columns resolved columns (see TvController::resolveColumns) * @var array $config board config (orientation/theme/accent/header/footer/spacing/…) * @var string $style the template/preview key (for the title) */ $c = $config; $vertical = ($c['orientation'] ?? 'horizontal') === 'vertical'; $logo = trim((string) ($restaurant['logo'] ?? '')); // A board shows the RESTAURANT's own logo — never the platform mark. A restaurant that has no // logo of its own (or was seeded pointing at the platform file) gets its own branded initials // monogram instead, exactly like restaurant_logo_html() does across the dashboard. if ($logo === '' || $logo === (string) setting('logo', 'assets/admin/logo.png') || $logo === (string) setting('logo_light', 'assets/admin/logo-light.png')) { $logo = ''; } $logoInitials = ''; foreach (preg_split('/\s+/', trim((string) ($restaurant['name'] ?? ''))) ?: [] as $w) { if ($w !== '') { $logoInitials .= mb_strtoupper(mb_substr($w, 0, 1)); } if (mb_strlen($logoInitials) >= 2) { break; } } if ($logoInitials === '') { $logoInitials = mb_strtoupper(mb_substr((string) ($restaurant['name'] ?? 'M'), 0, 1)); } $tagline = trim((string) ($restaurant['tagline'] ?? ($restaurant['description'] ?? ''))); $headerText = trim((string) ($c['headerText'] ?? '')); $footerText = trim((string) ($c['footerText'] ?? '')); $liveDevice = $liveDevice ?? null; // set when a paired TV is displaying this board (self-refresh) $liveVersion = $liveVersion ?? null; $cuisineFlag = $cuisineFlag ?? null; // the cuisine's flag, shown beside the logo when 'showCuisine' is on // Does this board actually play a clip? A decoding video composited over the ambient aurora layer is // what drops frames on a cheap HDMI stick, so the board is marked and tv.css parks the animation. $hasVideo = false; foreach ($columns as $__col) { if (($__col['type'] ?? '') !== 'video') { continue; } $__src = ($__col['provider'] ?? '') === 'youtube' ? (string) ($__col['youtubeId'] ?? '') : (string) ($__col['src'] ?? ''); if ($__src !== '') { $hasVideo = true; break; } } unset($__col, $__src); // A media column with no source (a template, or a not-yet-filled column) shows a labelled placeholder // instead of an empty gap — so a board template reads as complete. Suppressed on a live wall board. $ph = empty($liveDevice); $phBox = static function (string $label): string { $svg = ''; return '
{{ $tagline }}
@endif{{ $it['name'] }}{{ $calOn && $calPos === 'name' ? ' ' . $calTag(' is-inline') : '' }}
@if (!empty($col['descriptions']) && !empty($it['description'])){{ $it['description'] }}
@endif @if ($calOn && $calPos === 'desc'){!! $calTag(' is-block') !!}@endif{{ $it['description'] }}
@endif {{ money($it['price']) }}{{ $p['desc'] }}
@endif @if (!empty($p['showPrice'])){{ money($p['price']) }}@endif