feat(mobile): integrate QrTemplate9 Vintage Table Menu with 9.jpeg background and live editing

This commit is contained in:
AyrisAI
2026-08-21 01:19:04 +03:00
parent 102a9a744b
commit d00b45ce72
6 changed files with 528 additions and 1 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 516 KiB

@@ -0,0 +1,278 @@
import * as React from "react";
import Svg, {
Defs,
G,
Path,
Circle,
Rect,
Text,
TextPath,
Image,
} from "react-native-svg";
import { type QrTemplateProps, getFontFamily, renderSvgLines } from "./index";
// eslint-disable-next-line @typescript-eslint/no-var-requires
const template9Bg = require("../../../assets/templates/9.jpeg");
const QrTemplate9 = ({
qrBase64,
fields,
...props
}: QrTemplateProps) => {
const rName = fields?.restaurantName;
const sub = fields?.subtitle;
const table = fields?.tableNo;
const cta = fields?.ctaText;
const wifi = fields?.wifiText;
const social = fields?.socialText;
const rNameFont = getFontFamily(rName?.fontId, "System, -apple-system, Roboto, sans-serif");
const subFont = getFontFamily(sub?.fontId, "System, -apple-system, Roboto, sans-serif");
const ctaFont = getFontFamily(cta?.fontId, "System, -apple-system, Roboto, sans-serif");
const infoFont = getFontFamily(wifi?.fontId, "System, -apple-system, Roboto, sans-serif");
return (
<Svg width={300} height={300} viewBox="0 0 1024 1024" {...props}>
<Defs>
<Path id="arcTop9" fill="none" d="M330 260q182-115 364 0" />
</Defs>
<Path fill="#f8f6f0" d="M0 0h1024v1024H0z" />
<Image
width={1024}
height={1024}
href={template9Bg}
preserveAspectRatio="none"
/>
{/* QR Alanı (Merkez) */}
<G transform="translate(362 428)">
<Rect
width={300}
height={300}
fill="#fff"
stroke="#d5cebe"
strokeWidth={1.5}
rx={24}
/>
<Rect
width={276}
height={276}
x={12}
y={12}
fill="#fafaf7"
stroke="#1e3246"
strokeDasharray="6 4"
strokeOpacity={0.35}
strokeWidth={1.5}
rx={16}
/>
{qrBase64 ? (
<Image
href={`data:image/png;base64,${qrBase64}`}
x={16}
y={16}
width={268}
height={268}
/>
) : (
<>
<Circle
cx={150}
cy={132}
r={28}
fill="#f5efe6"
stroke="#1e3246"
strokeWidth={1.5}
/>
<Path
fill="none"
stroke="#1e3246"
strokeLinecap="round"
strokeWidth={1.9}
d="M142.4 116.8v11.4c0 3.8 5.7 3.8 5.7 0v-11.4m-2.85 0v11.4m0 3.8v15.2m9.5-30.4c4.75 3.8 4.75 15.2 0 17.1v13.3"
/>
<Text
x={150}
y={192}
fill="#1e3246"
fontFamily="System, -apple-system, Roboto, sans-serif"
fontSize={14}
fontWeight={800}
letterSpacing={2}
textAnchor="middle"
>
{"QR KOD ALANI"}
</Text>
</>
)}
</G>
{/* Üst Amblem & Rozet */}
<G stroke="#a88b58" transform="translate(290 142)">
<Circle cx={-16} cy={-8} r={4.5} fill="none" strokeWidth={1.5} />
<Path strokeLinecap="round" strokeWidth={1.5} d="M-16-12v8m-4-4h8" />
<Path
fill="none"
strokeLinecap="round"
strokeWidth={1.5}
d="M0-12c4 0 8 6 8 12S4 12 0 12"
/>
<Path
fill="none"
strokeLinecap="round"
strokeWidth={1.2}
d="M-32 20c12 8 52 8 64 0"
/>
</G>
{/* Masa Numarası / Rozet Metni */}
{table?.visible !== false &&
renderSvgLines({
text: table?.text || "TABLE MENU\nEST. 2026",
x: 290,
y: 164,
offsetY: table?.offsetY,
fill: "#1e3246",
fontFamily: infoFont,
fontSize: table?.fontSize ? table.fontSize * 1.3 : 15,
fontWeight: 900,
letterSpacing: 1,
lineHeight: 18,
})}
{/* Sol / Sağ Yönelticiler (SIAT / VIEW) */}
<Text
x={364}
y={248}
fill="#1e3246"
fontFamily="System, -apple-system, Roboto, sans-serif"
fontSize={23}
fontWeight={900}
letterSpacing={1}
textAnchor="middle"
transform="rotate(-26 364 248)"
>
{"SCAN"}
</Text>
<Text
x={670}
y={244}
fill="#1e3246"
fontFamily="System, -apple-system, Roboto, sans-serif"
fontSize={25}
fontWeight={900}
letterSpacing={1}
textAnchor="middle"
transform="rotate(24 670 244)"
>
{"VIEW"}
</Text>
{/* Kavisli Üst Yazı */}
{sub?.visible !== false && (
<Text
fill="#1e3246"
fontFamily={subFont}
fontSize={sub?.fontSize ? sub.fontSize * 1.8 : 46}
fontWeight={900}
letterSpacing={2}
>
<TextPath href="#arcTop9" startOffset="50%" textAnchor="middle">
{sub?.text || "DIGITAL MENU"}
</TextPath>
</Text>
)}
{/* Restoran Başlığı / Ana Başlık */}
{rName?.visible !== false &&
renderSvgLines({
text: rName?.text || "OUR MENU",
x: 512,
y: 326,
offsetY: rName?.offsetY,
fill: "#1e3246",
fontFamily: rNameFont,
fontSize: rName?.fontSize ? rName.fontSize * 2.4 : 76,
fontWeight: 900,
letterSpacing: 3,
})}
{/* Yönlendirici Oklar */}
<G stroke="#1e3246">
<Path
fill="none"
strokeLinecap="round"
strokeWidth={3}
d="M390 780c-16-8-16-26-8-36"
/>
<Path
fill="#1e3246"
strokeLinejoin="round"
strokeWidth={1.5}
d="m374 750 8-6 6 8Z"
/>
</G>
<G stroke="#1e3246">
<Path
fill="none"
strokeLinecap="round"
strokeWidth={3}
d="M634 780c16-8 16-26 8-36"
/>
<Path
fill="#1e3246"
strokeLinejoin="round"
strokeWidth={1.5}
d="m650 750-8-6-6 8Z"
/>
</G>
{/* CTA Metni */}
{cta?.visible !== false &&
renderSvgLines({
text: cta?.text || "VIEW OUR\nDELICIOUS MENU",
x: 512,
y: 752,
offsetY: cta?.offsetY,
fill: "#1e3246",
fontFamily: ctaFont,
fontSize: cta?.fontSize ? cta.fontSize * 1.6 : 20,
fontWeight: 900,
letterSpacing: 1,
lineHeight: 28,
})}
{/* Alt Bilgi / Karşılama & WiFi */}
{wifi?.visible !== false &&
renderSvgLines({
text: wifi?.text || "WELCOME TO OUR TABLE",
x: 500,
y: 894,
offsetY: wifi?.offsetY,
fill: "#1e3246",
fontFamily: infoFont,
fontSize: wifi?.fontSize ? wifi.fontSize * 1.5 : 18,
fontWeight: 900,
letterSpacing: 1.5,
})}
{/* Sosyal Medya */}
{social?.visible !== false &&
renderSvgLines({
text: social?.text || "@menulio.table",
x: 500,
y: 934,
offsetY: social?.offsetY,
fill: "#a88b58",
fontFamily: infoFont,
fontSize: social?.fontSize ? social.fontSize * 1.5 : 16,
fontWeight: 700,
letterSpacing: 1,
})}
</Svg>
);
};
export default QrTemplate9;
@@ -7,9 +7,9 @@ import QrTemplate4 from "./QrTemplate4";
import QrTemplate5 from "./QrTemplate5";
import QrTemplate6 from "./QrTemplate6";
import QrTemplate8 from "./QrTemplate8";
import QrTemplate9 from "./QrTemplate9";
export interface TextItemConfig {
text: string;
fontSize?: number;
fontId?: string;
@@ -130,6 +130,7 @@ export const COMPONENT_TEMPLATES: Record<
"qr-5": QrTemplate5,
"qr-6": QrTemplate6,
"qr-8": QrTemplate8,
"qr-9": QrTemplate9,
};
// Her template'in aspect ratio'su (width/height)
@@ -141,5 +142,7 @@ export const TEMPLATE_ASPECT_RATIOS: Record<string, number> = {
"qr-5": 380 / 500, // 380x500 = PNG arka planlı modern kart
"qr-6": 400 / 580, // 400x580 = taş & ızgara vintage stant
"qr-8": 1, // 1024x1024 = 1:1 Emerald Gold Özel Tasarım
"qr-9": 1, // 1024x1024 = 1:1 Vintage Table Menu Özel Tasarım
};
Binary file not shown.

