Storefront polish + QR share + importer deactivate fix
Deploy Ladill Merchant / deploy (push) Successful in 35s
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:
co-authored by
Claude Opus 4.8
parent
2fe8babab4
commit
00b1644887
@@ -126,7 +126,14 @@ class ImportLegacyStorefronts extends Command
|
|||||||
|
|
||||||
if ($existing && ! $refresh) {
|
if ($existing && ! $refresh) {
|
||||||
$skipped++;
|
$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.");
|
$this->line(" {$row->short_code}: already exists — skipped.");
|
||||||
|
}
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,13 +50,49 @@
|
|||||||
<img src="{{ $previewDataUri }}" alt="QR code" class="mx-auto h-44 w-44">
|
<img src="{{ $previewDataUri }}" alt="QR code" class="mx-auto h-44 w-44">
|
||||||
@endif
|
@endif
|
||||||
<p class="mt-3 break-all text-xs text-slate-400">{{ $publicUrl }}</p>
|
<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)
|
@foreach(['png' => 'PNG', 'svg' => 'SVG', 'pdf' => 'PDF'] as $fmt => $flabel)
|
||||||
<a href="{{ route('merchant.storefronts.download', [$qrCode, $fmt]) }}"
|
<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>
|
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
|
@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>
|
||||||
</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) }}"
|
<form method="post" action="{{ route('merchant.storefronts.destroy', $qrCode) }}"
|
||||||
onsubmit="return confirm('Delete this storefront? This cannot be undone.');">
|
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">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>{{ $title }}</title>
|
<title>{{ $title }}</title>
|
||||||
@include('partials.favicon')
|
@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 src="https://cdn.tailwindcss.com"></script>
|
||||||
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></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>
|
</head>
|
||||||
<body class="min-h-screen bg-slate-50">
|
<body class="min-h-screen bg-slate-50">
|
||||||
|
|
||||||
|
|||||||
@@ -16,9 +16,11 @@
|
|||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>{{ $title }}</title>
|
<title>{{ $title }}</title>
|
||||||
@include('partials.favicon')
|
@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 src="https://cdn.tailwindcss.com"></script>
|
||||||
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></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>
|
</head>
|
||||||
<body class="min-h-screen bg-slate-50 antialiased">
|
<body class="min-h-screen bg-slate-50 antialiased">
|
||||||
<div x-data="{
|
<div x-data="{
|
||||||
|
|||||||
@@ -22,8 +22,11 @@
|
|||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<title>{{ $title }}</title>
|
<title>{{ $title }}</title>
|
||||||
@include('partials.favicon')
|
@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 src="https://cdn.tailwindcss.com"></script>
|
||||||
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></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>
|
</head>
|
||||||
<body class="bg-slate-50 text-slate-900 antialiased">
|
<body class="bg-slate-50 text-slate-900 antialiased">
|
||||||
<div x-data="storefront({
|
<div x-data="storefront({
|
||||||
@@ -40,7 +43,7 @@
|
|||||||
<div class="relative -mx-4 mb-4 h-36 sm:h-44" style="background:{{ $brand }}">
|
<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
|
@if($coverUrl)<img src="{{ $coverUrl }}" alt="" class="h-full w-full object-cover opacity-90">@endif
|
||||||
</div>
|
</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 }}">
|
<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)
|
@if($logoUrl)
|
||||||
<img src="{{ $logoUrl }}" alt="{{ $title }}" class="h-full w-full object-cover">
|
<img src="{{ $logoUrl }}" alt="{{ $title }}" class="h-full w-full object-cover">
|
||||||
@@ -50,7 +53,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="pb-1">
|
<div class="pb-1">
|
||||||
<h1 class="text-xl font-bold text-slate-900">{{ $title }}</h1>
|
<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>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user