Spaces:
Running
Running
| """ | |
| 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> | |
| """ |