fix(brand): real transparent Meezi icon + guest-menu image placeholder
CI/CD / CI · API (dotnet build + test) (push) Successful in 42s
CI/CD / CI · Admin API (dotnet build) (push) Successful in 29s
CI/CD / CI · Dashboard (tsc) (push) Successful in 1m9s
CI/CD / CI · Admin Web (tsc) (push) Successful in 39s
CI/CD / CI · Website (tsc) (push) Successful in 44s
CI/CD / CI · Koja (tsc) (push) Successful in 50s
CI/CD / Deploy · all services (push) Successful in 3m24s

- Icons/favicon were a plain solid-green square (a 547B placeholder). Replaced
  with the actual Meezi mark (green rounded square + menu lines) on transparent
  corners, generated at 32/48/180/192/512 + a full-bleed green maskable-512.
  Wired 32/48 favicon + 180 apple-touch-icon into the panel and /q metadata.
  Copied the same icons to Koja for consistent branding.
- Guest QR menu showed blank muted boxes for items without a photo. Added a
  minimal themed café-cup placeholder (MenuImageFallback) across all four
  layouts so the menu looks intentional. (Admin/POS already had placeholders.)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
soroush.asadi
2026-06-15 18:17:52 +03:30
parent 456a446850
commit 72ab09189c
12 changed files with 44 additions and 8 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 547 B

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 28 KiB

+4 -2
View File
@@ -23,11 +23,13 @@ export const metadata: Metadata = {
manifest: "/manifest.webmanifest",
icons: {
icon: [
{ url: "/icons/icon-32.png", sizes: "32x32", type: "image/png" },
{ url: "/icons/icon-48.png", sizes: "48x48", type: "image/png" },
{ url: "/icons/icon-192.png", sizes: "192x192", type: "image/png" },
{ url: "/icons/icon-512.png", sizes: "512x512", type: "image/png" },
],
shortcut: "/icons/icon-192.png",
apple: "/icons/icon-192.png",
shortcut: "/icons/icon-32.png",
apple: "/icons/icon-180.png",
},
appleWebApp: {
capable: true,
+7 -1
View File
@@ -9,7 +9,13 @@ export const metadata: Metadata = {
title: "منوی کافه — میزی",
description: "مشاهده منو و ثبت سفارش از میز",
manifest: "/manifest.webmanifest",
icons: { icon: "/icons/icon-192.png", apple: "/icons/icon-192.png" },
icons: {
icon: [
{ url: "/icons/icon-32.png", sizes: "32x32", type: "image/png" },
{ url: "/icons/icon-192.png", sizes: "192x192", type: "image/png" },
],
apple: "/icons/icon-180.png",
},
robots: { index: false, follow: false },
};
@@ -14,6 +14,34 @@ import type { CafeThemePalette } from "@/lib/cafe-theme";
import { hasMenu3dView } from "@/lib/menu-3d";
import { Box } from "lucide-react";
/**
* Minimal placeholder shown when a menu item has no image — a faint café-cup
* glyph on the themed muted surface, so the guest menu looks intentional
* instead of showing blank boxes. `className` controls the box size/shape.
*/
function MenuImageFallback({ className }: { className?: string }) {
return (
<div
className={cn("flex items-center justify-center qr-fill-muted qr-muted", className)}
aria-hidden
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="1.4"
strokeLinecap="round"
strokeLinejoin="round"
className="h-2/5 max-h-7 w-2/5 max-w-7 opacity-40"
>
<path d="M4 8h13v5a4 4 0 0 1-4 4H8a4 4 0 0 1-4-4V8Z" />
<path d="M17 9h2.2a2.5 2.5 0 0 1 0 5H17" />
<path d="M7 3.5v2M11 3.5v2M14 3.5v2" />
</svg>
</div>
);
}
export type QrMenuBodyProps = {
menuStyle: string;
colors: CafeThemePalette;
@@ -377,8 +405,8 @@ function ListItems({
)}
/>
) : (
<div
className={cn("rounded-md qr-fill-muted", compact ? "size-10" : "size-12")}
<MenuImageFallback
className={cn("rounded-md", compact ? "size-10" : "size-12")}
/>
)}
{hasMenu3dView(item) && onView3d ? (
@@ -450,7 +478,7 @@ function MagazineItems({
{img ? (
<img src={img} alt="" className="aspect-[16/9] w-full object-cover" />
) : (
<div className="aspect-[16/9] w-full qr-fill-muted" />
<MenuImageFallback className="aspect-[16/9] w-full" />
)}
{hasMenu3dView(item) && onView3d ? (
<View3dChip
@@ -619,7 +647,7 @@ function ItemRowCard({
{img ? (
<img src={img} alt="" className="size-[4.5rem] rounded-lg object-cover" />
) : (
<div className="size-[4.5rem] rounded-lg qr-fill-muted" />
<MenuImageFallback className="size-[4.5rem] rounded-lg" />
)}
{hasMenu3dView(item) && onView3d ? (
<View3dChip
@@ -694,7 +722,7 @@ function GridCard({
{img ? (
<img src={img} alt="" className="aspect-square w-full object-cover" />
) : (
<div className="aspect-square w-full qr-fill-muted" />
<MenuImageFallback className="aspect-square w-full" />
)}
{hasMenu3dView(item) && onView3d ? (
<View3dChip label={view3dLabel} onClick={() => onView3d(item)} className="absolute bottom-2 start-2" />
Binary file not shown.

Before

Width:  |  Height:  |  Size: 547 B

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 28 KiB