feat: redesign web menu layout, add header cover banner & dynamic header layout, refine mobile inputs and theme selector
This commit is contained in:
@@ -13,3 +13,5 @@ build/
|
|||||||
supabase/.branches/
|
supabase/.branches/
|
||||||
supabase/.temp/
|
supabase/.temp/
|
||||||
coverage/
|
coverage/
|
||||||
|
*.ipa
|
||||||
|
*.apk
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { Link, router } from "expo-router";
|
import { Link, router } from "expo-router";
|
||||||
import { ActivityIndicator, Pressable, Text, TextInput, View } from "react-native";
|
import { ActivityIndicator, Image, Pressable, Text, TextInput, View } from "react-native";
|
||||||
import { Ionicons } from "@expo/vector-icons";
|
import { Ionicons } from "@expo/vector-icons";
|
||||||
import { supabase } from "@/lib/supabase";
|
import { supabase } from "@/lib/supabase";
|
||||||
|
|
||||||
@@ -30,28 +30,24 @@ export default function LoginScreen() {
|
|||||||
<View style={{ maxWidth: 400, width: "100%", alignSelf: "center" }}>
|
<View style={{ maxWidth: 400, width: "100%", alignSelf: "center" }}>
|
||||||
{/* Brand Icon Header */}
|
{/* Brand Icon Header */}
|
||||||
<View style={{ alignItems: "center", marginBottom: 28 }}>
|
<View style={{ alignItems: "center", marginBottom: 28 }}>
|
||||||
<View
|
<Image
|
||||||
|
source={require("../../../assets/icon.png")}
|
||||||
style={{
|
style={{
|
||||||
width: 64,
|
width: 72,
|
||||||
height: 64,
|
height: 72,
|
||||||
borderRadius: 32,
|
borderRadius: 18,
|
||||||
backgroundColor: "#1C1917",
|
|
||||||
alignItems: "center",
|
|
||||||
justifyContent: "center",
|
|
||||||
marginBottom: 14,
|
marginBottom: 14,
|
||||||
shadowColor: "#000",
|
shadowColor: "#000",
|
||||||
shadowOffset: { width: 0, height: 4 },
|
shadowOffset: { width: 0, height: 4 },
|
||||||
shadowOpacity: 0.15,
|
shadowOpacity: 0.12,
|
||||||
shadowRadius: 10,
|
shadowRadius: 8,
|
||||||
elevation: 4,
|
|
||||||
}}
|
}}
|
||||||
>
|
resizeMode="contain"
|
||||||
<Ionicons name="restaurant-outline" size={30} color="#C8A96B" />
|
/>
|
||||||
</View>
|
<Text style={{ fontSize: 28, fontWeight: "800", color: "#1C1917", letterSpacing: -0.5 }}>
|
||||||
<Text style={{ fontSize: 26, fontWeight: "800", color: "#1C1917", letterSpacing: -0.5 }}>
|
MenuL.io
|
||||||
Menulio'ya Giriş Yap
|
|
||||||
</Text>
|
</Text>
|
||||||
<Text style={{ fontSize: 13, color: "#78716C", marginTop: 4 }}>
|
<Text style={{ fontSize: 13, color: "#57534E", marginTop: 4, fontWeight: "500" }}>
|
||||||
AI destekli dijital restoran menü yöneticisi
|
AI destekli dijital restoran menü yöneticisi
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
@@ -81,22 +77,22 @@ export default function LoginScreen() {
|
|||||||
flexDirection: "row",
|
flexDirection: "row",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
backgroundColor: "#FFFFFF",
|
backgroundColor: "#FFFFFF",
|
||||||
borderWidth: 1,
|
borderWidth: 1.5,
|
||||||
borderColor: "#E7E5E4",
|
borderColor: "#D6D3D1",
|
||||||
borderRadius: 12,
|
borderRadius: 12,
|
||||||
paddingHorizontal: 14,
|
paddingHorizontal: 14,
|
||||||
marginBottom: 12,
|
marginBottom: 12,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Ionicons name="mail-outline" size={18} color="#A8A29E" style={{ marginRight: 10 }} />
|
<Ionicons name="mail-outline" size={18} color="#57534E" style={{ marginRight: 10 }} />
|
||||||
<TextInput
|
<TextInput
|
||||||
placeholder="E-posta adresiniz"
|
placeholder="E-posta adresiniz"
|
||||||
placeholderTextColor="#A8A29E"
|
placeholderTextColor="#57534E"
|
||||||
autoCapitalize="none"
|
autoCapitalize="none"
|
||||||
keyboardType="email-address"
|
keyboardType="email-address"
|
||||||
value={email}
|
value={email}
|
||||||
onChangeText={setEmail}
|
onChangeText={setEmail}
|
||||||
style={{ flex: 1, paddingVertical: 14, fontSize: 15, color: "#1C1917" }}
|
style={{ flex: 1, paddingVertical: 14, fontSize: 15, color: "#1C1917", fontWeight: "500" }}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
@@ -106,27 +102,27 @@ export default function LoginScreen() {
|
|||||||
flexDirection: "row",
|
flexDirection: "row",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
backgroundColor: "#FFFFFF",
|
backgroundColor: "#FFFFFF",
|
||||||
borderWidth: 1,
|
borderWidth: 1.5,
|
||||||
borderColor: "#E7E5E4",
|
borderColor: "#D6D3D1",
|
||||||
borderRadius: 12,
|
borderRadius: 12,
|
||||||
paddingHorizontal: 14,
|
paddingHorizontal: 14,
|
||||||
marginBottom: 20,
|
marginBottom: 20,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Ionicons name="lock-closed-outline" size={18} color="#A8A29E" style={{ marginRight: 10 }} />
|
<Ionicons name="lock-closed-outline" size={18} color="#57534E" style={{ marginRight: 10 }} />
|
||||||
<TextInput
|
<TextInput
|
||||||
placeholder="Şifreniz"
|
placeholder="Şifreniz"
|
||||||
placeholderTextColor="#A8A29E"
|
placeholderTextColor="#57534E"
|
||||||
secureTextEntry={!showPassword}
|
secureTextEntry={!showPassword}
|
||||||
value={password}
|
value={password}
|
||||||
onChangeText={setPassword}
|
onChangeText={setPassword}
|
||||||
style={{ flex: 1, paddingVertical: 14, fontSize: 15, color: "#1C1917" }}
|
style={{ flex: 1, paddingVertical: 14, fontSize: 15, color: "#1C1917", fontWeight: "500" }}
|
||||||
/>
|
/>
|
||||||
<Pressable onPress={() => setShowPassword(!showPassword)} style={{ padding: 4 }}>
|
<Pressable onPress={() => setShowPassword(!showPassword)} style={{ padding: 4 }}>
|
||||||
<Ionicons
|
<Ionicons
|
||||||
name={showPassword ? "eye-off-outline" : "eye-outline"}
|
name={showPassword ? "eye-off-outline" : "eye-outline"}
|
||||||
size={18}
|
size={18}
|
||||||
color="#A8A29E"
|
color="#57534E"
|
||||||
/>
|
/>
|
||||||
</Pressable>
|
</Pressable>
|
||||||
</View>
|
</View>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { Link, router } from "expo-router";
|
import { Link, router } from "expo-router";
|
||||||
import { ActivityIndicator, Pressable, Text, TextInput, View } from "react-native";
|
import { ActivityIndicator, Image, Pressable, Text, TextInput, View } from "react-native";
|
||||||
import { Ionicons } from "@expo/vector-icons";
|
import { Ionicons } from "@expo/vector-icons";
|
||||||
import { supabase } from "@/lib/supabase";
|
import { supabase } from "@/lib/supabase";
|
||||||
|
|
||||||
@@ -35,28 +35,24 @@ export default function RegisterScreen() {
|
|||||||
<View style={{ maxWidth: 400, width: "100%", alignSelf: "center" }}>
|
<View style={{ maxWidth: 400, width: "100%", alignSelf: "center" }}>
|
||||||
{/* Brand Icon Header */}
|
{/* Brand Icon Header */}
|
||||||
<View style={{ alignItems: "center", marginBottom: 28 }}>
|
<View style={{ alignItems: "center", marginBottom: 28 }}>
|
||||||
<View
|
<Image
|
||||||
|
source={require("../../../assets/icon.png")}
|
||||||
style={{
|
style={{
|
||||||
width: 64,
|
width: 72,
|
||||||
height: 64,
|
height: 72,
|
||||||
borderRadius: 32,
|
borderRadius: 18,
|
||||||
backgroundColor: "#1C1917",
|
|
||||||
alignItems: "center",
|
|
||||||
justifyContent: "center",
|
|
||||||
marginBottom: 14,
|
marginBottom: 14,
|
||||||
shadowColor: "#000",
|
shadowColor: "#000",
|
||||||
shadowOffset: { width: 0, height: 4 },
|
shadowOffset: { width: 0, height: 4 },
|
||||||
shadowOpacity: 0.15,
|
shadowOpacity: 0.12,
|
||||||
shadowRadius: 10,
|
shadowRadius: 8,
|
||||||
elevation: 4,
|
|
||||||
}}
|
}}
|
||||||
>
|
resizeMode="contain"
|
||||||
<Ionicons name="sparkles" size={28} color="#C8A96B" />
|
/>
|
||||||
</View>
|
<Text style={{ fontSize: 28, fontWeight: "800", color: "#1C1917", letterSpacing: -0.5 }}>
|
||||||
<Text style={{ fontSize: 26, fontWeight: "800", color: "#1C1917", letterSpacing: -0.5 }}>
|
MenuL.io
|
||||||
Hesap Oluştur
|
|
||||||
</Text>
|
</Text>
|
||||||
<Text style={{ fontSize: 13, color: "#78716C", marginTop: 4 }}>
|
<Text style={{ fontSize: 13, color: "#57534E", marginTop: 4, fontWeight: "500" }}>
|
||||||
Dakikalar içinde restoranınızı ve QR menünüzü hazırlayın
|
Dakikalar içinde restoranınızı ve QR menünüzü hazırlayın
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
@@ -86,22 +82,22 @@ export default function RegisterScreen() {
|
|||||||
flexDirection: "row",
|
flexDirection: "row",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
backgroundColor: "#FFFFFF",
|
backgroundColor: "#FFFFFF",
|
||||||
borderWidth: 1,
|
borderWidth: 1.5,
|
||||||
borderColor: "#E7E5E4",
|
borderColor: "#D6D3D1",
|
||||||
borderRadius: 12,
|
borderRadius: 12,
|
||||||
paddingHorizontal: 14,
|
paddingHorizontal: 14,
|
||||||
marginBottom: 12,
|
marginBottom: 12,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Ionicons name="mail-outline" size={18} color="#A8A29E" style={{ marginRight: 10 }} />
|
<Ionicons name="mail-outline" size={18} color="#57534E" style={{ marginRight: 10 }} />
|
||||||
<TextInput
|
<TextInput
|
||||||
placeholder="E-posta adresiniz"
|
placeholder="E-posta adresiniz"
|
||||||
placeholderTextColor="#A8A29E"
|
placeholderTextColor="#57534E"
|
||||||
autoCapitalize="none"
|
autoCapitalize="none"
|
||||||
keyboardType="email-address"
|
keyboardType="email-address"
|
||||||
value={email}
|
value={email}
|
||||||
onChangeText={setEmail}
|
onChangeText={setEmail}
|
||||||
style={{ flex: 1, paddingVertical: 14, fontSize: 15, color: "#1C1917" }}
|
style={{ flex: 1, paddingVertical: 14, fontSize: 15, color: "#1C1917", fontWeight: "500" }}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
@@ -111,27 +107,27 @@ export default function RegisterScreen() {
|
|||||||
flexDirection: "row",
|
flexDirection: "row",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
backgroundColor: "#FFFFFF",
|
backgroundColor: "#FFFFFF",
|
||||||
borderWidth: 1,
|
borderWidth: 1.5,
|
||||||
borderColor: "#E7E5E4",
|
borderColor: "#D6D3D1",
|
||||||
borderRadius: 12,
|
borderRadius: 12,
|
||||||
paddingHorizontal: 14,
|
paddingHorizontal: 14,
|
||||||
marginBottom: 20,
|
marginBottom: 20,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Ionicons name="lock-closed-outline" size={18} color="#A8A29E" style={{ marginRight: 10 }} />
|
<Ionicons name="lock-closed-outline" size={18} color="#57534E" style={{ marginRight: 10 }} />
|
||||||
<TextInput
|
<TextInput
|
||||||
placeholder="Güçlü bir şifre belirleyin"
|
placeholder="Güçlü bir şifre belirleyin"
|
||||||
placeholderTextColor="#A8A29E"
|
placeholderTextColor="#57534E"
|
||||||
secureTextEntry={!showPassword}
|
secureTextEntry={!showPassword}
|
||||||
value={password}
|
value={password}
|
||||||
onChangeText={setPassword}
|
onChangeText={setPassword}
|
||||||
style={{ flex: 1, paddingVertical: 14, fontSize: 15, color: "#1C1917" }}
|
style={{ flex: 1, paddingVertical: 14, fontSize: 15, color: "#1C1917", fontWeight: "500" }}
|
||||||
/>
|
/>
|
||||||
<Pressable onPress={() => setShowPassword(!showPassword)} style={{ padding: 4 }}>
|
<Pressable onPress={() => setShowPassword(!showPassword)} style={{ padding: 4 }}>
|
||||||
<Ionicons
|
<Ionicons
|
||||||
name={showPassword ? "eye-off-outline" : "eye-outline"}
|
name={showPassword ? "eye-off-outline" : "eye-outline"}
|
||||||
size={18}
|
size={18}
|
||||||
color="#A8A29E"
|
color="#57534E"
|
||||||
/>
|
/>
|
||||||
</Pressable>
|
</Pressable>
|
||||||
</View>
|
</View>
|
||||||
|
|||||||
@@ -96,20 +96,20 @@ export default function OnboardingRestaurantStep() {
|
|||||||
flexDirection: "row",
|
flexDirection: "row",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
backgroundColor: "#FFFFFF",
|
backgroundColor: "#FFFFFF",
|
||||||
borderWidth: 1,
|
borderWidth: 1.5,
|
||||||
borderColor: "#E7E5E4",
|
borderColor: "#D6D3D1",
|
||||||
borderRadius: 12,
|
borderRadius: 12,
|
||||||
paddingHorizontal: 14,
|
paddingHorizontal: 14,
|
||||||
marginBottom: 12,
|
marginBottom: 12,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Ionicons name="storefront-outline" size={18} color="#A8A29E" style={{ marginRight: 10 }} />
|
<Ionicons name="storefront-outline" size={18} color="#57534E" style={{ marginRight: 10 }} />
|
||||||
<TextInput
|
<TextInput
|
||||||
placeholder="Restoran adı (Örn: Kebapçı Ahmet)"
|
placeholder="Restoran adı (Örn: Kebapçı Ahmet)"
|
||||||
placeholderTextColor="#A8A29E"
|
placeholderTextColor="#57534E"
|
||||||
value={name}
|
value={name}
|
||||||
onChangeText={setName}
|
onChangeText={setName}
|
||||||
style={{ flex: 1, paddingVertical: 14, fontSize: 15, color: "#1C1917" }}
|
style={{ flex: 1, paddingVertical: 14, fontSize: 15, color: "#1C1917", fontWeight: "500" }}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
@@ -119,21 +119,21 @@ export default function OnboardingRestaurantStep() {
|
|||||||
flexDirection: "row",
|
flexDirection: "row",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
backgroundColor: "#FFFFFF",
|
backgroundColor: "#FFFFFF",
|
||||||
borderWidth: 1,
|
borderWidth: 1.5,
|
||||||
borderColor: "#E7E5E4",
|
borderColor: "#D6D3D1",
|
||||||
borderRadius: 12,
|
borderRadius: 12,
|
||||||
paddingHorizontal: 14,
|
paddingHorizontal: 14,
|
||||||
marginBottom: 12,
|
marginBottom: 12,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Ionicons name="call-outline" size={18} color="#A8A29E" style={{ marginRight: 10 }} />
|
<Ionicons name="call-outline" size={18} color="#57534E" style={{ marginRight: 10 }} />
|
||||||
<TextInput
|
<TextInput
|
||||||
placeholder="Telefon numarası (opsiyonel)"
|
placeholder="Telefon numarası (opsiyonel)"
|
||||||
placeholderTextColor="#A8A29E"
|
placeholderTextColor="#57534E"
|
||||||
keyboardType="phone-pad"
|
keyboardType="phone-pad"
|
||||||
value={phone}
|
value={phone}
|
||||||
onChangeText={setPhone}
|
onChangeText={setPhone}
|
||||||
style={{ flex: 1, paddingVertical: 14, fontSize: 15, color: "#1C1917" }}
|
style={{ flex: 1, paddingVertical: 14, fontSize: 15, color: "#1C1917", fontWeight: "500" }}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
@@ -143,20 +143,20 @@ export default function OnboardingRestaurantStep() {
|
|||||||
flexDirection: "row",
|
flexDirection: "row",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
backgroundColor: "#FFFFFF",
|
backgroundColor: "#FFFFFF",
|
||||||
borderWidth: 1,
|
borderWidth: 1.5,
|
||||||
borderColor: "#E7E5E4",
|
borderColor: "#D6D3D1",
|
||||||
borderRadius: 12,
|
borderRadius: 12,
|
||||||
paddingHorizontal: 14,
|
paddingHorizontal: 14,
|
||||||
marginBottom: 24,
|
marginBottom: 24,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Ionicons name="location-outline" size={18} color="#A8A29E" style={{ marginRight: 10 }} />
|
<Ionicons name="location-outline" size={18} color="#57534E" style={{ marginRight: 10 }} />
|
||||||
<TextInput
|
<TextInput
|
||||||
placeholder="Adres / Şehir (opsiyonel)"
|
placeholder="Adres / Şehir (opsiyonel)"
|
||||||
placeholderTextColor="#A8A29E"
|
placeholderTextColor="#57534E"
|
||||||
value={address}
|
value={address}
|
||||||
onChangeText={setAddress}
|
onChangeText={setAddress}
|
||||||
style={{ flex: 1, paddingVertical: 14, fontSize: 15, color: "#1C1917" }}
|
style={{ flex: 1, paddingVertical: 14, fontSize: 15, color: "#1C1917", fontWeight: "500" }}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
|
|||||||
@@ -560,8 +560,8 @@ export default function AccountScreen() {
|
|||||||
flexDirection: "row",
|
flexDirection: "row",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
backgroundColor: "#FAF8F5",
|
backgroundColor: "#FAF8F5",
|
||||||
borderWidth: 1,
|
borderWidth: 1.5,
|
||||||
borderColor: "#E7E5E4",
|
borderColor: "#D6D3D1",
|
||||||
borderRadius: 12,
|
borderRadius: 12,
|
||||||
paddingHorizontal: 12,
|
paddingHorizontal: 12,
|
||||||
}}
|
}}
|
||||||
@@ -570,7 +570,7 @@ export default function AccountScreen() {
|
|||||||
value={newDomainInput}
|
value={newDomainInput}
|
||||||
onChangeText={setNewDomainInput}
|
onChangeText={setNewDomainInput}
|
||||||
placeholder="Örn: menu.kebapciahmet.com"
|
placeholder="Örn: menu.kebapciahmet.com"
|
||||||
placeholderTextColor="#A8A29E"
|
placeholderTextColor="#57534E"
|
||||||
autoCapitalize="none"
|
autoCapitalize="none"
|
||||||
autoCorrect={false}
|
autoCorrect={false}
|
||||||
style={{
|
style={{
|
||||||
@@ -728,15 +728,17 @@ export default function AccountScreen() {
|
|||||||
value={name}
|
value={name}
|
||||||
onChangeText={setName}
|
onChangeText={setName}
|
||||||
placeholder="Restoran Adı"
|
placeholder="Restoran Adı"
|
||||||
|
placeholderTextColor="#57534E"
|
||||||
style={{
|
style={{
|
||||||
backgroundColor: "#FAF8F5",
|
backgroundColor: "#FAF8F5",
|
||||||
borderWidth: 1,
|
borderWidth: 1.5,
|
||||||
borderColor: "#E7E5E4",
|
borderColor: "#D6D3D1",
|
||||||
borderRadius: 10,
|
borderRadius: 10,
|
||||||
paddingHorizontal: 14,
|
paddingHorizontal: 14,
|
||||||
paddingVertical: 12,
|
paddingVertical: 12,
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
color: "#1C1917",
|
color: "#1C1917",
|
||||||
|
fontWeight: "500",
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
@@ -750,16 +752,18 @@ export default function AccountScreen() {
|
|||||||
value={phone}
|
value={phone}
|
||||||
onChangeText={setPhone}
|
onChangeText={setPhone}
|
||||||
placeholder="05xx xxx xx xx"
|
placeholder="05xx xxx xx xx"
|
||||||
|
placeholderTextColor="#57534E"
|
||||||
keyboardType="phone-pad"
|
keyboardType="phone-pad"
|
||||||
style={{
|
style={{
|
||||||
backgroundColor: "#FAF8F5",
|
backgroundColor: "#FAF8F5",
|
||||||
borderWidth: 1,
|
borderWidth: 1.5,
|
||||||
borderColor: "#E7E5E4",
|
borderColor: "#D6D3D1",
|
||||||
borderRadius: 10,
|
borderRadius: 10,
|
||||||
paddingHorizontal: 14,
|
paddingHorizontal: 14,
|
||||||
paddingVertical: 12,
|
paddingVertical: 12,
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
color: "#1C1917",
|
color: "#1C1917",
|
||||||
|
fontWeight: "500",
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
@@ -773,17 +777,19 @@ export default function AccountScreen() {
|
|||||||
value={address}
|
value={address}
|
||||||
onChangeText={setAddress}
|
onChangeText={setAddress}
|
||||||
placeholder="Restoran adresi"
|
placeholder="Restoran adresi"
|
||||||
|
placeholderTextColor="#57534E"
|
||||||
multiline
|
multiline
|
||||||
numberOfLines={2}
|
numberOfLines={2}
|
||||||
style={{
|
style={{
|
||||||
backgroundColor: "#FAF8F5",
|
backgroundColor: "#FAF8F5",
|
||||||
borderWidth: 1,
|
borderWidth: 1.5,
|
||||||
borderColor: "#E7E5E4",
|
borderColor: "#D6D3D1",
|
||||||
borderRadius: 10,
|
borderRadius: 10,
|
||||||
paddingHorizontal: 14,
|
paddingHorizontal: 14,
|
||||||
paddingVertical: 12,
|
paddingVertical: 12,
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
color: "#1C1917",
|
color: "#1C1917",
|
||||||
|
fontWeight: "500",
|
||||||
minHeight: 64,
|
minHeight: 64,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
@@ -806,85 +812,6 @@ export default function AccountScreen() {
|
|||||||
</Text>
|
</Text>
|
||||||
</Pressable>
|
</Pressable>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
{/* Theme Selector */}
|
|
||||||
<View
|
|
||||||
style={{
|
|
||||||
backgroundColor: "#FFFFFF",
|
|
||||||
borderRadius: 20,
|
|
||||||
padding: 20,
|
|
||||||
borderWidth: 1,
|
|
||||||
borderColor: "#E7E5E4",
|
|
||||||
gap: 14,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<View style={{ flexDirection: "row", alignItems: "center", gap: 8 }}>
|
|
||||||
<Ionicons name="color-palette-outline" size={20} color="#C8A96B" />
|
|
||||||
<Text style={{ fontSize: 16, fontWeight: "800", color: "#1C1917" }}>
|
|
||||||
Menü Şablonu (Tema)
|
|
||||||
</Text>
|
|
||||||
</View>
|
|
||||||
<Text style={{ fontSize: 12, color: "#78716C" }}>
|
|
||||||
Restoranınızın konseptine uygun tasarımı seçin. Seçtiğiniz tema QR menünüzde anında aktif olur.
|
|
||||||
</Text>
|
|
||||||
|
|
||||||
<View style={{ gap: 10 }}>
|
|
||||||
{THEME_OPTIONS.map((theme) => {
|
|
||||||
const isSelected = selectedTheme === theme.key;
|
|
||||||
return (
|
|
||||||
<Pressable
|
|
||||||
key={theme.key}
|
|
||||||
onPress={() => handleSelectTheme(theme.key)}
|
|
||||||
style={({ pressed }) => ({
|
|
||||||
flexDirection: "row",
|
|
||||||
alignItems: "center",
|
|
||||||
justifyContent: "space-between",
|
|
||||||
padding: 14,
|
|
||||||
borderRadius: 14,
|
|
||||||
backgroundColor: isSelected ? "#FAF8F5" : "#FAFAFA",
|
|
||||||
borderWidth: 2,
|
|
||||||
borderColor: isSelected ? theme.color : "#E7E5E4",
|
|
||||||
opacity: pressed ? 0.9 : 1,
|
|
||||||
})}
|
|
||||||
>
|
|
||||||
<View style={{ flexDirection: "row", alignItems: "center", gap: 12 }}>
|
|
||||||
<View
|
|
||||||
style={{
|
|
||||||
width: 20,
|
|
||||||
height: 20,
|
|
||||||
borderRadius: 10,
|
|
||||||
backgroundColor: theme.color,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<View>
|
|
||||||
<Text style={{ fontSize: 14, fontWeight: "700", color: "#1C1917" }}>
|
|
||||||
{theme.name}
|
|
||||||
</Text>
|
|
||||||
<Text style={{ fontSize: 11, color: "#78716C", marginTop: 2 }}>
|
|
||||||
{theme.desc}
|
|
||||||
</Text>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View
|
|
||||||
style={{
|
|
||||||
width: 22,
|
|
||||||
height: 22,
|
|
||||||
borderRadius: 11,
|
|
||||||
borderWidth: 2,
|
|
||||||
borderColor: isSelected ? theme.color : "#D6D3D1",
|
|
||||||
backgroundColor: isSelected ? theme.color : "transparent",
|
|
||||||
alignItems: "center",
|
|
||||||
justifyContent: "center",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{isSelected ? <Ionicons name="checkmark" size={14} color="#FFFFFF" /> : null}
|
|
||||||
</View>
|
|
||||||
</Pressable>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -101,12 +101,12 @@ export function AddCategoryModal({
|
|||||||
value={name}
|
value={name}
|
||||||
onChangeText={setName}
|
onChangeText={setName}
|
||||||
placeholder="Örn: Tatlılar, Başlangıçlar, Sıcak İçecekler"
|
placeholder="Örn: Tatlılar, Başlangıçlar, Sıcak İçecekler"
|
||||||
placeholderTextColor="#A8A29E"
|
placeholderTextColor="#57534E"
|
||||||
autoFocus
|
autoFocus
|
||||||
style={{
|
style={{
|
||||||
backgroundColor: "#FAFAFA",
|
backgroundColor: "#FAFAFA",
|
||||||
borderWidth: 1,
|
borderWidth: 1.5,
|
||||||
borderColor: "#E7E5E4",
|
borderColor: "#D6D3D1",
|
||||||
borderRadius: 12,
|
borderRadius: 12,
|
||||||
padding: 14,
|
padding: 14,
|
||||||
fontSize: 15,
|
fontSize: 15,
|
||||||
|
|||||||
@@ -218,11 +218,11 @@ export function AddItemModal({
|
|||||||
value={name}
|
value={name}
|
||||||
onChangeText={setName}
|
onChangeText={setName}
|
||||||
placeholder="Örn: Mercimek Çorbası"
|
placeholder="Örn: Mercimek Çorbası"
|
||||||
placeholderTextColor="#A8A29E"
|
placeholderTextColor="#57534E"
|
||||||
style={{
|
style={{
|
||||||
backgroundColor: "#FAFAFA",
|
backgroundColor: "#FAFAFA",
|
||||||
borderWidth: 1,
|
borderWidth: 1.5,
|
||||||
borderColor: "#E7E5E4",
|
borderColor: "#D6D3D1",
|
||||||
borderRadius: 12,
|
borderRadius: 12,
|
||||||
padding: 14,
|
padding: 14,
|
||||||
fontSize: 15,
|
fontSize: 15,
|
||||||
@@ -241,8 +241,8 @@ export function AddItemModal({
|
|||||||
flexDirection: "row",
|
flexDirection: "row",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
backgroundColor: "#FAFAFA",
|
backgroundColor: "#FAFAFA",
|
||||||
borderWidth: 1,
|
borderWidth: 1.5,
|
||||||
borderColor: "#E7E5E4",
|
borderColor: "#D6D3D1",
|
||||||
borderRadius: 12,
|
borderRadius: 12,
|
||||||
paddingHorizontal: 14,
|
paddingHorizontal: 14,
|
||||||
}}
|
}}
|
||||||
@@ -251,7 +251,7 @@ export function AddItemModal({
|
|||||||
value={price}
|
value={price}
|
||||||
onChangeText={setPrice}
|
onChangeText={setPrice}
|
||||||
placeholder="120"
|
placeholder="120"
|
||||||
placeholderTextColor="#A8A29E"
|
placeholderTextColor="#57534E"
|
||||||
keyboardType="decimal-pad"
|
keyboardType="decimal-pad"
|
||||||
style={{
|
style={{
|
||||||
flex: 1,
|
flex: 1,
|
||||||
@@ -273,13 +273,13 @@ export function AddItemModal({
|
|||||||
value={description}
|
value={description}
|
||||||
onChangeText={setDescription}
|
onChangeText={setDescription}
|
||||||
placeholder="Kısa içerik veya porsiyon açıklaması..."
|
placeholder="Kısa içerik veya porsiyon açıklaması..."
|
||||||
placeholderTextColor="#A8A29E"
|
placeholderTextColor="#57534E"
|
||||||
multiline
|
multiline
|
||||||
numberOfLines={3}
|
numberOfLines={3}
|
||||||
style={{
|
style={{
|
||||||
backgroundColor: "#FAFAFA",
|
backgroundColor: "#FAFAFA",
|
||||||
borderWidth: 1,
|
borderWidth: 1.5,
|
||||||
borderColor: "#E7E5E4",
|
borderColor: "#D6D3D1",
|
||||||
borderRadius: 12,
|
borderRadius: 12,
|
||||||
padding: 14,
|
padding: 14,
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
|
|||||||
@@ -311,11 +311,11 @@ export function ItemDetailSheet({
|
|||||||
value={name}
|
value={name}
|
||||||
onChangeText={setName}
|
onChangeText={setName}
|
||||||
placeholder="Örn: Izgara Levrek"
|
placeholder="Örn: Izgara Levrek"
|
||||||
placeholderTextColor="#A8A29E"
|
placeholderTextColor="#57534E"
|
||||||
style={{
|
style={{
|
||||||
backgroundColor: "#FAFAFA",
|
backgroundColor: "#FAFAFA",
|
||||||
borderWidth: 1,
|
borderWidth: 1.5,
|
||||||
borderColor: "#E7E5E4",
|
borderColor: "#D6D3D1",
|
||||||
borderRadius: 12,
|
borderRadius: 12,
|
||||||
padding: 14,
|
padding: 14,
|
||||||
fontSize: 15,
|
fontSize: 15,
|
||||||
@@ -335,8 +335,8 @@ export function ItemDetailSheet({
|
|||||||
flexDirection: "row",
|
flexDirection: "row",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
backgroundColor: "#FAFAFA",
|
backgroundColor: "#FAFAFA",
|
||||||
borderWidth: 1,
|
borderWidth: 1.5,
|
||||||
borderColor: "#E7E5E4",
|
borderColor: "#D6D3D1",
|
||||||
borderRadius: 12,
|
borderRadius: 12,
|
||||||
paddingHorizontal: 14,
|
paddingHorizontal: 14,
|
||||||
}}
|
}}
|
||||||
@@ -345,7 +345,7 @@ export function ItemDetailSheet({
|
|||||||
value={price}
|
value={price}
|
||||||
onChangeText={setPrice}
|
onChangeText={setPrice}
|
||||||
placeholder="0.00"
|
placeholder="0.00"
|
||||||
placeholderTextColor="#A8A29E"
|
placeholderTextColor="#57534E"
|
||||||
keyboardType="decimal-pad"
|
keyboardType="decimal-pad"
|
||||||
style={{
|
style={{
|
||||||
flex: 1,
|
flex: 1,
|
||||||
@@ -368,13 +368,13 @@ export function ItemDetailSheet({
|
|||||||
value={description}
|
value={description}
|
||||||
onChangeText={setDescription}
|
onChangeText={setDescription}
|
||||||
placeholder="İçindekiler, porsiyon bilgisi, pişirme tarzı..."
|
placeholder="İçindekiler, porsiyon bilgisi, pişirme tarzı..."
|
||||||
placeholderTextColor="#A8A29E"
|
placeholderTextColor="#57534E"
|
||||||
multiline
|
multiline
|
||||||
numberOfLines={3}
|
numberOfLines={3}
|
||||||
style={{
|
style={{
|
||||||
backgroundColor: "#FAFAFA",
|
backgroundColor: "#FAFAFA",
|
||||||
borderWidth: 1,
|
borderWidth: 1.5,
|
||||||
borderColor: "#E7E5E4",
|
borderColor: "#D6D3D1",
|
||||||
borderRadius: 12,
|
borderRadius: 12,
|
||||||
padding: 14,
|
padding: 14,
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
|
|||||||
@@ -285,7 +285,7 @@ export function ThemeSelectorSheet({
|
|||||||
Menü Şablonları & Canlı Önizleme
|
Menü Şablonları & Canlı Önizleme
|
||||||
</Text>
|
</Text>
|
||||||
<Text style={{ fontSize: 12, color: "#78716C", marginTop: 2 }}>
|
<Text style={{ fontSize: 12, color: "#78716C", marginTop: 2 }}>
|
||||||
5 lüks şablonu inceleyin, demolarını paylaşın veya menünüze uygulayın
|
Şablonları inceleyin, demolarını görün veya menünüze uygulayın
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
@@ -323,61 +323,21 @@ export function ThemeSelectorSheet({
|
|||||||
elevation: isSelected ? 3 : 1,
|
elevation: isSelected ? 3 : 1,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{/* Top Row: Color Pip, Name, Category Badge & Active Check */}
|
{/* Top Row: Theme Name */}
|
||||||
<View style={{ flexDirection: "row", justifyContent: "space-between", alignItems: "center", marginBottom: 8 }}>
|
<View style={{ marginBottom: 6 }}>
|
||||||
<View style={{ flexDirection: "row", alignItems: "center", gap: 10 }}>
|
<Text style={{ fontSize: 17, fontWeight: "800", color: "#1C1917" }}>
|
||||||
<View
|
|
||||||
style={{
|
|
||||||
width: 18,
|
|
||||||
height: 18,
|
|
||||||
borderRadius: 9,
|
|
||||||
backgroundColor: theme.color,
|
|
||||||
borderWidth: 2,
|
|
||||||
borderColor: "#FFFFFF",
|
|
||||||
shadowColor: "#000",
|
|
||||||
shadowOffset: { width: 0, height: 1 },
|
|
||||||
shadowOpacity: 0.2,
|
|
||||||
shadowRadius: 2,
|
|
||||||
elevation: 2,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<View>
|
|
||||||
<Text style={{ fontSize: 16, fontWeight: "800", color: "#1C1917" }}>
|
|
||||||
{theme.name}
|
{theme.name}
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
|
||||||
|
|
||||||
<View
|
|
||||||
style={{
|
|
||||||
backgroundColor: theme.badgeBg,
|
|
||||||
paddingHorizontal: 8,
|
|
||||||
paddingVertical: 3,
|
|
||||||
borderRadius: 6,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Text style={{ fontSize: 11, fontWeight: "700", color: theme.badgeText }}>
|
|
||||||
{theme.category}
|
|
||||||
</Text>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
{/* Description */}
|
{/* Description */}
|
||||||
<Text style={{ fontSize: 13, color: "#57534E", lineHeight: 18, marginBottom: 8 }}>
|
<Text style={{ fontSize: 13, color: "#57534E", lineHeight: 18, marginBottom: 12 }}>
|
||||||
{theme.desc}
|
{theme.desc}
|
||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
{/* Meta details */}
|
{/* Action Bar: Canlı Demo & Şablon Seç */}
|
||||||
<View style={{ flexDirection: "row", alignItems: "center", gap: 6, marginBottom: 14 }}>
|
<View style={{ flexDirection: "row", gap: 10, borderTopWidth: 1, borderTopColor: "#F5F5F4", paddingTop: 12 }}>
|
||||||
<Ionicons name="sparkles" size={13} color={theme.color} />
|
{/* Canlı Demo Önizle */}
|
||||||
<Text style={{ fontSize: 11, color: "#78716C", fontWeight: "600" }}>
|
|
||||||
Renk: <Text style={{ color: "#1C1917", fontWeight: "700" }}>{theme.accent}</Text> • {theme.suitableFor}
|
|
||||||
</Text>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
{/* Action Bar: Canlı Demo, Paylaş, Uygula */}
|
|
||||||
<View style={{ flexDirection: "row", gap: 8, borderTopWidth: 1, borderTopColor: "#F5F5F4", paddingTop: 12 }}>
|
|
||||||
{/* Canlı Demo Aç */}
|
|
||||||
<Pressable
|
<Pressable
|
||||||
onPress={() => handleOpenDemo(theme.key)}
|
onPress={() => handleOpenDemo(theme.key)}
|
||||||
style={({ pressed }) => ({
|
style={({ pressed }) => ({
|
||||||
@@ -385,43 +345,25 @@ export function ThemeSelectorSheet({
|
|||||||
flexDirection: "row",
|
flexDirection: "row",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
justifyContent: "center",
|
justifyContent: "center",
|
||||||
gap: 4,
|
gap: 6,
|
||||||
backgroundColor: "#F5F5F4",
|
backgroundColor: "#F5F5F4",
|
||||||
paddingVertical: 10,
|
paddingVertical: 12,
|
||||||
borderRadius: 10,
|
borderRadius: 12,
|
||||||
opacity: pressed ? 0.8 : 1,
|
opacity: pressed ? 0.8 : 1,
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<Ionicons name="eye-outline" size={15} color="#1C1917" />
|
<Ionicons name="eye-outline" size={17} color="#1C1917" />
|
||||||
<Text style={{ fontSize: 12, fontWeight: "700", color: "#1C1917" }}>
|
<Text style={{ fontSize: 13, fontWeight: "700", color: "#1C1917" }}>
|
||||||
Demo Menü
|
Demo Önizle
|
||||||
</Text>
|
</Text>
|
||||||
</Pressable>
|
</Pressable>
|
||||||
|
|
||||||
{/* Demo Linkini Gönder / Paylaş */}
|
|
||||||
<Pressable
|
|
||||||
onPress={() => handleShareDemo(theme)}
|
|
||||||
style={({ pressed }) => ({
|
|
||||||
width: 40,
|
|
||||||
alignItems: "center",
|
|
||||||
justifyContent: "center",
|
|
||||||
backgroundColor: "#FAF8F5",
|
|
||||||
borderWidth: 1,
|
|
||||||
borderColor: "#E7E5E4",
|
|
||||||
paddingVertical: 10,
|
|
||||||
borderRadius: 10,
|
|
||||||
opacity: pressed ? 0.8 : 1,
|
|
||||||
})}
|
|
||||||
>
|
|
||||||
<Ionicons name="share-outline" size={16} color="#78716C" />
|
|
||||||
</Pressable>
|
|
||||||
|
|
||||||
{/* Bu Şablonu Uygula / Aktif Rozeti */}
|
{/* Bu Şablonu Uygula / Aktif Rozeti */}
|
||||||
<Pressable
|
<Pressable
|
||||||
onPress={() => handleApplyTheme(theme.key)}
|
onPress={() => handleApplyTheme(theme.key)}
|
||||||
disabled={isSelected || isApplying}
|
disabled={isSelected || isApplying}
|
||||||
style={({ pressed }) => ({
|
style={({ pressed }) => ({
|
||||||
flex: 1.3,
|
flex: 1,
|
||||||
flexDirection: "row",
|
flexDirection: "row",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
justifyContent: "center",
|
justifyContent: "center",
|
||||||
@@ -429,8 +371,8 @@ export function ThemeSelectorSheet({
|
|||||||
backgroundColor: isSelected ? "#ECFDF5" : theme.color,
|
backgroundColor: isSelected ? "#ECFDF5" : theme.color,
|
||||||
borderWidth: isSelected ? 1 : 0,
|
borderWidth: isSelected ? 1 : 0,
|
||||||
borderColor: "#A7F3D0",
|
borderColor: "#A7F3D0",
|
||||||
paddingVertical: 10,
|
paddingVertical: 12,
|
||||||
borderRadius: 10,
|
borderRadius: 12,
|
||||||
opacity: pressed ? 0.85 : 1,
|
opacity: pressed ? 0.85 : 1,
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
@@ -438,15 +380,15 @@ export function ThemeSelectorSheet({
|
|||||||
<ActivityIndicator size="small" color="#FFFFFF" />
|
<ActivityIndicator size="small" color="#FFFFFF" />
|
||||||
) : isSelected ? (
|
) : isSelected ? (
|
||||||
<>
|
<>
|
||||||
<Ionicons name="checkmark-circle" size={16} color="#059669" />
|
<Ionicons name="checkmark-circle" size={17} color="#059669" />
|
||||||
<Text style={{ fontSize: 12, fontWeight: "800", color: "#059669" }}>
|
<Text style={{ fontSize: 13, fontWeight: "800", color: "#059669" }}>
|
||||||
Aktif Şablon
|
Aktif Şablon
|
||||||
</Text>
|
</Text>
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<Ionicons name="checkmark" size={15} color="#FFFFFF" />
|
<Ionicons name="checkmark" size={16} color="#FFFFFF" />
|
||||||
<Text style={{ fontSize: 12, fontWeight: "800", color: "#FFFFFF" }}>
|
<Text style={{ fontSize: 13, fontWeight: "800", color: "#FFFFFF" }}>
|
||||||
Şablonu Seç
|
Şablonu Seç
|
||||||
</Text>
|
</Text>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ export default async function DemoMenuPage({ searchParams }: PageProps) {
|
|||||||
restaurant={DEMO_RESTAURANT}
|
restaurant={DEMO_RESTAURANT}
|
||||||
categories={DEMO_CATEGORIES}
|
categories={DEMO_CATEGORIES}
|
||||||
initialThemeKey={theme}
|
initialThemeKey={theme}
|
||||||
allowThemeSwitching={true}
|
allowThemeSwitching={false}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ export default async function PublicMenuPage({ params, searchParams }: PageProps
|
|||||||
let restaurant: any = null;
|
let restaurant: any = null;
|
||||||
const { data: bySlug } = await supabase
|
const { data: bySlug } = await supabase
|
||||||
.from("restaurants")
|
.from("restaurants")
|
||||||
.select("id, name, slug, logo_url, phone, address")
|
.select("id, name, slug, logo_url, cover_url, phone, address")
|
||||||
.eq("slug", slug)
|
.eq("slug", slug)
|
||||||
.maybeSingle();
|
.maybeSingle();
|
||||||
|
|
||||||
@@ -84,7 +84,7 @@ export default async function PublicMenuPage({ params, searchParams }: PageProps
|
|||||||
// 2. Try finding restaurant by custom domain hostname
|
// 2. Try finding restaurant by custom domain hostname
|
||||||
const { data: domainRow } = await supabase
|
const { data: domainRow } = await supabase
|
||||||
.from("domains")
|
.from("domains")
|
||||||
.select("restaurant_id, restaurants(id, name, slug, logo_url, phone, address)")
|
.select("restaurant_id, restaurants(id, name, slug, logo_url, cover_url, phone, address)")
|
||||||
.eq("hostname", slug)
|
.eq("hostname", slug)
|
||||||
.maybeSingle();
|
.maybeSingle();
|
||||||
|
|
||||||
@@ -144,6 +144,7 @@ export default async function PublicMenuPage({ params, searchParams }: PageProps
|
|||||||
name: restaurant.name,
|
name: restaurant.name,
|
||||||
slug: restaurant.slug,
|
slug: restaurant.slug,
|
||||||
logo_url: restaurant.logo_url,
|
logo_url: restaurant.logo_url,
|
||||||
|
cover_url: restaurant.cover_url,
|
||||||
phone: restaurant.phone,
|
phone: restaurant.phone,
|
||||||
address: restaurant.address,
|
address: restaurant.address,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ export interface RestaurantData {
|
|||||||
name: string;
|
name: string;
|
||||||
slug: string;
|
slug: string;
|
||||||
logo_url: string | null;
|
logo_url: string | null;
|
||||||
|
cover_url?: string | null;
|
||||||
phone?: string | null;
|
phone?: string | null;
|
||||||
address?: string | null;
|
address?: string | null;
|
||||||
}
|
}
|
||||||
@@ -43,7 +44,7 @@ export function PublicMenuClient({
|
|||||||
categories,
|
categories,
|
||||||
initialThemeKey = "elegant",
|
initialThemeKey = "elegant",
|
||||||
customThemeConfig,
|
customThemeConfig,
|
||||||
allowThemeSwitching = true,
|
allowThemeSwitching = false,
|
||||||
}: PublicMenuClientProps) {
|
}: PublicMenuClientProps) {
|
||||||
const [selectedThemeKey, setSelectedThemeKey] = useState<string>(initialThemeKey);
|
const [selectedThemeKey, setSelectedThemeKey] = useState<string>(initialThemeKey);
|
||||||
const [searchQuery, setSearchQuery] = useState("");
|
const [searchQuery, setSearchQuery] = useState("");
|
||||||
@@ -176,26 +177,38 @@ export function PublicMenuClient({
|
|||||||
|
|
||||||
{/* Header Hero Banner */}
|
{/* Header Hero Banner */}
|
||||||
<header
|
<header
|
||||||
style={{ background: theme.headerGradient }}
|
style={{ background: restaurant.cover_url ? "none" : theme.headerGradient }}
|
||||||
className="relative text-white px-4 sm:px-6 pt-8 sm:pt-10 pb-7 sm:pb-8 rounded-b-3xl shadow-lg overflow-hidden"
|
className="relative text-white px-4 sm:px-6 pt-8 sm:pt-10 pb-7 sm:pb-8 rounded-b-3xl shadow-lg overflow-hidden min-h-[200px]"
|
||||||
>
|
>
|
||||||
|
{/* Background Cover Image if available */}
|
||||||
|
{restaurant.cover_url && (
|
||||||
|
<>
|
||||||
|
<img
|
||||||
|
src={restaurant.cover_url}
|
||||||
|
alt={restaurant.name}
|
||||||
|
className="absolute inset-0 w-full h-full object-cover z-0"
|
||||||
|
/>
|
||||||
|
<div className="absolute inset-0 bg-gradient-to-b from-black/65 via-black/45 to-black/85 z-0 backdrop-blur-[1px]" />
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* Subtle Ambient Glow */}
|
{/* Subtle Ambient Glow */}
|
||||||
|
{!restaurant.cover_url && (
|
||||||
<div
|
<div
|
||||||
className="absolute top-0 right-0 w-64 h-64 rounded-full blur-3xl opacity-20 pointer-events-none"
|
className="absolute top-0 right-0 w-64 h-64 rounded-full blur-3xl opacity-20 pointer-events-none"
|
||||||
style={{ backgroundColor: theme.config.primaryColor }}
|
style={{ backgroundColor: theme.config.primaryColor }}
|
||||||
/>
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* Top Bar: Table & Action Buttons */}
|
{/* Top Bar: Table & Action Buttons */}
|
||||||
<div className="flex items-center justify-between mb-4 sm:mb-5 relative z-10">
|
<div className="flex items-center justify-between mb-2 relative z-10">
|
||||||
{tableNumber ? (
|
{tableNumber ? (
|
||||||
<div className="inline-flex items-center gap-1.5 px-3 py-1 rounded-full bg-white/10 backdrop-blur-md border border-white/15 text-xs font-semibold tracking-wide">
|
<div className="inline-flex items-center gap-1.5 px-3 py-1 rounded-full bg-black/40 backdrop-blur-md border border-white/20 text-xs font-semibold tracking-wide text-white">
|
||||||
<span className="w-2 h-2 rounded-full bg-emerald-400 animate-pulse" />
|
<span className="w-2 h-2 rounded-full bg-emerald-400 animate-pulse" />
|
||||||
Masa {tableNumber}
|
Masa {tableNumber}
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="inline-flex items-center gap-1.5 px-3 py-1 rounded-full bg-white/10 backdrop-blur-md border border-white/15 text-xs font-medium tracking-wide">
|
<div />
|
||||||
<span>✨</span> Dijital QR Menü
|
|
||||||
</div>
|
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div className="flex items-center gap-1.5 sm:gap-2">
|
<div className="flex items-center gap-1.5 sm:gap-2">
|
||||||
@@ -230,24 +243,13 @@ export function PublicMenuClient({
|
|||||||
</svg>
|
</svg>
|
||||||
)}
|
)}
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
{/* Live Theme Switcher Trigger */}
|
|
||||||
{allowThemeSwitching && (
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
onClick={() => setShowThemePicker(!showThemePicker)}
|
|
||||||
className="px-2.5 py-1 sm:py-1.5 rounded-full bg-white/10 hover:bg-white/20 active:scale-95 transition-all flex items-center gap-1.5 border border-white/15 backdrop-blur-md text-[11px] sm:text-xs font-semibold"
|
|
||||||
aria-label="Tema Değiştir"
|
|
||||||
>
|
|
||||||
<span className="w-2 h-2 sm:w-2.5 sm:h-2.5 rounded-full" style={{ backgroundColor: theme.config.primaryColor }} />
|
|
||||||
<span>Tema</span>
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Restaurant Identity */}
|
{/* Restaurant Identity - Dynamic Header Layout (Centered or Left) */}
|
||||||
<div className="flex items-center gap-3 sm:gap-4 relative z-10">
|
{theme.config.headerLayout === "left" ? (
|
||||||
|
/* Left-Aligned Header Layout */
|
||||||
|
<div className="flex items-center gap-3.5 sm:gap-4 relative z-10 pt-1 pb-1">
|
||||||
{restaurant.logo_url ? (
|
{restaurant.logo_url ? (
|
||||||
<img
|
<img
|
||||||
src={restaurant.logo_url}
|
src={restaurant.logo_url}
|
||||||
@@ -268,16 +270,57 @@ export function PublicMenuClient({
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
<div className="flex-1 min-w-0">
|
<div className="flex-1 min-w-0">
|
||||||
<h1 className="text-xl sm:text-2xl font-bold tracking-tight leading-snug break-words">
|
<h1 className="text-xl sm:text-2xl font-bold tracking-tight leading-snug break-words text-white">
|
||||||
{restaurant.name}
|
{restaurant.name}
|
||||||
</h1>
|
</h1>
|
||||||
<p className="text-[11px] sm:text-xs text-white/70 mt-0.5 flex flex-wrap items-center gap-1.5">
|
<p className="text-[11px] sm:text-xs text-white/80 mt-0.5 flex items-center gap-1.5 font-medium">
|
||||||
<span>{totalItemsCount} Özel Lezzet</span>
|
<span>{totalItemsCount} Özel Lezzet</span>
|
||||||
<span>•</span>
|
|
||||||
<span className="capitalize">{theme.name} Şablonu</span>
|
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
) : (
|
||||||
|
/* Centered Header Layout */
|
||||||
|
<div className="flex flex-col items-center text-center relative z-10 pt-1 pb-2">
|
||||||
|
{/* Centered Logo Avatar */}
|
||||||
|
<div className="relative group">
|
||||||
|
{restaurant.logo_url ? (
|
||||||
|
<img
|
||||||
|
src={restaurant.logo_url}
|
||||||
|
alt={restaurant.name}
|
||||||
|
className="w-18 h-18 sm:w-20 sm:h-20 rounded-full object-cover border-2 shadow-2xl transition-transform duration-300 group-hover:scale-105"
|
||||||
|
style={{ borderColor: theme.config.primaryColor }}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<div
|
||||||
|
className="w-18 h-18 sm:w-20 sm:h-20 rounded-full flex items-center justify-center font-black text-2xl sm:text-3xl shadow-2xl border-2 backdrop-blur-md"
|
||||||
|
style={{
|
||||||
|
background: "rgba(255, 255, 255, 0.15)",
|
||||||
|
borderColor: theme.config.primaryColor,
|
||||||
|
color: "#FFFFFF",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{restaurant.name.charAt(0).toUpperCase()}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{/* Decorative Ambient Glow Ring */}
|
||||||
|
<div
|
||||||
|
className="absolute -inset-1 rounded-full blur-md opacity-30 pointer-events-none"
|
||||||
|
style={{ backgroundColor: theme.config.primaryColor }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Centered Restaurant Title */}
|
||||||
|
<h1 className="text-2xl sm:text-3xl font-extrabold tracking-tight leading-snug mt-3 text-white drop-shadow-md max-w-md">
|
||||||
|
{restaurant.name}
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
{/* Centered Subtitle Badge Pill */}
|
||||||
|
<div className="mt-2 inline-flex items-center gap-1.5 px-3.5 py-1 rounded-full bg-black/35 backdrop-blur-md border border-white/15 text-xs font-medium text-white/90 shadow-sm">
|
||||||
|
<span className="w-1.5 h-1.5 rounded-full bg-amber-400 animate-pulse" />
|
||||||
|
<span>{totalItemsCount} Özel Lezzet</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* Live Search Bar */}
|
{/* Live Search Bar */}
|
||||||
<div className="mt-6 relative z-10">
|
<div className="mt-6 relative z-10">
|
||||||
@@ -810,12 +853,6 @@ export function PublicMenuClient({
|
|||||||
>
|
>
|
||||||
₺{item.price.toFixed(0)}
|
₺{item.price.toFixed(0)}
|
||||||
</span>
|
</span>
|
||||||
<span
|
|
||||||
className="w-6 h-6 rounded-full flex items-center justify-center text-xs font-bold text-stone-950 shadow-sm transition-transform group-hover:scale-110"
|
|
||||||
style={{ backgroundColor: theme.config.primaryColor }}
|
|
||||||
>
|
|
||||||
+
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</article>
|
</article>
|
||||||
@@ -905,48 +942,19 @@ export function PublicMenuClient({
|
|||||||
</p>
|
</p>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
{/* Floating Quick Action Bar (Garson Çağır / Hesap İste / Başa Dön) */}
|
{/* Floating Back to Top Button */}
|
||||||
<aside aria-label="Masa Servis İşlemleri" className="fixed bottom-5 left-1/2 -translate-x-1/2 z-40 max-w-sm w-full px-4 flex items-center justify-between gap-2 pointer-events-none">
|
|
||||||
<div className="flex items-center gap-2 pointer-events-auto shadow-2xl rounded-full p-1 bg-stone-900/90 backdrop-blur-lg border border-stone-700 text-white">
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
onClick={() =>
|
|
||||||
triggerServiceAction(
|
|
||||||
tableNumber
|
|
||||||
? `Masa ${tableNumber} için Garson Çağrıldı! Garsonunuz en kısa sürede masanızda olacaktır.`
|
|
||||||
: "Garson çağrıldı! Garsonunuz hemen masanızda olacaktır.",
|
|
||||||
)
|
|
||||||
}
|
|
||||||
className="px-3.5 py-2 rounded-full hover:bg-white/15 active:scale-95 transition-all text-xs font-bold flex items-center gap-1.5"
|
|
||||||
>
|
|
||||||
<span>👋</span> Garson Çağır
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
onClick={() =>
|
|
||||||
triggerServiceAction(
|
|
||||||
tableNumber
|
|
||||||
? `Masa ${tableNumber} için Hesap İsteği iletildi!`
|
|
||||||
: "Hesap isteği iletildi!",
|
|
||||||
)
|
|
||||||
}
|
|
||||||
className="px-3.5 py-2 rounded-full hover:bg-white/15 active:scale-95 transition-all text-xs font-bold flex items-center gap-1.5"
|
|
||||||
>
|
|
||||||
<span>💳</span> Hesap İste
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{showBackToTop && (
|
{showBackToTop && (
|
||||||
|
<aside aria-label="Başa Dön" className="fixed bottom-5 right-5 z-40">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => window.scrollTo({ top: 0, behavior: "smooth" })}
|
onClick={() => window.scrollTo({ top: 0, behavior: "smooth" })}
|
||||||
className="w-11 h-11 rounded-full bg-stone-900 text-white shadow-2xl flex items-center justify-center pointer-events-auto active:scale-90 transition-all border border-stone-700"
|
className="w-11 h-11 rounded-full bg-stone-900 text-white shadow-2xl flex items-center justify-center active:scale-90 transition-all border border-stone-700 font-bold"
|
||||||
aria-label="Başa Dön"
|
aria-label="Başa Dön"
|
||||||
>
|
>
|
||||||
↑
|
↑
|
||||||
</button>
|
</button>
|
||||||
)}
|
|
||||||
</aside>
|
</aside>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Item Detail Modal */}
|
{/* Item Detail Modal */}
|
||||||
@@ -1003,30 +1011,17 @@ export function PublicMenuClient({
|
|||||||
{selectedItem.description}
|
{selectedItem.description}
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Quality Badges */}
|
|
||||||
<div className="pt-2 flex flex-wrap gap-2 text-xs">
|
|
||||||
<span className="px-3 py-1 rounded-full bg-emerald-50 text-emerald-700 font-semibold border border-emerald-200">
|
|
||||||
🌱 Taze & Günlük
|
|
||||||
</span>
|
|
||||||
<span className="px-3 py-1 rounded-full bg-amber-50 text-amber-700 font-semibold border border-amber-200">
|
|
||||||
⭐ Şefin İmzası
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Modal Footer */}
|
{/* Modal Footer */}
|
||||||
<div className="p-4 border-t" style={{ borderColor: theme.cardBorder }}>
|
<div className="p-4 border-t" style={{ borderColor: theme.cardBorder }}>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => {
|
onClick={() => setSelectedItem(null)}
|
||||||
setSelectedItem(null);
|
|
||||||
triggerServiceAction(`"${selectedItem.name}" sipariş tercihleriniz garsona iletildi!`);
|
|
||||||
}}
|
|
||||||
className="w-full py-3.5 rounded-2xl font-bold text-white shadow-lg active:scale-98 transition-all flex items-center justify-center gap-2 text-sm"
|
className="w-full py-3.5 rounded-2xl font-bold text-white shadow-lg active:scale-98 transition-all flex items-center justify-center gap-2 text-sm"
|
||||||
style={{ backgroundColor: theme.config.primaryColor }}
|
style={{ backgroundColor: theme.config.primaryColor }}
|
||||||
>
|
>
|
||||||
<span>➕</span> Garsona Sipariş Olarak Bildir
|
Kapat
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useState } from "react";
|
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { PublicMenuClient, type MenuCategory, type RestaurantData } from "@/components/PublicMenuClient";
|
import { PublicMenuClient, type MenuCategory, type RestaurantData } from "@/components/PublicMenuClient";
|
||||||
import { THEME_PRESETS, type ThemePreset } from "@/lib/theme";
|
import { THEME_PRESETS } from "@/lib/theme";
|
||||||
|
|
||||||
interface TemplateGalleryClientProps {
|
interface TemplateGalleryClientProps {
|
||||||
restaurant: RestaurantData;
|
restaurant: RestaurantData;
|
||||||
@@ -14,199 +13,86 @@ interface TemplateGalleryClientProps {
|
|||||||
export function TemplateGalleryClient({
|
export function TemplateGalleryClient({
|
||||||
restaurant,
|
restaurant,
|
||||||
categories,
|
categories,
|
||||||
initialThemeKey = "elegant",
|
|
||||||
}: TemplateGalleryClientProps) {
|
}: TemplateGalleryClientProps) {
|
||||||
const [selectedThemeKey, setSelectedThemeKey] = useState<string>(initialThemeKey);
|
const presetsList = Object.values(THEME_PRESETS);
|
||||||
const [viewMode, setViewMode] = useState<"phone" | "fullscreen">("phone");
|
|
||||||
|
|
||||||
const currentPreset: ThemePreset = THEME_PRESETS[selectedThemeKey] || THEME_PRESETS.elegant!;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen bg-stone-950 text-stone-100 flex flex-col font-sans">
|
<div className="min-h-screen bg-stone-950 text-stone-100 flex flex-col font-sans">
|
||||||
{/* Top Navbar */}
|
{/* Top Navbar */}
|
||||||
<header className="border-b border-stone-800/80 bg-stone-900/90 backdrop-blur-xl sticky top-0 z-50 px-4 sm:px-6 py-3.5">
|
<header className="border-b border-stone-800/80 bg-stone-900/90 backdrop-blur-xl sticky top-0 z-50 px-4 sm:px-6 py-3.5">
|
||||||
<div className="max-w-7xl mx-auto flex flex-col md:flex-row items-center justify-between gap-3">
|
<div className="max-w-7xl mx-auto flex items-center justify-between">
|
||||||
<div className="flex items-center justify-between w-full md:w-auto">
|
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-3">
|
||||||
<Link href="/" className="font-black text-xl tracking-tight text-amber-400">
|
<Link href="/" className="font-black text-xl tracking-tight text-amber-400">
|
||||||
MENULIO
|
MENULIO
|
||||||
</Link>
|
</Link>
|
||||||
<span className="text-stone-600 hidden sm:inline">/</span>
|
<span className="text-stone-600 hidden sm:inline">/</span>
|
||||||
<span className="text-xs font-semibold text-stone-400 hidden sm:inline">Şablon Galerisi</span>
|
<span className="text-xs font-semibold text-stone-400 hidden sm:inline">
|
||||||
</div>
|
Şablon Galerisi
|
||||||
|
</span>
|
||||||
{/* View Mode Toggle (Visible on desktop/tablet) */}
|
|
||||||
<div className="flex items-center bg-stone-800/80 p-1 rounded-xl border border-stone-700 md:hidden">
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
onClick={() => setViewMode("phone")}
|
|
||||||
className={`px-2.5 py-1 rounded-lg text-xs font-bold transition-all ${
|
|
||||||
viewMode === "phone" ? "bg-amber-400 text-stone-950 shadow" : "text-stone-400"
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
📱 Mobil
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
onClick={() => setViewMode("fullscreen")}
|
|
||||||
className={`px-2.5 py-1 rounded-lg text-xs font-bold transition-all ${
|
|
||||||
viewMode === "fullscreen" ? "bg-amber-400 text-stone-950 shadow" : "text-stone-400"
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
🖥️ Tam
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* 5 Theme Pills - Smooth Horizontal Scroll */}
|
|
||||||
<div className="flex items-center gap-2 overflow-x-auto w-full md:w-auto pb-1 md:pb-0 no-scrollbar">
|
|
||||||
{Object.values(THEME_PRESETS).map((preset) => {
|
|
||||||
const isActive = selectedThemeKey === preset.key;
|
|
||||||
return (
|
|
||||||
<button
|
|
||||||
key={preset.key}
|
|
||||||
type="button"
|
|
||||||
onClick={() => setSelectedThemeKey(preset.key)}
|
|
||||||
className={`px-3.5 py-1.5 rounded-xl text-xs font-bold transition-all flex items-center gap-2 whitespace-nowrap border flex-shrink-0 ${
|
|
||||||
isActive
|
|
||||||
? "bg-white text-stone-950 border-white shadow-lg scale-105"
|
|
||||||
: "bg-stone-800/90 text-stone-300 border-stone-700 hover:border-stone-500 hover:text-white"
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
<span
|
|
||||||
className="w-2.5 h-2.5 rounded-full"
|
|
||||||
style={{ backgroundColor: preset.config.primaryColor }}
|
|
||||||
/>
|
|
||||||
<span>{preset.name}</span>
|
|
||||||
</button>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="hidden md:flex items-center gap-3">
|
|
||||||
{/* View Mode Toggle (Desktop) */}
|
|
||||||
<div className="flex items-center bg-stone-800/80 p-1 rounded-xl border border-stone-700">
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
onClick={() => setViewMode("phone")}
|
|
||||||
className={`px-3 py-1 rounded-lg text-xs font-bold transition-all ${
|
|
||||||
viewMode === "phone" ? "bg-amber-400 text-stone-950 shadow" : "text-stone-400 hover:text-white"
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
📱 Telefon
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
onClick={() => setViewMode("fullscreen")}
|
|
||||||
className={`px-3 py-1 rounded-lg text-xs font-bold transition-all ${
|
|
||||||
viewMode === "fullscreen" ? "bg-amber-400 text-stone-950 shadow" : "text-stone-400 hover:text-white"
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
🖥️ Tam Ekran
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Link
|
<Link
|
||||||
href="/"
|
href="/"
|
||||||
className="text-xs font-bold px-4 py-2 rounded-xl bg-amber-500 hover:bg-amber-400 text-stone-950 transition-all shadow-md shadow-amber-500/20"
|
className="text-xs font-bold px-4 py-2 rounded-xl bg-amber-500 hover:bg-amber-400 text-stone-950 transition-all shadow-md shadow-amber-500/20"
|
||||||
>
|
>
|
||||||
Uygulamayı İndir →
|
Ana Sayfa →
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
{/* Main Content Area */}
|
{/* Main Content Area - Stacked Vertically */}
|
||||||
<main className="flex-1 w-full flex flex-col items-center justify-center p-0 sm:p-6 lg:p-8">
|
<main className="flex-1 w-full max-w-4xl mx-auto py-10 px-4 space-y-16">
|
||||||
{viewMode === "fullscreen" ? (
|
{presetsList.map((preset) => (
|
||||||
/* Fullscreen Fluid View */
|
<section
|
||||||
<div className="w-full flex-1 min-h-[85vh]">
|
key={preset.key}
|
||||||
<PublicMenuClient
|
className="flex flex-col items-center gap-8 border-b border-stone-800/80 pb-16 last:border-0"
|
||||||
restaurant={restaurant}
|
|
||||||
categories={categories}
|
|
||||||
initialThemeKey={selectedThemeKey}
|
|
||||||
allowThemeSwitching={true}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
/* Responsive Device Simulator / Side-by-Side on Desktop */
|
|
||||||
<div className="w-full max-w-6xl mx-auto grid grid-cols-1 lg:grid-cols-12 gap-8 items-center justify-center py-4">
|
|
||||||
{/* Left Info Panel (Visible on Desktop) */}
|
|
||||||
<div className="hidden lg:flex lg:col-span-5 flex-col space-y-6 pr-4">
|
|
||||||
<div className="space-y-2">
|
|
||||||
<span className="text-amber-400 text-xs font-bold uppercase tracking-wider">
|
|
||||||
ŞABLON DETAYI
|
|
||||||
</span>
|
|
||||||
<h2 className="text-3xl font-extrabold text-white">
|
|
||||||
{currentPreset.name}
|
|
||||||
</h2>
|
|
||||||
<p className="text-sm text-stone-400 leading-relaxed">
|
|
||||||
{currentPreset.key === "elegant" && "Fine dining restoranlar, şarap evleri ve lüks steakhouse mekanlar için altın & krem tonlarında yüksek prestijli tasarım."}
|
|
||||||
{currentPreset.key === "modern" && "Kafeler, burgerciler ve dinamik mekanlar için canlı mavi safir tonları ve hızlı arama odaklı ızgara düzeni."}
|
|
||||||
{currentPreset.key === "dark" && "Gece kulüpleri, kokteyl barlar ve lounge mekanlar için obsidian siyahı ve kehribar parıltılı lüks mod."}
|
|
||||||
{currentPreset.key === "minimal" && "Butik kahveciler, fırınlar ve üçüncü nesil mekanlar için ferah ve monokromatik Nordic mizanpaj."}
|
|
||||||
{currentPreset.key === "classic" && "Geleneksel brasserie'ler, meyhaneler ve trattoria'lar için Toskana bordo ve sıcak rustik doku."}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Theme Specs */}
|
|
||||||
<div className="p-5 rounded-2xl bg-stone-900 border border-stone-800 space-y-3.5 text-xs">
|
|
||||||
<div className="flex items-center justify-between">
|
|
||||||
<span className="text-stone-400">Vurgu Rengi</span>
|
|
||||||
<div className="flex items-center gap-2">
|
|
||||||
<span
|
|
||||||
className="w-4 h-4 rounded-full border border-white/20"
|
|
||||||
style={{ backgroundColor: currentPreset.config.primaryColor }}
|
|
||||||
/>
|
|
||||||
<span className="font-mono text-stone-200">{currentPreset.config.primaryColor}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="flex items-center justify-between">
|
|
||||||
<span className="text-stone-400">Tipografi Ailesi</span>
|
|
||||||
<span className="font-semibold text-stone-200 uppercase">{currentPreset.fontFamily}</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="flex items-center justify-between">
|
|
||||||
<span className="text-stone-400">Ürün Mizanpajı</span>
|
|
||||||
<span className="font-semibold text-stone-200 uppercase">{currentPreset.config.productLayout}</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="flex items-center justify-between">
|
|
||||||
<span className="text-stone-400">Kategori Gezintisi</span>
|
|
||||||
<span className="font-semibold text-stone-200 uppercase">{currentPreset.config.categoryLayout}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Direct Demo Link */}
|
|
||||||
<Link
|
|
||||||
href={`/demo?theme=${selectedThemeKey}`}
|
|
||||||
target="_blank"
|
|
||||||
className="w-full py-3.5 rounded-xl font-bold text-center bg-stone-800 hover:bg-stone-700 text-stone-200 border border-stone-700 transition-all text-xs flex items-center justify-center gap-2"
|
|
||||||
>
|
>
|
||||||
<span>↗</span> Yeni Sekmede Canlı Menüyü Aç
|
{/* Theme Info */}
|
||||||
|
<div className="text-center max-w-xl space-y-3">
|
||||||
|
<div className="inline-flex items-center gap-2.5 px-3.5 py-1.5 rounded-full bg-stone-900 border border-stone-800 text-xs font-bold text-stone-300">
|
||||||
|
<span
|
||||||
|
className="w-2.5 h-2.5 rounded-full"
|
||||||
|
style={{ backgroundColor: preset.config.primaryColor }}
|
||||||
|
/>
|
||||||
|
<span className="uppercase tracking-wider text-[11px]">{preset.key} Şablonu</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h2 className="text-2xl sm:text-3xl font-extrabold text-white">
|
||||||
|
{preset.name}
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
<p className="text-xs sm:text-sm text-stone-400 leading-relaxed">
|
||||||
|
Tipografi: <span className="uppercase text-stone-200 font-semibold">{preset.fontFamily}</span> • Mizanpaj: <span className="uppercase text-stone-200 font-semibold">{preset.config.productLayout}</span>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div className="pt-2">
|
||||||
|
<Link
|
||||||
|
href={`/demo?theme=${preset.key}`}
|
||||||
|
target="_blank"
|
||||||
|
className="inline-flex items-center gap-2 px-4 py-2.5 rounded-xl bg-stone-900 hover:bg-stone-800 text-stone-200 border border-stone-700/80 text-xs font-bold transition-all shadow-md"
|
||||||
|
>
|
||||||
|
<span>↗</span> Canlı Demoyu Sekmede Aç
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* Right Phone Mockup Container */}
|
{/* Phone Mockup Preview */}
|
||||||
<div className="lg:col-span-7 flex justify-center w-full">
|
|
||||||
<div className="w-full max-w-[420px] rounded-[36px] sm:rounded-[44px] overflow-hidden shadow-2xl border-0 sm:border-[8px] border-stone-800 bg-stone-900 relative">
|
<div className="w-full max-w-[420px] rounded-[36px] sm:rounded-[44px] overflow-hidden shadow-2xl border-0 sm:border-[8px] border-stone-800 bg-stone-900 relative">
|
||||||
{/* Dynamic Island (Desktop only) */}
|
{/* Dynamic Island */}
|
||||||
<div className="hidden sm:block w-24 h-4 bg-stone-800 rounded-full mx-auto mt-2 mb-1" />
|
<div className="hidden sm:block w-24 h-4 bg-stone-800 rounded-full mx-auto mt-2.5 mb-1" />
|
||||||
|
|
||||||
{/* Simulated Screen Body */}
|
{/* Screen Body */}
|
||||||
<div className="overflow-y-auto max-h-[85vh] sm:max-h-[780px] rounded-none sm:rounded-[32px] no-scrollbar">
|
<div className="overflow-y-auto max-h-[720px] rounded-none sm:rounded-[32px] no-scrollbar">
|
||||||
<PublicMenuClient
|
<PublicMenuClient
|
||||||
restaurant={restaurant}
|
restaurant={restaurant}
|
||||||
categories={categories}
|
categories={categories}
|
||||||
initialThemeKey={selectedThemeKey}
|
initialThemeKey={preset.key}
|
||||||
allowThemeSwitching={true}
|
allowThemeSwitching={false}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</section>
|
||||||
</div>
|
))}
|
||||||
)}
|
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ export const DEMO_RESTAURANT: RestaurantData = {
|
|||||||
name: "Gusto & Co. Brasserie",
|
name: "Gusto & Co. Brasserie",
|
||||||
slug: "gusto-brasserie",
|
slug: "gusto-brasserie",
|
||||||
logo_url: null,
|
logo_url: null,
|
||||||
|
cover_url: "https://images.unsplash.com/photo-1517248135467-4c7edcad34c4?w=1200&auto=format&fit=crop&q=80",
|
||||||
phone: "+90 (212) 555 0192",
|
phone: "+90 (212) 555 0192",
|
||||||
address: "Nişantaşı, Abdi İpekçi Cad. No: 42, İstanbul",
|
address: "Nişantaşı, Abdi İpekçi Cad. No: 42, İstanbul",
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ export const THEME_PRESETS: Record<string, ThemePreset> = {
|
|||||||
background: "#F7F3EC",
|
background: "#F7F3EC",
|
||||||
productLayout: "card",
|
productLayout: "card",
|
||||||
categoryLayout: "tabs",
|
categoryLayout: "tabs",
|
||||||
|
headerLayout: "centered",
|
||||||
},
|
},
|
||||||
cardBg: "#FCFAF6",
|
cardBg: "#FCFAF6",
|
||||||
cardBorder: "#E4DBCF",
|
cardBorder: "#E4DBCF",
|
||||||
@@ -44,6 +45,7 @@ export const THEME_PRESETS: Record<string, ThemePreset> = {
|
|||||||
background: "#0D1117",
|
background: "#0D1117",
|
||||||
productLayout: "card",
|
productLayout: "card",
|
||||||
categoryLayout: "tabs",
|
categoryLayout: "tabs",
|
||||||
|
headerLayout: "left",
|
||||||
},
|
},
|
||||||
cardBg: "#FCF7EC",
|
cardBg: "#FCF7EC",
|
||||||
cardBorder: "rgba(255, 42, 133, 0.3)",
|
cardBorder: "rgba(255, 42, 133, 0.3)",
|
||||||
@@ -63,6 +65,7 @@ export const THEME_PRESETS: Record<string, ThemePreset> = {
|
|||||||
background: "#EEEAE4",
|
background: "#EEEAE4",
|
||||||
productLayout: "card",
|
productLayout: "card",
|
||||||
categoryLayout: "tabs",
|
categoryLayout: "tabs",
|
||||||
|
headerLayout: "centered",
|
||||||
},
|
},
|
||||||
cardBg: "#F7F4EF",
|
cardBg: "#F7F4EF",
|
||||||
cardBorder: "rgba(36, 70, 58, 0.2)",
|
cardBorder: "rgba(36, 70, 58, 0.2)",
|
||||||
@@ -82,6 +85,7 @@ export const THEME_PRESETS: Record<string, ThemePreset> = {
|
|||||||
background: "#FFFFFF",
|
background: "#FFFFFF",
|
||||||
productLayout: "card",
|
productLayout: "card",
|
||||||
categoryLayout: "tabs",
|
categoryLayout: "tabs",
|
||||||
|
headerLayout: "left",
|
||||||
},
|
},
|
||||||
cardBg: "#FFFFFF",
|
cardBg: "#FFFFFF",
|
||||||
cardBorder: "#000000",
|
cardBorder: "#000000",
|
||||||
@@ -101,6 +105,7 @@ export const THEME_PRESETS: Record<string, ThemePreset> = {
|
|||||||
background: "#121316",
|
background: "#121316",
|
||||||
productLayout: "card",
|
productLayout: "card",
|
||||||
categoryLayout: "tabs",
|
categoryLayout: "tabs",
|
||||||
|
headerLayout: "centered",
|
||||||
},
|
},
|
||||||
cardBg: "#1C1E24",
|
cardBg: "#1C1E24",
|
||||||
cardBorder: "rgba(255, 255, 255, 0.08)",
|
cardBorder: "rgba(255, 255, 255, 0.08)",
|
||||||
@@ -120,6 +125,7 @@ export const THEME_PRESETS: Record<string, ThemePreset> = {
|
|||||||
background: "#FAF8F5",
|
background: "#FAF8F5",
|
||||||
productLayout: "card",
|
productLayout: "card",
|
||||||
categoryLayout: "accordion",
|
categoryLayout: "accordion",
|
||||||
|
headerLayout: "centered",
|
||||||
},
|
},
|
||||||
cardBg: "#FFFFFF",
|
cardBg: "#FFFFFF",
|
||||||
cardBorder: "rgba(200, 169, 107, 0.18)",
|
cardBorder: "rgba(200, 169, 107, 0.18)",
|
||||||
@@ -139,6 +145,7 @@ export const THEME_PRESETS: Record<string, ThemePreset> = {
|
|||||||
background: "#F8FAFC",
|
background: "#F8FAFC",
|
||||||
productLayout: "card",
|
productLayout: "card",
|
||||||
categoryLayout: "tabs",
|
categoryLayout: "tabs",
|
||||||
|
headerLayout: "left",
|
||||||
},
|
},
|
||||||
cardBg: "#FFFFFF",
|
cardBg: "#FFFFFF",
|
||||||
cardBorder: "rgba(226, 232, 240, 0.9)",
|
cardBorder: "rgba(226, 232, 240, 0.9)",
|
||||||
@@ -158,6 +165,7 @@ export const THEME_PRESETS: Record<string, ThemePreset> = {
|
|||||||
background: "#0F0F12",
|
background: "#0F0F12",
|
||||||
productLayout: "card",
|
productLayout: "card",
|
||||||
categoryLayout: "accordion",
|
categoryLayout: "accordion",
|
||||||
|
headerLayout: "centered",
|
||||||
},
|
},
|
||||||
cardBg: "#18181D",
|
cardBg: "#18181D",
|
||||||
cardBorder: "rgba(255, 255, 255, 0.07)",
|
cardBorder: "rgba(255, 255, 255, 0.07)",
|
||||||
@@ -177,6 +185,7 @@ export const THEME_PRESETS: Record<string, ThemePreset> = {
|
|||||||
background: "#FAFAFA",
|
background: "#FAFAFA",
|
||||||
productLayout: "list",
|
productLayout: "list",
|
||||||
categoryLayout: "flat",
|
categoryLayout: "flat",
|
||||||
|
headerLayout: "left",
|
||||||
},
|
},
|
||||||
cardBg: "#FFFFFF",
|
cardBg: "#FFFFFF",
|
||||||
cardBorder: "#E4E4E7",
|
cardBorder: "#E4E4E7",
|
||||||
@@ -196,6 +205,7 @@ export const THEME_PRESETS: Record<string, ThemePreset> = {
|
|||||||
background: "#FFF9F2",
|
background: "#FFF9F2",
|
||||||
productLayout: "list",
|
productLayout: "list",
|
||||||
categoryLayout: "accordion",
|
categoryLayout: "accordion",
|
||||||
|
headerLayout: "centered",
|
||||||
},
|
},
|
||||||
cardBg: "#FFFFFF",
|
cardBg: "#FFFFFF",
|
||||||
cardBorder: "rgba(139, 30, 30, 0.15)",
|
cardBorder: "rgba(139, 30, 30, 0.15)",
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ export const themeConfigSchema = z.object({
|
|||||||
background: z.string(),
|
background: z.string(),
|
||||||
productLayout: z.enum(["card", "list"]),
|
productLayout: z.enum(["card", "list"]),
|
||||||
categoryLayout: z.enum(["accordion", "tabs", "flat"]),
|
categoryLayout: z.enum(["accordion", "tabs", "flat"]),
|
||||||
|
headerLayout: z.enum(["centered", "left"]).optional().default("centered"),
|
||||||
});
|
});
|
||||||
|
|
||||||
export type ThemeConfig = z.infer<typeof themeConfigSchema>;
|
export type ThemeConfig = z.infer<typeof themeConfigSchema>;
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ create table restaurants (
|
|||||||
name text not null,
|
name text not null,
|
||||||
slug text not null unique,
|
slug text not null unique,
|
||||||
logo_url text,
|
logo_url text,
|
||||||
|
cover_url text,
|
||||||
phone text,
|
phone text,
|
||||||
address text,
|
address text,
|
||||||
created_by uuid not null references users (id) on delete restrict,
|
created_by uuid not null references users (id) on delete restrict,
|
||||||
|
|||||||
Reference in New Issue
Block a user