Styling Update
This commit is contained in:
parent
673a693020
commit
3d7b31f218
BIN
img/totoro_sitting.png
Normal file
BIN
img/totoro_sitting.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 225 KiB |
559
main.py
559
main.py
@ -12,8 +12,10 @@ import tkinter as tk
|
|||||||
from tkinter import ttk, messagebox, filedialog, simpledialog
|
from tkinter import ttk, messagebox, filedialog, simpledialog
|
||||||
from PIL import Image, ImageTk
|
from PIL import Image, ImageTk
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# ========================================
|
# ========================================
|
||||||
# UI STYLING - TOTORO THEME COLORS
|
# UI STYLING - TOTORO THEME COLORS + FONTS
|
||||||
# ========================================
|
# ========================================
|
||||||
COLORS = {
|
COLORS = {
|
||||||
'bg_main': '#F5F5DC', # Beige/Krem lembut (background utama)
|
'bg_main': '#F5F5DC', # Beige/Krem lembut (background utama)
|
||||||
@ -28,6 +30,19 @@ COLORS = {
|
|||||||
'warning': '#D4A574', # Coklat muda untuk warning
|
'warning': '#D4A574', # Coklat muda untuk warning
|
||||||
'danger': '#C9797A', # Merah lembut untuk danger
|
'danger': '#C9797A', # Merah lembut untuk danger
|
||||||
'border': '#D4C5B9', # Border coklat muda
|
'border': '#D4C5B9', # Border coklat muda
|
||||||
|
'shadow': '#D0D0D0', # Shadow abu-abu lembut
|
||||||
|
}
|
||||||
|
|
||||||
|
# Font configuration untuk tema Totoro
|
||||||
|
FONTS = {
|
||||||
|
'header': ('Comic Sans MS', 16, 'bold'),
|
||||||
|
'subheader': ('Segoe UI', 12, 'bold'),
|
||||||
|
'body': ('Segoe UI', 10),
|
||||||
|
'body_bold': ('Segoe UI', 10, 'bold'),
|
||||||
|
'small': ('Segoe UI', 9),
|
||||||
|
'tiny': ('Segoe UI', 8),
|
||||||
|
'button': ('Segoe UI', 11, 'bold'),
|
||||||
|
'mono': ('Consolas', 9),
|
||||||
}
|
}
|
||||||
|
|
||||||
USERS_CSV = "users.csv"
|
USERS_CSV = "users.csv"
|
||||||
@ -40,6 +55,28 @@ MEJA_CSV = "meja.csv"
|
|||||||
PEMBAYARAN_CSV = "pembayaran.csv"
|
PEMBAYARAN_CSV = "pembayaran.csv"
|
||||||
IMG_PREVIEW_SIZE = (120, 80)
|
IMG_PREVIEW_SIZE = (120, 80)
|
||||||
|
|
||||||
|
def create_placeholder_image():
|
||||||
|
"""Buat placeholder jika gambar belum ada"""
|
||||||
|
if not os.path.exists('img'):
|
||||||
|
os.makedirs('img')
|
||||||
|
|
||||||
|
if not os.path.exists('img/totoro_sitting.png'):
|
||||||
|
try:
|
||||||
|
from PIL import Image, ImageDraw
|
||||||
|
|
||||||
|
# Buat gambar placeholder 300x300
|
||||||
|
img = Image.new('RGB', (300, 300), color=COLORS['accent'])
|
||||||
|
draw = ImageDraw.Draw(img)
|
||||||
|
|
||||||
|
# Tulis text
|
||||||
|
draw.text((50, 140), "TOTORO\nPLACEHOLDER", fill=COLORS['brown'])
|
||||||
|
|
||||||
|
img.save('img/totoro_sitting.png')
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Panggil saat init
|
||||||
|
create_placeholder_image()
|
||||||
|
|
||||||
def ensure_file(path, fieldnames):
|
def ensure_file(path, fieldnames):
|
||||||
if not os.path.exists(path):
|
if not os.path.exists(path):
|
||||||
@ -1124,6 +1161,47 @@ class App:
|
|||||||
self.img_cache = {}
|
self.img_cache = {}
|
||||||
self.setup_ui()
|
self.setup_ui()
|
||||||
|
|
||||||
|
def create_hover_button(self, parent, text, command, style='primary', width=None):
|
||||||
|
"""Helper untuk membuat button dengan hover effect"""
|
||||||
|
|
||||||
|
bg_colors = {
|
||||||
|
'primary': (COLORS['primary'], COLORS['primary_dark']),
|
||||||
|
'success': (COLORS['success'], COLORS['primary_dark']),
|
||||||
|
'danger': (COLORS['danger'], '#B85555'),
|
||||||
|
'brown': (COLORS['brown'], '#6B5D48')
|
||||||
|
}
|
||||||
|
|
||||||
|
bg_normal, bg_hover = bg_colors.get(style, bg_colors['primary'])
|
||||||
|
|
||||||
|
btn = tk.Button(
|
||||||
|
parent,
|
||||||
|
text=text,
|
||||||
|
command=command,
|
||||||
|
bg=bg_normal,
|
||||||
|
fg='white',
|
||||||
|
font=FONTS['button'],
|
||||||
|
relief='flat',
|
||||||
|
cursor='hand2',
|
||||||
|
borderwidth=0,
|
||||||
|
padx=20,
|
||||||
|
pady=10
|
||||||
|
)
|
||||||
|
|
||||||
|
if width:
|
||||||
|
btn.config(width=width)
|
||||||
|
|
||||||
|
def on_enter(e):
|
||||||
|
btn['background'] = bg_hover
|
||||||
|
|
||||||
|
def on_leave(e):
|
||||||
|
btn['background'] = bg_normal
|
||||||
|
|
||||||
|
btn.bind('<Enter>', on_enter)
|
||||||
|
btn.bind('<Leave>', on_leave)
|
||||||
|
|
||||||
|
return btn
|
||||||
|
|
||||||
|
|
||||||
def setup_ui(self):
|
def setup_ui(self):
|
||||||
# UI STYLING - Window setup dengan tema Totoro
|
# UI STYLING - Window setup dengan tema Totoro
|
||||||
self.root.geometry("1200x750")
|
self.root.geometry("1200x750")
|
||||||
@ -1200,97 +1278,228 @@ class App:
|
|||||||
for w in self.root.winfo_children():
|
for w in self.root.winfo_children():
|
||||||
w.destroy()
|
w.destroy()
|
||||||
|
|
||||||
# UI STYLING - Main container dengan background Totoro
|
# ========================================
|
||||||
|
# TOTORO LOGIN - LANDSCAPE LAYOUT (FIXED)
|
||||||
|
# ========================================
|
||||||
|
|
||||||
|
# Main container dengan background
|
||||||
main_container = tk.Frame(self.root, bg=COLORS['bg_main'])
|
main_container = tk.Frame(self.root, bg=COLORS['bg_main'])
|
||||||
main_container.pack(fill='both', expand=True)
|
main_container.pack(fill='both', expand=True)
|
||||||
|
|
||||||
# UI STYLING - Center frame untuk login card
|
# Center frame untuk positioning
|
||||||
center_frame = tk.Frame(main_container, bg=COLORS['bg_main'])
|
center_frame = tk.Frame(main_container, bg=COLORS['bg_main'])
|
||||||
center_frame.place(relx=0.5, rely=0.5, anchor='center')
|
center_frame.pack(expand=True, pady=50)
|
||||||
|
|
||||||
# UI STYLING - Login card dengan shadow effect
|
# ========================================
|
||||||
card = tk.Frame(center_frame, bg='white', relief='flat', borderwidth=0)
|
# MAIN CARD - LANDSCAPE (TANPA SHADOW DULU)
|
||||||
card.pack(padx=20, pady=20)
|
# ========================================
|
||||||
|
card = tk.Frame(
|
||||||
|
center_frame,
|
||||||
|
bg='white',
|
||||||
|
relief='ridge',
|
||||||
|
borderwidth=3,
|
||||||
|
padx=0,
|
||||||
|
pady=0
|
||||||
|
)
|
||||||
|
card.pack()
|
||||||
|
|
||||||
# UI STYLING - Header dengan tema Totoro
|
# ========================================
|
||||||
header_frame = tk.Frame(card, bg=COLORS['primary'], height=100)
|
# CONTAINER HORIZONTAL (2 PANEL)
|
||||||
header_frame.pack(fill='x', pady=(0, 30))
|
# ========================================
|
||||||
|
container = tk.Frame(card, bg='white')
|
||||||
|
container.pack()
|
||||||
|
|
||||||
# UI STYLING - Logo Totoro di atas card
|
# ========================================
|
||||||
|
# LEFT PANEL - TOTORO ILLUSTRATION
|
||||||
|
# ========================================
|
||||||
|
left_panel = tk.Frame(container, bg=COLORS['accent'], width=350)
|
||||||
|
left_panel.pack(side='left', fill='y', padx=0, pady=0)
|
||||||
|
|
||||||
|
# Spacer atas
|
||||||
|
tk.Label(left_panel, text="", bg=COLORS['accent'], height=2).pack()
|
||||||
|
|
||||||
|
# Totoro illustration
|
||||||
try:
|
try:
|
||||||
totoro_img = Image.open("img/totoro_logo.png")
|
totoro_img = Image.open("img/totoro_sitting.png")
|
||||||
totoro_img = totoro_img.resize((100, 100), Image.Resampling.LANCZOS)
|
totoro_img = totoro_img.resize((250, 250), Image.Resampling.LANCZOS)
|
||||||
totoro_photo = ImageTk.PhotoImage(totoro_img)
|
totoro_photo = ImageTk.PhotoImage(totoro_img)
|
||||||
|
|
||||||
self.totoro_logo = totoro_photo
|
self.totoro_login_img = totoro_photo
|
||||||
|
|
||||||
img_label = tk.Label(card, image=totoro_photo, bg='white')
|
img_label = tk.Label(left_panel, image=totoro_photo, bg=COLORS['accent'])
|
||||||
img_label.pack(pady=(20, 10))
|
img_label.pack(pady=20)
|
||||||
except:
|
except Exception as e:
|
||||||
# Fallback jika gambar tidak ditemukan
|
print(f"⚠️ Gambar tidak ditemukan: {e}")
|
||||||
tk.Label(card, text="🌿", font=("Arial", 48), bg='white').pack(pady=(20, 10))
|
tk.Label(
|
||||||
|
left_panel,
|
||||||
|
text="🌿\n\n🍃\n\n🌳",
|
||||||
|
font=('Arial', 50),
|
||||||
|
bg=COLORS['accent'],
|
||||||
|
fg=COLORS['primary_dark']
|
||||||
|
).pack(pady=40)
|
||||||
|
|
||||||
|
# Welcome text
|
||||||
|
tk.Label(
|
||||||
|
left_panel,
|
||||||
|
text="Welome to Totoro Café\nTotoro is waiting for you!",
|
||||||
|
font=('Comic Sans MS', 11, 'italic'),
|
||||||
|
bg=COLORS['accent'],
|
||||||
|
fg=COLORS['brown']
|
||||||
|
).pack(pady=(10, 30))
|
||||||
|
|
||||||
tk.Label(header_frame,
|
# ========================================
|
||||||
text="🌿 TOTORO CAFÉ 🌿",
|
# RIGHT PANEL - LOGIN FORM
|
||||||
font=("Arial", 24, "bold"),
|
# ========================================
|
||||||
bg=COLORS['primary'],
|
right_panel = tk.Frame(container, bg='white', padx=40, pady=30)
|
||||||
fg='white').pack(pady=20)
|
right_panel.pack(side='right', fill='both')
|
||||||
|
|
||||||
tk.Label(header_frame,
|
# Header
|
||||||
text="Selamat Datang di Sistem Manajemen Cafe",
|
tk.Label(
|
||||||
font=("Arial", 10),
|
right_panel,
|
||||||
bg=COLORS['primary'],
|
text="🌿 TOTORO CAFÉ 🌿",
|
||||||
fg='white').pack(pady=(0, 10))
|
font=('Comic Sans MS', 22, 'bold'),
|
||||||
|
bg='white',
|
||||||
|
fg=COLORS['primary']
|
||||||
|
).pack(pady=(10, 5))
|
||||||
|
|
||||||
# UI STYLING - Form container
|
tk.Label(
|
||||||
form_frame = tk.Frame(card, bg='white')
|
right_panel,
|
||||||
form_frame.pack(padx=50, pady=20)
|
text="Cafe Management System",
|
||||||
|
font=('Segoe UI', 9),
|
||||||
|
bg='white',
|
||||||
|
fg=COLORS['text_light']
|
||||||
|
).pack(pady=(0, 20))
|
||||||
|
|
||||||
|
# Form container
|
||||||
|
form_frame = tk.Frame(right_panel, bg='white')
|
||||||
|
form_frame.pack(pady=10)
|
||||||
|
|
||||||
# Username
|
# Username
|
||||||
tk.Label(form_frame, text="Username:", font=("Arial", 11), bg='white', fg=COLORS['text_dark']).grid(row=0, column=0, sticky='w', pady=(10, 5))
|
tk.Label(
|
||||||
|
form_frame,
|
||||||
|
text="Username:",
|
||||||
|
font=('Segoe UI', 10, 'bold'),
|
||||||
|
bg='white',
|
||||||
|
fg=COLORS['text_dark']
|
||||||
|
).grid(row=0, column=0, sticky='w', pady=(10, 5), padx=5)
|
||||||
|
|
||||||
self.username_var = tk.StringVar()
|
self.username_var = tk.StringVar()
|
||||||
username_entry = tk.Entry(form_frame, textvariable=self.username_var, width=35, font=("Arial", 11), relief='solid', borderwidth=1)
|
username_entry = tk.Entry(
|
||||||
username_entry.grid(row=1, column=0, pady=(0, 15), ipady=8)
|
form_frame,
|
||||||
|
textvariable=self.username_var,
|
||||||
|
width=32,
|
||||||
|
font=('Segoe UI', 10),
|
||||||
|
relief='solid',
|
||||||
|
borderwidth=1
|
||||||
|
)
|
||||||
|
username_entry.grid(row=1, column=0, pady=(0, 15), ipady=7, padx=5)
|
||||||
|
|
||||||
# Password
|
# Password
|
||||||
tk.Label(form_frame, text="Password:", font=("Arial", 11), bg='white', fg=COLORS['text_dark']).grid(row=2, column=0, sticky='w', pady=(10, 5))
|
tk.Label(
|
||||||
|
form_frame,
|
||||||
|
text="Password:",
|
||||||
|
font=('Segoe UI', 10, 'bold'),
|
||||||
|
bg='white',
|
||||||
|
fg=COLORS['text_dark']
|
||||||
|
).grid(row=2, column=0, sticky='w', pady=(5, 5), padx=5)
|
||||||
|
|
||||||
self.password_var = tk.StringVar()
|
self.password_var = tk.StringVar()
|
||||||
password_entry = tk.Entry(form_frame, textvariable=self.password_var, show="●", width=35, font=("Arial", 11), relief='solid', borderwidth=1)
|
password_entry = tk.Entry(
|
||||||
password_entry.grid(row=3, column=0, pady=(0, 15), ipady=8)
|
form_frame,
|
||||||
|
textvariable=self.password_var,
|
||||||
|
show="●",
|
||||||
|
width=32,
|
||||||
|
font=('Segoe UI', 10),
|
||||||
|
relief='solid',
|
||||||
|
borderwidth=1
|
||||||
|
)
|
||||||
|
password_entry.grid(row=3, column=0, pady=(0, 15), ipady=7, padx=5)
|
||||||
|
|
||||||
# UI STYLING - Info untuk pembeli
|
# Separator
|
||||||
info_frame = tk.Frame(form_frame, bg='#FFF9E6', relief='solid', borderwidth=1)
|
separator = tk.Frame(form_frame, bg=COLORS['border'], height=2)
|
||||||
info_frame.grid(row=4, column=0, pady=15, sticky='ew')
|
separator.grid(row=4, column=0, sticky='ew', pady=12, padx=5)
|
||||||
|
|
||||||
tk.Label(info_frame, text="ℹ️ Khusus untuk Pembeli", font=("Arial", 9, "bold"), bg='#FFF9E6', fg=COLORS['brown']).pack(anchor='w', padx=10, pady=(10, 5))
|
# Info box
|
||||||
|
info_frame = tk.Frame(
|
||||||
|
form_frame,
|
||||||
|
bg='#FFF9E6',
|
||||||
|
relief='solid',
|
||||||
|
borderwidth=1
|
||||||
|
)
|
||||||
|
info_frame.grid(row=5, column=0, pady=8, sticky='ew', padx=5)
|
||||||
|
|
||||||
|
tk.Label(
|
||||||
|
info_frame,
|
||||||
|
text="ℹ️ Khusus untuk Pembeli",
|
||||||
|
font=('Segoe UI', 9, 'bold'),
|
||||||
|
bg='#FFF9E6',
|
||||||
|
fg=COLORS['brown']
|
||||||
|
).pack(anchor='w', padx=10, pady=(8, 3))
|
||||||
|
|
||||||
|
tk.Label(
|
||||||
|
info_frame,
|
||||||
|
text="Silakan isi Nama & Nomor Meja",
|
||||||
|
font=('Segoe UI', 8),
|
||||||
|
bg='#FFF9E6',
|
||||||
|
fg=COLORS['text_light']
|
||||||
|
).pack(anchor='w', padx=10, pady=(0, 8))
|
||||||
|
|
||||||
# Nama Lengkap
|
# Nama Lengkap
|
||||||
tk.Label(form_frame, text="Nama Lengkap:", font=("Arial", 10), bg='white', fg=COLORS['text_light']).grid(row=5, column=0, sticky='w', pady=(5, 3))
|
tk.Label(
|
||||||
|
form_frame,
|
||||||
|
text="Nama Lengkap:",
|
||||||
|
font=('Segoe UI', 9),
|
||||||
|
bg='white',
|
||||||
|
fg=COLORS['text_light']
|
||||||
|
).grid(row=6, column=0, sticky='w', pady=(10, 3), padx=5)
|
||||||
|
|
||||||
self.customer_name_var = tk.StringVar()
|
self.customer_name_var = tk.StringVar()
|
||||||
customer_entry = tk.Entry(form_frame, textvariable=self.customer_name_var, width=35, font=("Arial", 10), relief='solid', borderwidth=1)
|
customer_entry = tk.Entry(
|
||||||
customer_entry.grid(row=6, column=0, pady=(0, 10), ipady=6)
|
form_frame,
|
||||||
|
textvariable=self.customer_name_var,
|
||||||
|
width=32,
|
||||||
|
font=('Segoe UI', 9),
|
||||||
|
relief='solid',
|
||||||
|
borderwidth=1
|
||||||
|
)
|
||||||
|
customer_entry.grid(row=7, column=0, pady=(0, 10), ipady=6, padx=5)
|
||||||
|
|
||||||
# Nomor Meja
|
# Nomor Meja
|
||||||
tk.Label(form_frame, text="Nomor Meja (1-10):", font=("Arial", 10), bg='white', fg=COLORS['text_light']).grid(row=7, column=0, sticky='w', pady=(5, 3))
|
tk.Label(
|
||||||
|
form_frame,
|
||||||
|
text="Nomor Meja (1-10):",
|
||||||
|
font=('Segoe UI', 9),
|
||||||
|
bg='white',
|
||||||
|
fg=COLORS['text_light']
|
||||||
|
).grid(row=8, column=0, sticky='w', pady=(5, 3), padx=5)
|
||||||
|
|
||||||
self.customer_meja_var = tk.StringVar()
|
self.customer_meja_var = tk.StringVar()
|
||||||
meja_entry = tk.Entry(form_frame, textvariable=self.customer_meja_var, width=35, font=("Arial", 10), relief='solid', borderwidth=1)
|
meja_entry = tk.Entry(
|
||||||
meja_entry.grid(row=8, column=0, pady=(0, 20), ipady=6)
|
form_frame,
|
||||||
|
textvariable=self.customer_meja_var,
|
||||||
|
width=32,
|
||||||
|
font=('Segoe UI', 9),
|
||||||
|
relief='solid',
|
||||||
|
borderwidth=1
|
||||||
|
)
|
||||||
|
meja_entry.grid(row=9, column=0, pady=(0, 20), ipady=6, padx=5)
|
||||||
|
|
||||||
# UI STYLING - Login button dengan style Totoro
|
# Login button
|
||||||
login_btn = tk.Button(form_frame,
|
login_btn = tk.Button(
|
||||||
text="🌿 LOGIN",
|
form_frame,
|
||||||
command=self.handle_login,
|
text="LOGIN",
|
||||||
bg=COLORS['primary'],
|
command=self.handle_login,
|
||||||
fg='white',
|
bg=COLORS['primary'],
|
||||||
font=("Arial", 12, "bold"),
|
fg='white',
|
||||||
relief='flat',
|
font=('Segoe UI', 11, 'bold'),
|
||||||
cursor='hand2',
|
relief='flat',
|
||||||
width=30,
|
cursor='hand2',
|
||||||
height=2)
|
width=28,
|
||||||
login_btn.grid(row=9, column=0, pady=(10, 20))
|
height=2,
|
||||||
|
borderwidth=0
|
||||||
|
)
|
||||||
|
login_btn.grid(row=10, column=0, pady=(10, 15), padx=5)
|
||||||
|
|
||||||
# Hover effect untuk button
|
|
||||||
def on_enter(e):
|
def on_enter(e):
|
||||||
login_btn['background'] = COLORS['primary_dark']
|
login_btn['background'] = COLORS['primary_dark']
|
||||||
def on_leave(e):
|
def on_leave(e):
|
||||||
@ -1299,15 +1508,15 @@ class App:
|
|||||||
login_btn.bind("<Enter>", on_enter)
|
login_btn.bind("<Enter>", on_enter)
|
||||||
login_btn.bind("<Leave>", on_leave)
|
login_btn.bind("<Leave>", on_leave)
|
||||||
|
|
||||||
# UI STYLING - Footer
|
# Footer
|
||||||
footer_frame = tk.Frame(card, bg='white')
|
tk.Label(
|
||||||
footer_frame.pack(fill='x', pady=(0, 20))
|
right_panel,
|
||||||
|
text="© 2025 Café Totoro - UAS Informatika",
|
||||||
|
font=('Segoe UI', 7),
|
||||||
|
bg='white',
|
||||||
|
fg=COLORS['text_light']
|
||||||
|
).pack(side='bottom', pady=(20, 10))
|
||||||
|
|
||||||
tk.Label(footer_frame,
|
|
||||||
text="© 2025 Café Totoro - Proyek UAS Informatika",
|
|
||||||
font=("Arial", 8),
|
|
||||||
bg='white',
|
|
||||||
fg=COLORS['text_light']).pack()
|
|
||||||
|
|
||||||
|
|
||||||
def handle_login(self):
|
def handle_login(self):
|
||||||
@ -1392,58 +1601,94 @@ class App:
|
|||||||
def dashboard_frame(self):
|
def dashboard_frame(self):
|
||||||
for w in self.root.winfo_children():
|
for w in self.root.winfo_children():
|
||||||
w.destroy()
|
w.destroy()
|
||||||
# UI STYLING - Header dashboard dengan tema Totoro
|
|
||||||
top = tk.Frame(self.root, bg=COLORS['primary'], height=60)
|
# ========================================
|
||||||
|
# DASHBOARD HEADER - IMPROVED
|
||||||
|
# ========================================
|
||||||
|
top = tk.Frame(self.root, bg=COLORS['primary'], height=70)
|
||||||
top.pack(fill='x')
|
top.pack(fill='x')
|
||||||
|
|
||||||
# Left side - User info
|
# Left side - Logo + Title
|
||||||
left_info = tk.Frame(top, bg=COLORS['primary'])
|
left_side = tk.Frame(top, bg=COLORS['primary'])
|
||||||
left_info.pack(side='left', padx=20, pady=10)
|
left_side.pack(side='left', padx=20, pady=10)
|
||||||
|
|
||||||
# UI STYLING - Logo kecil di header
|
# Logo
|
||||||
try:
|
try:
|
||||||
totoro_header = Image.open("img/totoro_logo.png")
|
totoro_header = Image.open("img/totoro_logo.png")
|
||||||
totoro_header = totoro_header.resize((40, 40), Image.Resampling.LANCZOS)
|
totoro_header = totoro_header.resize((45, 45), Image.Resampling.LANCZOS)
|
||||||
totoro_header_photo = ImageTk.PhotoImage(totoro_header)
|
totoro_header_photo = ImageTk.PhotoImage(totoro_header)
|
||||||
|
|
||||||
self.totoro_header_logo = totoro_header_photo
|
self.totoro_header_logo = totoro_header_photo
|
||||||
|
|
||||||
tk.Label(top, image=totoro_header_photo, bg=COLORS['primary']).pack(side='left', padx=(20, 5))
|
tk.Label(left_side, image=totoro_header_photo, bg=COLORS['primary']).pack(side='left', padx=(0, 10))
|
||||||
except:
|
except:
|
||||||
tk.Label(top, text="🌿", font=("Arial", 24), bg=COLORS['primary']).pack(side='left', padx=(20, 5))
|
tk.Label(left_side, text="🌿", font=('Arial', 28), bg=COLORS['primary']).pack(side='left', padx=(0, 10))
|
||||||
|
|
||||||
|
# Title + Subtitle
|
||||||
|
title_frame = tk.Frame(left_side, bg=COLORS['primary'])
|
||||||
|
title_frame.pack(side='left')
|
||||||
|
|
||||||
|
tk.Label(
|
||||||
|
title_frame,
|
||||||
|
text="TOTORO CAFÉ",
|
||||||
|
font=('Comic Sans MS', 16, 'bold'),
|
||||||
|
bg=COLORS['primary'],
|
||||||
|
fg='white'
|
||||||
|
).pack(anchor='w')
|
||||||
|
|
||||||
|
tk.Label(
|
||||||
|
title_frame,
|
||||||
|
text="Your Cozy Corner for Every Order",
|
||||||
|
font=FONTS['small'],
|
||||||
|
bg=COLORS['primary'],
|
||||||
|
fg='white'
|
||||||
|
).pack(anchor='w')
|
||||||
|
|
||||||
|
# Center - User info (IMPROVED)
|
||||||
|
center_info = tk.Frame(top, bg=COLORS['primary'])
|
||||||
|
center_info.pack(side='left', expand=True, padx=20)
|
||||||
|
|
||||||
if self.session['role'] in ['pembeli', 'user'] and 'customer_name' in self.session:
|
if self.session['role'] in ['pembeli', 'user'] and 'customer_name' in self.session:
|
||||||
header_text = f"👤 {self.session['customer_name']}"
|
user_text = f"👤 {self.session['customer_name']}"
|
||||||
subtext = f"Meja {self.session.get('nomor_meja', '-')} • {self.session['role'].title()}"
|
role_text = f"🪑 Meja {self.session.get('nomor_meja', '-')} • {self.session['role'].title()}"
|
||||||
else:
|
else:
|
||||||
header_text = f"👤 {self.session['username']}"
|
user_text = f"👤 {self.session['username']}"
|
||||||
subtext = f"Role: {self.session['role'].title()}"
|
role_text = f"🎭 Role: {self.session['role'].title()}"
|
||||||
|
|
||||||
tk.Label(left_info,
|
tk.Label(
|
||||||
text=header_text,
|
center_info,
|
||||||
font=("Arial", 13, "bold"),
|
text=user_text,
|
||||||
bg=COLORS['primary'],
|
font=FONTS['subheader'],
|
||||||
fg='white').pack(anchor='w')
|
bg=COLORS['primary'],
|
||||||
|
fg='white'
|
||||||
|
).pack()
|
||||||
|
|
||||||
tk.Label(left_info,
|
tk.Label(
|
||||||
text=subtext,
|
center_info,
|
||||||
font=("Arial", 9),
|
text=role_text,
|
||||||
bg=COLORS['primary'],
|
font=FONTS['small'],
|
||||||
fg='white').pack(anchor='w')
|
bg=COLORS['primary'],
|
||||||
|
fg='white'
|
||||||
|
).pack()
|
||||||
|
|
||||||
# Right side - Logout button
|
# Right side - Logout button dengan shadow
|
||||||
logout_btn = tk.Button(top,
|
right_side = tk.Frame(top, bg=COLORS['primary'])
|
||||||
text="🚪 Logout",
|
right_side.pack(side='right', padx=20, pady=10)
|
||||||
command=self.logout,
|
|
||||||
bg=COLORS['brown'],
|
logout_btn = tk.Button(
|
||||||
fg='white',
|
right_side,
|
||||||
font=("Arial", 10, "bold"),
|
text="Logout",
|
||||||
relief='flat',
|
command=self.logout,
|
||||||
cursor='hand2',
|
bg=COLORS['brown'],
|
||||||
padx=20,
|
fg='white',
|
||||||
pady=8)
|
font=FONTS['button'],
|
||||||
logout_btn.pack(side='right', padx=20, pady=10)
|
relief='flat',
|
||||||
|
cursor='hand2',
|
||||||
|
padx=25,
|
||||||
|
pady=10,
|
||||||
|
borderwidth=0
|
||||||
|
)
|
||||||
|
logout_btn.pack()
|
||||||
|
|
||||||
# Hover effect
|
# Hover effect
|
||||||
def on_enter(e):
|
def on_enter(e):
|
||||||
@ -1453,13 +1698,14 @@ class App:
|
|||||||
logout_btn.bind("<Enter>", on_enter)
|
logout_btn.bind("<Enter>", on_enter)
|
||||||
logout_btn.bind("<Leave>", on_leave)
|
logout_btn.bind("<Leave>", on_leave)
|
||||||
|
|
||||||
# UI STYLING - Container untuk tabs
|
# Tab container dengan styling
|
||||||
tab_container = tk.Frame(self.root, bg=COLORS['bg_main'])
|
tab_container = tk.Frame(self.root, bg=COLORS['bg_main'])
|
||||||
tab_container.pack(fill='both', expand=True, padx=15, pady=10)
|
tab_container.pack(fill='both', expand=True, padx=15, pady=10)
|
||||||
|
|
||||||
main = ttk.Notebook(tab_container)
|
main = ttk.Notebook(tab_container)
|
||||||
main.pack(fill='both', expand=True)
|
main.pack(fill='both', expand=True)
|
||||||
|
|
||||||
|
|
||||||
self.tab_menu_manage = ttk.Frame(main)
|
self.tab_menu_manage = ttk.Frame(main)
|
||||||
self.tab_menu_view = ttk.Frame(main)
|
self.tab_menu_view = ttk.Frame(main)
|
||||||
self.tab_promo = ttk.Frame(main)
|
self.tab_promo = ttk.Frame(main)
|
||||||
@ -2054,21 +2300,27 @@ class App:
|
|||||||
for cart_item in self.cart_items:
|
for cart_item in self.cart_items:
|
||||||
cart_dict[cart_item['menu_id']] = cart_item['qty']
|
cart_dict[cart_item['menu_id']] = cart_item['qty']
|
||||||
|
|
||||||
# Render cards dalam grid (2 kolom)
|
# Configure grid columns (2 kolom sama lebar)
|
||||||
|
self.menu_cards_frame.columnconfigure(0, weight=1)
|
||||||
|
self.menu_cards_frame.columnconfigure(1, weight=1)
|
||||||
|
|
||||||
row = 0
|
row = 0
|
||||||
col = 0
|
col = 0
|
||||||
|
|
||||||
for menu_data in results:
|
for menu_data in results:
|
||||||
mid, nama, kategori, harga, stok, foto, tersedia, item_disc = menu_data
|
mid, nama, kategori, harga, stok, foto, tersedia, item_disc = menu_data
|
||||||
|
|
||||||
# Create card frame (DENGAN BACKGROUND PUTIH + BORDER)
|
|
||||||
card = tk.Frame(
|
card = tk.Frame(
|
||||||
self.menu_cards_frame,
|
self.menu_cards_frame,
|
||||||
relief='solid',
|
relief='solid',
|
||||||
borderwidth=1,
|
borderwidth=1,
|
||||||
bg='white',
|
bg='white',
|
||||||
padx=10,
|
padx=10,
|
||||||
pady=10
|
pady=10,
|
||||||
|
width=200,
|
||||||
|
height=320
|
||||||
)
|
)
|
||||||
|
card.grid_propagate(False)
|
||||||
card.grid(row=row, column=col, padx=8, pady=8, sticky='nsew')
|
card.grid(row=row, column=col, padx=8, pady=8, sticky='nsew')
|
||||||
|
|
||||||
# Gambar
|
# Gambar
|
||||||
@ -2080,41 +2332,85 @@ class App:
|
|||||||
|
|
||||||
img_label = tk.Label(card, image=photo, bg='white')
|
img_label = tk.Label(card, image=photo, bg='white')
|
||||||
img_label.image = photo
|
img_label.image = photo
|
||||||
img_label.pack()
|
img_label.pack(pady=(5, 5))
|
||||||
except:
|
except:
|
||||||
tk.Label(card, text="[No Image]", bg='#e0e0e0', width=20, height=6).pack()
|
tk.Label(
|
||||||
|
card,
|
||||||
|
text="[No Image]",
|
||||||
|
bg='#e0e0e0',
|
||||||
|
width=20,
|
||||||
|
height=6
|
||||||
|
).pack()
|
||||||
else:
|
else:
|
||||||
tk.Label(card, text="[No Image]", bg='#e0e0e0', width=20, height=6).pack()
|
tk.Label(
|
||||||
|
card,
|
||||||
|
text="[No Image]",
|
||||||
|
bg='#e0e0e0',
|
||||||
|
width=18,
|
||||||
|
height=5
|
||||||
|
).pack()
|
||||||
|
|
||||||
# Nama menu
|
# Nama menu
|
||||||
tk.Label(card, text=nama, font=("Arial", 11, "bold"), bg='white', wraplength=150).pack(pady=(5, 2))
|
tk.Label(
|
||||||
|
card,
|
||||||
|
text=nama,
|
||||||
|
font=("Arial", 10, "bold"),
|
||||||
|
bg='white',
|
||||||
|
wraplength=140,
|
||||||
|
justify='center',
|
||||||
|
height=2
|
||||||
|
).pack(pady=(3, 2))
|
||||||
|
|
||||||
# Kategori
|
# Kategori
|
||||||
tk.Label(card, text=kategori, font=("Arial", 9), fg='gray', bg='white').pack()
|
tk.Label(
|
||||||
|
card,
|
||||||
|
text=kategori,
|
||||||
|
font=("Arial", 8),
|
||||||
|
fg='gray',
|
||||||
|
bg='white'
|
||||||
|
).pack(pady=1)
|
||||||
|
|
||||||
# Harga
|
# Harga
|
||||||
harga_text = f"Rp {harga:,.0f}"
|
harga_text = f"Rp {harga:,.0f}"
|
||||||
if item_disc > 0:
|
if item_disc > 0:
|
||||||
harga_text += f" (-{item_disc}%)"
|
harga_text += f"\n(-{item_disc}%)"
|
||||||
tk.Label(card, text=harga_text, font=("Arial", 10, "bold"), fg='#4CAF50', bg='white').pack(pady=2)
|
tk.Label(
|
||||||
|
card,
|
||||||
|
text=harga_text,
|
||||||
|
font=("Arial", 9, "bold"),
|
||||||
|
fg='#4CAF50',
|
||||||
|
bg='white',
|
||||||
|
justify='center'
|
||||||
|
).pack(pady=2)
|
||||||
else:
|
else:
|
||||||
tk.Label(card, text=harga_text, font=("Arial", 10, "bold"), fg='green', bg='white').pack(pady=2)
|
tk.Label(
|
||||||
|
card,
|
||||||
|
text=harga_text,
|
||||||
|
font=("Arial", 9, "bold"),
|
||||||
|
fg='green',
|
||||||
|
bg='white'
|
||||||
|
).pack(pady=2)
|
||||||
|
|
||||||
# Stok info
|
# Stok
|
||||||
tk.Label(card, text=f"Stok: {stok}", font=("Arial", 8), fg='blue', bg='white').pack(pady=2)
|
stok_color = 'blue' if stok > 0 else 'red'
|
||||||
|
tk.Label(
|
||||||
|
card,
|
||||||
|
text=f"Stok: {stok}",
|
||||||
|
font=("Arial", 8),
|
||||||
|
fg=stok_color,
|
||||||
|
bg='white'
|
||||||
|
).pack(pady=2)
|
||||||
|
|
||||||
# Tombol +/- atau + saja
|
|
||||||
qty_in_cart = cart_dict.get(mid, 0)
|
qty_in_cart = cart_dict.get(mid, 0)
|
||||||
|
|
||||||
btn_frame = tk.Frame(card, bg='white')
|
btn_frame = tk.Frame(card, bg='white')
|
||||||
btn_frame.pack(pady=5)
|
btn_frame.pack(pady=(5, 5), fill='x')
|
||||||
|
|
||||||
if qty_in_cart > 0:
|
if qty_in_cart > 0:
|
||||||
# Tampilkan - [qty] +
|
|
||||||
tk.Button(
|
tk.Button(
|
||||||
btn_frame,
|
btn_frame,
|
||||||
text="➖",
|
text="➖",
|
||||||
font=("Arial", 12, "bold"),
|
font=("Arial", 10, "bold"),
|
||||||
bg='#FF5722',
|
bg='#FF5722',
|
||||||
fg='white',
|
fg='white',
|
||||||
width=3,
|
width=3,
|
||||||
@ -2126,15 +2422,15 @@ class App:
|
|||||||
tk.Label(
|
tk.Label(
|
||||||
btn_frame,
|
btn_frame,
|
||||||
text=str(qty_in_cart),
|
text=str(qty_in_cart),
|
||||||
font=("Arial", 12, "bold"),
|
font=("Arial", 10, "bold"),
|
||||||
bg='white',
|
bg='white',
|
||||||
width=3
|
width=4
|
||||||
).pack(side='left', padx=5)
|
).pack(side='left', padx=3)
|
||||||
|
|
||||||
tk.Button(
|
tk.Button(
|
||||||
btn_frame,
|
btn_frame,
|
||||||
text="➕",
|
text="➕",
|
||||||
font=("Arial", 12, "bold"),
|
font=("Arial", 10, "bold"),
|
||||||
bg='#4CAF50',
|
bg='#4CAF50',
|
||||||
fg='white',
|
fg='white',
|
||||||
width=3,
|
width=3,
|
||||||
@ -2143,25 +2439,26 @@ class App:
|
|||||||
command=lambda m=mid, s=stok: self.increase_from_card(m, s)
|
command=lambda m=mid, s=stok: self.increase_from_card(m, s)
|
||||||
).pack(side='left', padx=2)
|
).pack(side='left', padx=2)
|
||||||
else:
|
else:
|
||||||
# Tampilkan tombol + aja
|
|
||||||
tk.Button(
|
tk.Button(
|
||||||
btn_frame,
|
btn_frame,
|
||||||
text="➕ Tambah",
|
text="➕ Tambah",
|
||||||
font=("Arial", 10, "bold"),
|
font=("Arial", 9, "bold"),
|
||||||
bg='#4CAF50',
|
bg='#4CAF50',
|
||||||
fg='white',
|
fg='white',
|
||||||
width=12,
|
|
||||||
borderwidth=0,
|
borderwidth=0,
|
||||||
cursor='hand2',
|
cursor='hand2',
|
||||||
command=lambda m=mid, s=stok: self.increase_from_card(m, s)
|
command=lambda m=mid, s=stok: self.increase_from_card(m, s)
|
||||||
).pack()
|
).pack(fill='x', padx=2)
|
||||||
|
|
||||||
# Next column
|
|
||||||
col += 1
|
col += 1
|
||||||
if col >= 2:
|
if col >= 2:
|
||||||
col = 0
|
col = 0
|
||||||
row += 1
|
row += 1
|
||||||
|
|
||||||
|
for i in range(row + 1):
|
||||||
|
self.menu_cards_frame.rowconfigure(i, weight=1)
|
||||||
|
|
||||||
|
|
||||||
def reset_order_search(self):
|
def reset_order_search(self):
|
||||||
self.order_search_var.set("")
|
self.order_search_var.set("")
|
||||||
self.reload_order_menu_cards()
|
self.reload_order_menu_cards()
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user