diff --git a/img/totoro_logo.png b/img/totoro_logo.png new file mode 100644 index 0000000..7d1f543 Binary files /dev/null and b/img/totoro_logo.png differ diff --git a/main.py b/main.py index d5bf327..c04fa74 100644 --- a/main.py +++ b/main.py @@ -12,6 +12,24 @@ import tkinter as tk from tkinter import ttk, messagebox, filedialog, simpledialog from PIL import Image, ImageTk +# ======================================== +# UI STYLING - TOTORO THEME COLORS +# ======================================== +COLORS = { + 'bg_main': '#F5F5DC', # Beige/Krem lembut (background utama) + 'bg_secondary': '#FFFFFF', # Putih untuk cards + 'primary': '#8FBFA8', # Hijau Totoro (medium) + 'primary_dark': '#6B9080', # Hijau tua + 'accent': '#A8D5BA', # Hijau pastel lembut + 'brown': '#8B7355', # Coklat kayu + 'text_dark': '#3D3D3D', # Text gelap + 'text_light': '#666666', # Text abu-abu + 'success': '#6B9080', # Hijau untuk success + 'warning': '#D4A574', # Coklat muda untuk warning + 'danger': '#C9797A', # Merah lembut untuk danger + 'border': '#D4C5B9', # Border coklat muda +} + USERS_CSV = "users.csv" MENU_CSV = "menu.csv" PROMO_CSV = "promo.csv" @@ -793,7 +811,7 @@ def report_get_monthly_summary(year=None, month=None, method_filter=None): def report_export_to_text(report_data, report_type='daily'): """Export laporan ke format text""" text = "=" * 70 + "\n" - text += "LAPORAN PENJUALAN CAFE TOTORO MANIA\n" + text += "LAPORAN PENJUALAN CAFÉ TOTORO \n" text += "=" * 70 + "\n\n" if report_type == 'daily': @@ -1101,52 +1119,196 @@ def meja_get(nomor_meja): class App: def __init__(self, root): self.root = root - self.root.title("Cafe Totoro Mania") + self.root.title("Totoro Cafe") self.session = None self.img_cache = {} self.setup_ui() def setup_ui(self): - self.root.geometry("1000x650") - self.root.resizable(False, False) - self.login_frame() + # UI STYLING - Window setup dengan tema Totoro + self.root.geometry("1200x750") + self.root.resizable(True, True) # Bisa maximize + self.root.configure(bg=COLORS['bg_main']) + + # UI STYLING - Custom styles untuk tema Totoro style = ttk.Style() - style.configure("Accent.TButton", font=("Arial", 11, "bold")) - style.configure("TButton", padding=6) # Padding tombol lebih besar + style.theme_use('clam') + + # Background colors + style.configure(".", background=COLORS['bg_main'], foreground=COLORS['text_dark']) + + # Frame styles + style.configure("TFrame", background=COLORS['bg_main']) + style.configure("TLabelframe", background=COLORS['bg_main'], bordercolor=COLORS['border']) + style.configure("TLabelframe.Label", background=COLORS['bg_main'], foreground=COLORS['brown'], font=("Arial", 10, "bold")) + + # Button styles + style.configure("TButton", + background=COLORS['primary'], + foreground="white", + borderwidth=0, + focuscolor='none', + font=("Arial", 10), + padding=10) + style.map("TButton", + background=[('active', COLORS['primary_dark']), ('pressed', COLORS['primary_dark'])], + foreground=[('active', 'white')]) + + style.configure("Accent.TButton", + background=COLORS['brown'], + foreground="white", + font=("Arial", 11, "bold"), + padding=12) + style.map("Accent.TButton", + background=[('active', '#6B5D48'), ('pressed', '#6B5D48')]) + + # Label styles + style.configure("TLabel", background=COLORS['bg_main'], foreground=COLORS['text_dark'], font=("Arial", 10)) + + # Entry styles + style.configure("TEntry", fieldbackground="white", bordercolor=COLORS['border']) + + # Treeview styles + style.configure("Treeview", + background="white", + foreground=COLORS['text_dark'], + fieldbackground="white", + borderwidth=0, + font=("Arial", 9)) + style.configure("Treeview.Heading", + background=COLORS['primary'], + foreground="white", + font=("Arial", 10, "bold")) + style.map("Treeview.Heading", + background=[('active', COLORS['primary_dark'])]) + + # Notebook (tabs) styles + style.configure("TNotebook", background=COLORS['bg_main'], borderwidth=0) + style.configure("TNotebook.Tab", + background=COLORS['accent'], + foreground=COLORS['text_dark'], + padding=[20, 10], + font=("Arial", 10)) + style.map("TNotebook.Tab", + background=[('selected', COLORS['primary'])], + foreground=[('selected', 'white')], + expand=[('selected', [1, 1, 1, 0])]) + + self.login_frame() def login_frame(self): for w in self.root.winfo_children(): w.destroy() - frame = ttk.Frame(self.root, padding=20) - frame.pack(expand=True) - - ttk.Label(frame, text="Login Duluu...", font=("Arial", 24)).grid(row=0, column=0, columnspan=2, pady=10) - - ttk.Label(frame, text="Username:").grid(row=1, column=0, sticky='e', pady=5) - self.username_var = tk.StringVar() - ttk.Entry(frame, textvariable=self.username_var, width=30).grid(row=1, column=1, pady=5) - - ttk.Label(frame, text="Password:").grid(row=2, column=0, sticky='e', pady=5) - self.password_var = tk.StringVar() - ttk.Entry(frame, textvariable=self.password_var, show="*", width=30).grid(row=2, column=1, pady=5) - # TAMBAHAN: Input nama pembeli (untuk role pembeli) - ttk.Label(frame, text="Nama Lengkap:", font=("Arial", 9)).grid(row=3, column=0, sticky='e', pady=5) + # UI STYLING - Main container dengan background Totoro + 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 = tk.Frame(main_container, bg=COLORS['bg_main']) + center_frame.place(relx=0.5, rely=0.5, anchor='center') + + # UI STYLING - Login card dengan shadow effect + card = tk.Frame(center_frame, bg='white', relief='flat', borderwidth=0) + card.pack(padx=20, pady=20) + + # UI STYLING - Header dengan tema Totoro + header_frame = tk.Frame(card, bg=COLORS['primary'], height=100) + header_frame.pack(fill='x', pady=(0, 30)) + + # UI STYLING - Logo Totoro di atas card + try: + totoro_img = Image.open("img/totoro_logo.png") + totoro_img = totoro_img.resize((100, 100), Image.Resampling.LANCZOS) + totoro_photo = ImageTk.PhotoImage(totoro_img) + + self.totoro_logo = 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)) + + + tk.Label(header_frame, + text="🌿 TOTORO CAFÉ 🌿", + font=("Arial", 24, "bold"), + bg=COLORS['primary'], + fg='white').pack(pady=20) + + tk.Label(header_frame, + text="Selamat Datang di Sistem Manajemen Cafe", + font=("Arial", 10), + bg=COLORS['primary'], + fg='white').pack(pady=(0, 10)) + + # UI STYLING - Form container + form_frame = tk.Frame(card, bg='white') + form_frame.pack(padx=50, pady=20) + + # 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)) + 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) + + # 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)) + 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) + + # 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') + + 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)) + + # 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)) self.customer_name_var = tk.StringVar() - customer_entry = ttk.Entry(frame, textvariable=self.customer_name_var, width=30) - customer_entry.grid(row=3, column=1, pady=5) - ttk.Label(frame, text="(Khusus untuk Pembeli)", font=("Arial", 7), foreground='gray').grid(row=4, column=1, sticky='w') - - # TAMBAHAN BARU: Input nomor meja (untuk role pembeli) - ttk.Label(frame, text="Nomor Meja:", font=("Arial", 9)).grid(row=5, column=0, sticky='e', pady=5) + 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) + + # 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)) self.customer_meja_var = tk.StringVar() - meja_entry = ttk.Entry(frame, textvariable=self.customer_meja_var, width=30) - meja_entry.grid(row=5, column=1, pady=5) - ttk.Label(frame, text="(Khusus untuk Pembeli - Meja 1-10)", font=("Arial", 7), foreground='gray').grid(row=6, column=1, sticky='w') + 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) + + # 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)) + + # Hover effect untuk button + def on_enter(e): + login_btn['background'] = COLORS['primary_dark'] + def on_leave(e): + login_btn['background'] = COLORS['primary'] + + login_btn.bind("", on_enter) + login_btn.bind("", on_leave) + + # UI STYLING - Footer + footer_frame = tk.Frame(card, bg='white') + footer_frame.pack(fill='x', pady=(0, 20)) + + tk.Label(footer_frame, + text="© 2025 Café Totoro - Proyek UAS Informatika", + font=("Arial", 8), + bg='white', + fg=COLORS['text_light']).pack() - ttk.Button(frame, text="Login", command=self.handle_login).grid(row=7, column=0, columnspan=2, pady=12) - - def handle_login(self): u = self.username_var.get().strip() @@ -1230,23 +1392,74 @@ class App: def dashboard_frame(self): for w in self.root.winfo_children(): w.destroy() - top = ttk.Frame(self.root) + # UI STYLING - Header dashboard dengan tema Totoro + top = tk.Frame(self.root, bg=COLORS['primary'], height=60) top.pack(fill='x') - # Text untuk header - if self.session['role'] in ['pembeli', 'user'] and 'customer_name' in self.session: - header_text = f"👤 {self.session['customer_name']} | User: {self.session['username']} | Role: {self.session['role']}" - else: - header_text = f"User: {self.session['username']} | Role: {self.session['role']}" + # Left side - User info + left_info = tk.Frame(top, bg=COLORS['primary']) + left_info.pack(side='left', padx=20, pady=10) - ttk.Label( - top, - text=header_text, - font=("Arial", 12) - ).pack(side='left', padx=10, pady=6) - ttk.Button(top, text="Logout", command=self.logout).pack(side='right', padx=10) - main = ttk.Notebook(self.root) - main.pack(fill='both', expand=True, padx=10, pady=8) + # UI STYLING - Logo kecil di header + try: + totoro_header = Image.open("img/totoro_logo.png") + totoro_header = totoro_header.resize((40, 40), 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)) + except: + tk.Label(top, text="🌿", font=("Arial", 24), bg=COLORS['primary']).pack(side='left', padx=(20, 5)) + + + 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()}" + else: + header_text = f"👤 {self.session['username']}" + subtext = 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(left_info, + text=subtext, + font=("Arial", 9), + bg=COLORS['primary'], + fg='white').pack(anchor='w') + + # 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) + + # Hover effect + def on_enter(e): + logout_btn['background'] = '#6B5D48' + def on_leave(e): + logout_btn['background'] = COLORS['brown'] + logout_btn.bind("", on_enter) + logout_btn.bind("", on_leave) + + # UI STYLING - Container untuk tabs + 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) @@ -4328,8 +4541,8 @@ class App: # Build struk string struk = "═════════════════════════════════════════\n" - struk += " CAFE TOTORO MANIA\n" - struk += " Jl. Raya Kampus No. 123, Surabaya\n" + struk += " TOTORO CAFE\n" + struk += " Jl. Raya Totoro No. 123, Surabaya\n" struk += " Telp: 031-123456\n" struk += "═════════════════════════════════════════\n\n" struk += f"No. Struk : STR-{tid}-{datetime.now().strftime('%Y%m%d')}\n"