Styling Update

This commit is contained in:
Jevinca Marvella 2025-12-14 19:54:04 +07:00
parent 673a693020
commit 3d7b31f218
3 changed files with 464 additions and 167 deletions

BIN
img/totoro_sitting.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 225 KiB

559
main.py
View File

@ -12,8 +12,10 @@ import tkinter as tk
from tkinter import ttk, messagebox, filedialog, simpledialog
from PIL import Image, ImageTk
# ========================================
# UI STYLING - TOTORO THEME COLORS
# UI STYLING - TOTORO THEME COLORS + FONTS
# ========================================
COLORS = {
'bg_main': '#F5F5DC', # Beige/Krem lembut (background utama)
@ -28,6 +30,19 @@ COLORS = {
'warning': '#D4A574', # Coklat muda untuk warning
'danger': '#C9797A', # Merah lembut untuk danger
'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"
@ -40,6 +55,28 @@ MEJA_CSV = "meja.csv"
PEMBAYARAN_CSV = "pembayaran.csv"
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):
if not os.path.exists(path):
@ -1124,6 +1161,47 @@ class App:
self.img_cache = {}
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):
# UI STYLING - Window setup dengan tema Totoro
self.root.geometry("1200x750")
@ -1200,97 +1278,228 @@ class App:
for w in self.root.winfo_children():
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.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.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)
card.pack(padx=20, pady=20)
# ========================================
# MAIN CARD - LANDSCAPE (TANPA SHADOW DULU)
# ========================================
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)
header_frame.pack(fill='x', pady=(0, 30))
# ========================================
# CONTAINER HORIZONTAL (2 PANEL)
# ========================================
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:
totoro_img = Image.open("img/totoro_logo.png")
totoro_img = totoro_img.resize((100, 100), Image.Resampling.LANCZOS)
totoro_img = Image.open("img/totoro_sitting.png")
totoro_img = totoro_img.resize((250, 250), Image.Resampling.LANCZOS)
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.pack(pady=(20, 10))
except:
# Fallback jika gambar tidak ditemukan
tk.Label(card, text="🌿", font=("Arial", 48), bg='white').pack(pady=(20, 10))
img_label = tk.Label(left_panel, image=totoro_photo, bg=COLORS['accent'])
img_label.pack(pady=20)
except Exception as e:
print(f"⚠️ Gambar tidak ditemukan: {e}")
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É 🌿",
font=("Arial", 24, "bold"),
bg=COLORS['primary'],
fg='white').pack(pady=20)
# ========================================
# RIGHT PANEL - LOGIN FORM
# ========================================
right_panel = tk.Frame(container, bg='white', padx=40, pady=30)
right_panel.pack(side='right', fill='both')
tk.Label(header_frame,
text="Selamat Datang di Sistem Manajemen Cafe",
font=("Arial", 10),
bg=COLORS['primary'],
fg='white').pack(pady=(0, 10))
# Header
tk.Label(
right_panel,
text="🌿 TOTORO CAFÉ 🌿",
font=('Comic Sans MS', 22, 'bold'),
bg='white',
fg=COLORS['primary']
).pack(pady=(10, 5))
# UI STYLING - Form container
form_frame = tk.Frame(card, bg='white')
form_frame.pack(padx=50, pady=20)
tk.Label(
right_panel,
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
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()
username_entry = tk.Entry(form_frame, textvariable=self.username_var, width=35, font=("Arial", 11), relief='solid', borderwidth=1)
username_entry.grid(row=1, column=0, pady=(0, 15), ipady=8)
username_entry = tk.Entry(
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
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()
password_entry = tk.Entry(form_frame, textvariable=self.password_var, show="", width=35, font=("Arial", 11), relief='solid', borderwidth=1)
password_entry.grid(row=3, column=0, pady=(0, 15), ipady=8)
password_entry = tk.Entry(
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
info_frame = tk.Frame(form_frame, bg='#FFF9E6', relief='solid', borderwidth=1)
info_frame.grid(row=4, column=0, pady=15, sticky='ew')
# Separator
separator = tk.Frame(form_frame, bg=COLORS['border'], height=2)
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
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()
customer_entry = tk.Entry(form_frame, textvariable=self.customer_name_var, width=35, font=("Arial", 10), relief='solid', borderwidth=1)
customer_entry.grid(row=6, column=0, pady=(0, 10), ipady=6)
customer_entry = tk.Entry(
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
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()
meja_entry = tk.Entry(form_frame, textvariable=self.customer_meja_var, width=35, font=("Arial", 10), relief='solid', borderwidth=1)
meja_entry.grid(row=8, column=0, pady=(0, 20), ipady=6)
meja_entry = tk.Entry(
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_btn = tk.Button(form_frame,
text="🌿 LOGIN",
command=self.handle_login,
bg=COLORS['primary'],
fg='white',
font=("Arial", 12, "bold"),
relief='flat',
cursor='hand2',
width=30,
height=2)
login_btn.grid(row=9, column=0, pady=(10, 20))
# Login button
login_btn = tk.Button(
form_frame,
text="LOGIN",
command=self.handle_login,
bg=COLORS['primary'],
fg='white',
font=('Segoe UI', 11, 'bold'),
relief='flat',
cursor='hand2',
width=28,
height=2,
borderwidth=0
)
login_btn.grid(row=10, column=0, pady=(10, 15), padx=5)
# Hover effect untuk button
def on_enter(e):
login_btn['background'] = COLORS['primary_dark']
def on_leave(e):
@ -1299,15 +1508,15 @@ class App:
login_btn.bind("<Enter>", on_enter)
login_btn.bind("<Leave>", on_leave)
# UI STYLING - Footer
footer_frame = tk.Frame(card, bg='white')
footer_frame.pack(fill='x', pady=(0, 20))
# Footer
tk.Label(
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):
@ -1392,58 +1601,94 @@ class App:
def dashboard_frame(self):
for w in self.root.winfo_children():
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')
# Left side - User info
left_info = tk.Frame(top, bg=COLORS['primary'])
left_info.pack(side='left', padx=20, pady=10)
# Left side - Logo + Title
left_side = tk.Frame(top, bg=COLORS['primary'])
left_side.pack(side='left', padx=20, pady=10)
# UI STYLING - Logo kecil di header
# Logo
try:
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)
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:
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:
header_text = f"👤 {self.session['customer_name']}"
subtext = f"Meja {self.session.get('nomor_meja', '-')}{self.session['role'].title()}"
user_text = f"👤 {self.session['customer_name']}"
role_text = f"🪑 Meja {self.session.get('nomor_meja', '-')}{self.session['role'].title()}"
else:
header_text = f"👤 {self.session['username']}"
subtext = f"Role: {self.session['role'].title()}"
user_text = f"👤 {self.session['username']}"
role_text = f"🎭 Role: {self.session['role'].title()}"
tk.Label(left_info,
text=header_text,
font=("Arial", 13, "bold"),
bg=COLORS['primary'],
fg='white').pack(anchor='w')
tk.Label(
center_info,
text=user_text,
font=FONTS['subheader'],
bg=COLORS['primary'],
fg='white'
).pack()
tk.Label(left_info,
text=subtext,
font=("Arial", 9),
bg=COLORS['primary'],
fg='white').pack(anchor='w')
tk.Label(
center_info,
text=role_text,
font=FONTS['small'],
bg=COLORS['primary'],
fg='white'
).pack()
# Right side - Logout button
logout_btn = tk.Button(top,
text="🚪 Logout",
command=self.logout,
bg=COLORS['brown'],
fg='white',
font=("Arial", 10, "bold"),
relief='flat',
cursor='hand2',
padx=20,
pady=8)
logout_btn.pack(side='right', padx=20, pady=10)
# Right side - Logout button dengan shadow
right_side = tk.Frame(top, bg=COLORS['primary'])
right_side.pack(side='right', padx=20, pady=10)
logout_btn = tk.Button(
right_side,
text="Logout",
command=self.logout,
bg=COLORS['brown'],
fg='white',
font=FONTS['button'],
relief='flat',
cursor='hand2',
padx=25,
pady=10,
borderwidth=0
)
logout_btn.pack()
# Hover effect
def on_enter(e):
@ -1453,13 +1698,14 @@ class App:
logout_btn.bind("<Enter>", on_enter)
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.pack(fill='both', expand=True, padx=15, pady=10)
main = ttk.Notebook(tab_container)
main.pack(fill='both', expand=True)
self.tab_menu_manage = ttk.Frame(main)
self.tab_menu_view = ttk.Frame(main)
self.tab_promo = ttk.Frame(main)
@ -2054,21 +2300,27 @@ class App:
for cart_item in self.cart_items:
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
col = 0
for menu_data in results:
mid, nama, kategori, harga, stok, foto, tersedia, item_disc = menu_data
# Create card frame (DENGAN BACKGROUND PUTIH + BORDER)
card = tk.Frame(
self.menu_cards_frame,
relief='solid',
borderwidth=1,
bg='white',
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')
# Gambar
@ -2080,41 +2332,85 @@ class App:
img_label = tk.Label(card, image=photo, bg='white')
img_label.image = photo
img_label.pack()
img_label.pack(pady=(5, 5))
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:
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
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
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_text = f"Rp {harga:,.0f}"
if item_disc > 0:
harga_text += f" (-{item_disc}%)"
tk.Label(card, text=harga_text, font=("Arial", 10, "bold"), fg='#4CAF50', bg='white').pack(pady=2)
harga_text += f"\n(-{item_disc}%)"
tk.Label(
card,
text=harga_text,
font=("Arial", 9, "bold"),
fg='#4CAF50',
bg='white',
justify='center'
).pack(pady=2)
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
tk.Label(card, text=f"Stok: {stok}", font=("Arial", 8), fg='blue', bg='white').pack(pady=2)
# Stok
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)
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:
# Tampilkan - [qty] +
tk.Button(
btn_frame,
text="",
font=("Arial", 12, "bold"),
font=("Arial", 10, "bold"),
bg='#FF5722',
fg='white',
width=3,
@ -2126,15 +2422,15 @@ class App:
tk.Label(
btn_frame,
text=str(qty_in_cart),
font=("Arial", 12, "bold"),
font=("Arial", 10, "bold"),
bg='white',
width=3
).pack(side='left', padx=5)
width=4
).pack(side='left', padx=3)
tk.Button(
btn_frame,
text="",
font=("Arial", 12, "bold"),
font=("Arial", 10, "bold"),
bg='#4CAF50',
fg='white',
width=3,
@ -2143,25 +2439,26 @@ class App:
command=lambda m=mid, s=stok: self.increase_from_card(m, s)
).pack(side='left', padx=2)
else:
# Tampilkan tombol + aja
tk.Button(
btn_frame,
text=" Tambah",
font=("Arial", 10, "bold"),
font=("Arial", 9, "bold"),
bg='#4CAF50',
fg='white',
width=12,
borderwidth=0,
cursor='hand2',
command=lambda m=mid, s=stok: self.increase_from_card(m, s)
).pack()
).pack(fill='x', padx=2)
# Next column
col += 1
if col >= 2:
col = 0
row += 1
for i in range(row + 1):
self.menu_cards_frame.rowconfigure(i, weight=1)
def reset_order_search(self):
self.order_search_var.set("")
self.reload_order_menu_cards()

View File

@ -1,5 +1,5 @@
nomor_meja,status,transaksi_id
1,kosong,
1,terisi,
2,kosong,
3,kosong,
4,kosong,

1 nomor_meja status transaksi_id
2 1 kosong terisi
3 2 kosong
4 3 kosong
5 4 kosong