@extends('layouts.dashboard') @section('content') @php /** * "Start from a template" gallery: the platform's active starter designs for one surface as live preview * thumbnails (rendered against the vendor's OWN data via $previewBase), plus a "Start blank" card. * Picking one POSTs its id to $applyUrl, which copies it into a new editable instance the vendor owns. * * The PRINT-MENU gallery mirrors the admin gallery: a double-sided card shows the FRONT and flips (in 3D, * on hover) to the BACK — NOT both sides side by side — and Style + Folds dropdowns narrow the grid. It * lays out three per row. Other surfaces keep their single-thumbnail card. * * @var array $templates design_templates rows (id, name, type, config) * @var string $previewBase URL that renders a config -> a thumbnail (?config=... appended) * @var string $applyUrl POST template_id here to copy + open * @var string $blankUrl start from a blank design * @var string $backUrl @var string $heading @var string $subtitle @var string $previewAspect */ $templates = $templates ?? []; $previewBase = (string) ($previewBase ?? ''); $applyUrl = (string) ($applyUrl ?? ''); $blankUrl = (string) ($blankUrl ?? ''); $aspect = (string) ($previewAspect ?? '4 / 3'); /* PER-CARD SHAPE IS OPT-IN, and only one surface wants it. Giving every card its own aspect sounds right and looks wrong: a grid row is as tall as its tallest card, so one vertical board among widescreen ones — or one portrait sheet among landscape ones — leaves a band of white inside every other card on that row. The QR surfaces ask for it because a landscape card there is a genuinely different product from a portrait one and must read as such; boards and printable menus keep ONE frame per surface and letterbox inside it, which is how they looked before and why they looked even. */ $aspectPerCard = !empty($aspectPerCard); $aspectWide = (string) ($aspectWide ?? $aspect); $aspectTall = (string) ($aspectTall ?? $aspect); // Columns are the caller's call too: three is the default that boards and sheets are laid out for. $tplCols = (int) ($previewCols ?? 3); $tplCols = $tplCols >= 2 && $tplCols <= 4 ? $tplCols : 3; // collect()->first(), not reset(): reset() on a Collection hands back its internal // items array, so $first['type'] was '' and the print gallery silently lost its // Style/Folds filters and its double-sided flip cards. $first = collect($templates)->first(); $isPrint = $first && (($first['type'] ?? '') === 'print_menu'); // Build the card list once: preview src + (print) the two filter axes + the double-sided flag. The style // label is just the template name's prefix ("Fine Dining · Single Page" -> "Fine Dining"), so that filter // needs no config parsing; the fold count comes from the config, since it is what the sheet physically is. $cards = []; $styles = []; $folds = []; foreach ($templates as $tpl) { $double = false; $fold = 0; $cfg = \App\Models\DesignTemplate::config($tpl); // One frame per surface unless the caller opted into per-card shapes (see above). $cardAspect = $aspect; if ($aspectPerCard) { $orient = (string) ($cfg['orientation'] ?? ''); $cardAspect = in_array($orient, ['portrait', 'vertical'], true) ? $aspectTall : $aspectWide; } if (isset($tpl['_preview'])) { $src = (string) $tpl['_preview']; } else { if ($isPrint) { // Keep each template's showcase scope so the card is a CLEAN style preview of the vendor's own // menu (a curated volume), not a crammed dump; applying resets the cap so the real menu is whole. $double = !empty($cfg['doubleSided']); $fold = max(1, min(5, (int) ($cfg['fold'] ?? 1))); } $src = $previewBase . '?config=' . rawurlencode((string) json_encode($cfg, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE)); } $label = trim((string) ($tpl['name'] ?? '')); $style = $isPrint ? trim(explode(' · ', $label)[0] ?? '') : ''; $slug = $style !== '' ? preg_replace('/[^a-z0-9]+/', '-', strtolower($style)) : ''; if ($slug !== '') { $styles[$slug] = $style; } if ($fold > 0) { $folds[$fold] = $fold; } $cards[] = ['id' => (int) ($tpl['id'] ?? 0), 'name' => $label, 'src' => $src, 'double' => $double, 'slug' => $slug, 'fold' => $fold, 'aspect' => $cardAspect]; } ksort($styles); ksort($folds); /* THE FILTERS NARROW THE LIBRARY, NOT THE PAGE — so they have to run BEFORE the slice below. Both axes are built from every template (the loop above), so the dropdowns offer the whole library; the grid, however, is paginated nine at a time. Hiding cards in the DOM could therefore never reveal a match that sits on page 2 — "Ocean Navy" showed 1 of its 5, and picking fold 2, an option the page itself offers, emptied the gallery while four two-fold sheets existed. Filtering here instead means the grid, the "showing X of Y" count and the pager all describe the same set, and pagination.php already carries these parameters through its page links. Anything not on the offered axes falls back to "all", so a hand-typed value can only ever widen. */ $fStyle = trim((string) (is_scalar($st = request()->query('style')) ? $st : '')); $fFold = (int) request()->query('fold', 0); if (!isset($styles[$fStyle])) { $fStyle = ''; } if (!isset($folds[$fFold])) { $fFold = 0; } if ($fStyle !== '' || $fFold > 0) { $cards = array_values(array_filter( $cards, static fn ($c) => ($fStyle === '' || $c['slug'] === $fStyle) && ($fFold === 0 || $c['fold'] === $fFold) )); } @endphp
{{ $subtitle ?? '' }}