Storefront polish + QR share + importer deactivate fix
Deploy Ladill Merchant / deploy (push) Successful in 35s

- Storefronts use Figtree as the default font (shop/menu, booking, book)
- Remove "Powered by Ladill" branding from the storefront header
- Fix storefront logo hiding behind the cover (logo row now relative z-10)
- Add a Share button to storefront QR downloads using the Web Share API
  (native mobile share sheet for image+link; clipboard fallback)
- storefronts:import-legacy: --deactivate-source now also retires the
  platform copy of already-imported (skipped) codes, no --refresh needed

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
isaacclad
2026-06-10 19:16:48 +00:00
co-authored by Claude Opus 4.8
parent 2fe8babab4
commit 00b1644887
5 changed files with 56 additions and 6 deletions
@@ -126,7 +126,14 @@ class ImportLegacyStorefronts extends Command
if ($existing && ! $refresh) {
$skipped++;
$this->line(" {$row->short_code}: already exists — skipped.");
if ($deactivateSource && ! $dry && $row->is_active) {
$platform->table('qr_codes')->where('id', $row->id)->update(['is_active' => 0]);
$deactivated++;
$this->line(" {$row->short_code}: already exists — skipped (platform copy deactivated).");
} else {
$this->line(" {$row->short_code}: already exists — skipped.");
}
continue;
}
@@ -50,13 +50,49 @@
<img src="{{ $previewDataUri }}" alt="QR code" class="mx-auto h-44 w-44">
@endif
<p class="mt-3 break-all text-xs text-slate-400">{{ $publicUrl }}</p>
<div class="mt-4 flex justify-center gap-2">
<div class="mt-4 flex flex-wrap justify-center gap-2">
@foreach(['png' => 'PNG', 'svg' => 'SVG', 'pdf' => 'PDF'] as $fmt => $flabel)
<a href="{{ route('merchant.storefronts.download', [$qrCode, $fmt]) }}"
class="rounded-lg border border-slate-200 px-3 py-1.5 text-xs font-semibold text-slate-600 hover:bg-slate-50">{{ $flabel }}</a>
@endforeach
<button type="button"
onclick="ladillShareQr(this)"
data-url="{{ $publicUrl }}"
data-title="{{ $qrCode->label }}"
data-png="{{ route('merchant.storefronts.download', [$qrCode, 'png']) }}"
class="inline-flex items-center gap-1.5 rounded-lg border border-slate-200 px-3 py-1.5 text-xs font-semibold text-slate-600 hover:bg-slate-50">
<svg class="h-3.5 w-3.5" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M7.217 10.907a2.25 2.25 0 1 0 0 2.186m0-2.186c.18.324.283.696.283 1.093s-.103.77-.283 1.093m0-2.186 9.566-5.314m-9.566 7.5 9.566 5.314m0 0a2.25 2.25 0 1 0 3.935 2.186 2.25 2.25 0 0 0-3.935-2.186Zm0-12.814a2.25 2.25 0 1 0 3.933-2.185 2.25 2.25 0 0 0-3.933 2.185Z"/></svg>
<span data-label>Share</span>
</button>
</div>
</div>
@once
<script>
window.ladillShareQr = window.ladillShareQr || async function (btn) {
const url = btn.dataset.url;
const title = btn.dataset.title || 'QR code';
const png = btn.dataset.png;
const label = btn.querySelector('[data-label]') || btn;
try {
if (png && navigator.canShare) {
try {
const blob = await (await fetch(png)).blob();
const file = new File([blob], 'qr-code.png', { type: blob.type || 'image/png' });
if (navigator.canShare({ files: [file] })) {
await navigator.share({ files: [file], title, text: url });
return;
}
} catch (e) { /* fall through */ }
}
if (navigator.share) { await navigator.share({ title, text: title, url }); return; }
await navigator.clipboard.writeText(url);
const original = label.textContent;
label.textContent = 'Link copied';
setTimeout(() => { label.textContent = original; }, 1500);
} catch (e) { /* user cancelled */ }
};
</script>
@endonce
<form method="post" action="{{ route('merchant.storefronts.destroy', $qrCode) }}"
onsubmit="return confirm('Delete this storefront? This cannot be undone.');">
@@ -16,9 +16,11 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ $title }}</title>
@include('partials.favicon')
<link rel="preconnect" href="https://fonts.bunny.net">
<link href="https://fonts.bunny.net/css?family=figtree:400,500,600,700&display=swap" rel="stylesheet">
<script src="https://cdn.tailwindcss.com"></script>
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>
<style>[x-cloak] { display: none !important; }</style>
<style>[x-cloak] { display: none !important; } body { font-family: 'Figtree', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif; }</style>
</head>
<body class="min-h-screen bg-slate-50">
@@ -16,9 +16,11 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ $title }}</title>
@include('partials.favicon')
<link rel="preconnect" href="https://fonts.bunny.net">
<link href="https://fonts.bunny.net/css?family=figtree:400,500,600,700&display=swap" rel="stylesheet">
<script src="https://cdn.tailwindcss.com"></script>
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>
<style>[x-cloak] { display: none !important; }</style>
<style>[x-cloak] { display: none !important; } body { font-family: 'Figtree', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif; }</style>
</head>
<body class="min-h-screen bg-slate-50 antialiased">
<div x-data="{
@@ -22,8 +22,11 @@
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{{ $title }}</title>
@include('partials.favicon')
<link rel="preconnect" href="https://fonts.bunny.net">
<link href="https://fonts.bunny.net/css?family=figtree:400,500,600,700&display=swap" rel="stylesheet">
<script src="https://cdn.tailwindcss.com"></script>
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>
<style>body{font-family:'Figtree',ui-sans-serif,system-ui,-apple-system,'Segoe UI',Roboto,Helvetica,Arial,sans-serif}</style>
</head>
<body class="bg-slate-50 text-slate-900 antialiased">
<div x-data="storefront({
@@ -40,7 +43,7 @@
<div class="relative -mx-4 mb-4 h-36 sm:h-44" style="background:{{ $brand }}">
@if($coverUrl)<img src="{{ $coverUrl }}" alt="" class="h-full w-full object-cover opacity-90">@endif
</div>
<div class="-mt-12 flex items-end gap-4 px-1">
<div class="relative z-10 -mt-12 flex items-end gap-4 px-1">
<div class="flex h-20 w-20 shrink-0 items-center justify-center overflow-hidden rounded-2xl bg-white shadow-md ring-4 ring-white" style="color:{{ $brand }}">
@if($logoUrl)
<img src="{{ $logoUrl }}" alt="{{ $title }}" class="h-full w-full object-cover">
@@ -50,7 +53,7 @@
</div>
<div class="pb-1">
<h1 class="text-xl font-bold text-slate-900">{{ $title }}</h1>
<p class="text-xs text-slate-500">{{ $isShop ? 'Shop' : 'Menu' }} · Powered by Ladill</p>
<p class="text-xs text-slate-500">{{ $isShop ? 'Shop' : 'Menu' }}</p>
</div>
</div>