After

Width:  |  Height:  |  Size: 516 KiB

+231
View File
@@ -0,0 +1,231 @@
import Svg, {
SvgProps,
Defs,
Path,
Image,
G,
Rect,
Circle,
Text,
TextPath,
} from "react-native-svg"
import { memo } from "react"
const SvgComponent = (props: SvgProps) => (
<Svg width={1024} height={1024} {...props}>
<Defs>
<Path id="a" fill="none" d="M330 260q182-115 364 0" />
</Defs>
<Path fill="#f8f6f0" d="M0 0h1024v1024H0z" />
<Image
width={1024}
height={1024}
href="xx.png"
preserveAspectRatio="none"
/>
<G transform="translate(362 428)">
<Rect
width={300}
height={300}
fill="#fff"
stroke="#d5cebe"
strokeWidth={1.5}
rx={24}
/>
<Rect
width={276}
height={276}
x={12}
y={12}
fill="#fafaf7"
stroke="#1e3246"
strokeDasharray="6 4"
strokeOpacity={0.35}
strokeWidth={1.5}
rx={16}
/>
<Circle
cx={150}
cy={132}
r={28}
fill="#f5efe6"
stroke="#1e3246"
strokeWidth={1.5}
/>
<Path
fill="none"
stroke="#1e3246"
strokeLinecap="round"
strokeWidth={1.9}
d="M142.4 116.8v11.4c0 3.8 5.7 3.8 5.7 0v-11.4m-2.85 0v11.4m0 3.8v15.2m9.5-30.4c4.75 3.8 4.75 15.2 0 17.1v13.3"
/>
<Text
x={150}
y={192}
fill="#1e3246"
fontFamily="Inter, Arial, sans-serif"
fontSize={14}
fontWeight={800}
letterSpacing={2}
textAnchor="middle"
>
{"QR KOD ALANI"}
</Text>
</G>
<G stroke="#a88b58" transform="translate(290 142)">
<Circle cx={-16} cy={-8} r={4.5} fill="none" strokeWidth={1.5} />
<Path strokeLinecap="round" strokeWidth={1.5} d="M-16-12v8m-4-4h8" />
<Path
fill="none"
strokeLinecap="round"
strokeWidth={1.5}
d="M0-12c4 0 8 6 8 12S4 12 0 12"
/>
<Path
fill="none"
strokeLinecap="round"
strokeWidth={1.2}
d="M-32 20c12 8 52 8 64 0"
/>
</G>
<G stroke="#1e3246">
<Path
fill="none"
strokeLinecap="round"
strokeWidth={3}
d="M390 780c-16-8-16-26-8-36"
/>
<Path
fill="#1e3246"
strokeLinejoin="round"
strokeWidth={1.5}
d="m374 750 8-6 6 8Z"
/>
</G>
<G stroke="#1e3246">
<Path
fill="none"
strokeLinecap="round"
strokeWidth={3}
d="M634 780c16-8 16-26 8-36"
/>
<Path
fill="#1e3246"
strokeLinejoin="round"
strokeWidth={1.5}
d="m650 750-8-6-6 8Z"
/>
</G>
<Text
x={290}
y={164}
fill="#1e3246"
fontFamily="'Arial Black', 'Impact', sans-serif"
fontSize={16}
fontWeight={900}
letterSpacing={1}
textAnchor="middle"
>
{"TABLE MENU"}
</Text>
<Text
x={290}
y={180}
fill="#8c7348"
fontFamily="Georgia, serif"
fontSize={9}
fontStyle="italic"
fontWeight={700}
letterSpacing={1}
textAnchor="middle"
>
{"EST. 2023"}
</Text>
<Text
x={364}
y={248}
fill="#1e3246"
fontFamily="'Arial Black', 'Impact', sans-serif"
fontSize={23}
fontWeight={900}
letterSpacing={1}
textAnchor="middle"
transform="rotate(-26 364 248)"
>
{"SIAT"}
</Text>
<Text
fill="#1e3246"
fontFamily="'Arial Black', 'Impact', sans-serif"
fontSize={52}
fontWeight={900}
letterSpacing={2}
>
<TextPath href="#a" startOffset="50%" textAnchor="middle">
{"\n SCAN TO\n "}
</TextPath>
</Text>
<Text
x={670}
y={244}
fill="#1e3246"
fontFamily="'Arial Black', 'Impact', sans-serif"
fontSize={25}
fontWeight={900}
letterSpacing={1}
textAnchor="middle"
transform="rotate(24 670 244)"
>
{"VIEW"}
</Text>
<Text
x={512}
y={320}
fill="#1e3246"
fontFamily="'Arial Black', 'Impact', sans-serif"
fontSize={82}
fontWeight={900}
letterSpacing={3}
textAnchor="middle"
>
{"OUR MENU"}
</Text>
<Text
x={512}
y={748}
fill="#1e3246"
fontFamily="'Arial Black', sans-serif"
fontSize={18.5}
fontWeight={900}
letterSpacing={1}
textAnchor="middle"
>
{"VIEW OUR"}
</Text>
<Text
x={512}
y={774}
fill="#1e3246"
fontFamily="'Arial Black', sans-serif"
fontSize={18.5}
fontWeight={900}
letterSpacing={1}
textAnchor="middle"
>
{"DELICIOUS MENU"}
</Text>
<Text
x={500}
y={894}
fill="#1e3246"
fontFamily="'Arial Black', 'Montserrat', sans-serif"
fontSize={18}
fontWeight={900}
letterSpacing={1.5}
textAnchor="middle"
>
{"WELCOME TO OUR TABLE"}
</Text>
</Svg>
)
const Memo = memo(SvgComponent)
export default Memo