Autosave: 20260217-135934

This commit is contained in:
Flatlogic Bot 2026-02-17 13:59:34 +00:00
parent 12ab3d7339
commit e17a272296
20 changed files with 1323 additions and 178 deletions

View File

@ -1,3 +1,23 @@
from django.contrib import admin
from .models import Category, Shop, Product
# Register your models here.
@admin.register(Category)
class CategoryAdmin(admin.ModelAdmin):
list_display = ('name', 'slug')
prepopulated_fields = {'slug': ('name',)}
@admin.register(Shop)
class ShopAdmin(admin.ModelAdmin):
list_display = ('name', 'owner', 'whatsapp_number', 'created_at')
prepopulated_fields = {'slug': ('name',)}
def save_model(self, request, obj, form, change):
if not obj.pk:
obj.owner = request.user
super().save_model(request, obj, form, change)
@admin.register(Product)
class ProductAdmin(admin.ModelAdmin):
list_display = ('name', 'shop', 'category', 'price', 'stock', 'is_active')
list_filter = ('shop', 'category', 'is_active')
prepopulated_fields = {'slug': ('name',)}

View File

@ -0,0 +1,58 @@
# Generated by Django 5.2.7 on 2026-02-17 04:38
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(
name='Category',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=100)),
('slug', models.SlugField(blank=True, unique=True)),
('icon', models.CharField(default='fa-tag', help_text='FontAwesome icon class (e.g., fa-shopping-basket)', max_length=50)),
],
options={
'verbose_name_plural': 'Categories',
},
),
migrations.CreateModel(
name='Shop',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=255)),
('slug', models.SlugField(blank=True, unique=True)),
('description', models.TextField(blank=True)),
('logo', models.FileField(blank=True, null=True, upload_to='shop_logos/')),
('whatsapp_number', models.CharField(help_text='Format: 628123456789', max_length=20)),
('created_at', models.DateTimeField(auto_now_add=True)),
('owner', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='shops', to=settings.AUTH_USER_MODEL)),
],
),
migrations.CreateModel(
name='Product',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=255)),
('slug', models.SlugField(blank=True, unique=True)),
('description', models.TextField()),
('price', models.DecimalField(decimal_places=2, max_digits=12)),
('image', models.FileField(blank=True, null=True, upload_to='product_images/')),
('stock', models.IntegerField(default=0)),
('is_active', models.BooleanField(default=True)),
('created_at', models.DateTimeField(auto_now_add=True)),
('category', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='products', to='core.category')),
('shop', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='products', to='core.shop')),
],
),
]

View File

@ -1,3 +1,63 @@
from django.db import models
from django.contrib.auth.models import User
from django.utils.text import slugify
import urllib.parse
# Create your models here.
class Category(models.Model):
name = models.CharField(max_length=100)
slug = models.SlugField(unique=True, blank=True)
icon = models.CharField(max_length=50, help_text="FontAwesome icon class (e.g., fa-shopping-basket)", default="fa-tag")
def save(self, *args, **kwargs):
if not self.slug:
self.slug = slugify(self.name)
super().save(*args, **kwargs)
class Meta:
verbose_name_plural = "Categories"
def __str__(self):
return str(self.name)
class Shop(models.Model):
owner = models.ForeignKey(User, on_delete=models.CASCADE, related_name='shops')
name = models.CharField(max_length=255)
slug = models.SlugField(unique=True, blank=True)
description = models.TextField(blank=True)
logo = models.FileField(upload_to='shop_logos/', blank=True, null=True)
whatsapp_number = models.CharField(max_length=20, help_text="Format: 628123456789")
created_at = models.DateTimeField(auto_now_add=True)
def save(self, *args, **kwargs):
if not self.slug:
self.slug = slugify(self.name)
super().save(*args, **kwargs)
def __str__(self):
return str(self.name)
class Product(models.Model):
shop = models.ForeignKey(Shop, on_delete=models.CASCADE, related_name='products')
category = models.ForeignKey(Category, on_delete=models.SET_NULL, null=True, related_name='products')
name = models.CharField(max_length=255)
slug = models.SlugField(unique=True, blank=True)
description = models.TextField()
price = models.DecimalField(max_digits=12, decimal_places=2)
image = models.FileField(upload_to='product_images/', blank=True, null=True)
stock = models.IntegerField(default=0)
is_active = models.BooleanField(default=True)
created_at = models.DateTimeField(auto_now_add=True)
def save(self, *args, **kwargs):
if not self.slug:
self.slug = slugify(self.name)
super().save(*args, **kwargs)
def __str__(self):
return str(self.name)
@property
def whatsapp_link(self):
message = f"Halo {self.shop.name}, saya tertarik dengan produk *{self.name}* seharga Rp {self.price:,.0f}. Apakah masih tersedia?"
encoded_message = urllib.parse.quote(message)
return f"https://wa.me/{self.shop.whatsapp_number}?text={encoded_message}"

View File

