UNPKG

gentelella

Version:

Gentelella v4 — free admin template. 60 pages, 20 chart variants, fully interactive inbox & kanban, live theme generator, component playground, PWA-ready. Vite 8, vanilla JS, no Bootstrap, no jQuery.

165 lines (150 loc) 10.7 kB
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Orders | Gentelella 2026 v4</title> <link rel="icon" href="../images/favicon.svg" type="image/svg+xml"> <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@300;400;500;600;700&display=swap" rel="stylesheet"> <script type="module" src="/src/main-v4.js"></script> </head> <body data-shell="admin" data-page="orders" data-breadcrumb="Home > Shop > Orders"> <main class="main"> <div class="page-wrapper"> <div class="page-header"> <div class="page-header-row"> <div> <div class="page-pretitle">Shop</div> <h1 class="page-title">Orders</h1> </div> <div class="page-actions"> <button class="btn btn-outline">Export CSV</button> <button class="btn btn-primary">+ Manual order</button> </div> </div> </div> <!-- Stat row --> <div class="row col-3" style="margin-bottom:16px"> <div class="card"><div class="stat"><div class="stat-icon teal"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M6 2L3 6v14a2 2 0 002 2h14a2 2 0 002-2V6l-3-4z"/><line x1="3" y1="6" x2="21" y2="6"/></svg></div><div class="stat-content"><div class="stat-label">Total orders</div><div class="stat-value-row"><span class="stat-value">1,240</span><span class="stat-change up">12%</span></div><div class="stat-subtext">78 today</div></div></div></div> <div class="card"><div class="stat"><div class="stat-icon green"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><line x1="12" y1="1" x2="12" y2="23"/><path d="M17 5H9.5a3.5 3.5 0 000 7h5a3.5 3.5 0 010 7H6"/></svg></div><div class="stat-content"><div class="stat-label">Revenue</div><div class="stat-value-row"><span class="stat-value">$84,520</span><span class="stat-change up">18%</span></div><div class="stat-subtext">$3,218 today</div></div></div></div> <div class="card"><div class="stat"><div class="stat-icon yellow"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg></div><div class="stat-content"><div class="stat-label">Pending</div><div class="stat-value-row"><span class="stat-value">42</span><span class="stat-change down">3%</span></div><div class="stat-subtext">5 awaiting payment</div></div></div></div> </div> <div class="card"> <div class="card-header"> <div> <div class="card-title">All orders</div> <div class="card-subtitle">1,240 results</div> </div> <div class="card-options"> <label style="font-size:11.5px;color:var(--text-muted);margin-right:6px">Status</label> <select class="form-control" style="width:170px;height:32px" aria-label="Filter by status"> <option>All statuses</option> <option>Paid</option> <option>Processing</option> <option>Pending</option> <option>Cancelled</option> </select> </div> </div> <div class="card-body p-0"> <div class="table-responsive"> <table class="table" data-datatable data-page-length="10" data-export="orders"> <thead> <tr> <th>Order</th> <th>Customer</th> <th>Items</th> <th>Total</th> <th>Status</th> <th>Payment</th> <th>Date</th> <th data-orderable="false"></th> </tr> </thead> <tbody id="orders-rows"></tbody> </table> </div> </div> </div> </div> </main> <script type="module"> // This page demonstrates the data-adapter pattern. By default it uses // a hardcoded SEED array — the standard "self-contained demo" mode. // Add `?api=1` to the URL to fetch from /api/orders instead. Run the // example backend in `examples/express-sqlite/` to see it in action. import { useApiMode, seedAdapter, httpAdapter } from '/src/v4/data-adapter.js'; const SEED = [ { id:'#7841', customer:'John Doe', initials:'JD', avatarColor:'primary', items:3, total:245, status:'paid', payment:'Visa •••• 4242', createdAt:'Apr 28, 2026' }, { id:'#7840', customer:'Anna Smith', initials:'AS', avatarColor:'azure', items:1, total: 89, status:'processing', payment:'Mastercard •••• 8841', createdAt:'Apr 28, 2026' }, { id:'#7839', customer:'Robert Jones', initials:'RJ', avatarColor:'purple', items:5, total:490, status:'paid', payment:'PayPal', createdAt:'Apr 28, 2026' }, { id:'#7838', customer:'Emily Wang', initials:'EW', avatarColor:'yellow', items:2, total:125, status:'pending', payment:'Stripe checkout', createdAt:'Apr 27, 2026' }, { id:'#7837', customer:'Mark Kim', initials:'MK', avatarColor:'red', items:1, total: 67, status:'cancelled', payment:'Visa •••• 1234', createdAt:'Apr 27, 2026' }, { id:'#7836', customer:'Lina Park', initials:'LP', avatarColor:'green', items:4, total:312, status:'paid', payment:'Visa •••• 4242', createdAt:'Apr 27, 2026' }, { id:'#7835', customer:'Diego Reyes', initials:'DR', avatarColor:'blue', items:2, total:178, status:'paid', payment:'Apple Pay', createdAt:'Apr 26, 2026' }, { id:'#7834', customer:'Yuki Tanaka', initials:'YT', avatarColor:'primary', items:3, total:234, status:'processing', payment:'Mastercard •••• 7712', createdAt:'Apr 26, 2026' }, { id:'#7833', customer:'Sarah Kowalski',initials:'SK', avatarColor:'primary', items:6, total:549, status:'paid', payment:'Stripe checkout', createdAt:'Apr 26, 2026' }, { id:'#7832', customer:'Michael Reyes', initials:'MR', avatarColor:'purple', items:1, total: 45, status:'pending', payment:'PayPal', createdAt:'Apr 25, 2026' }, { id:'#7831', customer:'Tom Hardy', initials:'TH', avatarColor:'purple', items:2, total:195, status:'paid', payment:'Visa •••• 4242', createdAt:'Apr 25, 2026' }, { id:'#7830', customer:'Anna Smith', initials:'AS', avatarColor:'azure', items:3, total:220, status:'paid', payment:'Mastercard •••• 8841', createdAt:'Apr 24, 2026' }, { id:'#7829', customer:'John Doe', initials:'JD', avatarColor:'primary', items:1, total: 79, status:'paid', payment:'Apple Pay', createdAt:'Apr 24, 2026' }, { id:'#7828', customer:'Robert Jones', initials:'RJ', avatarColor:'purple', items:2, total:168, status:'cancelled', payment:'Visa •••• 5566', createdAt:'Apr 23, 2026' }, { id:'#7827', customer:'Emily Wang', initials:'EW', avatarColor:'yellow', items:4, total:388, status:'paid', payment:'Stripe checkout', createdAt:'Apr 23, 2026' }, { id:'#7826', customer:'Mark Kim', initials:'MK', avatarColor:'red', items:1, total:112, status:'paid', payment:'Google Pay', createdAt:'Apr 22, 2026' }, { id:'#7825', customer:'Diego Reyes', initials:'DR', avatarColor:'blue', items:2, total:156, status:'processing', payment:'PayPal', createdAt:'Apr 22, 2026' }, { id:'#7824', customer:'Lina Park', initials:'LP', avatarColor:'green', items:3, total:247, status:'paid', payment:'Visa •••• 4242', createdAt:'Apr 21, 2026' }, { id:'#7823', customer:'Yuki Tanaka', initials:'YT', avatarColor:'primary', items:1, total: 58, status:'paid', payment:'Apple Pay', createdAt:'Apr 21, 2026' }, { id:'#7822', customer:'Sarah Kowalski',initials:'SK', avatarColor:'primary', items:2, total:132, status:'paid', payment:'Stripe checkout', createdAt:'Apr 20, 2026' } ]; const colorMap = { primary:'var(--primary)', azure:'var(--azure)', purple:'var(--purple)', yellow:'var(--yellow)', red:'var(--red)', green:'var(--green)', blue:'var(--blue)' }; const STATUS = { paid:'green', processing:'blue', pending:'yellow', cancelled:'red' }; const adapter = useApiMode() ? httpAdapter('/api/orders', { listKey: 'orders' }) : seedAdapter(SEED); const tbody = document.getElementById('orders-rows'); function rowHtml(o) { return ` <tr> <td class="cell-mono"><a href="order_detail.html" style="color:var(--primary);font-weight:var(--font-weight-medium)">${o.id}</a></td> <td><div class="cell-customer"><div class="cell-avatar" style="background:${colorMap[o.avatarColor] || 'var(--primary)'}">${o.initials}</div><span class="cell-strong">${o.customer}</span></div></td> <td>${o.items}</td> <td class="cell-strong">$${o.total}</td> <td><span class="status status-${STATUS[o.status]}">${o.status[0].toUpperCase() + o.status.slice(1)}</span></td> <td style="font-size:12px;color:var(--text-muted)">${o.payment}</td> <td>${o.createdAt}</td> <td><button class="card-opt-btn" aria-label="More"><svg viewBox="0 0 16 16" fill="currentColor"><circle cx="8" cy="3" r="1.2"/><circle cx="8" cy="8" r="1.2"/><circle cx="8" cy="13" r="1.2"/></svg></button></td> </tr>`; } // Loading state during fetch — emit 5 skeleton rows so the table looks "alive" // while the network request resolves. In seed mode this flashes briefly. function skeletonRows(n = 5) { const cell = '<td><span class="skeleton skeleton-text" style="width:80%"></span></td>'; return Array.from({ length: n }, () => `<tr>${cell.repeat(8)}</tr>`).join(''); } async function load() { tbody.innerHTML = skeletonRows(); try { const orders = await adapter.list(); if (!orders.length) { tbody.innerHTML = `<tr><td colspan="8" style="padding:40px;text-align:center;color:var(--text-muted)">No orders yet.</td></tr>`; return; } tbody.innerHTML = orders.map(rowHtml).join(''); } catch (err) { tbody.innerHTML = ` <tr><td colspan="8" style="padding:24px"> <div class="banner banner-danger"> <svg class="banner-icon" width="18" height="18" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5"><circle cx="8" cy="8" r="6"/><path d="M5 5l6 6M11 5l-6 6"/></svg> <div class="banner-body"><strong>Failed to load orders.</strong> ${err.message || err}</div> <div class="banner-actions"><button class="btn btn-outline btn-sm" id="orders-retry">Retry</button></div> </div> </td></tr>`; document.getElementById('orders-retry')?.addEventListener('click', load); } } load(); </script> </body> </html>