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.
1 lines • 3.42 kB
JavaScript
import"./main-v4-BFwmMcfm.js";import{t as e}from"./toast-DgCSlJPv.js";var t=[{desc:"Gentelella Pro license",sub:"Annual subscription · 50 seats",qty:1,rate:2499},{desc:"Custom theme development",sub:"Branded variant · 24h",qty:24,rate:120},{desc:"Priority support",sub:"12 months · 4h response SLA",qty:12,rate:99},{desc:"Onboarding workshop",sub:"Half-day remote session",qty:1,rate:450}],n=e=>"$"+e.toLocaleString("en-US",{minimumFractionDigits:2,maximumFractionDigits:2}),a=document.getElementById("line-items");function s(e,t){return`\n <div class="line-row" data-i="${t}">\n <div class="desc-wrap">\n <input type="text" class="desc" value="${e.desc.replace(/"/g,""")}" placeholder="Item description" aria-label="Item description">\n <input type="text" class="desc desc-sub" value="${e.sub.replace(/"/g,""")}" placeholder="Optional details" aria-label="Item details">\n </div>\n <input type="number" class="qty" aria-label="Quantity" value="${e.qty}" min="0" step="1">\n <input type="number" class="rate" aria-label="Rate" value="${e.rate}" min="0" step="0.01">\n <div class="amount">${n(e.qty*e.rate)}</div>\n <button type="button" class="remove-btn" aria-label="Remove">\n <svg width="13" height="13" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M3 6h10M8 6V4a1.5 1.5 0 013 0v2"/><path d="M5 6l1 8.5h6L13 6"/></svg>\n </button>\n </div>\n `}function o(){a.innerHTML=t.map(s).join(""),i()}function i(){let e=0;document.querySelectorAll("#line-items .line-row").forEach((a,s)=>{const o=parseFloat(a.querySelector(".qty").value)||0,i=parseFloat(a.querySelector(".rate").value)||0,l=o*i;a.querySelector(".amount").textContent=n(l),e+=l,t[s]&&(t[s].qty=o,t[s].rate=i,t[s].desc=a.querySelector(".desc:not(.desc-sub)").value,t[s].sub=a.querySelector(".desc-sub").value)});const a=parseFloat(document.getElementById("t-discount").value)||0,s=parseFloat(document.getElementById("t-tax").value)||0,o=e*a/100,i=e-o,l=i*s/100,r=i+l;document.getElementById("t-subtotal").textContent=n(e),document.getElementById("t-discount-amount").textContent="−"+n(o),document.getElementById("t-tax-amount").textContent=n(l),document.getElementById("t-grand").textContent=n(r)}a.addEventListener("input",i),a.addEventListener("click",e=>{const n=e.target.closest(".remove-btn");if(!n)return;const a=n.closest(".line-row"),s=parseInt(a.dataset.i,10);t.splice(s,1),o()}),document.getElementById("add-line").addEventListener("click",()=>{t.push({desc:"New item",sub:"",qty:1,rate:0}),o();const e=a.querySelector(".line-row:last-child .desc");e&&(e.focus(),e.select())}),document.getElementById("t-discount").addEventListener("input",i),document.getElementById("t-tax").addEventListener("input",i);var l=document.getElementById("status-pill"),r=document.getElementById("ips-paid"),d=document.getElementById("mark-paid-btn"),c=!1;d.addEventListener("click",()=>{(c=!c)?(l.className="status status-green",l.textContent="Paid",r.classList.add("paid"),r.querySelector(".ips-time").textContent=(new Date).toLocaleDateString("en-US",{month:"short",day:"numeric",year:"numeric"}),d.textContent="Mark unpaid",e("Marked as paid",{variant:"success"})):(l.className="status status-yellow",l.textContent="Pending",r.classList.remove("paid"),r.querySelector(".ips-time").textContent="—",d.textContent="Mark as paid",e("Marked unpaid"))}),o();