@ -1,25 +1,97 @@
<!DOCTYPE html>
<html lang="en">
<html lang="id">
<head>
<meta charset="UTF-8">
<title>{% block title %}Knowledge Base{% endblock %}</title>
{% if project_description %}
<meta name="description" content="{{ project_description }}">
<meta property="og:description" content="{{ project_description }}">
<meta property="twitter:description" content="{{ project_description }}">
{% endif %}
{% if project_image_url %}
<meta property="og:image" content="{{ project_image_url }}">
<meta property="twitter:image" content="{{ project_image_url }}">
{% endif %}
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% block title %}Marketplace UMKM Pemagarsari{% endblock %}</title>
<!-- Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Poppins:wght@500;600;700&display=swap" rel="stylesheet">
<!-- Bootstrap 5 -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<!-- FontAwesome -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
{% load static %}
<link rel="stylesheet" href="{% static 'css/custom.css' %}?v={{ deployment_timestamp }}">
<link rel="stylesheet" href="{% static 'css/custom.css' %}">
{% block head %}{% endblock %}
</head>
<body>
{% block content %}{% endblock %}
<!-- Navbar -->
<nav class="navbar navbar-expand-lg sticky-top">
<div class="container">
<a class="navbar-brand fw-bold" href="{% url 'home' %}">
<i class="fa-solid fa-shop text-emerald me-2"></i><span class="text-emerald">UMKM</span> Pemagarsari
</a>
<button class="navbar-toggler border-0 shadow-none" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav ms-auto align-items-center">
<li class="nav-item">
<a class="nav-link px-3" href="{% url 'home' %}">Beranda</a>
</li>
<li class="nav-item">
<a class="nav-link px-3" href="{% url 'shop_list' %}">Toko</a>
</li>
<li class="nav-item">
<a class="nav-link px-3" href="{% url 'home' %}#produk">Produk</a>
</li>
{% if user.is_authenticated %}
<li class="nav-item dropdown ms-lg-3">
<a class="nav-link dropdown-toggle btn btn-light rounded-pill px-4" href="#" role="button" data-bs-toggle="dropdown">
<i class="fa-solid fa-user-circle me-2"></i>{{ user.username }}
</a>
<ul class="dropdown-menu dropdown-menu-end border-0 shadow-sm rounded-3">
<li><a class="dropdown-item" href="{% url 'dashboard' %}">Dashboard</a></li>
<li><hr class="dropdown-divider"></li>
<li>
<form action="{% url 'logout' %}" method="POST">
{% csrf_token %}
<button type="submit" class="dropdown-item text-danger">Logout</button>
</form>
</li>
</ul>
</li>
{% else %}
<li class="nav-item ms-lg-3">
<a class="btn btn-emerald rounded-pill px-4" href="{% url 'login' %}">
<i class="fa-solid fa-right-to-bracket me-2"></i>Masuk
</a>
</li>
{% endif %}
</ul>
</div>
</div>
</nav>
<main>
{% block content %}{% endblock %}
</main>
<!-- Footer -->
<footer class="py-5 mt-5">
<div class="container text-center">
<h5 class="fw-bold mb-3">UMKM Desa Pemagarsari</h5>
<p class="text-muted small mb-4">Membangun ekonomi desa melalui digitalisasi marketplace mandiri.</p>
<div class="social-links mb-4">
<a href="#" class="mx-2"><i class="fa-brands fa-facebook text-muted"></i></a>
<a href="#" class="mx-2"><i class="fa-brands fa-instagram text-muted"></i></a>
<a href="#" class="mx-2"><i class="fa-brands fa-whatsapp text-muted"></i></a>
</div>
<hr class="w-25 mx-auto">
<p class="text-muted small mt-4">&copy; 2026 Desa Pemagarsari. Powered by Flatlogic.</p>
</div>
</footer>
<!-- Scripts -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>

View File

