feat(mobile): add multiline text with Enter, per-text independent font selection and font size controls

This commit is contained in:
AyrisAI
2026-08-21 00:55:44 +03:00
parent b72846bd91
commit 2530ab4005
8 changed files with 1522 additions and 1608 deletions
+241 -288
View File
@@ -23,7 +23,8 @@ import {
COMPONENT_TEMPLATES,
TEMPLATE_ASPECT_RATIOS,
FONT_OPTIONS,
type QrCustomTextConfig,
type QrCustomFields,
type TextItemConfig,
} from "@/components/qr-templates";
@@ -45,24 +46,49 @@ export default function QrScreen() {
(p) => !!COMPONENT_TEMPLATES[p.key]
);
const [selectedKey, setSelectedKey] = useState<string>(
availablePresets[0]?.key || "qr-lumiere"
availablePresets[0]?.key || "qr-1"
);
const [exportingPng, setExportingPng] = useState(false);
const [exportingPdf, setExportingPdf] = useState(false);
const [showCustomizePanel, setShowCustomizePanel] = useState(false);
const [selectedFontId, setSelectedFontId] = useState<string>("didot");
const [customText, setCustomText] = useState<QrCustomTextConfig>({
restaurantName: "Gourmet Bistro",
subtitle: "RESTAURANT & BAR | MODERN CUISINE",
tableNo: "MASA NO: 01",
ctaText: "MENÜYÜ GÖRMEK İÇİN OKUTUN",
wifiText: "WiFi: Gourmet_Guest | Şifre: lezzetli01",
socialText: "@gourmetbistro",
showTableNo: true,
showSubtitle: true,
showCta: true,
showWifi: true,
showSocial: true,
const [fields, setFields] = useState<QrCustomFields>({
restaurantName: {
text: "Gourmet Bistro",
fontSize: 26,
fontId: "serif",
visible: true,
},
subtitle: {
text: "RESTAURANT & BAR\nMODERN CUISINE",
fontSize: 11,
fontId: "sans",
visible: true,
},
tableNo: {
text: "MASA NO: 01",
fontSize: 11,
fontId: "sans",
visible: true,
},
ctaText: {
text: "MENÜYÜ GÖRMEK İÇİN OKUTUN",
fontSize: 13,
fontId: "serif",
visible: true,
},
wifiText: {
text: "WiFi: Gourmet_Guest | Şifre: lezzetli01",
fontSize: 10,
fontId: "sans",
visible: true,
},
socialText: {
text: "@gourmetbistro",
fontSize: 10,
fontId: "sans",
visible: true,
},
});
// eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -71,10 +97,6 @@ export default function QrScreen() {
const activePreset: QrStandPreset =
QR_STAND_PRESETS[selectedKey] || availablePresets[0] || Object.values(QR_STAND_PRESETS)[0]!;
const activeFont =
FONT_OPTIONS.find((f) => f.id === selectedFontId)?.fontFamily ||
"'Playfair Display', Georgia, serif";
// Component-based template sistemi
const TemplateComponent =
COMPONENT_TEMPLATES[selectedKey] ?? Object.values(COMPONENT_TEMPLATES)[0];
@@ -84,6 +106,7 @@ export default function QrScreen() {
useEffect(() => {
(async () => {
const activeRest = await getActiveRestaurant();
@@ -99,9 +122,12 @@ export default function QrScreen() {
const restDetail = await api.get<{ name?: string }>(`/restaurants/${activeRest.restaurantId}`);
if (restDetail?.name) {
setRestaurantName(restDetail.name);
setCustomText((prev) => ({
setFields((prev) => ({
...prev,
restaurantName: restDetail.name,
restaurantName: {
...prev.restaurantName,
text: restDetail.name || "Gourmet Bistro",
},
}));
}
} catch {
@@ -116,6 +142,7 @@ export default function QrScreen() {
}, []);
async function handleCopy() {
if (!qr?.targetUrl) return;
await Clipboard.setStringAsync(qr.targetUrl);
@@ -355,25 +382,14 @@ export default function QrScreen() {
qrBase64={qr.pngBase64}
width={displayWidth}
height={displayHeight}
restaurantName={customText.restaurantName}
subtitle={customText.subtitle}
tableNo={customText.tableNo}
ctaText={customText.ctaText}
wifiText={customText.wifiText}
socialText={customText.socialText}
fontFamily={activeFont}
showTableNo={customText.showTableNo}
showSubtitle={customText.showSubtitle}
showCta={customText.showCta}
showWifi={customText.showWifi}
showSocial={customText.showSocial}
fields={fields}
/>
) : null}
</View>
</ViewShot>
</View>
{/* Metin & Font Özelleştirme Kartı (Açılır/Kapanır) */}
{/* Metin & Font & Boyut Özelleştirme Kartı (Açılır/Kapanır) */}
<View
style={{
backgroundColor: "#18181B",
@@ -395,22 +411,22 @@ export default function QrScreen() {
<View style={{ flexDirection: "row", alignItems: "center", gap: 10 }}>
<View
style={{
width: 32,
height: 32,
borderRadius: 8,
width: 34,
height: 34,
borderRadius: 10,
backgroundColor: "rgba(212, 175, 55, 0.15)",
alignItems: "center",
justifyContent: "center",
}}
>
<Ionicons name="text-outline" size={18} color="#D4AF37" />
<Ionicons name="text-outline" size={19} color="#D4AF37" />
</View>
<View>
<Text style={{ color: "#FFFFFF", fontSize: 15, fontWeight: "700" }}>
Metin ve Yazı Tipi Özelleştir
Metin, Font & Boyut Özelleştir
</Text>
<Text style={{ color: "#A1A1AA", fontSize: 12 }}>
İstediğiniz alanları düzenleyin veya kaldırın
Çok satırlı metin (Enter), özel font ve boyut ayarı
</Text>
</View>
</View>
@@ -423,264 +439,201 @@ export default function QrScreen() {
{showCustomizePanel && (
<View style={{ marginTop: 16, gap: 16, borderTopWidth: 1, borderTopColor: "rgba(255,255,255,0.06)", paddingTop: 16 }}>
{/* Yazı Tipi (Font) Seçici */}
<View>
<Text style={{ color: "#D4AF37", fontSize: 12, fontWeight: "700", marginBottom: 8, letterSpacing: 0.5 }}>
YAZI TİPİ (FONT)
{/* Yardımcı Açıklama */}
<View
style={{
backgroundColor: "rgba(212, 175, 55, 0.08)",
borderRadius: 10,
padding: 10,
flexDirection: "row",
alignItems: "center",
gap: 8,
}}
>
<Ionicons name="information-circle-outline" size={16} color="#D4AF37" />
<Text style={{ color: "#E5C378", fontSize: 11.5, flex: 1 }}>
İpucu: Uzun metinlerde alt satıra geçmek için klavyeden Enter&apos;a basabilirsiniz.
</Text>
<ScrollView horizontal showsHorizontalScrollIndicator={false} contentContainerStyle={{ gap: 8 }}>
{FONT_OPTIONS.map((f) => {
const isSelected = f.id === selectedFontId;
return (
<Pressable
key={f.id}
onPress={() => setSelectedFontId(f.id)}
style={{
backgroundColor: isSelected ? "#D4AF37" : "#242429",
paddingHorizontal: 14,
paddingVertical: 8,
borderRadius: 10,
borderWidth: 1,
borderColor: isSelected ? "#D4AF37" : "rgba(255,255,255,0.08)",
}}
>
<Text
style={{
color: isSelected ? "#0C0C0E" : "#FFFFFF",
fontSize: 12,
fontWeight: isSelected ? "700" : "500",
}}
>
{f.label}
</View>
{/* Alan Düzenleyicileri */}
{(
[
{ key: "restaurantName", label: "RESTORAN BAŞLIĞI", placeholder: "Restoran Adı", min: 14, max: 48 },
{ key: "subtitle", label: "SLOGAN / ALT BAŞLIK", placeholder: "Slogan (Enter ile alt satıra geçebilir)", min: 8, max: 24 },
{ key: "ctaText", label: "YÖNLENDİRME (CTA) METNİ", placeholder: "Yönlendirme Metni", min: 9, max: 28 },
{ key: "tableNo", label: "MASA NUMARASI", placeholder: "Örn: MASA NO: 01", min: 8, max: 22 },
{ key: "wifiText", label: "WIFI BİLGİSİ", placeholder: "Örn: WiFi: Bistro | Şifre: 12345", min: 7, max: 20 },
{ key: "socialText", label: "SOSYAL MEDYA / İLETİŞİM", placeholder: "Örn: @menulio", min: 7, max: 20 },
] as const
).map(({ key, label, placeholder, min, max }) => {
const item = fields[key];
return (
<View
key={key}
style={{
gap: 8,
paddingBottom: 12,
borderBottomWidth: 1,
borderBottomColor: "rgba(255,255,255,0.06)",
}}
>
{/* Başlık ve Görünürlük Anahtarı */}
<View style={{ flexDirection: "row", justifyContent: "space-between", alignItems: "center" }}>
<Text style={{ color: "#D4AF37", fontSize: 12, fontWeight: "700" }}>{label}</Text>
<View style={{ flexDirection: "row", alignItems: "center", gap: 8 }}>
<Text style={{ color: item.visible ? "#10B981" : "#71717A", fontSize: 11, fontWeight: "600" }}>
{item.visible ? "Açık" : "Gizli"}
</Text>
</Pressable>
);
})}
</ScrollView>
</View>
<Switch
value={item.visible}
onValueChange={(v) =>
setFields((prev) => ({
...prev,
[key]: { ...prev[key], visible: v },
}))
}
trackColor={{ false: "#27272A", true: "#D4AF37" }}
thumbColor="#FFFFFF"
ios_backgroundColor="#27272A"
/>
</View>
</View>
{/* Alan 1: Restoran Başlığı */}
<View style={{ gap: 6 }}>
<Text style={{ color: "#D4AF37", fontSize: 12, fontWeight: "700" }}>
RESTORAN BAŞLIĞI
</Text>
<TextInput
value={customText.restaurantName}
onChangeText={(t) => setCustomText((p) => ({ ...p, restaurantName: t }))}
placeholder="Restoran Adı"
placeholderTextColor="#71717A"
style={{
backgroundColor: "#121215",
borderWidth: 1,
borderColor: "rgba(255,255,255,0.1)",
borderRadius: 12,
paddingHorizontal: 14,
paddingVertical: 10,
color: "#FFFFFF",
fontSize: 14,
}}
/>
</View>
{item.visible && (
<>
{/* Çok Satırlı TextInput */}
<TextInput
value={item.text}
onChangeText={(t) =>
setFields((prev) => ({
...prev,
[key]: { ...prev[key], text: t },
}))
}
placeholder={placeholder}
placeholderTextColor="#71717A"
multiline
style={{
backgroundColor: "#121215",
borderWidth: 1,
borderColor: "rgba(255,255,255,0.1)",
borderRadius: 12,
paddingHorizontal: 12,
paddingVertical: 8,
color: "#FFFFFF",
fontSize: 13,
minHeight: 42,
}}
/>
{/* Alan 2: Slogan / Alt Başlık */}
<View style={{ gap: 6 }}>
<View style={{ flexDirection: "row", justifyContent: "space-between", alignItems: "center" }}>
<Text style={{ color: "#D4AF37", fontSize: 12, fontWeight: "700" }}>
SLOGAN / ALT BAŞLIK
</Text>
<View style={{ flexDirection: "row", alignItems: "center", gap: 6 }}>
<Text style={{ color: "#71717A", fontSize: 11 }}>
{customText.showSubtitle ? "Göster" : "Gizle"}
</Text>
<Switch
value={customText.showSubtitle}
onValueChange={(v) => setCustomText((p) => ({ ...p, showSubtitle: v }))}
trackColor={{ false: "#27272A", true: "#D4AF37" }}
thumbColor="#FFFFFF"
ios_backgroundColor="#27272A"
/>
{/* Font ve Boyut Kontrol Çubuğu */}
<View style={{ flexDirection: "row", alignItems: "center", justifyContent: "space-between", gap: 8 }}>
{/* Font Hapları */}
<ScrollView
horizontal
showsHorizontalScrollIndicator={false}
contentContainerStyle={{ gap: 6 }}
style={{ flex: 1 }}
>
{FONT_OPTIONS.map((f) => {
const isSelected = item.fontId === f.id;
return (
<Pressable
key={f.id}
onPress={() =>
setFields((prev) => ({
...prev,
[key]: { ...prev[key], fontId: f.id },
}))
}
style={{
backgroundColor: isSelected ? "#D4AF37" : "#242429",
paddingHorizontal: 9,
paddingVertical: 5,
borderRadius: 8,
borderWidth: 1,
borderColor: isSelected ? "#D4AF37" : "rgba(255,255,255,0.06)",
}}
>
<Text
style={{
color: isSelected ? "#0C0C0E" : "#D4D4D8",
fontSize: 10.5,
fontWeight: isSelected ? "700" : "500",
}}
>
{f.label}
</Text>
</Pressable>
);
})}
</ScrollView>
{/* Boyut Artır / Azalt */}
<View
style={{
flexDirection: "row",
alignItems: "center",
backgroundColor: "#242429",
borderRadius: 8,
paddingHorizontal: 4,
borderWidth: 1,
borderColor: "rgba(255,255,255,0.06)",
}}
>
<Pressable
onPress={() =>
setFields((prev) => ({
...prev,
[key]: {
...prev[key],
fontSize: Math.max(min, (prev[key].fontSize || 12) - 1),
},
}))
}
style={{ padding: 6 }}
>
<Ionicons name="remove" size={13} color="#FFFFFF" />
</Pressable>
<Text
style={{
color: "#D4AF37",
fontSize: 11,
fontWeight: "700",
minWidth: 26,
textAlign: "center",
}}
>
{item.fontSize || 12}
</Text>
<Pressable
onPress={() =>
setFields((prev) => ({
...prev,
[key]: {
...prev[key],
fontSize: Math.min(max, (prev[key].fontSize || 12) + 1),
},
}))
}
style={{ padding: 6 }}
>
<Ionicons name="add" size={13} color="#FFFFFF" />
</Pressable>
</View>
</View>
</>
)}
</View>
</View>
{customText.showSubtitle && (
<TextInput
value={customText.subtitle}
onChangeText={(t) => setCustomText((p) => ({ ...p, subtitle: t }))}
placeholder="Slogan / Açıklama"
placeholderTextColor="#71717A"
style={{
backgroundColor: "#121215",
borderWidth: 1,
borderColor: "rgba(255,255,255,0.1)",
borderRadius: 12,
paddingHorizontal: 14,
paddingVertical: 10,
color: "#FFFFFF",
fontSize: 14,
}}
/>
)}
</View>
{/* Alan 3: Masa Numarası */}
<View style={{ gap: 6 }}>
<View style={{ flexDirection: "row", justifyContent: "space-between", alignItems: "center" }}>
<Text style={{ color: "#D4AF37", fontSize: 12, fontWeight: "700" }}>
MASA NUMARASI
</Text>
<View style={{ flexDirection: "row", alignItems: "center", gap: 6 }}>
<Text style={{ color: "#71717A", fontSize: 11 }}>
{customText.showTableNo ? "Göster" : "Gizle"}
</Text>
<Switch
value={customText.showTableNo}
onValueChange={(v) => setCustomText((p) => ({ ...p, showTableNo: v }))}
trackColor={{ false: "#27272A", true: "#D4AF37" }}
thumbColor="#FFFFFF"
ios_backgroundColor="#27272A"
/>
</View>
</View>
{customText.showTableNo && (
<TextInput
value={customText.tableNo}
onChangeText={(t) => setCustomText((p) => ({ ...p, tableNo: t }))}
placeholder="Örn: MASA NO: 01"
placeholderTextColor="#71717A"
style={{
backgroundColor: "#121215",
borderWidth: 1,
borderColor: "rgba(255,255,255,0.1)",
borderRadius: 12,
paddingHorizontal: 14,
paddingVertical: 10,
color: "#FFFFFF",
fontSize: 14,
}}
/>
)}
</View>
{/* Alan 4: Yönlendirme (CTA) */}
<View style={{ gap: 6 }}>
<View style={{ flexDirection: "row", justifyContent: "space-between", alignItems: "center" }}>
<Text style={{ color: "#D4AF37", fontSize: 12, fontWeight: "700" }}>
YÖNLENDİRME (CTA) METNİ
</Text>
<View style={{ flexDirection: "row", alignItems: "center", gap: 6 }}>
<Text style={{ color: "#71717A", fontSize: 11 }}>
{customText.showCta ? "Göster" : "Gizle"}
</Text>
<Switch
value={customText.showCta}
onValueChange={(v) => setCustomText((p) => ({ ...p, showCta: v }))}
trackColor={{ false: "#27272A", true: "#D4AF37" }}
thumbColor="#FFFFFF"
ios_backgroundColor="#27272A"
/>
</View>
</View>
{customText.showCta && (
<TextInput
value={customText.ctaText}
onChangeText={(t) => setCustomText((p) => ({ ...p, ctaText: t }))}
placeholder="Örn: MENÜYÜ GÖRMEK İÇİN OKUTUN"
placeholderTextColor="#71717A"
style={{
backgroundColor: "#121215",
borderWidth: 1,
borderColor: "rgba(255,255,255,0.1)",
borderRadius: 12,
paddingHorizontal: 14,
paddingVertical: 10,
color: "#FFFFFF",
fontSize: 14,
}}
/>
)}
</View>
{/* Alan 5: WiFi Bilgileri */}
<View style={{ gap: 6 }}>
<View style={{ flexDirection: "row", justifyContent: "space-between", alignItems: "center" }}>
<Text style={{ color: "#D4AF37", fontSize: 12, fontWeight: "700" }}>
WIFI BİLGİSİ
</Text>
<View style={{ flexDirection: "row", alignItems: "center", gap: 6 }}>
<Text style={{ color: "#71717A", fontSize: 11 }}>
{customText.showWifi ? "Göster" : "Gizle"}
</Text>
<Switch
value={customText.showWifi}
onValueChange={(v) => setCustomText((p) => ({ ...p, showWifi: v }))}
trackColor={{ false: "#27272A", true: "#D4AF37" }}
thumbColor="#FFFFFF"
ios_backgroundColor="#27272A"
/>
</View>
</View>
{customText.showWifi && (
<TextInput
value={customText.wifiText}
onChangeText={(t) => setCustomText((p) => ({ ...p, wifiText: t }))}
placeholder="Örn: WiFi: Bistro | Şifre: 12345"
placeholderTextColor="#71717A"
style={{
backgroundColor: "#121215",
borderWidth: 1,
borderColor: "rgba(255,255,255,0.1)",
borderRadius: 12,
paddingHorizontal: 14,
paddingVertical: 10,
color: "#FFFFFF",
fontSize: 14,
}}
/>
)}
</View>
{/* Alan 6: Sosyal Medya / İletişim */}
<View style={{ gap: 6 }}>
<View style={{ flexDirection: "row", justifyContent: "space-between", alignItems: "center" }}>
<Text style={{ color: "#D4AF37", fontSize: 12, fontWeight: "700" }}>
SOSYAL MEDYA / İLETİŞİM
</Text>
<View style={{ flexDirection: "row", alignItems: "center", gap: 6 }}>
<Text style={{ color: "#71717A", fontSize: 11 }}>
{customText.showSocial ? "Göster" : "Gizle"}
</Text>
<Switch
value={customText.showSocial}
onValueChange={(v) => setCustomText((p) => ({ ...p, showSocial: v }))}
trackColor={{ false: "#27272A", true: "#D4AF37" }}
thumbColor="#FFFFFF"
ios_backgroundColor="#27272A"
/>
</View>
</View>
{customText.showSocial && (
<TextInput
value={customText.socialText}
onChangeText={(t) => setCustomText((p) => ({ ...p, socialText: t }))}
placeholder="Örn: @menulio"
placeholderTextColor="#71717A"
style={{
backgroundColor: "#121215",
borderWidth: 1,
borderColor: "rgba(255,255,255,0.1)",
borderRadius: 12,
paddingHorizontal: 14,
paddingVertical: 10,
color: "#FFFFFF",
fontSize: 14,
}}
/>
)}
</View>
);
})}
</View>
)}
</View>
{/* Output Action Buttons */}
<View style={{ width: "100%", gap: 10 }}>
{/* PDF Download Button */}
@@ -8,313 +8,300 @@ import Svg, {
Text,
Image,
} from "react-native-svg";
import type { QrTemplateProps } from "./index";
import { type QrTemplateProps, getFontFamily, renderSvgLines } from "./index";
const QrTemplate2 = ({
qrBase64,
restaurantName = "The Daily Grind",
subtitle = "COFFEE & KITCHEN",
tableNo = "MASA NO: 04",
ctaText = "MENÜYÜ GÖRMEK İÇİN OKUTUN",
wifiText = "WiFi: DailyGrind | Şifre: coffee2026",
socialText = "@dailygrind",
fontFamily = "'Playfair Display', Georgia, serif",
showTableNo = true,
showSubtitle = true,
showCta = true,
showWifi = true,
showSocial = true,
fields,
...props
}: QrTemplateProps) => (
<Svg
viewBox="0 0 400 650"
width={300}
height={487.5}
{...props}
>
{/* Arka Plan */}
<Path fill="#252c36" d="M0 0h400v650H0z" />
}: 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;
{/* Ana Kart */}
<Rect
width={360}
height={610}
x={20}
y={20}
fill="#f6efe2"
stroke="#3a2312"
strokeWidth={1.5}
rx={20}
/>
<Rect
width={344}
height={594}
x={28}
y={28}
fill="none"
stroke="#8c6239"
strokeOpacity={0.4}
rx={14}
/>
<Rect
width={336}
height={586}
x={32}
y={32}
fill="none"
stroke="#8c6239"
strokeOpacity={0.25}
strokeWidth={0.5}
rx={10}
/>
const rNameFont = getFontFamily(rName?.fontId, "Georgia, 'Times New Roman', serif");
const subFont = getFontFamily(sub?.fontId, "System, -apple-system, Roboto, sans-serif");
const ctaFont = getFontFamily(cta?.fontId, "Georgia, 'Times New Roman', serif");
const infoFont = getFontFamily(wifi?.fontId, "System, -apple-system, Roboto, sans-serif");
{/* Sol Üst Botanik Dal */}
<G fill="none" stroke="#3a2312" strokeLinecap="round" strokeWidth={1.05}>
<Path d="M36 36c11.25 11.25 18.75 26.25 22.5 48.75" />
<Path
fill="#eadcc7"
d="M43.5 45c-3.75-7.5 7.5-10.5 9-3 0 7.5-9 3-9 3Zm6 11.25C45 51 57 46.5 60 53.25c0 6.75-10.5 3-10.5 3Zm4.5 13.5C60 64.5 69.75 72 64.5 78c-6 4.5-10.5-8.25-10.5-8.25Z"
/>
</G>
return (
<Svg viewBox="0 0 400 650" width={300} height={487.5} {...props}>
{/* Arka Plan */}
<Path fill="#252c36" d="M0 0h400v650H0z" />
{/* Sağ Üst Kahve İkonu */}
<G transform="translate(340 52)">
<Circle r={32} fill="#eadcc7" stroke="#3a2312" strokeWidth={1.2} />
<Circle
r={26}
{/* Ana Kart */}
<Rect
width={360}
height={610}
x={20}
y={20}
fill="#f6efe2"
stroke="#3a2312"
strokeWidth={1.5}
rx={20}
/>
<Rect
width={344}
height={594}
x={28}
y={28}
fill="none"
stroke="#8c6239"
strokeDasharray="2 2"
strokeWidth={0.8}
strokeOpacity={0.4}
rx={14}
/>
<Circle r={21} fill="#7a4b26" stroke="#3a2312" strokeWidth={1.4} />
<Path fill="#f6efe2" d="M0 10C-8 4-4-6 0-12 4-6 8 4 0 10" />
<Path fill="#7a4b26" d="M0 4C-5 0-2-5 0-8 2-5 5 0 0 4" />
<Circle cy={-14} r={1.8} fill="#f6efe2" />
</G>
{/* Sol Orta Kahve Bardağı */}
<G transform="translate(48 250)">
<Circle r={26} fill="#eadcc7" stroke="#3a2312" />
<Circle r={17} fill="#6a3b18" stroke="#3a2312" strokeWidth={1.2} />
<Path fill="#f6efe2" d="M-5-3c-3-4 5-7 5-1 0-6 8-3 5 1L0 7z" />
<Path fill="none" stroke="#3a2312" strokeWidth={1.5} d="M17-4c6 0 6 8 0 8" />
</G>
{/* Sağ Dal */}
<G fill="none" stroke="#3a2312" strokeWidth={0.91}>
<Path d="M352 230c-7 21-10.5 49-3.5 77" />
<Path
fill="#eadcc7"
d="M349.2 247.5c8.4-7 15.4 2.1 5.6 7.7-5.6 0-5.6-7.7-5.6-7.7Zm-2.8 24.5c-9.8-8.4-15.4 1.4-7 7 7 0 7-7 7-7Zm2.1 19.6c9.1-7 13.3 2.8 4.9 8.4-4.9 0-4.9-8.4-4.9-8.4Z"
<Rect
width={336}
height={586}
x={32}
y={32}
fill="none"
stroke="#8c6239"
strokeOpacity={0.25}
strokeWidth={0.5}
rx={10}
/>
</G>
{/* Dekoratif Çizgi */}
<Path
fill="none"
stroke="#8c6239"
strokeLinecap="round"
strokeWidth={1.2}
d="M142 66c6-2 12 2 18 0m80 0c6 2 12-2 18 0"
/>
{/* Sol Alt Dal */}
<G fill="none" stroke="#3a2312" strokeWidth={0.91}>
<Path d="M42 601.5c13-26 9.75-52 0-71.5" />
<Path
fill="#eadcc7"
d="M47.2 549.5c10.4-9.75 17.55 0 6.5 7.8Zm2.6 26c11.7-9.75 18.2 1.3 5.2 9.1Z"
/>
</G>
{/* Kahve Çekirdekleri */}
<G stroke="#3a2312" strokeWidth={1.2} transform="rotate(-20 1741.206 -8.75) scale(.8)">
<Ellipse fill="#cbb296" rx={9} ry={6.5} />
<Path fill="none" d="M-7 0q7 3 7 0t7 0" />
</G>
<G stroke="#3a2312" strokeWidth={1.2} transform="rotate(35 -862.106 494.982) scale(.8)">
<Ellipse fill="#cbb296" rx={9} ry={6.5} />
<Path fill="none" d="M-7 0q7 3 7 0t7 0" />
</G>
<G stroke="#3a2312" strokeWidth={1.2} transform="rotate(-45 602.558 -225.588) scale(.7)">
<Ellipse fill="#cbb296" rx={9} ry={6.5} />
<Path fill="none" d="M-7 0q7 3 7 0t7 0" />
</G>
{/* Sağ Alt Fincan */}
<G transform="translate(325 590)">
<Ellipse cy={18} fill="#eadcc7" stroke="#3a2312" strokeWidth={1.2} rx={28} ry={7} />
<Path fill="#f6efe2" stroke="#3a2312" strokeWidth={1.4} d="M-18 2c0 14 36 14 36 0Z" />
<Ellipse cy={2} fill="#6a3b18" stroke="#3a2312" strokeWidth={1.2} rx={18} ry={4} />
<Path fill="none" stroke="#3a2312" strokeWidth={1.3} d="M16 4c8 0 8 8 0 10" />
<Path fill="none" stroke="#8c6239" strokeLinecap="round" d="M-6-4c-2-5 2-8 0-13M2-5c-2-5 2-8 0-14" />
</G>
{/* QR Köşe Çerçeveleri */}
<Path
fill="none"
stroke="#3a2312"
strokeLinecap="round"
strokeWidth={2}
d="M80 205c0-10 0-10 10-10m230 10c0-10 0-10-10-10M80 445c0 10 0 10 10 10m230-10c0 10 0 10-10 10"
/>
<Path stroke="#8c6239" strokeWidth={0.8} d="M145 608h30m50 0h30" />
{/* QR Placeholder / Gerçek QR */}
<G transform="translate(90 215)">
<Rect width={220} height={220} fill="#fbf8f2" stroke="#d8c7b0" strokeWidth={1.5} rx={20} />
{qrBase64 ? (
<Image
href={`data:image/png;base64,${qrBase64}`}
x={10}
y={10}
width={200}
height={200}
{/* Sol Üst Botanik Dal */}
<G fill="none" stroke="#3a2312" strokeLinecap="round" strokeWidth={1.05}>
<Path d="M36 36c11.25 11.25 18.75 26.25 22.5 48.75" />
<Path
fill="#eadcc7"
d="M43.5 45c-3.75-7.5 7.5-10.5 9-3 0 7.5-9 3-9 3Zm6 11.25C45 51 57 46.5 60 53.25c0 6.75-10.5 3-10.5 3Zm4.5 13.5C60 64.5 69.75 72 64.5 78c-6 4.5-10.5-8.25-10.5-8.25Z"
/>
) : (
<>
<Rect
width={200}
height={200}
</G>
{/* Sağ Üst Kahve İkonu */}
<G transform="translate(340 52)">
<Circle r={32} fill="#eadcc7" stroke="#3a2312" strokeWidth={1.2} />
<Circle
r={26}
fill="#f6efe2"
stroke="#8c6239"
strokeDasharray="2 2"
strokeWidth={0.8}
/>
<Circle r={21} fill="#7a4b26" stroke="#3a2312" strokeWidth={1.4} />
<Path fill="#f6efe2" d="M0 10C-8 4-4-6 0-12 4-6 8 4 0 10" />
<Path fill="#7a4b26" d="M0 4C-5 0-2-5 0-8 2-5 5 0 0 4" />
<Circle cy={-14} r={1.8} fill="#f6efe2" />
</G>
{/* Sol Orta Kahve Bardağı */}
<G transform="translate(48 250)">
<Circle r={26} fill="#eadcc7" stroke="#3a2312" />
<Circle r={17} fill="#6a3b18" stroke="#3a2312" strokeWidth={1.2} />
<Path fill="#f6efe2" d="M-5-3c-3-4 5-7 5-1 0-6 8-3 5 1L0 7z" />
<Path fill="none" stroke="#3a2312" strokeWidth={1.5} d="M17-4c6 0 6 8 0 8" />
</G>
{/* Sağ Dal */}
<G fill="none" stroke="#3a2312" strokeWidth={0.91}>
<Path d="M352 230c-7 21-10.5 49-3.5 77" />
<Path
fill="#eadcc7"
d="M349.2 247.5c8.4-7 15.4 2.1 5.6 7.7-5.6 0-5.6-7.7-5.6-7.7Zm-2.8 24.5c-9.8-8.4-15.4 1.4-7 7 7 0 7-7 7-7Zm2.1 19.6c9.1-7 13.3 2.8 4.9 8.4-4.9 0-4.9-8.4-4.9-8.4Z"
/>
</G>
{/* Dekoratif Çizgi */}
<Path
fill="none"
stroke="#8c6239"
strokeLinecap="round"
strokeWidth={1.2}
d="M142 66c6-2 12 2 18 0m80 0c6 2 12-2 18 0"
/>
{/* Sol Alt Dal */}
<G fill="none" stroke="#3a2312" strokeWidth={0.91}>
<Path d="M42 601.5c13-26 9.75-52 0-71.5" />
<Path
fill="#eadcc7"
d="M47.2 549.5c10.4-9.75 17.55 0 6.5 7.8Zm2.6 26c11.7-9.75 18.2 1.3 5.2 9.1Z"
/>
</G>
{/* Kahve Çekirdekleri */}
<G stroke="#3a2312" strokeWidth={1.2} transform="rotate(-20 1741.206 -8.75) scale(.8)">
<Ellipse fill="#cbb296" rx={9} ry={6.5} />
<Path fill="none" d="M-7 0q7 3 7 0t7 0" />
</G>
<G stroke="#3a2312" strokeWidth={1.2} transform="rotate(35 -862.106 494.982) scale(.8)">
<Ellipse fill="#cbb296" rx={9} ry={6.5} />
<Path fill="none" d="M-7 0q7 3 7 0t7 0" />
</G>
<G stroke="#3a2312" strokeWidth={1.2} transform="rotate(-45 602.558 -225.588) scale(.7)">
<Ellipse fill="#cbb296" rx={9} ry={6.5} />
<Path fill="none" d="M-7 0q7 3 7 0t7 0" />
</G>
{/* Sağ Alt Fincan */}
<G transform="translate(325 590)">
<Ellipse cy={18} fill="#eadcc7" stroke="#3a2312" strokeWidth={1.2} rx={28} ry={7} />
<Path fill="#f6efe2" stroke="#3a2312" strokeWidth={1.4} d="M-18 2c0 14 36 14 36 0Z" />
<Ellipse cy={2} fill="#6a3b18" stroke="#3a2312" strokeWidth={1.2} rx={18} ry={4} />
<Path fill="none" stroke="#3a2312" strokeWidth={1.3} d="M16 4c8 0 8 8 0 10" />
<Path fill="none" stroke="#8c6239" strokeLinecap="round" d="M-6-4c-2-5 2-8 0-13M2-5c-2-5 2-8 0-14" />
</G>
{/* QR Köşe Çerçeveleri */}
<Path
fill="none"
stroke="#3a2312"
strokeLinecap="round"
strokeWidth={2}
d="M80 205c0-10 0-10 10-10m230 10c0-10 0-10-10-10M80 445c0 10 0 10 10 10m230-10c0 10 0 10-10 10"
/>
<Path stroke="#8c6239" strokeWidth={0.8} d="M145 608h30m50 0h30" />
{/* QR Placeholder / Gerçek QR */}
<G transform="translate(90 215)">
<Rect width={220} height={220} fill="#fbf8f2" stroke="#d8c7b0" strokeWidth={1.5} rx={20} />
{qrBase64 ? (
<Image
href={`data:image/png;base64,${qrBase64}`}
x={10}
y={10}
fill="#f5efe6"
stroke="#d8c7b0"
strokeDasharray="4 3"
rx={14}
width={200}
height={200}
/>
<Circle cx={110} cy={98} r={18} fill="#fbf8f2" stroke="#8c6239" />
<G fill="#3a2312" transform="matrix(.65 0 0 .65 110 98)">
<Ellipse cx={-5} cy={2} rx={7} ry={5} transform="rotate(-30)" />
<Ellipse cx={5} rx={7} ry={5} transform="rotate(40)" />
</G>
<Text
x={110}
y={132}
fill="#8c6239"
fontFamily="Inter, Arial, sans-serif"
fontSize={11}
fontWeight={700}
letterSpacing={1}
textAnchor="middle"
>
{"QR KOD ALANI"}
</Text>
</>
)}
</G>
) : (
<>
<Rect
width={200}
height={200}
x={10}
y={10}
fill="#f5efe6"
stroke="#d8c7b0"
strokeDasharray="4 3"
rx={14}
/>
<Circle cx={110} cy={98} r={18} fill="#fbf8f2" stroke="#8c6239" />
<G fill="#3a2312" transform="matrix(.65 0 0 .65 110 98)">
<Ellipse cx={-5} cy={2} rx={7} ry={5} transform="rotate(-30)" />
<Ellipse cx={5} rx={7} ry={5} transform="rotate(40)" />
</G>
<Text
x={110}
y={132}
fill="#8c6239"
fontFamily="System, sans-serif"
fontSize={11}
fontWeight={700}
letterSpacing={1}
textAnchor="middle"
>
{"QR KOD ALANI"}
</Text>
</>
)}
</G>
{/* Metinler */}
<G textAnchor="middle">
{/* Üst Tag / Takı */}
<Text
x={200}
y={70}
fill="#3a2312"
fontFamily={fontFamily}
fontSize={14}
fontStyle="italic"
fontWeight={700}
letterSpacing={4}
>
{"THE"}
</Text>
{/* Restoran Adı */}
{restaurantName ? (
{/* Metinler (Çok satırlı destekli) */}
<G textAnchor="middle">
<Text
x={200}
y={114}
fill="#2c1a0e"
fontFamily={fontFamily}
fontSize={30}
fontWeight={800}
letterSpacing={0.5}
>
{restaurantName}
</Text>
) : null}
{/* Slogan */}
{showSubtitle && subtitle ? (
<Text
x={200}
y={146}
y={68}
fill="#3a2312"
fontFamily="Inter, Arial, sans-serif"
fontSize={12}
fontFamily={rNameFont}
fontSize={14}
fontStyle="italic"
fontWeight={700}
letterSpacing={2.5}
letterSpacing={4}
>
{subtitle}
{"THE"}
</Text>
) : null}
{/* CTA */}
{showCta && ctaText ? (
{/* Restoran Adı */}
{rName?.visible !== false &&
renderSvgLines({
text: rName?.text || "The Daily Grind",
x: 200,
y: 110,
fill: "#2c1a0e",
fontFamily: rNameFont,
fontSize: rName?.fontSize || 28,
fontWeight: "bold",
letterSpacing: 0.5,
})}
{/* Slogan */}
{sub?.visible !== false &&
renderSvgLines({
text: sub?.text || "COFFEE & KITCHEN",
x: 200,
y: 144,
fill: "#3a2312",
fontFamily: subFont,
fontSize: sub?.fontSize || 12,
fontWeight: 700,
letterSpacing: 2.5,
})}
{/* CTA */}
{cta?.visible !== false &&
renderSvgLines({
text: cta?.text || "MENÜYÜ GÖRMEK İÇİN OKUTUN",
x: 200,
y: 486,
fill: "#2c1a0e",
fontFamily: ctaFont,
fontSize: cta?.fontSize || 15,
fontWeight: "bold",
letterSpacing: 1.2,
})}
{/* WiFi */}
{wifi?.visible !== false &&
renderSvgLines({
text: wifi?.text || "WiFi: DailyGrind | Şifre: coffee2026",
x: 200,
y: 520,
fill: "#3a2312",
fontFamily: infoFont,
fontSize: wifi?.fontSize || 10.5,
fontWeight: 700,
letterSpacing: 0.5,
})}
{/* Masa No & Sosyal */}
{(table?.visible !== false || social?.visible !== false) &&
renderSvgLines({
text: [
table?.visible !== false && table?.text ? table.text : "",
social?.visible !== false && social?.text ? social.text : "",
]
.filter(Boolean)
.join(" • "),
x: 200,
y: 544,
fill: "#8c6239",
fontFamily: infoFont,
fontSize: table?.fontSize || social?.fontSize || 10,
fontWeight: 600,
letterSpacing: 1,
})}
<Text
x={200}
y={488}
fill="#2c1a0e"
fontFamily={fontFamily}
fontSize={16}
fontWeight={800}
letterSpacing={1.2}
>
{ctaText}
</Text>
) : null}
{/* WiFi */}
{showWifi && wifiText ? (
<Text
x={200}
y={520}
y={611}
fill="#3a2312"
fontFamily="Inter, Arial, sans-serif"
fontSize={10.5}
fontFamily={rNameFont}
fontSize={11}
fontStyle="italic"
fontWeight={700}
letterSpacing={0.5}
letterSpacing={2}
>
{wifiText}
{"EST. 2026"}
</Text>
) : null}
{/* Masa No & Sosyal */}
{showTableNo || showSocial ? (
<Text
x={200}
y={544}
fill="#8c6239"
fontFamily="Inter, Arial, sans-serif"
fontSize={10}
fontWeight={600}
letterSpacing={1}
>
{[
showTableNo && tableNo ? tableNo : "",
showSocial && socialText ? socialText : "",
]
.filter(Boolean)
.join(" • ")}
</Text>
) : null}
<Text
x={200}
y={611}
fill="#3a2312"
fontFamily={fontFamily}
fontSize={11}
fontStyle="italic"
fontWeight={700}
letterSpacing={2}
>
{"EST. 2026"}
</Text>
</G>
</Svg>
);
</G>
</Svg>
);
};
export default QrTemplate2;
@@ -12,356 +12,336 @@ import Svg, {
Text,
Image,
} from "react-native-svg";
import type { QrTemplateProps } from "./index";
import { type QrTemplateProps, getFontFamily, renderSvgLines } from "./index";
const QrTemplate3 = ({
qrBase64,
restaurantName = "BELLA NAPOLI",
subtitle = "AUTENTICA CUCINA ITALIANA",
tableNo = "MASA NO: 01",
ctaText = "MENÜYÜ GÖRMEK İÇİN OKUTUN",
wifiText = "WiFi: GourmetBistro | Şifre: lezzetli01",
socialText = "@gourmetbistro",
fontFamily = "'Playfair Display', Georgia, serif",
showTableNo = true,
showSubtitle = true,
showCta = true,
showWifi = true,
showSocial = true,
fields,
...props
}: QrTemplateProps) => (
<Svg
viewBox="0 0 400 650"
width={300}
height={487.5}
{...props}
>
<Defs>
<LinearGradient id="card-grad-3" x1="0%" x2="0%" y1="0%" y2="100%">
<Stop offset="0%" stopColor="#fdfbf5" />
<Stop offset="50%" stopColor="#faf4e6" />
<Stop offset="100%" stopColor="#f7eed8" />
</LinearGradient>
<LinearGradient id="oven-fire-3" x1="0%" x2="0%" y1="100%" y2="0%">
<Stop offset="0%" stopColor="#c0392b" />
<Stop offset="50%" stopColor="#e67e22" />
<Stop offset="100%" stopColor="#f1c40f" />
</LinearGradient>
<LinearGradient id="wine-grad-3" x1="0%" x2="0%" y1="0%" y2="100%">
<Stop offset="0%" stopColor="#7b1123" />
<Stop offset="100%" stopColor="#4a0512" />
</LinearGradient>
<Pattern
id="checkered-border-3"
width={20}
height={20}
patternUnits="userSpaceOnUse"
>
<Path fill="#b92b27" d="M0 0h20v20H0z" />
<Path fill="#fdf8ee" d="M0 0h10v10H0zm10 10h10v10H10z" />
</Pattern>
</Defs>
}: 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;
{/* Arka Plan */}
<Path fill="url(#checkered-border-3)" d="M0 0h400v650H0z" />
const rNameFont = getFontFamily(rName?.fontId, "Georgia, 'Playfair Display', serif");
const subFont = getFontFamily(sub?.fontId, "System, -apple-system, Roboto, sans-serif");
const ctaFont = getFontFamily(cta?.fontId, "Georgia, 'Playfair Display', serif");
const infoFont = getFontFamily(wifi?.fontId, "System, -apple-system, Roboto, sans-serif");
{/* Kart */}
<G id="layer-card">
<Rect
width={356}
height={606}
x={22}
y={22}
fill="url(#card-grad-3)"
stroke="#b92b27"
strokeWidth={2}
rx={20}
/>
<Rect
width={344}
height={594}
x={28}
y={28}
fill="none"
stroke="#8c6239"
strokeOpacity={0.5}
strokeWidth={0.8}
rx={15}
/>
{showTableNo && tableNo ? (
return (
<Svg viewBox="0 0 400 650" width={300} height={487.5} {...props}>
<Defs>
<LinearGradient id="card-grad-3" x1="0%" x2="0%" y1="0%" y2="100%">
<Stop offset="0%" stopColor="#fdfbf5" />
<Stop offset="50%" stopColor="#faf4e6" />
<Stop offset="100%" stopColor="#f7eed8" />
</LinearGradient>
<LinearGradient id="oven-fire-3" x1="0%" x2="0%" y1="100%" y2="0%">
<Stop offset="0%" stopColor="#c0392b" />
<Stop offset="50%" stopColor="#e67e22" />
<Stop offset="100%" stopColor="#f1c40f" />
</LinearGradient>
<LinearGradient id="wine-grad-3" x1="0%" x2="0%" y1="0%" y2="100%">
<Stop offset="0%" stopColor="#7b1123" />
<Stop offset="100%" stopColor="#4a0512" />
</LinearGradient>
<Pattern
id="checkered-border-3"
width={20}
height={20}
patternUnits="userSpaceOnUse"
>
<Path fill="#b92b27" d="M0 0h20v20H0z" />
<Path fill="#fdf8ee" d="M0 0h10v10H0zm10 10h10v10H10z" />
</Pattern>
</Defs>
{/* Arka Plan */}
<Path fill="url(#checkered-border-3)" d="M0 0h400v650H0z" />
{/* Kart */}
<G id="layer-card">
<Rect
width={140}
height={24}
x={130}
y={34}
fill="#faf4e6"
width={356}
height={606}
x={22}
y={22}
fill="url(#card-grad-3)"
stroke="#b92b27"
strokeWidth={2}
rx={20}
/>
<Rect
width={344}
height={594}
x={28}
y={28}
fill="none"
stroke="#8c6239"
strokeWidth={1.2}
rx={12}
/>
) : null}
</G>
{/* İkonlar */}
<G id="layer-icons">
<Path
fill="none"
stroke="#c5a880"
strokeLinecap="round"
strokeWidth={1.5}
d="M68 88q12-13 28-2 6 5 10 2m226 0q-12-13-28-2-6 5-10 2"
/>
{/* Pizza Fırını */}
<G id="pizza-oven" transform="translate(200 192)">
<Rect
width={88}
height={6}
x={-44}
fill="#d7ccc8"
stroke="#5d4037"
rx={2}
/>
<Path
fill="#d7ccc8"
stroke="#5d4037"
strokeWidth={1.5}
d="M-40 0a40 38 0 0 1 80 0Z"
/>
<Path stroke="#8d6e63" d="m-30-25 7 6m6-15 4 8M0-38v9m17-5-4 8m17 1-7 6" />
<Path fill="#3e2723" stroke="#271c19" d="M-28 0a28 26 0 0 1 56 0Z" />
<Path fill="url(#oven-fire-3)" d="M-18 0q3-16 12-10 6-12 12-2 9-6 12 12Z" />
<Path fill="#fff9c4" d="M-10 0q5-10 10-6 5-6 10 6Z" />
</G>
{/* Sol Malzemeler */}
<G id="left-ingredients" transform="translate(108 185)">
<Ellipse
cx={-16}
cy={6}
fill="#d32f2f"
stroke="#8e0000"
strokeOpacity={0.5}
strokeWidth={0.8}
rx={14}
ry={10}
transform="rotate(-25 -16 6)"
rx={15}
/>
<Ellipse
cx={-16}
cy={6}
fill="#e53935"
rx={10}
ry={6.5}
transform="rotate(-25 -16 6)"
/>
<Ellipse
cx={2}
cy={7}
fill="#c62828"
stroke="#8e0000"
strokeWidth={0.8}
rx={13}
ry={9}
transform="rotate(-10 2 7)"
/>
<Ellipse cx={2} cy={7} fill="#e53935" rx={9} ry={5.5} transform="rotate(-10 2 7)" />
<Circle cx={2} cy={7} r={1.5} fill="#fdd835" />
<Circle cx={16} cy={-2} r={14} fill="#e53935" stroke="#b71c1c" strokeWidth={0.8} />
<Ellipse cx={12} cy={-6} fill="#ff8a80" opacity={0.6} rx={4} ry={2} />
<Path
stroke="#2e7d32"
strokeLinecap="round"
strokeWidth={1.5}
d="M16-16v3m0 0-5 2m5-2 5 2m-5-2-3-2m3 2 3-2"
/>
</G>
{/* Sağ Malzemeler */}
<G id="right-ingredients" transform="translate(290 182)">
<Circle cx={-14} cy={2} r={15} fill="#e53935" stroke="#b71c1c" strokeWidth={0.8} />
<Ellipse cx={-18} cy={-3} fill="#ff8a80" opacity={0.6} rx={4} ry={2} />
<Path
stroke="#2e7d32"
strokeLinecap="round"
strokeWidth={1.5}
d="M-14-13v3m0 0-4 2m4-2 4 2"
/>
<Path fill="#2e7d32" stroke="#1b5e20" strokeWidth={0.8} d="M-2 0C8-16 26-12 24 2 22 14 6 10-2 0Z" />
<Path fill="none" stroke="#4caf50" strokeWidth={0.7} d="M-2 0q14-4 26 2" />
<Path fill="#388e3c" stroke="#1b5e20" strokeWidth={0.8} d="M8 6c10-6 24 4 18 16-8 6-18-4-18-16Z" />
<Path fill="none" stroke="#81c784" strokeWidth={0.7} d="M8 6q12 6 18 16" />
</G>
{/* Alt Pizza Dilimi */}
<G id="footer-pizza-slice" transform="rotate(-10 3278.565 44.969)">
<Path fill="#deac68" stroke="#8d6e63" strokeWidth={1.2} d="m0 0 46-18c4 8 6 32 0 40Z" />
<Path fill="#fbc02d" d="m2 0 40-15c3 7 5 25 0 33Z" />
<Circle cx={28} cy={-5} r={5} fill="#c62828" stroke="#8e0000" strokeWidth={0.8} />
<Circle cx={32} cy={8} r={4.5} fill="#c62828" stroke="#8e0000" strokeWidth={0.8} />
<Circle cx={16} r={3.5} fill="#c62828" stroke="#8e0000" strokeWidth={0.8} />
<Ellipse cx={23} cy={4} fill="#2e7d32" rx={2} ry={4} transform="rotate(30 23 4)" />
<Ellipse cx={34} cy={-11} fill="#2e7d32" rx={2} ry={3} transform="rotate(-40 34 -11)" />
</G>
{/* Şarap Kadehi */}
<G id="footer-wine-glass" transform="translate(345 562)">
<Path fill="none" stroke="#71717a" strokeWidth={1.2} d="M-14-24C-15-8-11 4 0 6 11 4 15-8 14-24Z" />
<Path fill="url(#wine-grad-3)" d="M-13-12C-11 0-7 4 0 5.5 7 4 11 0 13-12Z" />
<Ellipse cy={-12} fill="#991b1b" rx={13} ry={2} />
<Path stroke="#71717a" strokeWidth={1.4} d="M0 6v22" />
<Ellipse cy={28} fill="#e4e4e7" stroke="#71717a" strokeWidth={1.2} rx={11} ry={2} />
<Path fill="none" stroke="#fff" strokeLinecap="round" d="M-10-20c-2 8 1 18 6 23" opacity={0.6} />
</G>
{/* QR Köşe Aksanları */}
<G id="qr-corner-accents">
<Path fill="none" stroke="#2e7d32" strokeLinecap="round" strokeWidth={3} d="M78 227v-22h22" />
<Path fill="none" stroke="#b92b27" strokeLinecap="round" strokeWidth={3} d="M322 227v-22h-22M78 423v22h22" />
<Path fill="none" stroke="#2e7d32" strokeLinecap="round" strokeWidth={3} d="M322 423v22h-22" />
</G>
</G>
{/* QR Placeholder / Gerçek QR */}
<G id="qr-placeholder" transform="translate(90 215)">
<Rect width={220} height={220} fill="#fff" stroke="#e4e4e7" strokeWidth={2} rx={20} />
{qrBase64 ? (
<Image
href={`data:image/png;base64,${qrBase64}`}
x={10}
y={10}
width={200}
height={200}
/>
) : (
<>
{table?.visible !== false && table?.text ? (
<Rect
width={196}
height={196}
x={12}
y={12}
fill="#fafafa"
stroke="#e4e4e7"
strokeDasharray="4 3"
rx={14}
width={140}
height={24}
x={130}
y={34}
fill="#faf4e6"
stroke="#8c6239"
strokeWidth={1.2}
rx={12}
/>
<Text
x={110}
y={115}
fill="#71717a"
fontFamily="Inter, Arial, sans-serif"
fontSize={12}
fontWeight={700}
textAnchor="middle"
>
{"QR KOD ALANI"}
</Text>
</>
)}
</G>
) : null}
</G>
{/* İkonlar */}
<G id="layer-icons">
<Path
fill="none"
stroke="#c5a880"
strokeLinecap="round"
strokeWidth={1.5}
d="M68 88q12-13 28-2 6 5 10 2m226 0q-12-13-28-2-6 5-10 2"
/>
{/* Pizza Fırını */}
<G id="pizza-oven" transform="translate(200 192)">
<Rect
width={88}
height={6}
x={-44}
fill="#d7ccc8"
stroke="#5d4037"
rx={2}
/>
<Path
fill="#d7ccc8"
stroke="#5d4037"
strokeWidth={1.5}
d="M-40 0a40 38 0 0 1 80 0Z"
/>
<Path stroke="#8d6e63" d="m-30-25 7 6m6-15 4 8M0-38v9m17-5-4 8m17 1-7 6" />
<Path fill="#3e2723" stroke="#271c19" d="M-28 0a28 26 0 0 1 56 0Z" />
<Path fill="url(#oven-fire-3)" d="M-18 0q3-16 12-10 6-12 12-2 9-6 12 12Z" />
<Path fill="#fff9c4" d="M-10 0q5-10 10-6 5-6 10 6Z" />
</G>
{/* Sol Malzemeler */}
<G id="left-ingredients" transform="translate(108 185)">
<Ellipse
cx={-16}
cy={6}
fill="#d32f2f"
stroke="#8e0000"
strokeWidth={0.8}
rx={14}
ry={10}
transform="rotate(-25 -16 6)"
/>
<Ellipse
cx={-16}
cy={6}
fill="#e53935"
rx={10}
ry={6.5}
transform="rotate(-25 -16 6)"
/>
<Ellipse
cx={2}
cy={7}
fill="#c62828"
stroke="#8e0000"
strokeWidth={0.8}
rx={13}
ry={9}
transform="rotate(-10 2 7)"
/>
<Ellipse cx={2} cy={7} fill="#e53935" rx={9} ry={5.5} transform="rotate(-10 2 7)" />
<Circle cx={2} cy={7} r={1.5} fill="#fdd835" />
<Circle cx={16} cy={-2} r={14} fill="#e53935" stroke="#b71c1c" strokeWidth={0.8} />
<Ellipse cx={12} cy={-6} fill="#ff8a80" opacity={0.6} rx={4} ry={2} />
<Path
stroke="#2e7d32"
strokeLinecap="round"
strokeWidth={1.5}
d="M16-16v3m0 0-5 2m5-2 5 2m-5-2-3-2m3 2 3-2"
/>
</G>
{/* Sağ Malzemeler */}
<G id="right-ingredients" transform="translate(290 182)">
<Circle cx={-14} cy={2} r={15} fill="#e53935" stroke="#b71c1c" strokeWidth={0.8} />
<Ellipse cx={-18} cy={-3} fill="#ff8a80" opacity={0.6} rx={4} ry={2} />
<Path
stroke="#2e7d32"
strokeLinecap="round"
strokeWidth={1.5}
d="M-14-13v3m0 0-4 2m4-2 4 2"
/>
<Path fill="#2e7d32" stroke="#1b5e20" strokeWidth={0.8} d="M-2 0C8-16 26-12 24 2 22 14 6 10-2 0Z" />
<Path fill="none" stroke="#4caf50" strokeWidth={0.7} d="M-2 0q14-4 26 2" />
<Path fill="#388e3c" stroke="#1b5e20" strokeWidth={0.8} d="M8 6c10-6 24 4 18 16-8 6-18-4-18-16Z" />
<Path fill="none" stroke="#81c784" strokeWidth={0.7} d="M8 6q12 6 18 16" />
</G>
{/* Alt Pizza Dilimi */}
<G id="footer-pizza-slice" transform="rotate(-10 3278.565 44.969)">
<Path fill="#deac68" stroke="#8d6e63" strokeWidth={1.2} d="m0 0 46-18c4 8 6 32 0 40Z" />
<Path fill="#fbc02d" d="m2 0 40-15c3 7 5 25 0 33Z" />
<Circle cx={28} cy={-5} r={5} fill="#c62828" stroke="#8e0000" strokeWidth={0.8} />
<Circle cx={32} cy={8} r={4.5} fill="#c62828" stroke="#8e0000" strokeWidth={0.8} />
<Circle cx={16} r={3.5} fill="#c62828" stroke="#8e0000" strokeWidth={0.8} />
<Ellipse cx={23} cy={4} fill="#2e7d32" rx={2} ry={4} transform="rotate(30 23 4)" />
<Ellipse cx={34} cy={-11} fill="#2e7d32" rx={2} ry={3} transform="rotate(-40 34 -11)" />
</G>
{/* Şarap Kadehi */}
<G id="footer-wine-glass" transform="translate(345 562)">
<Path fill="none" stroke="#71717a" strokeWidth={1.2} d="M-14-24C-15-8-11 4 0 6 11 4 15-8 14-24Z" />
<Path fill="url(#wine-grad-3)" d="M-13-12C-11 0-7 4 0 5.5 7 4 11 0 13-12Z" />
<Ellipse cy={-12} fill="#991b1b" rx={13} ry={2} />
<Path stroke="#71717a" strokeWidth={1.4} d="M0 6v22" />
<Ellipse cy={28} fill="#e4e4e7" stroke="#71717a" strokeWidth={1.2} rx={11} ry={2} />
<Path fill="none" stroke="#fff" strokeLinecap="round" d="M-10-20c-2 8 1 18 6 23" opacity={0.6} />
</G>
{/* QR Köşe Aksanları */}
<G id="qr-corner-accents">
<Path fill="none" stroke="#2e7d32" strokeLinecap="round" strokeWidth={3} d="M78 227v-22h22" />
<Path fill="none" stroke="#b92b27" strokeLinecap="round" strokeWidth={3} d="M322 227v-22h-22M78 423v22h22" />
<Path fill="none" stroke="#2e7d32" strokeLinecap="round" strokeWidth={3} d="M322 423v22h-22" />
</G>
</G>
{/* QR Placeholder / Gerçek QR */}
<G id="qr-placeholder" transform="translate(90 215)">
<Rect width={220} height={220} fill="#fff" stroke="#e4e4e7" strokeWidth={2} rx={20} />
{qrBase64 ? (
<Image
href={`data:image/png;base64,${qrBase64}`}
x={10}
y={10}
width={200}
height={200}
/>
) : (
<>
<Rect
width={196}
height={196}
x={12}
y={12}
fill="#fafafa"
stroke="#e4e4e7"
strokeDasharray="4 3"
rx={14}
/>
<Text
x={110}
y={115}
fill="#71717a"
fontFamily="System, sans-serif"
fontSize={12}
fontWeight={700}
textAnchor="middle"
>
{"QR KOD ALANI"}
</Text>
</>
)}
</G>
{/* Metinler (Çok satırlı destekli) */}
<G id="layer-texts">
{/* Masa No */}
{table?.visible !== false &&
renderSvgLines({
text: table?.text || "MASA NO: 01",
x: 200,
y: 50,
fill: "#18181b",
fontFamily: infoFont,
fontSize: table?.fontSize || 11,
fontWeight: "bold",
letterSpacing: 1.2,
})}
{/* Metinler */}
<G id="layer-texts">
{/* Masa No */}
{showTableNo && tableNo ? (
<Text
x={200}
y={50}
fill="#18181b"
fontFamily="Inter, Arial, sans-serif"
fontSize={11}
fontWeight={800}
letterSpacing={1.2}
textAnchor="middle"
>
{tableNo}
</Text>
) : null}
<Text
x={200}
y={96}
fill="#3e2723"
fontFamily={fontFamily}
fontSize={24}
textAnchor="middle"
>
{"PIZZERIA"}
</Text>
{/* Restoran Adı */}
{restaurantName ? (
<Text
x={200}
y={132}
fill="#18181b"
fontFamily={fontFamily}
fontSize={28}
fontWeight={700}
letterSpacing={1}
textAnchor="middle"
>
{restaurantName}
</Text>
) : null}
{/* Slogan */}
{showSubtitle && subtitle ? (
<Text
x={200}
y={222}
fill="#2e7d32"
fontFamily="Inter, Arial, sans-serif"
fontSize={11.5}
fontWeight={800}
letterSpacing={1.8}
textAnchor="middle"
>
{subtitle}
</Text>
) : null}
{/* CTA */}
{showCta && ctaText ? (
<Text
x={200}
y={474}
fill="#b92b27"
fontFamily={fontFamily}
fontSize={14}
fontWeight={700}
letterSpacing={1.2}
textAnchor="middle"
>
{ctaText}
</Text>
) : null}
{/* WiFi */}
{showWifi && wifiText ? (
<Text
x={200}
y={546}
y={96}
fill="#3e2723"
fontFamily="Inter, Arial, sans-serif"
fontSize={10.5}
fontWeight={700}
fontFamily={rNameFont}
fontSize={24}
textAnchor="middle"
>
{wifiText}
{"PIZZERIA"}
</Text>
) : null}
{/* Sosyal Medya */}
{showSocial && socialText ? (
<Text
x={200}
y={570}
fill="#b92b27"
fontFamily="Inter, Arial, sans-serif"
fontSize={10.5}
fontWeight={700}
letterSpacing={0.5}
textAnchor="middle"
>
{socialText}
</Text>
) : null}
</G>
</Svg>
);
{/* Restoran Adı */}
{rName?.visible !== false &&
renderSvgLines({
text: rName?.text || "BELLA NAPOLI",
x: 200,
y: 130,
fill: "#18181b",
fontFamily: rNameFont,
fontSize: rName?.fontSize || 26,
fontWeight: "bold",
letterSpacing: 1,
})}
{/* Slogan (Enter ile çok satır olabilir) */}
{sub?.visible !== false &&
renderSvgLines({
text: sub?.text || "AUTENTICA CUCINA ITALIANA",
x: 200,
y: 222,
fill: "#2e7d32",
fontFamily: subFont,
fontSize: sub?.fontSize || 11.5,
fontWeight: "bold",
letterSpacing: 1.8,
})}
{/* CTA */}
{cta?.visible !== false &&
renderSvgLines({
text: cta?.text || "MENÜYÜ GÖRMEK İÇİN OKUTUN",
x: 200,
y: 474,
fill: "#b92b27",
fontFamily: ctaFont,
fontSize: cta?.fontSize || 13,
fontWeight: "bold",
letterSpacing: 1.2,
})}
{/* WiFi */}
{wifi?.visible !== false &&
renderSvgLines({
text: wifi?.text || "WiFi: GourmetBistro | Şifre: lezzetli01",
x: 200,
y: 546,
fill: "#3e2723",
fontFamily: infoFont,
fontSize: wifi?.fontSize || 10.5,
fontWeight: "bold",
})}
{/* Sosyal Medya */}
{social?.visible !== false &&
renderSvgLines({
text: social?.text || "BİZİ TAKİP EDİN | @gourmetbistro",
x: 200,
y: 570,
fill: "#b92b27",
fontFamily: infoFont,
fontSize: social?.fontSize || 10.5,
fontWeight: "bold",
letterSpacing: 0.5,
})}
</G>
</Svg>
);
};
export default QrTemplate3;
@@ -9,271 +9,262 @@ import Svg, {
Text,
Image,
} from "react-native-svg";
import type { QrTemplateProps } from "./index";
import { type QrTemplateProps, getFontFamily, renderSvgLines } from "./index";
const QrTemplate4 = ({
qrBase64,
restaurantName = "THE CRIMSON PETAL",
subtitle = "FINE DINING EXPERIENCE",
tableNo = "MASA NO: 01",
ctaText = "MENÜYÜ GÖRMEK İÇİN OKUTUN",
wifiText = "WiFi: CrimsonGuest | Şifre: petal2026",
socialText = "@thecrimsonpetal",
fontFamily = "Georgia, 'Times New Roman', serif",
showTableNo = true,
showSubtitle = true,
showCta = true,
showWifi = true,
showSocial = true,
fields,
...props
}: QrTemplateProps) => (
<Svg width={300} height={435} viewBox="0 0 400 580" {...props}>
<Defs>
<G id="b4">
<Path
fill="none"
stroke="#c59b4b"
strokeWidth={1.3}
d="M0-22c22-8 36 6 38 22-2 16-16 30-38 22Z"
/>
<Path
fill="none"
stroke="#c59b4b"
strokeWidth={0.9}
d="M0-12c14-6 24 2 26 12-2 10-12 18-26 12Z"
/>
<Path stroke="#c59b4b" strokeWidth={0.8} d="M0 0h26" />
<Path
fill="none"
stroke="#c59b4b"
strokeWidth={1.2}
d="M0-8c16-28 34-32 46-18C36-12 20-4 0-8ZM0 8c16 28 34 32 46 18C36 12 20 4 0 8Z"
/>
<Circle cx={48} cy={-28} r={1.5} fill="#c59b4b" />
<Circle cx={48} cy={28} r={1.5} fill="#c59b4b" />
<Path
fill="none"
stroke="#c59b4b"
strokeWidth={1.1}
d="M0-35c24-21 52-15 56-1-14 6-32 12-56 1Zm0 70c24 21 52 15 56 1-14-6-32-12-56-1Z"
/>
<Path
fill="none"
stroke="#c59b4b"
d="M28-44c14-20 36-10 30 2-10 6-20 4-30-2Zm0 88c14 20 36 10 30-2-10-6-20-4-30 2Z"
/>
<Circle cx={60} cy={-44} r={1.2} fill="#c59b4b" />
<Circle cx={60} cy={44} r={1.2} fill="#c59b4b" />
<Circle cx={34} cy={-58} r={1.2} fill="#c59b4b" />
<Circle cx={34} cy={58} r={1.2} fill="#c59b4b" />
<Path
fill="none"
stroke="#c59b4b"
strokeLinecap="round"
d="M0-60c22-15 36-35 32-55-6 15-16 30-32 55M0 60c22 15 36 35 32 55-6-15-16-30-32-55"
/>
<Path
fill="none"
stroke="#c59b4b"
strokeWidth={0.9}
d="M14-78c8-6 12 2 6 6-4 0-6-4-6-6Zm0 156c8 6 12-2 6-6-4 0-6 4-6 6Z"
/>
<Circle cx={32} cy={-116} r={1.5} fill="#c59b4b" />
<Circle cx={32} cy={116} r={1.5} fill="#c59b4b" />
</G>
<G id="a4">
<Path
fill="none"
stroke="#c59b4b"
strokeWidth={1.3}
d="M18 64c0-28 18-46 46-46"
/>
<Path
fill="none"
stroke="#c59b4b"
strokeWidth={0.8}
d="M24 52c0-16 12-28 28-28"
/>
<Path
fill="none"
stroke="#c59b4b"
strokeLinecap="round"
strokeWidth={0.9}
d="M28 32c4-6 10-4 8 2-2 4-8 2-6-4s10-6 14-2"
/>
<Circle cx={28} cy={28} r={1.8} fill="#c59b4b" />
<Circle cx={48} cy={18} r={1.4} fill="#c59b4b" />
<Circle cx={18} cy={48} r={1.4} fill="#c59b4b" />
</G>
</Defs>
<Path fill="#fdfdfd" d="M0 0h400v580H0z" />
<Path
fill="none"
stroke="#c59b4b"
strokeWidth={1.2}
d="M20 14h360v552H20z"
/>
<Use href="#a4" />
<Use href="#a4" transform="matrix(-1 0 0 1 400 0)" />
<Use href="#a4" transform="matrix(1 0 0 -1 0 580)" />
<Use href="#a4" transform="rotate(180 200 290)" />
<Path
fill="none"
stroke="#c59b4b"
strokeLinecap="round"
strokeWidth={1.2}
d="M132 62c8-4 16 2 24-2 4-2 2-6-2-4m114 6c-8-4-16 2-24-2-4-2-2-6 2-4"
/>
<Use href="#b4" transform="translate(0 310)" />
<Use href="#b4" transform="matrix(-1 0 0 1 400 310)" />
<Path
fill="none"
stroke="#c59b4b"
strokeLinecap="square"
strokeWidth={2.2}
d="M114 278v-58h54m118 58v-58h-54M114 342v58h54m118-58v58h-54"
/>
}: 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;
{/* QR Placeholder / Live QR */}
<G transform="translate(125 230)">
<Rect
width={150}
height={150}
fill="#fff"
stroke="#eae5d9"
strokeWidth={1.5}
rx={12}
const rNameFont = getFontFamily(rName?.fontId, "Georgia, 'Times New Roman', serif");
const subFont = getFontFamily(sub?.fontId, "System, -apple-system, Roboto, sans-serif");
const ctaFont = getFontFamily(cta?.fontId, "Georgia, 'Times New Roman', serif");
const infoFont = getFontFamily(wifi?.fontId, "System, -apple-system, Roboto, sans-serif");
return (
<Svg width={300} height={435} viewBox="0 0 400 580" {...props}>
<Defs>
<G id="b4">
<Path
fill="none"
stroke="#c59b4b"
strokeWidth={1.3}
d="M0-22c22-8 36 6 38 22-2 16-16 30-38 22Z"
/>
<Path
fill="none"
stroke="#c59b4b"
strokeWidth={0.9}
d="M0-12c14-6 24 2 26 12-2 10-12 18-26 12Z"
/>
<Path stroke="#c59b4b" strokeWidth={0.8} d="M0 0h26" />
<Path
fill="none"
stroke="#c59b4b"
strokeWidth={1.2}
d="M0-8c16-28 34-32 46-18C36-12 20-4 0-8ZM0 8c16 28 34 32 46 18C36 12 20 4 0 8Z"
/>
<Circle cx={48} cy={-28} r={1.5} fill="#c59b4b" />
<Circle cx={48} cy={28} r={1.5} fill="#c59b4b" />
<Path
fill="none"
stroke="#c59b4b"
strokeWidth={1.1}
d="M0-35c24-21 52-15 56-1-14 6-32 12-56 1Zm0 70c24 21 52 15 56 1-14-6-32-12-56-1Z"
/>
<Path
fill="none"
stroke="#c59b4b"
d="M28-44c14-20 36-10 30 2-10 6-20 4-30-2Zm0 88c14 20 36 10 30-2-10-6-20-4-30 2Z"
/>
<Circle cx={60} cy={-44} r={1.2} fill="#c59b4b" />
<Circle cx={60} cy={44} r={1.2} fill="#c59b4b" />
<Circle cx={34} cy={-58} r={1.2} fill="#c59b4b" />
<Circle cx={34} cy={58} r={1.2} fill="#c59b4b" />
<Path
fill="none"
stroke="#c59b4b"
strokeLinecap="round"
d="M0-60c22-15 36-35 32-55-6 15-16 30-32 55M0 60c22 15 36 35 32 55-6-15-16-30-32-55"
/>
<Path
fill="none"
stroke="#c59b4b"
strokeWidth={0.9}
d="M14-78c8-6 12 2 6 6-4 0-6-4-6-6Zm0 156c8 6 12-2 6-6-4 0-6 4-6 6Z"
/>
<Circle cx={32} cy={-116} r={1.5} fill="#c59b4b" />
<Circle cx={32} cy={116} r={1.5} fill="#c59b4b" />
</G>
<G id="a4">
<Path
fill="none"
stroke="#c59b4b"
strokeWidth={1.3}
d="M18 64c0-28 18-46 46-46"
/>
<Path
fill="none"
stroke="#c59b4b"
strokeWidth={0.8}
d="M24 52c0-16 12-28 28-28"
/>
<Path
fill="none"
stroke="#c59b4b"
strokeLinecap="round"
strokeWidth={0.9}
d="M28 32c4-6 10-4 8 2-2 4-8 2-6-4s10-6 14-2"
/>
<Circle cx={28} cy={28} r={1.8} fill="#c59b4b" />
<Circle cx={48} cy={18} r={1.4} fill="#c59b4b" />
<Circle cx={18} cy={48} r={1.4} fill="#c59b4b" />
</G>
</Defs>
<Path fill="#fdfdfd" d="M0 0h400v580H0z" />
<Path
fill="none"
stroke="#c59b4b"
strokeWidth={1.2}
d="M20 14h360v552H20z"
/>
{qrBase64 ? (
<Image
href={`data:image/png;base64,${qrBase64}`}
x={8}
y={8}
width={134}
height={134}
<Use href="#a4" />
<Use href="#a4" transform="matrix(-1 0 0 1 400 0)" />
<Use href="#a4" transform="matrix(1 0 0 -1 0 580)" />
<Use href="#a4" transform="rotate(180 200 290)" />
<Path
fill="none"
stroke="#c59b4b"
strokeLinecap="round"
strokeWidth={1.2}
d="M132 62c8-4 16 2 24-2 4-2 2-6-2-4m114 6c-8-4-16 2-24-2-4-2-2-6 2-4"
/>
<Use href="#b4" transform="translate(0 310)" />
<Use href="#b4" transform="matrix(-1 0 0 1 400 310)" />
<Path
fill="none"
stroke="#c59b4b"
strokeLinecap="square"
strokeWidth={2.2}
d="M114 278v-58h54m118 58v-58h-54M114 342v58h54m118-58v58h-54"
/>
{/* QR Placeholder / Live QR */}
<G transform="translate(125 230)">
<Rect
width={150}
height={150}
fill="#fff"
stroke="#eae5d9"
strokeWidth={1.5}
rx={12}
/>
) : (
<>
<Rect
width={134}
height={134}
{qrBase64 ? (
<Image
href={`data:image/png;base64,${qrBase64}`}
x={8}
y={8}
fill="#fafaf8"
stroke="#c59b4b"
strokeDasharray="4 3"
strokeOpacity={0.35}
rx={8}
width={134}
height={134}
/>
<Text
x={75}
y={79}
fill="#c59b4b"
fontFamily="Inter, Arial, sans-serif"
fontSize={10}
fontWeight={700}
letterSpacing={1}
textAnchor="middle"
>
{"QR KOD ALANI"}
</Text>
</>
)}
</G>
) : (
<>
<Rect
width={134}
height={134}
x={8}
y={8}
fill="#fafaf8"
stroke="#c59b4b"
strokeDasharray="4 3"
strokeOpacity={0.35}
rx={8}
/>
<Text
x={75}
y={79}
fill="#c59b4b"
fontFamily="System, sans-serif"
fontSize={10}
fontWeight={700}
letterSpacing={1}
textAnchor="middle"
>
{"QR KOD ALANI"}
</Text>
</>
)}
</G>
{/* Metinler */}
<G fill="#111" textAnchor="middle">
{/* Masa No */}
{showTableNo && tableNo ? (
<Text
x={200}
y={56}
fill="#c59b4b"
fontFamily={fontFamily}
fontSize={11}
fontWeight={700}
letterSpacing={1.5}
>
{tableNo}
</Text>
) : null}
{/* Metinler */}
<G fill="#111" textAnchor="middle">
{/* Masa No */}
{table?.visible !== false &&
renderSvgLines({
text: table?.text || "MASA NO: 01",
x: 200,
y: 56,
fill: "#c59b4b",
fontFamily: infoFont,
fontSize: table?.fontSize || 11,
fontWeight: "bold",
letterSpacing: 1.5,
})}
{/* Restoran Başlığı */}
{restaurantName ? (
<Text
x={200}
y={116}
fill="#111111"
fontFamily={fontFamily}
fontSize={26}
fontWeight={700}
letterSpacing={2}
>
{restaurantName}
</Text>
) : null}
{/* Restoran Başlığı (Enter ile alt satıra geçebilir) */}
{rName?.visible !== false &&
renderSvgLines({
text: rName?.text || "THE CRIMSON PETAL",
x: 200,
y: 114,
fill: "#111111",
fontFamily: rNameFont,
fontSize: rName?.fontSize || 24,
fontWeight: "bold",
letterSpacing: 1.5,
})}
{/* Slogan */}
{showSubtitle && subtitle ? (
<Text
x={200}
y={154}
fill="#71717a"
fontFamily={fontFamily}
fontSize={11}
fontWeight={600}
letterSpacing={1.8}
>
{subtitle}
</Text>
) : null}
{/* Slogan */}
{sub?.visible !== false &&
renderSvgLines({
text: sub?.text || "FINE DINING EXPERIENCE",
x: 200,
y: 154,
fill: "#71717a",
fontFamily: subFont,
fontSize: sub?.fontSize || 11,
fontWeight: 600,
letterSpacing: 1.8,
})}
{/* CTA Metni */}
{showCta && ctaText ? (
<Text
x={200}
y={440}
fill="#111111"
fontFamily={fontFamily}
fontSize={15}
fontWeight={700}
letterSpacing={1}
>
{ctaText}
</Text>
) : null}
{/* CTA Metni */}
{cta?.visible !== false &&
renderSvgLines({
text: cta?.text || "MENÜYÜ GÖRMEK İÇİN OKUTUN",
x: 200,
y: 440,
fill: "#111111",
fontFamily: ctaFont,
fontSize: cta?.fontSize || 15,
fontWeight: "bold",
letterSpacing: 1,
})}
{/* WiFi Bilgisi */}
{showWifi && wifiText ? (
<Text
x={200}
y={488}
fill="#71717a"
fontFamily="System, -apple-system, Roboto, sans-serif"
fontSize={10.5}
fontWeight={600}
letterSpacing={0.5}
>
{wifiText}
</Text>
) : null}
{/* WiFi Bilgisi */}
{wifi?.visible !== false &&
renderSvgLines({
text: wifi?.text || "WiFi: CrimsonGuest | Şifre: petal2026",
x: 200,
y: 488,
fill: "#71717a",
fontFamily: infoFont,
fontSize: wifi?.fontSize || 10.5,
fontWeight: 600,
letterSpacing: 0.5,
})}
{/* Sosyal Medya */}
{showSocial && socialText ? (
<Text
x={200}
y={514}
fill="#c59b4b"
fontFamily="System, -apple-system, Roboto, sans-serif"
fontSize={10.5}
fontWeight={600}
letterSpacing={0.5}
>
{socialText}
</Text>
) : null}
</G>
</Svg>
);
{/* Sosyal Medya */}
{social?.visible !== false &&
renderSvgLines({
text: social?.text || "@thecrimsonpetal",
x: 200,
y: 514,
fill: "#c59b4b",
fontFamily: infoFont,
fontSize: social?.fontSize || 10.5,
fontWeight: 600,
letterSpacing: 0.5,
})}
</G>
</Svg>
);
};
export default QrTemplate4;
@@ -6,183 +6,174 @@ import Svg, {
Path,
Text,
} from "react-native-svg";
import type { QrTemplateProps } from "./index";
import { type QrTemplateProps, getFontFamily, renderSvgLines } from "./index";
// eslint-disable-next-line @typescript-eslint/no-require-imports
const bgImage = require("../../../assets/templates/5.png");
const QrTemplate5 = ({
qrBase64,
restaurantName = "THE URBAN FORK",
subtitle = "FRESH FLAVORS DAILY",
tableNo = "MASA NO: 01",
ctaText = "DİJİTAL MENÜYÜ GÖRÜNTÜLE",
wifiText = "WiFi: UrbanFork | Şifre: urban2026",
socialText = "@theurbanfork",
fontFamily = "System, -apple-system, Roboto, Arial, sans-serif",
showTableNo = true,
showSubtitle = true,
showCta = true,
showWifi = true,
showSocial = true,
fields,
...props
}: QrTemplateProps) => (
<Svg width={300} height={394.7} viewBox="0 0 380 500" {...props}>
{/* PNG Arka Plan */}
<Image
width={380}
height={500}
href={bgImage}
preserveAspectRatio="none"
/>
}: 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;
{/* QR Placeholder / Live QR */}
<G transform="translate(108 206)">
<Rect
width={164}
height={164}
fill="#fff"
stroke="#dce5ea"
strokeWidth={1.2}
rx={16}
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={394.7} viewBox="0 0 380 500" {...props}>
{/* PNG Arka Plan */}
<Image
width={380}
height={500}
href={bgImage}
preserveAspectRatio="none"
/>
<Path
fill="none"
stroke="#003554"
strokeLinecap="round"
strokeWidth={3}
d="M6 30V12a6 6 0 0 1 6-6h18m128 24V12a6 6 0 0 0-6-6h-18M6 134v18a6 6 0 0 0 6 6h18m128-24v18a6 6 0 0 1-6 6h-18"
/>
{qrBase64 ? (
<Image
href={`data:image/png;base64,${qrBase64}`}
x={12}
y={12}
width={140}
height={140}
{/* QR Placeholder / Live QR */}
<G transform="translate(108 206)">
<Rect
width={164}
height={164}
fill="#fff"
stroke="#dce5ea"
strokeWidth={1.2}
rx={16}
/>
) : (
<>
<Rect
width={140}
height={140}
<Path
fill="none"
stroke="#003554"
strokeLinecap="round"
strokeWidth={3}
d="M6 30V12a6 6 0 0 1 6-6h18m128 24V12a6 6 0 0 0-6-6h-18M6 134v18a6 6 0 0 0 6 6h18m128-24v18a6 6 0 0 1-6 6h-18"
/>
{qrBase64 ? (
<Image
href={`data:image/png;base64,${qrBase64}`}
x={12}
y={12}
fill="#fafcfd"
stroke="#003554"
strokeDasharray="4 3"
strokeOpacity={0.2}
rx={10}
width={140}
height={140}
/>
<Text
x={82}
y={87}
fill="#003554"
fontFamily="Inter, Arial, sans-serif"
fontSize={11}
fontWeight={700}
letterSpacing={1}
textAnchor="middle"
>
{"QR KOD ALANI"}
</Text>
</>
)}
</G>
) : (
<>
<Rect
width={140}
height={140}
x={12}
y={12}
fill="#fafcfd"
stroke="#003554"
strokeDasharray="4 3"
strokeOpacity={0.2}
rx={10}
/>
<Text
x={82}
y={87}
fill="#003554"
fontFamily="System, sans-serif"
fontSize={11}
fontWeight={700}
letterSpacing={1}
textAnchor="middle"
>
{"QR KOD ALANI"}
</Text>
</>
)}
</G>
{/* Metinler */}
<G fill="#003554" textAnchor="middle">
{/* Masa Numarası */}
{showTableNo && tableNo ? (
<Text
x={190}
y={40}
fill="#003554"
fontFamily={fontFamily}
fontSize={11}
fontWeight={800}
letterSpacing={1.5}
>
{tableNo}
</Text>
) : null}
{/* Metinler */}
<G fill="#003554" textAnchor="middle">
{/* Masa Numarası */}
{table?.visible !== false &&
renderSvgLines({
text: table?.text || "MASA NO: 01",
x: 190,
y: 40,
fill: "#003554",
fontFamily: infoFont,
fontSize: table?.fontSize || 11,
fontWeight: "bold",
letterSpacing: 1.5,
})}
{/* Restoran Başlığı */}
{restaurantName ? (
<Text
x={190}
y={86}
fill="#003554"
fontFamily={fontFamily}
fontSize={24}
fontWeight={900}
letterSpacing={1}
>
{restaurantName}
</Text>
) : null}
{/* Restoran Başlığı */}
{rName?.visible !== false &&
renderSvgLines({
text: rName?.text || "THE URBAN FORK",
x: 190,
y: 86,
fill: "#003554",
fontFamily: rNameFont,
fontSize: rName?.fontSize || 24,
fontWeight: "bold",
letterSpacing: 1,
})}
{/* Yönlendirme (CTA) */}
{showCta && ctaText ? (
<Text
x={190}
y={160}
fill="#003554"
fontFamily={fontFamily}
fontSize={13}
fontWeight={800}
letterSpacing={0.5}
>
{ctaText}
</Text>
) : null}
{/* Yönlendirme (CTA) */}
{cta?.visible !== false &&
renderSvgLines({
text: cta?.text || "DİJİTAL MENÜYÜ GÖRÜNTÜLE",
x: 190,
y: 160,
fill: "#003554",
fontFamily: ctaFont,
fontSize: cta?.fontSize || 13,
fontWeight: "bold",
letterSpacing: 0.5,
})}
{/* Slogan */}
{showSubtitle && subtitle ? (
<Text
x={190}
y={402}
fill="#003554"
fontFamily={fontFamily}
fontSize={14}
fontWeight={900}
letterSpacing={0.8}
>
{subtitle}
</Text>
) : null}
{/* Slogan (Enter ile çok satır olabilir) */}
{sub?.visible !== false &&
renderSvgLines({
text: sub?.text || "FRESH FLAVORS DAILY",
x: 190,
y: 402,
fill: "#003554",
fontFamily: subFont,
fontSize: sub?.fontSize || 13,
fontWeight: "bold",
letterSpacing: 0.8,
})}
{/* WiFi */}
{showWifi && wifiText ? (
<Text
x={190}
y={430}
fill="#003554"
fontFamily="System, -apple-system, Roboto, sans-serif"
fontSize={10}
fontWeight={700}
letterSpacing={0.2}
>
{wifiText}
</Text>
) : null}
{/* WiFi */}
{wifi?.visible !== false &&
renderSvgLines({
text: wifi?.text || "WiFi: UrbanFork | Şifre: urban2026",
x: 190,
y: 430,
fill: "#003554",
fontFamily: infoFont,
fontSize: wifi?.fontSize || 10,
fontWeight: 700,
letterSpacing: 0.2,
})}
{/* Sosyal Medya */}
{showSocial && socialText ? (
<Text
x={190}
y={454}
fill="#003554"
fontFamily="System, -apple-system, Roboto, sans-serif"
fontSize={10}
fontWeight={700}
letterSpacing={0.2}
>
{socialText}
</Text>
) : null}
</G>
</Svg>
);
{/* Sosyal Medya */}
{social?.visible !== false &&
renderSvgLines({
text: social?.text || "@theurbanfork",
x: 190,
y: 454,
fill: "#003554",
fontFamily: infoFont,
fontSize: social?.fontSize || 10,
fontWeight: 700,
letterSpacing: 0.2,
})}
</G>
</Svg>
);
};
export default QrTemplate5;
@@ -7,246 +7,202 @@ import Svg, {
Text,
Image,
} from "react-native-svg";
import type { QrTemplateProps } from "./index";
import { type QrTemplateProps, getFontFamily, renderSvgLines } from "./index";
const QrTemplateLumiere = ({
qrBase64,
restaurantName = "LUMIÈRE",
subtitle = "RESTAURANT & BAR | MODERN CUISINE",
tableNo = "MASA NO: 01",
ctaText = "MENÜYÜ GÖRMEK İÇİN OKUTUN",
wifiText = "WiFi: Lumiere_Guest | Şifre: lumiere2026",
socialText = "Rezervasyon: 0212 555 0199",
fontFamily = "'Playfair Display', Georgia, serif",
showTableNo = true,
showSubtitle = true,
showCta = true,
showWifi = true,
showSocial = true,
fields,
...props
}: QrTemplateProps) => (
<Svg
viewBox="0 0 600 600"
width={300}
height={300}
{...props}
>
<Path fill="#0b0d13" d="M0 0h600v600H0z" />
<Rect
width={560}
height={560}
x={20}
y={20}
fill="#132034"
stroke="#d4af37"
strokeWidth={1.5}
rx={24}
/>
<Path
fill="none"
stroke="#d4af37"
strokeOpacity={0.85}
strokeWidth={1.5}
d="M56 40h488a16 16 0 0 1 16 16v488a16 16 0 0 1-16 16H56a16 16 0 0 1-16-16V56a16 16 0 0 1 16-16Z"
/>
<Rect
width={504}
height={504}
x={48}
y={48}
fill="none"
stroke="#c5a059"
strokeOpacity={0.45}
strokeWidth={0.8}
rx={8}
/>
{/* Köşe süslemeleri */}
<Path
fill="none"
stroke="#d4af37"
strokeWidth={1.5}
d="M40 68a18 18 0 0 0 28-28"
/>
<Circle cx={52} cy={52} r={2} fill="#d4af37" />
<Path
fill="none"
stroke="#d4af37"
strokeWidth={1.5}
d="M560 68a18 18 0 0 1-28-28"
/>
<Circle cx={548} cy={52} r={2} fill="#d4af37" />
<Path
fill="none"
stroke="#d4af37"
strokeWidth={1.5}
d="M40 532a18 18 0 0 1 28 28"
/>
<Circle cx={52} cy={548} r={2} fill="#d4af37" />
<Path
fill="none"
stroke="#d4af37"
strokeWidth={1.5}
d="M560 532a18 18 0 0 0-28 28"
/>
<Circle cx={548} cy={548} r={2} fill="#d4af37" />
}: 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;
{/* Merkez amblem */}
<G transform="translate(300 85)">
<Path
fill="none"
stroke="#d4af37"
strokeLinejoin="round"
strokeWidth={2}
d="M0-26C-8-16-8-6 0 0c8-6 8-16 0-26Z"
/>
<Path fill="#d4af37" d="M0-18C-4-12-4-4 0 0c4-4 4-12 0-18" />
<Path
fill="none"
stroke="#d4af37"
strokeLinejoin="round"
strokeWidth={2}
d="M-3 3c-13-2-25 7-21 21C-12 24-3 12-3 3Zm6 0c13-2 25 7 21 21C12 24 3 12 3 3Z"
/>
<Circle cy={10} r={1.8} fill="#d4af37" />
</G>
const rNameFont = getFontFamily(rName?.fontId, "Georgia, 'Playfair Display', serif");
const subFont = getFontFamily(sub?.fontId, "System, -apple-system, Roboto, sans-serif");
const ctaFont = getFontFamily(cta?.fontId, "Georgia, 'Playfair Display', serif");
const infoFont = getFontFamily(wifi?.fontId, "System, -apple-system, Roboto, sans-serif");
{/* Yatay çizgi */}
<Path
stroke="#d4af37"
strokeOpacity={0.4}
strokeWidth={0.8}
d="M120 198h360"
/>
{/* QR Placeholder / Gerçek QR */}
<G transform="translate(190 215)">
return (
<Svg viewBox="0 0 600 600" width={300} height={300} {...props}>
<Path fill="#0b0d13" d="M0 0h600v600H0z" />
<Rect
width={220}
height={220}
fill="#fff"
width={560}
height={560}
x={20}
y={20}
fill="#132034"
stroke="#d4af37"
strokeWidth={2}
rx={20}
strokeWidth={1.5}
rx={24}
/>
{qrBase64 ? (
<Image
href={`data:image/png;base64,${qrBase64}`}
x={10}
y={10}
width={200}
height={200}
<Path
fill="none"
stroke="#d4af37"
strokeOpacity={0.85}
strokeWidth={1.5}
d="M56 40h488a16 16 0 0 1 16 16v488a16 16 0 0 1-16 16H56a16 16 0 0 1-16-16V56a16 16 0 0 1 16-16Z"
/>
<Rect
width={504}
height={504}
x={48}
y={48}
fill="none"
stroke="#c5a059"
strokeOpacity={0.45}
strokeWidth={0.8}
rx={8}
/>
{/* Köşe süslemeleri */}
<Path fill="none" stroke="#d4af37" strokeWidth={1.5} d="M40 68a18 18 0 0 0 28-28" />
<Circle cx={52} cy={52} r={2} fill="#d4af37" />
<Path fill="none" stroke="#d4af37" strokeWidth={1.5} d="M560 68a18 18 0 0 1-28-28" />
<Circle cx={548} cy={52} r={2} fill="#d4af37" />
<Path fill="none" stroke="#d4af37" strokeWidth={1.5} d="M40 532a18 18 0 0 1 28 28" />
<Circle cx={52} cy={548} r={2} fill="#d4af37" />
<Path fill="none" stroke="#d4af37" strokeWidth={1.5} d="M560 532a18 18 0 0 0-28 28" />
<Circle cx={548} cy={548} r={2} fill="#d4af37" />
{/* Merkez amblem */}
<G transform="translate(300 85)">
<Path
fill="none"
stroke="#d4af37"
strokeLinejoin="round"
strokeWidth={2}
d="M0-26C-8-16-8-6 0 0c8-6 8-16 0-26Z"
/>
) : (
<>
<Rect
width={196}
height={196}
x={12}
y={12}
fill="#fafafa"
stroke="#d4af37"
strokeDasharray="4 3"
strokeOpacity={0.4}
rx={14}
<Path fill="#d4af37" d="M0-18C-4-12-4-4 0 0c4-4 4-12 0-18" />
<Path
fill="none"
stroke="#d4af37"
strokeLinejoin="round"
strokeWidth={2}
d="M-3 3c-13-2-25 7-21 21C-12 24-3 12-3 3Zm6 0c13-2 25 7 21 21C12 24 3 12 3 3Z"
/>
<Circle cy={10} r={1.8} fill="#d4af37" />
</G>
{/* Yatay çizgi */}
<Path stroke="#d4af37" strokeOpacity={0.4} strokeWidth={0.8} d="M120 198h360" />
{/* QR Placeholder / Gerçek QR */}
<G transform="translate(190 215)">
<Rect width={220} height={220} fill="#fff" stroke="#d4af37" strokeWidth={2} rx={20} />
{qrBase64 ? (
<Image
href={`data:image/png;base64,${qrBase64}`}
x={10}
y={10}
width={200}
height={200}
/>
<Text
x={110}
y={115}
fill="#71717a"
fontFamily="Inter, Arial, sans-serif"
fontSize={12}
fontWeight={600}
textAnchor="middle"
>
{"QR KOD ALANI"}
</Text>
</>
)}
</G>
) : (
<>
<Rect
width={196}
height={196}
x={12}
y={12}
fill="#fafafa"
stroke="#d4af37"
strokeDasharray="4 3"
strokeOpacity={0.4}
rx={14}
/>
<Text
x={110}
y={115}
fill="#71717a"
fontFamily="System, sans-serif"
fontSize={12}
fontWeight={600}
textAnchor="middle"
>
{"QR KOD ALANI"}
</Text>
</>
)}
</G>
{/* Metinler */}
<G textAnchor="middle">
{/* Restoran Adı */}
{restaurantName ? (
<Text
x={300}
y={150}
fill="#d4af37"
fontFamily={fontFamily}
fontSize={32}
fontWeight={700}
letterSpacing={4}
>
{restaurantName}
</Text>
) : null}
{/* Metinler (Çok satırlı ve bağımsız font destekli) */}
<G textAnchor="middle">
{/* Restoran Adı */}
{rName?.visible !== false &&
renderSvgLines({
text: rName?.text || "LUMIÈRE",
x: 300,
y: 148,
fill: "#d4af37",
fontFamily: rNameFont,
fontSize: rName?.fontSize || 30,
fontWeight: "bold",
letterSpacing: 4,
})}
{/* Slogan / Alt Başlık */}
{showSubtitle && subtitle ? (
<Text
x={300}
y={180}
fill="#e5c378"
fontFamily="Inter, Arial, sans-serif"
fontSize={11}
fontWeight={600}
letterSpacing={3}
>
{subtitle}
</Text>
) : null}
{/* Slogan / Alt Başlık (Enter ile alt satıra geçebilir) */}
{sub?.visible !== false &&
renderSvgLines({
text: sub?.text || "RESTAURANT & BAR | MODERN CUISINE",
x: 300,
y: 178,
fill: "#e5c378",
fontFamily: subFont,
fontSize: sub?.fontSize || 11,
fontWeight: 600,
letterSpacing: 2.5,
})}
{/* CTA / Yönlendirme */}
{showCta && ctaText ? (
<Text
x={300}
y={472}
fill="#d4af37"
fontFamily={fontFamily}
fontSize={13}
fontWeight={700}
letterSpacing={2}
>
{ctaText}
</Text>
) : null}
{/* CTA */}
{cta?.visible !== false &&
renderSvgLines({
text: cta?.text || "MENÜYÜ GÖRMEK İÇİN OKUTUN",
x: 300,
y: 472,
fill: "#d4af37",
fontFamily: ctaFont,
fontSize: cta?.fontSize || 13,
fontWeight: "bold",
letterSpacing: 2,
})}
{/* Sosyal / İletişim */}
{showSocial && socialText ? (
<Text
x={300}
y={508}
fill="#e2ddd2"
fontFamily="Inter, Arial, sans-serif"
fontSize={10.5}
fontWeight={500}
letterSpacing={1}
>
{socialText}
</Text>
) : null}
{/* Sosyal Medya / İletişim */}
{social?.visible !== false &&
renderSvgLines({
text: social?.text || "Rezervasyon: 0212 555 0199",
x: 300,
y: 504,
fill: "#e2ddd2",
fontFamily: infoFont,
fontSize: social?.fontSize || 10.5,
fontWeight: 500,
letterSpacing: 1,
})}
{/* Masa No & WiFi */}
{showTableNo || showWifi ? (
<Text
x={300}
y={528}
fill="#c5a059"
fontFamily="Inter, Arial, sans-serif"
fontSize={10}
fontWeight={600}
letterSpacing={1}
>
{[
showTableNo && tableNo ? tableNo : "",
showWifi && wifiText ? wifiText : "",
]
.filter(Boolean)
.join(" • ")}
</Text>
) : null}
</G>
</Svg>
);
{/* Masa No & WiFi */}
{(table?.visible !== false || wifi?.visible !== false) &&
renderSvgLines({
text: [
table?.visible !== false && table?.text ? table.text : "",
wifi?.visible !== false && wifi?.text ? wifi.text : "",
]
.filter(Boolean)
.join(" • "),
x: 300,
y: 526,
fill: "#c5a059",
fontFamily: infoFont,
fontSize: table?.fontSize || wifi?.fontSize || 10,
fontWeight: 600,
letterSpacing: 1,
})}
</G>
</Svg>
);
};
export default QrTemplateLumiere;
@@ -1,77 +0,0 @@
import type React from "react";
import type { SvgProps } from "react-native-svg";
import QrTemplate1 from "./QrTemplateLumiere";
import QrTemplate2 from "./QrTemplate2";
import QrTemplate3 from "./QrTemplate3";
import QrTemplate4 from "./QrTemplate4";
import QrTemplate5 from "./QrTemplate5";
export interface QrCustomTextConfig {
restaurantName?: string;
subtitle?: string;
tableNo?: string;
ctaText?: string;
wifiText?: string;
socialText?: string;
fontFamily?: string;
// Görünürlük anahtarları
showTableNo?: boolean;
showSubtitle?: boolean;
showCta?: boolean;
showWifi?: boolean;
showSocial?: boolean;
}
export interface QrTemplateProps extends SvgProps, QrCustomTextConfig {
qrBase64?: string;
}
// Türkçe karakterleri (İ, ı, Ş, ş, Ğ, ğ, Ü, ü, Ö, ö, Ç, ç) eksiksiz destekleyen sistem fontları
export const FONT_OPTIONS = [
{
id: "sans",
label: "Modern Sans (Sistem)",
fontFamily: "System, -apple-system, Roboto, 'Helvetica Neue', Arial, sans-serif",
},
{
id: "serif",
label: "Zarif Serif (Georgia)",
fontFamily: "Georgia, 'Times New Roman', serif",
},
{
id: "times",
label: "Klasik (Times New Roman)",
fontFamily: "'Times New Roman', Times, Georgia, serif",
},
{
id: "palatino",
label: "Lüks Palatino",
fontFamily: "Palatino, 'Palatino Linotype', Georgia, serif",
},
{
id: "trebuchet",
label: "Dinamik (Trebuchet)",
fontFamily: "'Trebuchet MS', 'Segoe UI', Arial, sans-serif",
},
];
// Yeni component eklemek için buraya import edip COMPONENT_TEMPLATES'e kaydet
export const COMPONENT_TEMPLATES: Record<
string,
React.FC<QrTemplateProps>
> = {
"qr-1": QrTemplate1,
"qr-2": QrTemplate2,
"qr-3": QrTemplate3,
"qr-4": QrTemplate4,
"qr-5": QrTemplate5,
};
// Her template'in aspect ratio'su (width/height)
export const TEMPLATE_ASPECT_RATIOS: Record<string, number> = {
"qr-1": 1, // 600x600 = 1:1
"qr-2": 400 / 650, // 400x650 = standart kart
"qr-3": 400 / 650, // 400x650 = standart kart
"qr-4": 400 / 580, // 400x580 = zarif altın çerçeve
"qr-5": 380 / 500, // 380x500 = PNG arka planlı modern kart
};
@@ -0,0 +1,133 @@
import React from "react";
import { Text as SvgText, type SvgProps } from "react-native-svg";
import QrTemplate1 from "./QrTemplateLumiere";
import QrTemplate2 from "./QrTemplate2";
import QrTemplate3 from "./QrTemplate3";
import QrTemplate4 from "./QrTemplate4";
import QrTemplate5 from "./QrTemplate5";
export interface TextItemConfig {
text: string;
fontSize?: number;
fontId?: string;
visible?: boolean;
}
export interface QrCustomFields {
restaurantName: TextItemConfig;
subtitle: TextItemConfig;
tableNo: TextItemConfig;
ctaText: TextItemConfig;
wifiText: TextItemConfig;
socialText: TextItemConfig;
}
export interface QrTemplateProps extends SvgProps {
qrBase64?: string;
fields?: Partial<QrCustomFields>;
}
// Türkçe karakterleri (İ, ı, Ş, ş, Ğ, ğ, Ü, ü, Ö, ö, Ç, ç) eksiksiz destekleyen sistem fontları
export const FONT_OPTIONS = [
{
id: "sans",
label: "Modern Sans",
fontFamily: "System, -apple-system, Roboto, 'Helvetica Neue', Arial, sans-serif",
},
{
id: "serif",
label: "Zarif Serif",
fontFamily: "Georgia, 'Times New Roman', serif",
},
{
id: "times",
label: "Klasik (Times)",
fontFamily: "'Times New Roman', Times, Georgia, serif",
},
{
id: "palatino",
label: "Lüks Palatino",
fontFamily: "Palatino, 'Palatino Linotype', Georgia, serif",
},
{
id: "trebuchet",
label: "Dinamik",
fontFamily: "'Trebuchet MS', 'Segoe UI', Arial, sans-serif",
},
];
export function getFontFamily(fontId?: string, defaultFamily = "Georgia, serif"): string {
if (!fontId) return defaultFamily;
const found = FONT_OPTIONS.find((f) => f.id === fontId);
return found ? found.fontFamily : defaultFamily;
}
// Çok satırlı (Enter / \n) metinleri SVG içinde alt alta kusursuz render eden yardımcı fonksiyon
export function renderSvgLines({
text,
x,
y,
lineHeight,
fill,
fontFamily,
fontSize,
fontWeight = "normal",
letterSpacing,
textAnchor = "middle",
}: {
text?: string;
x: number;
y: number;
lineHeight?: number;
fill?: string;
fontFamily?: string;
fontSize?: number;
fontWeight?: string | number;
letterSpacing?: number;
textAnchor?: "middle" | "start" | "end";
}) {
if (!text) return null;
const lines = text.split("\n");
const computedLineHeight = lineHeight || (fontSize ? fontSize * 1.25 : 18);
return (
<>
{lines.map((line, idx) => (
<SvgText
key={idx}
x={x}
y={y + idx * computedLineHeight}
fill={fill}
fontFamily={fontFamily}
fontSize={fontSize}
fontWeight={fontWeight}
letterSpacing={letterSpacing}
textAnchor={textAnchor}
>
{line}
</SvgText>
))}
</>
);
}
// Yeni component eklemek için buraya import edip COMPONENT_TEMPLATES'e kaydet
export const COMPONENT_TEMPLATES: Record<
string,
React.FC<QrTemplateProps>
> = {
"qr-1": QrTemplate1,
"qr-2": QrTemplate2,
"qr-3": QrTemplate3,
"qr-4": QrTemplate4,
"qr-5": QrTemplate5,
};
// Her template'in aspect ratio'su (width/height)
export const TEMPLATE_ASPECT_RATIOS: Record<string, number> = {
"qr-1": 1, // 600x600 = 1:1
"qr-2": 400 / 650, // 400x650 = standart kart
"qr-3": 400 / 650, // 400x650 = standart kart
"qr-4": 400 / 580, // 400x580 = zarif altın çerçeve
"qr-5": 380 / 500, // 380x500 = PNG arka planlı modern kart
};