anycoder-82edf70e / utils.py
moaazhosam69's picture
Update utils.py from anycoder
4344f34 verified
Raw
History Blame Contribute Delete
16.8 kB
"""
Utility functions for Voltix Marketplace Gradio App.
Contains mock data and HTML generation helpers.
"""
# --- Mock Data ---
PRODUCTS = [
{"id": 1, "name": "Quantum Wireless Headphones", "price": 129.99, "img": "https://images.unsplash.com/photo-1505740420928-5b52d58b4468?w=500", "vendor": "TechNova", "rating": 4.8},
{"id": 2, "name": "Ergonomic Mechanical Keyboard", "price": 89.50, "img": "https://images.unsplash.com/photo-1587829741301-dc798b91a45e?w=500", "vendor": "KeyMasters", "rating": 4.6},
{"id": 3, "name": "Smart Fitness Watch Pro", "price": 199.00, "img": "https://images.unsplash.com/photo-1523275335681-00071a7dc1c1?w=500", "vendor": "FitLife", "rating": 4.9},
{"id": 4, "name": "Minimalist Leather Backpack", "price": 145.00, "img": "https://images.unsplash.com/photo-1553062407-98eeb64c6a62?w=500", "vendor": "UrbanStyle", "rating": 4.5},
{"id": 5, "name": "4K Ultra Monitor", "price": 350.00, "img": "https://images.unsplash.com/photo-1527443224154-c4a3942d3acf?w=500", "vendor": "TechNova", "rating": 4.7},
{"id": 6, "name": "Ceramic Coffee Mug Set", "price": 24.99, "img": "https://images.unsplash.com/photo-1514228742587-6b1558fcca3d?w=500", "vendor": "HomeEssentials", "rating": 4.3},
]
PLANS = [
{"name": "Free", "price": 0, "features": ["10 Products", "Basic Analytics", "Standard Support"]},
{"name": "Basic", "price": 19, "features": ["50 Products", "Advanced Analytics", "Email Support", "Custom Domain"]},
{"name": "Professional", "price": 49, "features": ["500 Products", "AI Tools", "Priority Support", "Lower Fees"], "featured": True},
{"name": "Enterprise", "price": 99, "features": ["Unlimited Products", "API Access", "24/7 Support", "Dedicated Manager"]}
]
# --- CSS Extraction ---
def get_css():
return """
/* --- CSS VARIABLES & THEME --- */
:root {
--primary: #4f46e5;
--primary-hover: #4338ca;
--secondary: #ec4899;
--accent: #06b6d4;
--bg-body: #f3f4f6;
--bg-card: #ffffff;
--text-main: #111827;
--text-muted: #6b7280;
--border: #e5e7eb;
--shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
--radius: 0.75rem;
--transition: all 0.3s ease;
--font-en: 'Inter', sans-serif;
--font-ar: 'Noto Sans Arabic', sans-serif;
}
[data-theme="dark"] {
--bg-body: #0f172a;
--bg-card: #1e293b;
--text-main: #f8fafc;
--text-muted: #94a3b8;
--border: #334155;
--shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.5);
}
/* --- RESET & BASE --- */
* { box-sizing: box-sizing; margin: 0; padding: 0; }
body {
font-family: var(--font-en);
background-color: var(--bg-body);
color: var(--text-main);
transition: var(--transition);
line-height: 1.6;
}
body.rtl { font-family: var(--font-ar); direction: rtl; }
a { text-decoration: none; color: inherit; }
ul { list-style: none; }
img { max-width: 100%; display: block; }
/* --- UTILITIES --- */
.container { max-width: 1280px; margin: 0 auto; padding: 0 1.5rem; }
.flex { display: flex; }
.flex-col { display: flex; flex-direction: column; }
.items-center { align-items: center; }
.justify-between { justify-content: space-between; }
.justify-end { justify-content: flex-end; }
.gap-2 { gap: 0.5rem; }
.gap-4 { gap: 1rem; }
.grid { display: grid; }
.text-center { text-align: center; }
.text-primary { color: var(--primary); }
.bg-primary { background-color: var(--primary); }
.rounded { border-radius: var(--radius); }
.shadow { box-shadow: var(--shadow); }
.p-4 { padding: 1rem; }
.m-4 { margin: 1rem; }
.mt-4 { margin-top: 1rem; }
.mb-4 { margin-bottom: 1rem; }
.w-100 { width: 100%; }
.hidden { display: none; }
/* --- BUTTONS --- */
.btn {
display: inline-flex; align-items: center; justify-content: center;
padding: 0.6rem 1.2rem; border-radius: var(--radius);
font-weight: 600; cursor: pointer; transition: var(--transition);
border: none; gap: 0.5rem; background: transparent; color: inherit;
}
.btn-primary { background: var(--primary); color: white; }
.btn-primary:hover { background: var(--primary-hover); transform: translateY(-2px); }
.btn-outline { border: 1px solid var(--border); background: transparent; color: var(--text-main); }
.btn-outline:hover { border-color: var(--primary); color: var(--primary); }
.btn-secondary { background: var(--bg-card); border: 1px solid var(--border); color: var(--text-main); }
.btn-secondary:hover { background: var(--bg-body); }
/* --- HEADER --- */
.top-bar { padding: 0.8rem 0; background: var(--bg-card); border-bottom: 1px solid var(--border); }
.nav-links a { margin-left: 1.5rem; font-weight: 500; color: var(--text-muted); }
.nav-links a:hover { color: var(--primary); }
.rtl .nav-links a { margin-left: 0; margin-right: 1.5rem; }
/* --- HERO SECTION --- */
.hero {
background: linear-gradient(135deg, var(--primary) 0%, var(--secondary) 100%);
color: white; padding: 4rem 0; border-radius: 0 0 2rem 2rem; margin-bottom: 2rem;
}
.hero-content { max-width: 600px; }
.hero h1 { font-size: 2.5rem; margin-bottom: 1rem; line-height: 1.2; }
.hero p { font-size: 1.1rem; opacity: 0.9; margin-bottom: 2rem; }
/* --- GRID LAYOUTS --- */
.product-grid { grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); gap: 1.5rem; }
.plan-grid { grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 2rem; }
/* --- CARDS --- */
.card {
background: var(--bg-card); border: 1px solid var(--border);
border-radius: var(--radius); overflow: hidden; transition: var(--transition);
}
.card:hover { transform: translateY(-5px); box-shadow: var(--shadow); }
.card-img { height: 200px; background: #ddd; position: relative; }
.card-img img { width: 100%; height: 100%; object-fit: cover; }
.badge {
position: absolute; top: 10px; right: 10px;
background: var(--secondary); color: white;
padding: 0.2rem 0.6rem; font-size: 0.8rem; border-radius: 4px;
}
.rtl .badge { right: auto; left: 10px; }
.card-body { padding: 1rem; }
.card-title { font-size: 1.1rem; font-weight: 600; margin-bottom: 0.5rem; }
.card-price { font-size: 1.2rem; font-weight: 700; color: var(--primary); }
.card-meta { font-size: 0.85rem; color: var(--text-muted); margin-bottom: 0.5rem; }
/* --- STOREFRONT --- */
.store-header {
background: var(--bg-card); padding: 2rem; border-radius: var(--radius);
margin-bottom: 2rem; display: flex; align-items: center; gap: 2rem;
}
.store-logo { width: 100px; height: 100px; border-radius: 50%; border: 3px solid var(--border); }
.store-stats { display: flex; gap: 2rem; margin-top: 1rem; }
.stat-item { font-size: 0.9rem; color: var(--text-muted); }
.stat-item span { font-weight: 700; color: var(--text-main); }
/* --- DASHBOARD --- */
.dashboard-layout { display: grid; grid-template-columns: 250px 1fr; gap: 2rem; min-height: 80vh; }
.sidebar { background: var(--bg-card); padding: 1.5rem; border-radius: var(--radius); }
.sidebar li { padding: 0.8rem; cursor: pointer; border-radius: 0.5rem; margin-bottom: 0.5rem; color: var(--text-muted); }
.sidebar li:hover, .sidebar li.active { background: var(--bg-body); color: var(--primary); font-weight: 600; }
.dash-content { background: var(--bg-card); padding: 2rem; border-radius: var(--radius); }
.stat-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1rem; margin-bottom: 2rem; }
.stat-box { background: var(--bg-body); padding: 1.5rem; border-radius: var(--radius); text-align: center; }
.stat-box h3 { font-size: 2rem; color: var(--primary); }
/* --- PLANS --- */
.plan-card { border: 1px solid var(--border); padding: 2rem; border-radius: var(--radius); text-align: center; position: relative; }
.plan-card.featured { border: 2px solid var(--primary); background: rgba(79, 46, 225, 0.05); }
.plan-price { font-size: 2.5rem; font-weight: 700; margin: 1rem 0; }
.plan-features li { margin: 0.5rem 0; color: var(--text-muted); }
/* --- MODAL --- */
.modal {
position: fixed; top: 0; left: 0; width: 100%; height: 100%;
background: rgba(0, 0, 0, 0.5); z-index: 1000;
display: flex; align-items: center; justify-content: center;
opacity: 0; pointer-events: none; transition: 0.3s;
}
.modal.open { opacity: 1; pointer-events: auto; }
.modal-content {
background: var(--bg-card); width: 400px; padding: 2rem;
border-radius: var(--radius); transform: scale(0.9); transition: 0.3s;
}
.modal.open .modal-content { transform: scale(1); }
/* --- RESPONSIVE --- */
@media (max-width: 768px) {
.dashboard-layout { grid-template-columns: 1fr; }
.hero { padding: 2rem 0; text-align: center; }
.store-header { flex-direction: column; text-align: center; }
.nav-links { display: none; }
.stat-grid { grid-template-columns: repeat(2, 1fr); }
}
/* Gradio Overrides */
.gradio-container { background-color: var(--bg-body) !important; }
"""
# --- HTML Generators ---
def generate_hero_html():
return """
<div class="hero">
<div class="container hero-content">
<h1>The Future of Digital Commerce</h1>
<p>Rent a storefront, sell globally, and scale your business with Voltix Marketplace.</p>
<div class="flex gap-4">
<button class="btn btn-outline" style="background:white; color:var(--primary)">Start Selling</button>
<button class="btn btn-outline" style="border:white; color:white">Browse Stores</button>
</div>
</div>
</div>
"""
def generate_product_html(products):
html_parts = []
for p in products:
card = f"""
<div class="card">
<div class="card-img">
<span class="badge">Best Seller</span>
<img src="{p['img']}" alt="{p['name']}">
</div>
<div class="card-body">
<div class="card-meta flex justify-between">
<span>{p['vendor']}</span>
<span><i class="fa-solid fa-star text-primary"></i> {p['rating']}</span>
</div>
<h3 class="card-title">{p['name']}</h3>
<div class="flex justify-between items-center mt-2">
<span class="card-price">${p['price']}</span>
<button class="btn btn-outline" style="padding:0.4rem 0.8rem; font-size:0.8rem;">
<i class="fa-solid fa-cart-plus"></i> Add
</button>
</div>
</div>
</div>
"""
html_parts.append(card)
return f"""
<div class="container">
<div class="flex justify-between items-center mb-4">
<h2 class="text-2xl font-bold">Trending Products</h2>
<button class="btn btn-outline">View All</button>
</div>
<div class="grid product-grid">
{''.join(html_parts)}
</div>
</div>
"""
def generate_plan_html(plans):
html_parts = []
for plan in plans:
featured_class = "featured" if plan.get("featured") else ""
badge = '<span class="badge">Most Popular</span>' if plan.get("featured") else ""
features_list = "".join([f"<li><i class='fa-solid fa-check text-primary'></i> {f}</li>" for f in plan["features"]])
card = f"""
<div class="plan-card {featured_class}">
{badge}
<h3>{plan['name']}</h3>
<div class="plan-price">${plan['price']}<span style="font-size:1rem; color:var(--text-muted)">/mo</span></div>
<ul class="plan-features">
{features_list}
</ul>
<button class="btn btn-primary mt-4 w-100">Select Plan</button>
</div>
"""
html_parts.append(card)
return f"""
<div class="container mt-4">
<div class="text-center mb-4">
<h1 style="font-size:2.5rem; margin-bottom:0.5rem;">Choose Your Plan</h1>
<p class="text-muted">Scale your store with features tailored to your growth.</p>
</div>
<div class="grid plan-grid">
{''.join(html_parts)}
</div>
</div>
"""
def generate_store_html():
# Filter mock products for TechNova
tech_products = [p for p in PRODUCTS if p['vendor'] == 'TechNova']
product_grid = generate_product_html(tech_products * 2) # Duplicate for demo
return f"""
<div class="container mt-4">
<div class="store-header shadow">
<img src="https://images.unsplash.com/photo-1560179707-f14e90ef3dab?w=200" class="store-logo rounded">
<div class="flex-col">
<h2 style="font-size:2rem; font-weight:700;">TechNova Electronics</h2>
<p class="text-muted">Premium gadgets for the modern lifestyle. Verified Seller since 2023.</p>
<div class="store-stats">
<div class="stat-item"><span>4.9</span> Rating</div>
<div class="stat-item"><span>1.2k</span> Sales</div>
<div class="stat-item"><span>24h</span> Response Time</div>
</div>
<div class="flex gap-2 mt-2">
<button class="btn btn-primary"><i class="fa-solid fa-heart"></i> Follow</button>
<button class="btn btn-outline"><i class="fa-solid fa-message"></i> Contact</button>
</div>
</div>
</div>
<h3 class="mb-4">Shop Products</h3>
{product_grid}
</div>
"""
def generate_dashboard_html():
return """
<div class="dashboard-layout">
<div class="sidebar">
<ul>
<li class="active"><i class="fa-solid fa-chart-line"></i> Overview</li>
<li><i class="fa-solid fa-box"></i> Products</li>
<li><i class="fa-solid fa-users"></i> Customers</li>
<li><i class="fa-solid fa-file-invoice-dollar"></i> Orders</li>
<li><i class="fa-solid fa-store"></i> Store Settings</li>
<li><i class="fa-solid fa-credit-card"></i> Subscription</li>
</ul>
</div>
<div class="dash-content">
<h2 class="mb-4">Seller Dashboard</h2>
<div class="stat-grid">
<div class="stat-box">
<h3>$4,250</h3>
<p>Total Revenue</p>
</div>
<div class="stat-box">
<h3>128</h3>
<p>Orders</p>
</div>
<div class="stat-box">
<h3>45</h3>
<p>Products</p>
</div>
<div class="stat-box">
<h3>98%</h3>
<p>Rating</p>
</div>
</div>
<h3 class="mb-4">Recent Orders</h3>
<div style="overflow-x:auto;">
<table style="width:100%; text-align:left; border-collapse:collapse;">
<thead>
<tr style="background:var(--bg-body); border-bottom:1px solid var(--border);">
<th class="p-4">Order ID</th>
<th class="p-4">Product</th>
<th class="p-4">Status</th>
<th class="p-4">Amount</th>
</tr>
</thead>
<tbody>
<tr style="border-bottom:1px solid var(--border);">
<td class="p-4">#ORD-992</td>
<td class="p-4">Quantum Headphones</td>
<td class="p-4"><span style="background:#e0f2fe; padding:2px 8px; border-radius:4px; font-size:0.8rem;">Processing</span></td>
<td class="p-4">$129.99</td>
</tr>
<tr style="border-bottom:1px solid var(--border);">
<td class="p-4">#ORD-991</td>
<td class="p-4">Mechanical Keyboard</td>
<td class="p-4"><span style="background:#dcfce7; padding:2px 8px; border-radius:4px; font-size:0.8rem;">Completed</span></td>
<td class="p-4">$89.50</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
"""