@ -0,0 +1,37 @@
{% extends 'base.html' %}
{% block title %}Masuk - Marketplace UMKM Pemagarsari{% endblock %}
{% block content %}
<div class="container py-5">
<div class="row justify-content-center py-5">
<div class="col-md-5">
<div class="card border-0 rounded-4 shadow-sm p-4 p-md-5">
<div class="text-center mb-4">
<h2 class="fw-bold">Selamat Datang</h2>
<p class="text-muted">Masuk untuk mengelola toko Anda</p>
</div>
<form method="POST">
{% csrf_token %}
<div class="mb-3">
<label class="form-label fw-bold">Username</label>
<input type="text" name="username" class="form-control rounded-3 shadow-none py-2" required>
</div>
<div class="mb-4">
<label class="form-label fw-bold">Password</label>
<input type="password" name="password" class="form-control rounded-3 shadow-none py-2" required>
</div>
<button type="submit" class="btn btn-emerald w-100 rounded-pill py-3 mb-3">
Masuk Sekarang
</button>
</form>
<div class="text-center mt-4">
<p class="small text-muted mb-0">Belum punya akun? <br>Silakan hubungi Admin Desa untuk pendaftaran akun Penjual.</p>
</div>
</div>
</div>
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,167 @@
{% extends 'base.html' %}
{% block title %}Dashboard Penjual - UMKM Pemagarsari{% endblock %}
{% block content %}
<div class="container py-5">
<div class="d-flex justify-content-between align-items-center mb-5">
<div>
<h1 class="fw-bold mb-1">Dashboard Penjual</h1>
<p class="text-muted mb-0">Kelola toko dan produk Anda di sini.</p>
</div>
<div class="d-flex gap-2">
<a href="{% url 'shop_add' %}" class="btn btn-outline-emerald rounded-pill px-4">
<i class="fa-solid fa-shop me-2"></i>Tambah Toko
</a>
<a href="{% url 'product_add' %}" class="btn btn-emerald rounded-pill px-4">
<i class="fa-solid fa-plus me-2"></i>Tambah Produk
</a>
</div>
</div>
<!-- Stats -->
<div class="row g-4 mb-5">
<div class="col-md-6 col-lg-3">
<div class="card border-0 rounded-4 shadow-sm p-4">
<div class="d-flex align-items-center mb-2">
<div class="bg-emerald bg-opacity-10 p-2 rounded-3 me-3">
<i class="fa-solid fa-shop text-emerald"></i>
</div>
<span class="text-muted small">Toko Anda</span>
</div>
<h3 class="fw-bold mb-0">{{ shops.count }}</h3>
</div>
</div>
<div class="col-md-6 col-lg-3">
<div class="card border-0 rounded-4 shadow-sm p-4">
<div class="d-flex align-items-center mb-2">
<div class="bg-primary bg-opacity-10 p-2 rounded-3 me-3">
<i class="fa-solid fa-box text-primary"></i>
</div>
<span class="text-muted small">Total Produk</span>
</div>
<h3 class="fw-bold mb-0">{{ products.count }}</h3>
</div>
</div>
</div>
<!-- Shops Table -->
<div class="card border-0 rounded-4 shadow-sm overflow-hidden mb-5">
<div class="card-header bg-white py-3 border-0">
<h5 class="fw-bold mb-0">Toko Saya</h5>
</div>
<div class="table-responsive">
<table class="table table-hover align-middle mb-0">
<thead class="bg-light text-muted small uppercase">
<tr>
<th class="ps-4">Toko</th>
<th>WhatsApp</th>
<th class="text-end pe-4">Aksi</th>
</tr>
</thead>
<tbody>
{% for shop in shops %}
<tr>
<td class="ps-4">
<div class="d-flex align-items-center">
<div class="rounded-3 bg-light me-3 overflow-hidden" style="width: 40px; height: 40px;">
{% if shop.logo %}
<img src="{{ shop.logo.url }}" class="w-100 h-100 object-fit-cover">
{% else %}
<div class="w-100 h-100 d-flex align-items-center justify-content-center">
<i class="fa-solid fa-shop text-muted"></i>
</div>
{% endif %}
</div>
<span class="fw-bold">{{ shop.name }}</span>
</div>
</td>
<td>{{ shop.whatsapp_number }}</td>
<td class="text-end pe-4">
<a href="{% url 'shop_edit' shop.pk %}" class="btn btn-light btn-sm rounded-pill px-3">
<i class="fa-solid fa-pen-to-square me-1"></i> Edit
</a>
</td>
</tr>
{% empty %}
<tr>
<td colspan="3" class="text-center py-4">
<p class="text-muted mb-0">Anda belum memiliki toko.</p>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
<!-- Products Table -->
<div class="card border-0 rounded-4 shadow-sm overflow-hidden">
<div class="card-header bg-white py-3 border-0">
<h5 class="fw-bold mb-0">Produk Saya</h5>
</div>
<div class="table-responsive">
<table class="table table-hover align-middle mb-0">
<thead class="bg-light text-muted small uppercase">
<tr>
<th class="ps-4">Produk</th>
<th>Toko</th>
<th>Kategori</th>
<th>Harga</th>
<th>Stok</th>
<th class="text-end pe-4">Aksi</th>
</tr>
</thead>
<tbody>
{% for product in products %}
<tr>
<td class="ps-4">
<div class="d-flex align-items-center">
<div class="rounded-3 bg-light me-3 overflow-hidden" style="width: 48px; height: 48px;">
{% if product.image %}
<img src="{{ product.image.url }}" class="w-100 h-100 object-fit-cover">
{% else %}
<div class="w-100 h-100 d-flex align-items-center justify-content-center">
<i class="fa-solid fa-image text-muted"></i>
</div>
{% endif %}
</div>
<span class="fw-bold">{{ product.name }}</span>
</div>
</td>
<td>{{ product.shop.name }}</td>
<td><span class="badge bg-light text-dark rounded-pill">{{ product.category.name }}</span></td>
<td>Rp {{ product.price|floatformat:0 }}</td>
<td>{{ product.stock }}</td>
<td class="text-end pe-4">
<div class="dropdown">
<button class="btn btn-light btn-sm rounded-circle shadow-none" type="button" data-bs-toggle="dropdown">
<i class="fa-solid fa-ellipsis-vertical"></i>
</button>
<ul class="dropdown-menu dropdown-menu-end border-0 shadow-sm rounded-3">
<li><a class="dropdown-item" href="{% url 'product_edit' product.pk %}"><i class="fa-solid fa-pen-to-square me-2 text-muted"></i> Edit</a></li>
<li><hr class="dropdown-divider"></li>
<li>
<form action="{% url 'product_delete' product.pk %}" method="POST" onsubmit="return confirm('Yakin ingin menghapus produk ini?')">
{% csrf_token %}
<button type="submit" class="dropdown-item text-danger"><i class="fa-solid fa-trash me-2"></i> Hapus</button>
</form>
</li>
</ul>
</div>
</td>
</tr>
{% empty %}
<tr>
<td colspan="6" class="text-center py-5">
<p class="text-muted mb-3">Anda belum menambahkan produk.</p>
<a href="{% url 'product_add' %}" class="btn btn-emerald btn-sm rounded-pill px-4">Tambah Sekarang</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,74 @@
{% extends 'base.html' %}
{% block title %}{{ title }} - Dashboard{% endblock %}
{% block content %}
<div class="container py-5">
<div class="row justify-content-center">
<div class="col-lg-8">
<div class="card border-0 rounded-4 shadow-sm p-4 p-md-5">
<div class="d-flex align-items-center mb-4">
<a href="{% url 'dashboard' %}" class="btn btn-light rounded-circle me-3">
<i class="fa-solid fa-arrow-left"></i>
</a>
<h2 class="fw-bold mb-0">{{ title }}</h2>
</div>
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
<div class="row g-4">
<div class="col-md-6">
<label class="form-label fw-bold">Pilih Toko</label>
<select name="shop" class="form-select rounded-3 shadow-none" required>
{% for shop in shops %}
<option value="{{ shop.id }}" {% if product.shop.id == shop.id %}selected{% endif %}>{{ shop.name }}</option>
{% endfor %}
</select>
</div>
<div class="col-md-6">
<label class="form-label fw-bold">Kategori</label>
<select name="category" class="form-select rounded-3 shadow-none" required>
{% for cat in categories %}
<option value="{{ cat.id }}" {% if product.category.id == cat.id %}selected{% endif %}>{{ cat.name }}</option>
{% endfor %}
</select>
</div>
<div class="col-12">
<label class="form-label fw-bold">Nama Produk</label>
<input type="text" name="name" value="{{ product.name }}" class="form-control rounded-3 shadow-none" placeholder="Contoh: Kerupuk Jengkol Pedas" required>
</div>
<div class="col-12">
<label class="form-label fw-bold">Deskripsi</label>
<textarea name="description" class="form-control rounded-3 shadow-none" rows="4" placeholder="Jelaskan keunggulan produk Anda..." required>{{ product.description }}</textarea>
</div>
<div class="col-md-6">
<label class="form-label fw-bold">Harga (Rp)</label>
<input type="number" name="price" value="{{ product.price|floatformat:0 }}" class="form-control rounded-3 shadow-none" placeholder="0" required>
</div>
<div class="col-md-6">
<label class="form-label fw-bold">Stok</label>
<input type="number" name="stock" value="{{ product.stock|default:0 }}" class="form-control rounded-3 shadow-none" required>
</div>
<div class="col-12">
<label class="form-label fw-bold">Foto Produk</label>
{% if product.image %}
<div class="mb-2">
<img src="{{ product.image.url }}" class="rounded-3" style="height: 100px;">
</div>
{% endif %}
<input type="file" name="image" class="form-control rounded-3 shadow-none">
<small class="text-muted">Kosongkan jika tidak ingin mengubah foto.</small>
</div>
<div class="col-12 pt-3">
<button type="submit" class="btn btn-emerald btn-lg w-100 rounded-pill py-3">
<i class="fa-solid fa-save me-2"></i>Simpan Produk
</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,54 @@
{% extends 'base.html' %}
{% block title %}{{ title }} - Dashboard{% endblock %}
{% block content %}
<div class="container py-5">
<div class="row justify-content-center">
<div class="col-lg-8">
<div class="card border-0 rounded-4 shadow-sm p-4 p-md-5">
<div class="d-flex align-items-center mb-4">
<a href="{% url 'dashboard' %}" class="btn btn-light rounded-circle me-3">
<i class="fa-solid fa-arrow-left"></i>
</a>
<h2 class="fw-bold mb-0">{{ title }}</h2>
</div>
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
<div class="row g-4">
<div class="col-12">
<label class="form-label fw-bold">Nama Toko</label>
<input type="text" name="name" value="{{ shop.name }}" class="form-control rounded-3 shadow-none" placeholder="Contoh: Dapur Sejahtera" required>
</div>
<div class="col-12">
<label class="form-label fw-bold">Deskripsi Toko</label>
<textarea name="description" class="form-control rounded-3 shadow-none" rows="4" placeholder="Ceritakan tentang toko Anda..." required>{{ shop.description }}</textarea>
</div>
<div class="col-12">
<label class="form-label fw-bold">Nomor WhatsApp</label>
<input type="text" name="whatsapp_number" value="{{ shop.whatsapp_number }}" class="form-control rounded-3 shadow-none" placeholder="Contoh: 628123456789" required>
<small class="text-muted">Gunakan format internasional tanpa tanda plus (+). Contoh: 628123456789</small>
</div>
<div class="col-12">
<label class="form-label fw-bold">Logo Toko (Opsional)</label>
{% if shop.logo %}
<div class="mb-2">
<img src="{{ shop.logo.url }}" class="rounded-3" style="height: 100px;">
</div>
{% endif %}
<input type="file" name="logo" class="form-control rounded-3 shadow-none">
</div>
<div class="col-12 pt-3">
<button type="submit" class="btn btn-emerald btn-lg w-100 rounded-pill py-3">
<i class="fa-solid fa-save me-2"></i>Simpan Toko
</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
{% endblock %}

View File

@ -1,145 +1,135 @@
{% extends "base.html" %}
{% block title %}{{ project_name }}{% endblock %}
{% block head %}
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap" rel="stylesheet">
<style>
:root {
--bg-color-start: #6a11cb;
--bg-color-end: #2575fc;
--text-color: #ffffff;
--card-bg-color: rgba(255, 255, 255, 0.01);
--card-border-color: rgba(255, 255, 255, 0.1);
}
* {
box-sizing: border-box;
}
body {
margin: 0;
font-family: 'Inter', sans-serif;
background: linear-gradient(45deg, var(--bg-color-start), var(--bg-color-end));
color: var(--text-color);
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
text-align: center;
overflow: hidden;
position: relative;
}
body::before {
content: '';
position: absolute;
inset: 0;
background-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='100' height='100' viewBox='0 0 100 100'><path d='M-10 10L110 10M10 -10L10 110' stroke-width='1' stroke='rgba(255,255,255,0.05)'/></svg>");
animation: bg-pan 20s linear infinite;
z-index: -1;
}
@keyframes bg-pan {
0% {
background-position: 0% 0%;
}
100% {
background-position: 100% 100%;
}
}
main {
padding: 2rem;
}
.card {
background: var(--card-bg-color);
border: 1px solid var(--card-border-color);
border-radius: 16px;
padding: 2.5rem 2rem;
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
box-shadow: 0 12px 36px rgba(0, 0, 0, 0.25);
}
h1 {
font-size: clamp(2.2rem, 3vw + 1.2rem, 3.2rem);
font-weight: 700;
margin: 0 0 1.2rem;
letter-spacing: -0.02em;
}
p {
margin: 0.5rem 0;
font-size: 1.1rem;
opacity: 0.92;
}
.loader {
margin: 1.5rem auto;
width: 56px;
height: 56px;
border: 4px solid rgba(255, 255, 255, 0.25);
border-top-color: #fff;
border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes spin {
to {
transform: rotate(360deg);
}
}
.runtime code {
background: rgba(0, 0, 0, 0.25);
padding: 0.15rem 0.45rem;
border-radius: 4px;
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
border: 0;
}
footer {
position: absolute;
bottom: 1rem;
width: 100%;
text-align: center;
font-size: 0.85rem;
opacity: 0.75;
}
</style>
{% endblock %}
{% extends 'base.html' %}
{% load static %}
{% block content %}
<main>
<div class="card">
<h1>Analyzing your requirements and generating your app…</h1>
<div class="loader" role="status" aria-live="polite" aria-label="Applying initial changes">
<span class="sr-only">Loading…</span>
<!-- Hero Section -->
<section class="hero-section">
<div class="container">
<div class="row align-items-center">
<div class="col-lg-6">
<span class="badge bg-emerald mb-3 px-3 py-2 rounded-pill">Digitalisasi UMKM Desa</span>
<h1 class="hero-title mb-4">Majukan Ekonomi Desa Pemagarsari</h1>
<p class="lead text-muted mb-4">Temukan produk unggulan dari warga desa kami. Pesan langsung via WhatsApp tanpa ribet, dukung produk lokal hari ini.</p>
<!-- Search Bar -->
<form action="{% url 'home' %}" method="GET" class="mb-4">
<div class="search-box p-2 bg-white rounded-pill shadow-sm d-flex">
<input type="text" name="q" value="{{ query }}" class="form-control border-0 bg-transparent px-4 shadow-none" placeholder="Cari kerajinan, makanan, atau jasa...">
<button type="submit" class="btn btn-emerald rounded-pill px-4">
<i class="fa-solid fa-magnifying-glass me-2"></i>Cari
</button>
</div>
</form>
<div class="d-flex flex-wrap gap-3">
<a href="#produk" class="btn btn-outline-emerald rounded-pill px-4">Jelajahi Produk</a>
{% if query or selected_category %}
<a href="{% url 'home' %}" class="btn btn-link text-muted text-decoration-none">Reset Filter</a>
{% endif %}
</div>
</div>
<div class="col-lg-6 d-none d-lg-block text-center">
<div class="position-relative p-4">
<div class="bg-emerald rounded-circle position-absolute top-50 start-50 translate-middle opacity-10" style="width: 500px; height: 500px; filter: blur(60px);"></div>
<div class="position-relative z-1 shadow-lg rounded-4 overflow-hidden border border-white border-4 transform-hover transition-all">
<img src="https://images.unsplash.com/photo-1590632823277-285f21442df1?auto=format&fit=crop&q=80&w=800" alt="Pasar Tradisional Desa" class="img-fluid" style="max-height: 450px; width: 100%; object-fit: cover;">
</div>
</div>
</div>
</div>
</div>
<p class="hint">AppWizzy AI is collecting your requirements and applying the first changes.</p>
<p class="hint">This page will refresh automatically as the plan is implemented.</p>
<p class="runtime">
Runtime: Django <code>{{ django_version }}</code> · Python <code>{{ python_version }}</code>
— UTC <code>{{ current_time|date:"Y-m-d H:i:s" }}</code>
</p>
</div>
</main>
<footer>
Page updated: {{ current_time|date:"Y-m-d H:i:s" }} (UTC)
</footer>
{% endblock %}
</section>
<!-- Categories -->
<section id="kategori" class="py-5">
<div class="container">
<div class="text-center mb-5">
<h2 class="fw-bold">Kategori Populer</h2>
<p class="text-muted">Cari produk berdasarkan kategori</p>
</div>
<div class="row g-4 justify-content-center">
<div class="col-6 col-md-2">
<a href="{% url 'home' %}" class="category-card {% if not selected_category %}active{% endif %}">
<div class="category-icon">
<i class="fa-solid fa-border-all"></i>
</div>
<h6 class="fw-bold mb-0 text-dark">Semua</h6>
</a>
</div>
{% for category in categories %}
<div class="col-6 col-md-2">
<a href="?category={{ category.slug }}{% if query %}&q={{ query }}{% endif %}" class="category-card {% if selected_category == category.slug %}active{% endif %}">
<div class="category-icon">
<i class="fa-solid {{ category.icon }}"></i>
</div>
<h6 class="fw-bold mb-0 text-dark">{{ category.name }}</h6>
</a>
</div>
{% endfor %}
</div>
</div>
</section>
<!-- Featured Products -->
<section id="produk" class="py-5 bg-light">
<div class="container">
<div class="text-center mb-5">
<h2 class="fw-bold">Produk Terbaru</h2>
<p class="text-muted">Produk unggulan dari para pengrajin dan pedagang desa</p>
</div>
<div class="row g-4">
{% for product in featured_products %}
<div class="col-12 col-sm-6 col-lg-3">
<div class="product-card">
<div class="product-img-wrapper">
{% if product.image %}
<img src="{{ product.image.url }}" alt="{{ product.name }}" class="img-fluid w-100 h-100 object-fit-cover">
{% else %}
<i class="fa-solid fa-image"></i>
{% endif %}
</div>
<div class="p-4">
<div class="d-flex justify-content-between align-items-center mb-2">
<span class="shop-badge">{{ product.shop.name }}</span>
<small class="text-muted">{{ product.category.name }}</small>
</div>
<h5 class="fw-bold mb-3">
<a href="{% url 'product_detail' product.slug %}" class="text-decoration-none text-dark">{{ product.name }}</a>
</h5>
<div class="d-flex justify-content-between align-items-center">
<span class="product-price">Rp {{ product.price|floatformat:0 }}</span>
<a href="{{ product.whatsapp_link }}" target="_blank" class="btn btn-whatsapp btn-sm px-3">
<i class="fa-brands fa-whatsapp me-2"></i>Pesan
</a>
</div>
</div>
</div>
</div>
{% empty %}
<div class="col-12 text-center py-5">
<div class="bg-white p-5 rounded-4 shadow-sm">
<i class="fa-solid fa-box-open fa-3x text-muted mb-3"></i>
<p class="text-muted">Belum ada produk untuk ditampilkan.</p>
<a href="/admin/core/product/add/" class="btn btn-emerald mt-3">Tambah Produk Pertama</a>
</div>
</div>
{% endfor %}
</div>
</div>
</section>
<!-- Call to Action -->
<section class="py-5">
<div class="container">
<div class="p-5 rounded-4 text-white text-center position-relative overflow-hidden shadow-lg" style="background: linear-gradient(135deg, rgba(6, 78, 59, 0.9) 0%, rgba(16, 185, 129, 0.9) 100%), url('https://images.unsplash.com/photo-1544333346-64e4fe18204b?auto=format&fit=crop&q=80&w=1200'); background-size: cover; background-position: center;">
<div class="position-relative z-1">
<h2 class="fw-bold mb-3">Punya Usaha di Desa Pemagarsari?</h2>
<p class="mb-4 opacity-75">Daftarkan toko Anda dan mulai jualan online hari ini. Mudah, gratis, dan langsung ke WhatsApp!</p>
<div class="d-flex justify-content-center gap-3">
<a href="{% if user.is_authenticated %}{% url 'dashboard' %}{% else %}{% url 'login' %}{% endif %}" class="btn btn-emerald btn-lg px-5 rounded-pill shadow-lg">Mulai Jualan Sekarang</a>
</div>
</div>
</div>
</div>
</section>
{% endblock %}

View File

@ -0,0 +1,105 @@
{% extends 'base.html' %}
{% load static %}
{% block title %}{{ product.name }} - UMKM Pemagarsari{% endblock %}
{% block content %}
<section class="py-5">
<div class="container">
<nav aria-label="breadcrumb" class="mb-4">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="{% url 'home' %}" class="text-decoration-none text-emerald">Beranda</a></li>
<li class="breadcrumb-item active" aria-current="page">{{ product.name }}</li>
</ol>
</nav>
<div class="row g-5">
<div class="col-md-6">
<div class="bg-white rounded-4 p-2 shadow-sm">
<div class="product-img-wrapper rounded-3" style="height: 450px;">
{% if product.image %}
<img src="{{ product.image.url }}" alt="{{ product.name }}" class="img-fluid w-100 h-100 object-fit-cover rounded-3">
{% else %}
<i class="fa-solid fa-image fa-4x"></i>
{% endif %}
</div>
</div>
</div>
<div class="col-md-6">
<div class="ps-lg-4">
<span class="badge bg-emerald mb-2 px-3 py-2 rounded-pill">{{ product.category.name }}</span>
<h1 class="fw-bold mb-3">{{ product.name }}</h1>
<div class="d-flex align-items-center mb-4">
<div class="bg-light p-2 rounded-3 me-3">
<i class="fa-solid fa-shop text-emerald"></i>
</div>
<div>
<p class="mb-0 small text-muted">Dijual oleh</p>
<h6 class="fw-bold mb-0">{{ product.shop.name }}</h6>
</div>
</div>
<h2 class="product-price mb-4" style="font-size: 2.5rem;">Rp {{ product.price|floatformat:0 }}</h2>
<div class="mb-4">
<h6 class="fw-bold">Deskripsi Produk</h6>
<p class="text-muted">{{ product.description|linebreaks }}</p>
</div>
<div class="card border-0 bg-light rounded-4 p-4 mb-4">
<div class="d-flex align-items-center mb-3">
<i class="fa-solid fa-circle-info text-emerald me-2"></i>
<h6 class="fw-bold mb-0">Cara Pemesanan</h6>
</div>
<p class="small text-muted mb-0">Klik tombol di bawah untuk terhubung langsung dengan WhatsApp penjual. Pesan otomatis akan terisi dengan detail produk ini.</p>
</div>
<div class="d-grid">
<a href="{{ product.whatsapp_link }}" target="_blank" class="btn btn-whatsapp btn-lg py-3 rounded-pill">
<i class="fa-brands fa-whatsapp me-2"></i>Pesan via WhatsApp Sekarang
</a>
</div>
</div>
</div>
</div>
</div>
</section>
<!-- Related Products Placeholder -->
<section class="py-5 bg-light mt-5">
<div class="container text-center">
<h4 class="fw-bold mb-4">Dukung UMKM Lainnya</h4>
<div class="row g-4 opacity-50">
<!-- Simulated related products -->
<div class="col-md-3">
<div class="bg-white p-4 rounded-4 shadow-sm">
<div class="bg-light mb-3 rounded" style="height: 150px;"></div>
<div class="bg-light w-75 h-25 mb-2 mx-auto"></div>
<div class="bg-light w-50 h-25 mx-auto"></div>
</div>
</div>
<div class="col-md-3 d-none d-md-block">
<div class="bg-white p-4 rounded-4 shadow-sm">
<div class="bg-light mb-3 rounded" style="height: 150px;"></div>
<div class="bg-light w-75 h-25 mb-2 mx-auto"></div>
<div class="bg-light w-50 h-25 mx-auto"></div>
</div>
</div>
<div class="col-md-3 d-none d-md-block">
<div class="bg-white p-4 rounded-4 shadow-sm">
<div class="bg-light mb-3 rounded" style="height: 150px;"></div>
<div class="bg-light w-75 h-25 mb-2 mx-auto"></div>
<div class="bg-light w-50 h-25 mx-auto"></div>
</div>
</div>
<div class="col-md-3 d-none d-md-block">
<div class="bg-white p-4 rounded-4 shadow-sm">
<div class="bg-light mb-3 rounded" style="height: 150px;"></div>
<div class="bg-light w-75 h-25 mb-2 mx-auto"></div>
<div class="bg-light w-50 h-25 mx-auto"></div>
</div>
</div>
</div>
</div>
</section>
{% endblock %}

View File

@ -0,0 +1,83 @@
{% extends 'base.html' %}
{% block title %}{{ shop.name }} - UMKM Pemagarsari{% endblock %}
{% block content %}
<section class="py-5">
<div class="container">
<!-- Shop Header -->
<div class="bg-white rounded-4 shadow-sm p-4 p-md-5 mb-5 overflow-hidden position-relative">
<div class="position-absolute top-0 end-0 p-4 opacity-10">
<i class="fa-solid fa-shop fa-8x"></i>
</div>
<div class="row align-items-center position-relative z-1">
<div class="col-md-auto mb-4 mb-md-0 text-center">
<div class="bg-emerald rounded-circle d-flex align-items-center justify-content-center text-white mx-auto" style="width: 120px; height: 120px; overflow: hidden;">
{% if shop.logo %}
<img src="{{ shop.logo.url }}" alt="{{ shop.name }}" class="img-fluid w-100 h-100 object-fit-cover">
{% else %}
<i class="fa-solid fa-shop fa-3x"></i>
{% endif %}
</div>
</div>
<div class="col-md ps-md-4">
<h1 class="fw-bold mb-2">{{ shop.name }}</h1>
<p class="text-muted mb-4">{{ shop.description }}</p>
<div class="d-flex flex-wrap gap-3">
<div class="d-flex align-items-center bg-light px-3 py-2 rounded-pill">
<i class="fa-brands fa-whatsapp text-success me-2"></i>
<span class="fw-bold">{{ shop.whatsapp_number }}</span>
</div>
<div class="d-flex align-items-center bg-light px-3 py-2 rounded-pill">
<i class="fa-solid fa-box text-emerald me-2"></i>
<span>{{ products.count }} Produk</span>
</div>
</div>
</div>
<div class="col-md-auto mt-4 mt-md-0">
<a href="https://wa.me/{{ shop.whatsapp_number }}" target="_blank" class="btn btn-whatsapp rounded-pill px-4 py-2 w-100">
<i class="fa-brands fa-whatsapp me-2"></i>Chat Penjual
</a>
</div>
</div>
</div>
<!-- Shop Products -->
<div class="d-flex justify-content-between align-items-center mb-4">
<h4 class="fw-bold mb-0">Produk dari {{ shop.name }}</h4>
</div>
<div class="row g-4">
{% for product in products %}
<div class="col-12 col-sm-6 col-lg-3">
<div class="product-card">
<div class="product-img-wrapper">
{% if product.image %}
<img src="{{ product.image.url }}" alt="{{ product.name }}" class="img-fluid w-100 h-100 object-fit-cover">
{% else %}
<i class="fa-solid fa-image"></i>
{% endif %}
</div>
<div class="p-4">
<small class="text-muted d-block mb-2">{{ product.category.name }}</small>
<h5 class="fw-bold mb-3">
<a href="{% url 'product_detail' product.slug %}" class="text-decoration-none text-dark">{{ product.name }}</a>
</h5>
<div class="d-flex justify-content-between align-items-center">
<span class="product-price">Rp {{ product.price|floatformat:0 }}</span>
<a href="{{ product.whatsapp_link }}" target="_blank" class="btn btn-whatsapp btn-sm px-3">
<i class="fa-brands fa-whatsapp me-2"></i>Pesan
</a>
</div>
</div>
</div>
</div>
{% empty %}
<div class="col-12 text-center py-5">
<p class="text-muted">Toko ini belum menambahkan produk.</p>
</div>
{% endfor %}
</div>
</div>
</section>
{% endblock %}

View File

@ -0,0 +1,47 @@
{% extends 'base.html' %}
{% block title %}Daftar Toko UMKM - Pemagarsari{% endblock %}
{% block content %}
<section class="py-5 bg-light">
<div class="container">
<div class="text-center mb-5">
<h1 class="fw-bold">Para Pelaku UMKM</h1>
<p class="text-muted">Dukung usaha warga Desa Pemagarsari dengan berbelanja langsung dari toko mereka.</p>
</div>
<div class="row g-4">
{% for shop in shops %}
<div class="col-md-6 col-lg-4">
<div class="card border-0 rounded-4 shadow-sm h-100 overflow-hidden">
<div class="row g-0 h-100">
<div class="col-4 bg-emerald d-flex align-items-center justify-content-center text-white">
{% if shop.logo %}
<img src="{{ shop.logo.url }}" alt="{{ shop.name }}" class="img-fluid w-100 h-100 object-fit-cover">
{% else %}
<i class="fa-solid fa-shop fa-3x opacity-50"></i>
{% endif %}
</div>
<div class="col-8">
<div class="card-body p-4">
<h5 class="fw-bold mb-2">{{ shop.name }}</h5>
<p class="text-muted small mb-3 text-truncate-2">{{ shop.description|default:"Pelaku UMKM Desa Pemagarsari" }}</p>
<div class="d-flex align-items-center mb-3">
<i class="fa-brands fa-whatsapp text-success me-2"></i>
<span class="small text-muted">{{ shop.whatsapp_number }}</span>
</div>
<a href="{% url 'shop_detail' shop.slug %}" class="btn btn-outline-emerald btn-sm rounded-pill px-4">Kunjungi Toko</a>
</div>
</div>
</div>
</div>
</div>
{% empty %}
<div class="col-12 text-center py-5">
<p class="text-muted">Belum ada toko yang terdaftar.</p>
</div>
{% endfor %}
</div>
</div>
</section>
{% endblock %}

View File

@ -1,7 +1,26 @@
from django.urls import path
from .views import home
from django.urls import path, include
from django.contrib.auth import views as auth_views
from .views import (
home, product_detail, shop_list, shop_detail,
dashboard, shop_add, shop_edit,
product_add, product_edit, product_delete
)
urlpatterns = [
path("", home, name="home"),
path("shops/", shop_list, name="shop_list"),
path("shop/<slug:slug>/", shop_detail, name="shop_detail"),
path("product/<slug:slug>/", product_detail, name="product_detail"),
# Dashboard
path("dashboard/", dashboard, name="dashboard"),
path("dashboard/shop/add/", shop_add, name="shop_add"),
path("dashboard/shop/edit/<int:pk>/", shop_edit, name="shop_edit"),
path("dashboard/product/add/", product_add, name="product_add"),
path("dashboard/product/edit/<int:pk>/", product_edit, name="product_edit"),
path("dashboard/product/delete/<int:pk>/", product_delete, name="product_delete"),
# Auth
path("login/", auth_views.LoginView.as_view(template_name="core/auth/login.html"), name="login"),
path("logout/", auth_views.LogoutView.as_view(next_page="home"), name="logout"),
]

View File

@ -2,24 +2,174 @@ import os
import platform
from django import get_version as django_version
from django.shortcuts import render
from django.shortcuts import render, get_object_or_404, redirect
from django.contrib.auth.decorators import login_required
from django.utils import timezone
from .models import Category, Shop, Product
def home(request):
"""Render the landing screen with loader and environment details."""
host_name = request.get_host().lower()
agent_brand = "AppWizzy" if host_name == "appwizzy.com" else "Flatlogic"
now = timezone.now()
"""Render the marketplace landing page with search and filter."""
categories = Category.objects.all()
# Get query parameters
query = request.GET.get('q', '')
category_slug = request.GET.get('category', '')
products = Product.objects.filter(is_active=True).order_by('-created_at')
if query:
products = products.filter(name__icontains=query)
if category_slug:
products = products.filter(category__slug=category_slug)
featured_products = products[:12] # Show more products on home
context = {
"project_name": "New Style",
"agent_brand": agent_brand,
"django_version": django_version(),
"python_version": platform.python_version(),
"current_time": now,
"host_name": host_name,
"project_description": os.getenv("PROJECT_DESCRIPTION", ""),
"project_image_url": os.getenv("PROJECT_IMAGE_URL", ""),
"categories": categories,
"featured_products": featured_products,
"query": query,
"selected_category": category_slug,
"current_time": timezone.now(),
}
return render(request, "core/index.html", context)
def product_detail(request, slug):
"""Render the product detail page."""
product = get_object_or_404(Product, slug=slug, is_active=True)
return render(request, "core/product_detail.html", {"product": product})
def shop_list(request):
"""Render a list of all shops."""
shops = Shop.objects.all().order_by('name')
return render(request, "core/shop_list.html", {"shops": shops})
def shop_detail(request, slug):
"""Render a specific shop's page with its products."""
shop = get_object_or_404(Shop, slug=slug)
products = Product.objects.filter(shop=shop, is_active=True)
return render(request, "core/shop_detail.html", {"shop": shop, "products": products})
@login_required
def dashboard(request):
"""Seller dashboard showing their shops and products."""
shops = Shop.objects.filter(owner=request.user)
products = Product.objects.filter(shop__owner=request.user).order_by('-created_at')
context = {
"shops": shops,
"products": products,
}
return render(request, "core/dashboard/index.html", context)
@login_required
def shop_add(request):
"""Add a new shop."""
if request.method == "POST":
name = request.POST.get('name')
description = request.POST.get('description')
whatsapp_number = request.POST.get('whatsapp_number')
logo = request.FILES.get('logo')
Shop.objects.create(
owner=request.user,
name=name,
description=description,
whatsapp_number=whatsapp_number,
logo=logo
)
return redirect('dashboard')
return render(request, "core/dashboard/shop_form.html", {
"title": "Tambah Toko Baru"
})
@login_required
def shop_edit(request, pk):
"""Edit an existing shop."""
shop = get_object_or_404(Shop, pk=pk, owner=request.user)
if request.method == "POST":
shop.name = request.POST.get('name')
shop.description = request.POST.get('description')
shop.whatsapp_number = request.POST.get('whatsapp_number')
if request.FILES.get('logo'):
shop.logo = request.FILES.get('logo')
shop.save()
return redirect('dashboard')
return render(request, "core/dashboard/shop_form.html", {
"shop": shop,
"title": "Edit Toko"
})
@login_required
def product_add(request):
"""Add a new product."""
shops = Shop.objects.filter(owner=request.user)
categories = Category.objects.all()
if request.method == "POST":
shop_id = request.POST.get('shop')
category_id = request.POST.get('category')
name = request.POST.get('name')
description = request.POST.get('description')
price = request.POST.get('price')
stock = request.POST.get('stock')
image = request.FILES.get('image')
shop = get_object_or_404(Shop, id=shop_id, owner=request.user)
category = get_object_or_404(Category, id=category_id)
Product.objects.create(
shop=shop,
category=category,
name=name,
description=description,
price=price,
stock=stock,
image=image
)
return redirect('dashboard')
return render(request, "core/dashboard/product_form.html", {
"shops": shops,
"categories": categories,
"title": "Tambah Produk Baru"
})
@login_required
def product_edit(request, pk):
"""Edit an existing product."""
product = get_object_or_404(Product, pk=pk, shop__owner=request.user)
shops = Shop.objects.filter(owner=request.user)
categories = Category.objects.all()
if request.method == "POST":
product.shop = get_object_or_404(Shop, id=request.POST.get('shop'), owner=request.user)
product.category = get_object_or_404(Category, id=request.POST.get('category'))
product.name = request.POST.get('name')
product.description = request.POST.get('description')
product.price = request.POST.get('price')
product.stock = request.POST.get('stock')
if request.FILES.get('image'):
product.image = request.FILES.get('image')
product.save()
return redirect('dashboard')
return render(request, "core/dashboard/product_form.html", {
"product": product,
"shops": shops,
"categories": categories,
"title": "Edit Produk"
})
@login_required
def product_delete(request, pk):
"""Delete a product."""
product = get_object_or_404(Product, pk=pk, shop__owner=request.user)
if request.method == "POST":
product.delete()
return redirect('dashboard')

View File

@ -1,4 +1,213 @@
/* Custom styles for the application */
body {
font-family: system-ui, -apple-system, sans-serif;
:root {
--emerald-primary: #10B981;
--emerald-dark: #059669;
--forest-deep: #064E3B;
--amber-warm: #F59E0B;
--glass-bg: rgba(255, 255, 255, 0.8);
--soft-shadow: 0 10px 30px rgba(0, 0, 0, 0.05);
}
body {
font-family: 'Inter', sans-serif;
background-color: #f8fafc;
color: #1e293b;
}
h1, h2, h3, h4, .navbar-brand {
font-family: 'Poppins', sans-serif;
}
.text-emerald {
color: var(--emerald-primary);
}
.bg-emerald {
background-color: var(--emerald-primary);
}
.btn-emerald {
background-color: var(--emerald-primary);
border-color: var(--emerald-primary);
color: white;
font-weight: 600;
transition: all 0.3s ease;
}
.btn-emerald:hover {
background-color: var(--emerald-dark);
border-color: var(--emerald-dark);
color: white;
transform: translateY(-2px);
box-shadow: 0 5px 15px rgba(16, 185, 129, 0.4);
}
.navbar {
background: var(--glass-bg);
backdrop-filter: blur(10px);
border-bottom: 1px solid rgba(0, 0, 0, 0.05);
padding: 1rem 0;
}
.navbar-brand {
font-size: 1.5rem;
color: var(--forest-deep);
}
/* Hero Section */
.hero-section {
padding: 100px 0;
background: linear-gradient(135deg, #ecfdf5 0%, #ffffff 100%);
position: relative;
overflow: hidden;
}
.hero-section::after {
content: "";
position: absolute;
top: -10%;
right: -5%;
width: 400px;
height: 400px;
background: radial-gradient(circle, rgba(16, 185, 129, 0.1) 0%, rgba(255, 255, 255, 0) 70%);
z-index: 0;
}
.hero-title {
font-size: 3.5rem;
font-weight: 800;
line-height: 1.2;
color: var(--forest-deep);
}
/* Cards */
.category-card {
background: white;
border: none;
border-radius: 20px;
padding: 2rem;
text-align: center;
transition: all 0.3s ease;
box-shadow: var(--soft-shadow);
text-decoration: none;
display: block;
}
.category-card:hover {
transform: translateY(-5px);
box-shadow: 0 15px 40px rgba(0, 0, 0, 0.1);
}
.category-icon {
width: 60px;
height: 60px;
background: #ecfdf5;
color: var(--emerald-primary);
border-radius: 15px;
display: flex;
align-items: center;
justify-content: center;
margin: 0 auto 1.5rem;
font-size: 1.5rem;
}
.product-card {
background: white;
border: none;
border-radius: 20px;
overflow: hidden;
transition: all 0.3s ease;
box-shadow: var(--soft-shadow);
height: 100%;
}
.product-card:hover {
transform: translateY(-5px);
box-shadow: 0 15px 40px rgba(0, 0, 0, 0.1);
}
.product-img-wrapper {
height: 220px;
background: #f1f5f9;
display: flex;
align-items: center;
justify-content: center;
overflow: hidden;
}
.product-img-wrapper i {
font-size: 4rem;
color: #cbd5e1;
}
.product-price {
color: var(--emerald-primary);
font-weight: 700;
font-size: 1.25rem;
}
.shop-badge {
background: #f1f5f9;
color: #64748b;
padding: 4px 12px;
border-radius: 100px;
font-size: 0.75rem;
font-weight: 600;
}
/* WhatsApp Button */
.btn-whatsapp {
background-color: #25D366;
color: white;
font-weight: 600;
border-radius: 12px;
}
.btn-whatsapp:hover {
background-color: #128C7E;
color: white;
}
.transform-hover {
transition: all 0.5s cubic-bezier(0.4, 0, 0.2, 1);
}
.transform-hover:hover {
transform: scale(1.02) translateY(-10px) rotate(1deg);
box-shadow: 0 25px 50px -12px rgba(16, 185, 129, 0.25) !important;
}
.transition-all {
transition: all 0.3s ease;
}
/* Search Box */
.search-box {
border: 1px solid rgba(0,0,0,0.05);
transition: all 0.3s ease;
}
.search-box:focus-within {
border-color: var(--emerald-primary);
box-shadow: 0 0 0 4px rgba(16, 185, 129, 0.1) !important;
}
/* Categories Active State */
.category-card.active {
background: var(--forest-deep);
color: white !important;
}
.category-card.active .category-icon {
background: rgba(255, 255, 255, 0.1);
color: white;
}
.category-card.active h6 {
color: white !important;
}
@media (max-width: 768px) {
.hero-title {
font-size: 2.5rem;
}
}