Last active
May 1, 2026 21:29
-
-
Save sebastianjnuwu/95dd894f71befdca5ceb0239af5689e4 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <!DOCTYPE html> | |
| <html lang="pt-br"> | |
| <head> | |
| <meta charset="UTF-8" /> | |
| <meta name="viewport" content="width=device-width, initial-scale=1" /> | |
| <meta name="loja-id" content="ecf68475-0fe1-4224-a2f3-cb1cd3311d84" /> | |
| <!-- HTML Meta Tags --> | |
| <title>Theme Light Shop | Template de Loja Virtual Moderna</title> | |
| <meta name="description" | |
| content="Template moderno para e-commerce com visual claro, performance elevada, SEO otimizado e experiência premium para lojas virtuais."> | |
| <!-- Facebook Meta Tags --> | |
| <meta property="og:url" content="https://demo-theme-light-shop-web.cabrapi.com.br/"> | |
| <meta property="og:type" content="website"> | |
| <meta property="og:title" content="Theme Light Shop | Template de Loja Virtual Moderna"> | |
| <meta property="og:description" | |
| content="Template moderno para e-commerce com visual claro, performance elevada, SEO otimizado e experiência premium para lojas virtuais."> | |
| <meta property="og:image" | |
| content="https://blob.cabrapi.com.br/blob/808ff623-b490-414a-8b82-abeadeb87b0d/download"> | |
| <!-- Twitter Meta Tags --> | |
| <meta name="twitter:card" content="summary_large_image"> | |
| <meta property="twitter:domain" content="demo-theme-light-shop-web.cabrapi.com.br"> | |
| <meta property="twitter:url" content="https://demo-theme-light-shop-web.cabrapi.com.br/"> | |
| <meta name="twitter:title" content="Theme Light Shop | Template de Loja Virtual Moderna"> | |
| <meta name="twitter:description" | |
| content="Template moderno para e-commerce com visual claro, performance elevada, SEO otimizado e experiência premium para lojas virtuais."> | |
| <meta name="twitter:image" | |
| content="https://blob.cabrapi.com.br/blob/808ff623-b490-414a-8b82-abeadeb87b0d/download"> | |
| <link rel="icon" href="https://blob.cabrapi.com.br/blob/808ff623-b490-414a-8b82-abeadeb87b0d/download" | |
| sizes="32x32"> | |
| <link rel="icon" href="https://blob.cabrapi.com.br/blob/808ff623-b490-414a-8b82-abeadeb87b0d/download" | |
| sizes="192x192"> | |
| <link rel="apple-touch-icon" | |
| href="https://blob.cabrapi.com.br/blob/808ff623-b490-414a-8b82-abeadeb87b0d/download"> | |
| <link href="https://fonts.googleapis.com/css2?family=DM+Sans:ital,opsz,wght@0,9..40,300;0,9..40,400;0,9..40,500;0,9..40,600;0,9..40,700;1,9..40,400&family=DM+Serif+Display&display=swap" | |
| rel="stylesheet" /> | |
| <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.0/css/all.min.css" rel="stylesheet" /> | |
| <script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script> | |
| <style> | |
| :root { | |
| --c-bg: #f8f7f4; | |
| --c-surface: #ffffff; | |
| --c-border: #e8e4df; | |
| --c-ink: #1a1714; | |
| --c-ink-muted: #6b6560; | |
| --c-ink-subtle: #a09a94; | |
| --c-accent: #c8502a; | |
| --c-accent-light: #fef3ec; | |
| --c-green: #2d7a4f; | |
| } | |
| *, | |
| *::before, | |
| *::after { | |
| box-sizing: border-box; | |
| } | |
| body { | |
| font-family: 'DM Sans', sans-serif; | |
| background: var(--c-bg); | |
| color: var(--c-ink); | |
| } | |
| a { | |
| text-decoration: none; | |
| color: inherit; | |
| } | |
| img { | |
| max-width: 100%; | |
| height: auto; | |
| } | |
| button { | |
| font-family: inherit; | |
| cursor: pointer; | |
| } | |
| section img { | |
| pointer-events: none; | |
| } | |
| </style> | |
| <script src="https://code.jquery.com/jquery-3.7.1.min.js"></script> | |
| <script type="module"> | |
| import { caBRAPI as p } from "https://cdn.jsdelivr.net/npm/@cabrapi/sdk/dist/index.js"; | |
| var l = { | |
| CART_STORAGE_KEY: "cabrapi_theme_light_shop_cart", | |
| PRODUCTS_PAGE: 1, | |
| PRODUCTS_LIMIT: 3, | |
| PRODUCT_IMAGE_FIT_DEFAULT: "cover", | |
| BUTTON_FEEDBACK_MS: 1400, | |
| COPY_FEEDBACK_MS: 1800 | |
| }, m = { | |
| PIX: "MERCADOPAGO_SERVICE_PIX", | |
| CARD: "MERCADOPAGO_SERVICE_CARD" | |
| }, b = class { | |
| #t; | |
| #e; | |
| constructor(t, e) { | |
| this.#t = new t({ | |
| type: "public", | |
| config: {} | |
| }), this.#e = e; | |
| } | |
| async getProducts(t = l.PRODUCTS_PAGE) { | |
| const e = await this.#t.products.get(this.#e, { | |
| page: t, | |
| limit: l.PRODUCTS_LIMIT | |
| }); | |
| if (!e?.status && e?.error) throw new Error(e?.message || "Erro ao buscar produtos."); | |
| return { | |
| products: Array.isArray(e?.products) ? e.products : [], | |
| pagination: { | |
| page: Number(e?.pagination?.page || t || 1), | |
| limit: Number(e?.pagination?.limit || l.PRODUCTS_LIMIT), | |
| total: Number(e?.pagination?.total || 0), | |
| totalPages: Number(e?.pagination?.totalPages || 1) | |
| } | |
| }; | |
| } | |
| async getCategories() { | |
| const t = await this.#t.categories.get(this.#e, { | |
| page: 1, | |
| limit: 100 | |
| }); | |
| if (!t?.status && t?.error) throw new Error(t?.message || "Erro ao buscar categorias."); | |
| return Array.isArray(t?.categories) ? t.categories : []; | |
| } | |
| async validateCoupon(t) { | |
| return await this.#t.coupons.getByCode(this.#e, t); | |
| } | |
| async createPayment(t) { | |
| return await this.#t.payments.post(this.#e, t); | |
| } | |
| }, C = class { | |
| #t = null; | |
| getItems() { | |
| if (this.#t) return this.#t; | |
| try { | |
| const t = localStorage.getItem(l.CART_STORAGE_KEY); | |
| this.#t = t ? JSON.parse(t) : []; | |
| } catch { | |
| this.#t = []; | |
| } | |
| return this.#t; | |
| } | |
| #e(t) { | |
| this.#t = Array.isArray(t) ? t : [], localStorage.setItem(l.CART_STORAGE_KEY, JSON.stringify(this.#t)); | |
| } | |
| addProduct(t) { | |
| const e = this.getItems(), o = String(t.id), s = e.find((i) => String(i.id) === o), a = t.stock === null || t.stock === void 0 ? null : Number(t.stock); | |
| if (a !== null && a <= 0) return e; | |
| if (s) { | |
| const i = s.stock === null || s.stock === void 0 ? null : Number(s.stock); | |
| if (i !== null && s.qty >= i) return e; | |
| s.qty += 1; | |
| } else e.push({ | |
| id: o, | |
| name: String(t.name || "Produto"), | |
| image: t.image || null, | |
| price: Number(t.price || 0), | |
| qty: 1, | |
| stock: a | |
| }); | |
| return this.#e(e), e; | |
| } | |
| removeProduct(t) { | |
| const e = String(t), o = this.getItems().filter((s) => String(s.id) !== e); | |
| return this.#e(o), o; | |
| } | |
| changeQuantity(t, e) { | |
| const o = String(t), s = this.getItems(), a = s.find((n) => String(n.id) === o); | |
| if (!a) return s; | |
| const i = a.stock === null || a.stock === void 0 ? null : Number(a.stock); | |
| if (e > 0 && i !== null && a.qty >= i) return s; | |
| if (a.qty += e, a.qty <= 0) return this.removeProduct(t); | |
| const c = s.filter((n) => n.qty > 0); | |
| return this.#e(c), c; | |
| } | |
| clear() { | |
| this.#e([]); | |
| } | |
| getTotalItems() { | |
| return this.getItems().reduce((t, e) => t + Number(e.qty || 0), 0); | |
| } | |
| getTotalPrice() { | |
| return this.getItems().reduce((t, e) => t + Number(e.price || 0) * Number(e.qty || 0), 0); | |
| } | |
| }; | |
| function x(t) { | |
| return String(t || "").trim().length >= 3; | |
| } | |
| function y(t) { | |
| const e = String(t || "").trim(); | |
| return e ? e.length >= 4 && e.length <= 32 : !0; | |
| } | |
| function v(t) { | |
| return String(t || "").replace(/\D/g, "").length === 11; | |
| } | |
| function k(t) { | |
| const e = String(t || "").trim(); | |
| return e ? /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(e) : !1; | |
| } | |
| function w(t) { | |
| return Array.isArray(t) && t.length > 0; | |
| } | |
| function S(t, e, o = 1400) { | |
| const s = t.html(); | |
| t.prop("disabled", !0).html(e), setTimeout(() => { | |
| t.prop("disabled", !1).html(s); | |
| }, o); | |
| } | |
| function d(t, e) { | |
| if (e) { | |
| t.removeClass("opacity-0 pointer-events-none"); | |
| return; | |
| } | |
| t.addClass("opacity-0 pointer-events-none"); | |
| } | |
| function r(t) { | |
| return String(t || "").replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/\"/g, """).replace(/'/g, "'"); | |
| } | |
| var P = class { | |
| constructor({ onCategoryChange: t }) { | |
| this.$filters = $("#category-filters"), this.onCategoryChange = t, this.categories = [], this.activeCategory = "all", this.#t(); | |
| } | |
| #t() { | |
| $(document).on("click", ".category-filter-btn", (t) => { | |
| const e = String($(t.currentTarget).data("category") || "all"); | |
| e !== this.activeCategory && (this.activeCategory = e, this.render(), typeof this.onCategoryChange == "function" && this.onCategoryChange(e)); | |
| }); | |
| } | |
| setCategories(t) { | |
| this.categories = (Array.isArray(t) ? t : []).filter((e) => e?.name).map((e) => ({ | |
| id: String(e.id || e.name), | |
| name: String(e.name) | |
| })), this.render(); | |
| } | |
| setActiveCategory(t) { | |
| this.activeCategory = String(t || "all"), this.render(); | |
| } | |
| render() { | |
| const t = [`<button class="category-filter-btn px-4 py-2 rounded-full text-sm font-medium transition-all ${this.activeCategory === "all" ? "bg-[#c8502a] text-white" : "bg-white text-[#6b6560] border border-[#e8e4df]"}" data-category="all">Todos</button>`]; | |
| for (const e of this.categories) { | |
| const o = this.activeCategory === e.name ? "bg-[#c8502a] text-white" : "bg-white text-[#6b6560] border border-[#e8e4df] hover:border-[#c8502a] hover:text-[#c8502a]"; | |
| t.push(`<button class="category-filter-btn px-4 py-2 rounded-full text-sm font-medium transition-all ${o}" data-category="${r(e.name)}">${r(e.name)}</button>`); | |
| } | |
| this.$filters.html(t.join("")); | |
| } | |
| }; | |
| function h(t) { | |
| return new Intl.NumberFormat("pt-BR", { | |
| style: "currency", | |
| currency: "BRL" | |
| }).format(Number(t || 0)); | |
| } | |
| function A(t = "Produto") { | |
| return `https://placehold.co/600x420/F0EDE8/9CA3AF?text=${encodeURIComponent(t)}`; | |
| } | |
| var I = class { | |
| constructor({ onAddToCart: t, onPageChange: e }) { | |
| this.$list = $("#products-list"), this.$pagination = $("#products-pagination"), this.onAddToCart = t, this.onPageChange = e, this.products = [], this.activeCategory = "all", this.pagination = { | |
| page: 1, | |
| totalPages: 1, | |
| total: 0 | |
| }, this.#t(); | |
| } | |
| #t() { | |
| $(document).on("click", ".product-add-btn", (t) => { | |
| const e = $(t.currentTarget); | |
| if (e.prop("disabled") || e.hasClass("cursor-not-allowed")) return; | |
| const o = String(e.data("id")), s = this.products.find((a) => String(a.id) === o); | |
| s && this.onAddToCart(s) !== !1 && S(e, '<i class="fas fa-check mr-2"></i> Adicionado', l.BUTTON_FEEDBACK_MS); | |
| }), $(document).on("click", ".products-page-btn", (t) => { | |
| const e = Number($(t.currentTarget).data("page")); | |
| !e || e === this.pagination.page || typeof this.onPageChange == "function" && this.onPageChange(e); | |
| }); | |
| } | |
| #e() { | |
| this.$list.find(".product-card-image").each((t, e) => { | |
| $(e).css({ | |
| width: "100%", | |
| height: "100%", | |
| "object-fit": "cover", | |
| "object-position": "center", | |
| display: "block" | |
| }); | |
| }); | |
| } | |
| setProducts(t) { | |
| const e = Array.isArray(t?.products) ? t.products : []; | |
| this.pagination = { | |
| page: Number(t?.pagination?.page || 1), | |
| totalPages: Number(t?.pagination?.totalPages || 1), | |
| total: Number(t?.pagination?.total || e.length) | |
| }, this.products = e.filter((o) => !o.disabled), this.#o(), this.#a(); | |
| } | |
| setActiveCategory(t) { | |
| this.activeCategory = String(t || "all"), this.#o(); | |
| } | |
| #s() { | |
| return this.activeCategory === "all" ? this.products : this.products.filter((t) => (t.categories || []).some((e) => String(e.name) === this.activeCategory)); | |
| } | |
| #o() { | |
| const t = this.#s(); | |
| if (!t.length) { | |
| this.$list.html(` | |
| <div class="col-span-full text-center py-20 text-[#6b6560]"> | |
| <i class="fas fa-box-open text-5xl mb-4 block opacity-20"></i> | |
| <p>Nenhum produto encontrado.</p> | |
| </div> | |
| `); | |
| return; | |
| } | |
| const e = t.map((o) => { | |
| const s = r(o.image || A(o.name)), a = Number(o.stock), i = !(!Number.isNaN(a) && a > 0); | |
| return ` | |
| <article class="group bg-white rounded-3xl border border-[#e8e4df] overflow-hidden hover:shadow-xl transition-all duration-300 flex flex-col h-full"> | |
| <div class="product-card-image-frame relative overflow-hidden bg-[#f8f7f4]" style="aspect-ratio: 4/3; width: 100%;"> | |
| <img src="${s}" | |
| alt="${r(o.name)}" | |
| class="product-card-image transition-transform duration-700 group-hover:scale-110" | |
| style="width: 100% !important; height: 100% !important; object-fit: cover !important; object-position: center !important; display: block !important;" | |
| /> | |
| <div class="absolute inset-0 bg-gradient-to-t from-[#1a1714]/10 to-transparent pointer-events-none"></div> | |
| </div> | |
| <div class="p-5 flex flex-col flex-1"> | |
| <div class="flex-1"> | |
| <h3 class="font-bold text-[#1a1714] text-lg mb-1 line-clamp-2 leading-tight"> | |
| ${r(o.name)} | |
| </h3> | |
| <p class="text-sm text-[#6b6560] mb-4 line-clamp-2 leading-relaxed"> | |
| ${r(o.description || "Asset digital exclusivo.")} | |
| </p> | |
| </div> | |
| <div class="mt-auto"> | |
| <div class="mb-4"> | |
| <span class="text-[10px] text-[#6b6560] font-bold uppercase tracking-widest">Valor</span> | |
| <div class="text-2xl text-[#c8502a] font-black leading-none"> | |
| ${h(o.price)} | |
| </div> | |
| </div> | |
| <button class="product-add-btn w-full py-3.5 bg-[#1a1714] text-white font-bold rounded-2xl hover:bg-[#c8502a] transition-all flex items-center justify-center gap-2 shadow-sm disabled:opacity-50 disabled:cursor-not-allowed disabled:hover:bg-[#1a1714]" | |
| ${i ? 'disabled aria-disabled="true"' : ""} | |
| data-id="${r(o.id)}" | |
| data-stock="${r(o.stock)}"> | |
| <i class="fas fa-shopping-bag text-sm"></i> | |
| <span>${i ? "ESGOTADO" : "ADICIONAR"}</span> | |
| </button> | |
| </div> | |
| </div> | |
| </article> | |
| `; | |
| }); | |
| this.$list.html(` | |
| <div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6"> | |
| ${e.join("")} | |
| </div> | |
| `), this.#e(); | |
| } | |
| #a() { | |
| const { page: t, totalPages: e } = this.pagination; | |
| if (e <= 1) { | |
| this.$pagination.html(""); | |
| return; | |
| } | |
| let o = ""; | |
| for (let s = 1; s <= e; s++) s === 1 || s === e || s >= t - 1 && s <= t + 1 ? o += ` | |
| <button class="products-page-btn w-10 h-10 md:w-12 md:h-12 ${s === t ? "flex" : "hidden md:flex"} items-center justify-center rounded-xl border-2 transition-all font-bold ${s === t ? "bg-[#1a1714] border-[#1a1714] text-white active-page shadow-lg" : "border-[#e8e4df] text-[#1a1714] hover:border-[#1a1714]"}" data-page="${s}"> | |
| ${s} | |
| </button> | |
| ` : (s === t - 2 || s === t + 2) && (o += '<span class="text-[#e8e4df] hidden md:inline">...</span>'); | |
| this.$pagination.html(` | |
| <div class="flex items-center justify-between gap-2 mt-12 mb-8 p-3 md:p-6 bg-white rounded-2xl md:rounded-[2rem] border border-[#e8e4df] mx-2"> | |
| <button class="products-page-btn flex items-center justify-center w-10 h-10 md:w-auto md:px-6 md:py-3 rounded-xl font-bold border-2 border-[#e8e4df] transition-all ${t <= 1 ? "opacity-20 cursor-not-allowed" : "text-[#1a1714] hover:bg-[#f8f7f4]"}" | |
| ${t <= 1 ? "disabled" : ""} data-page="${t - 1}"> | |
| <i class="fas fa-chevron-left text-xs"></i> | |
| <span class="hidden md:inline ml-2">Anterior</span> | |
| </button> | |
| <div class="flex items-center gap-1 md:gap-2"> | |
| ${o} | |
| <span class="md:hidden text-xs font-bold text-[#6b6560] ml-2">de ${e}</span> | |
| </div> | |
| <button class="products-page-btn flex items-center justify-center w-10 h-10 md:w-auto md:px-6 md:py-3 rounded-xl font-bold border-2 border-[#e8e4df] transition-all ${t >= e ? "opacity-20 cursor-not-allowed" : "text-[#1a1714] hover:bg-[#f8f7f4]"}" | |
| ${t >= e ? "disabled" : ""} data-page="${t + 1}"> | |
| <span class="hidden md:inline mr-2">Próxima</span> | |
| <i class="fas fa-chevron-right text-xs"></i> | |
| </button> | |
| </div> | |
| `); | |
| } | |
| updateButtonsStates(t) { | |
| $(".product-add-btn").each((e, o) => { | |
| const s = $(o), a = s.data("id"), i = t.find((f) => String(f.id) === String(a)), c = Number(s.data("stock")), n = i ? i.stock : isNaN(c) ? null : c, g = i ? i.qty : 0, u = n !== null && n <= 0 || n > 0 && g >= n; | |
| u ? s.prop("disabled", !0).attr("disabled", "disabled").addClass("opacity-50 cursor-not-allowed") : s.prop("disabled", !1).removeAttr("disabled").removeClass("opacity-50 cursor-not-allowed"), s.find("span").text(u ? "ESGOTADO" : "ADICIONAR"); | |
| }); | |
| } | |
| }, T = class { | |
| constructor() { | |
| this.$drawer = $("#checkout"), this.$openButton = $("#cart-toggle"), this.$closeButton = $("#checkout-close"), this.$count = $("#cart-count"); | |
| } | |
| bindEvents() { | |
| this.$openButton.on("click", (t) => { | |
| t.preventDefault(), this.open(); | |
| }), this.$closeButton.on("click", () => this.close()), this.$drawer.on("click", (t) => { | |
| $(t.target).is(this.$drawer) && this.close(); | |
| }); | |
| } | |
| open() { | |
| d(this.$drawer, !0); | |
| } | |
| close() { | |
| d(this.$drawer, !1); | |
| } | |
| setCount(t) { | |
| this.$count.text(String(Number(t || 0))); | |
| } | |
| }, E = class { | |
| constructor(t) { | |
| this.handlers = t, this.$items = $("#checkout-items"), this.$total = $("#checkout-total"), this.$message = $("#checkout-message"), this.$couponStatus = $("#checkout-coupon-status"), this.$couponInput = $("#checkout-coupon"), this.$cpfInput = $("#checkout-cpf"), this.$submitButton = $("#checkout-submit"), this.$couponButton = $("#checkout-apply-coupon"), this.$fieldErrors = { | |
| name: $("#checkout-name-error"), | |
| cpf: $("#checkout-cpf-error"), | |
| email: $("#checkout-email-error"), | |
| nickname: $("#checkout-nickname-error") | |
| }, this.#t(); | |
| } | |
| #t() { | |
| this.$items.on("click", ".checkout-remove-btn", (t) => { | |
| const e = String($(t.currentTarget).data("id")); | |
| this.handlers.onRemoveItem(e); | |
| }), this.$items.on("click", ".checkout-qty-btn", (t) => { | |
| const e = $(t.currentTarget), o = String(e.data("id")), s = Number(e.data("delta")); | |
| this.handlers.onQuantityChange(o, s); | |
| }), this.$couponButton.on("click", async () => { | |
| await this.handlers.onApplyCoupon(); | |
| }), this.$couponInput.on("input", () => { | |
| this.setCouponStatus(null); | |
| }), this.$cpfInput.on("input", (t) => { | |
| const e = $(t.currentTarget), o = this.#e(e.val()); | |
| e.val() !== o && e.val(o); | |
| }), $('input[name="payment_method"]').on("change", (t) => { | |
| this.handlers.onPaymentMethodChange(String($(t.currentTarget).val())); | |
| }), $("#checkout-form").on("submit", async (t) => { | |
| t.preventDefault(), await this.handlers.onSubmit(); | |
| }); | |
| } | |
| renderItems(t) { | |
| if (!t.length) { | |
| this.$items.html('<p class="text-center py-8 text-[#6b6560]">Carrinho vazio</p>'); | |
| return; | |
| } | |
| const e = t.map((o) => ` | |
| <div class="flex items-center gap-2 p-2 bg-[#f8f7f4] rounded-xl"> | |
| <img src="${r(o.image || "https://placehold.co/64x64/F0EDE8/9CA3AF")}" alt="${r(o.name)}" class="w-12 h-12 rounded-lg object-cover shrink-0" /> | |
| <div class="flex-1 min-w-0"> | |
| <p class="font-medium text-xs text-[#1a1714] truncate">${r(o.name)}</p> | |
| <p class="text-[#6b6560] text-xs">${h(o.price)}</p> | |
| </div> | |
| <div class="flex items-center gap-1 shrink-0"> | |
| <button class="checkout-qty-btn w-7 h-7 rounded-lg bg-white border border-[#e8e4df] text-[#1a1714] hover:bg-[#f8f7f4] disabled:opacity-50 disabled:cursor-not-allowed" ${Number(o.qty) <= 1 ? "disabled" : ""} data-id="${r(o.id)}" data-delta="-1"> | |
| <i class="fas fa-minus text-xs"></i> | |
| </button> | |
| <span class="w-6 text-center text-sm font-bold">${Number(o.qty)}</span> | |
| <button class="checkout-qty-btn w-7 h-7 rounded-lg bg-white border border-[#e8e4df] text-[#1a1714] hover:bg-[#f8f7f4] disabled:opacity-50 disabled:cursor-not-allowed" ${o.stock !== null && Number(o.stock) > 0 && Number(o.qty) >= Number(o.stock) ? "disabled" : ""} data-id="${r(o.id)}" data-delta="1"> | |
| <i class="fas fa-plus text-xs"></i> | |
| </button> | |
| </div> | |
| <button class="checkout-remove-btn text-red-500 hover:text-red-700 p-1 shrink-0 disabled:opacity-50 disabled:cursor-not-allowed" data-id="${r(o.id)}"> | |
| <i class="fas fa-trash text-xs"></i> | |
| </button> | |
| </div> | |
| `).join(""); | |
| this.$items.html(e); | |
| } | |
| setTotal(t) { | |
| this.$total.text(h(t)); | |
| } | |
| getFormData() { | |
| return { | |
| name: String($("#checkout-name").val() || "").trim(), | |
| nickname: String($("#checkout-nickname").val() || "").trim(), | |
| email: String($("#checkout-email").val() || "").trim(), | |
| cpf: String($("#checkout-cpf").val() || "").replace(/\D/g, ""), | |
| note: String($("#checkout-note").val() || "").trim(), | |
| coupon: String($("#checkout-coupon").val() || "").trim(), | |
| paymentMethod: String($('input[name="payment_method"]:checked').val() || "PIX") | |
| }; | |
| } | |
| setFieldError(t, e) { | |
| const o = this.$fieldErrors[t]; | |
| if (!(!o || !o.length)) { | |
| if (!e) { | |
| o.addClass("hidden").text(""); | |
| return; | |
| } | |
| o.removeClass("hidden").text(e); | |
| } | |
| } | |
| clearFieldErrors() { | |
| Object.keys(this.$fieldErrors).forEach((t) => { | |
| this.setFieldError(t, ""); | |
| }); | |
| } | |
| #e(t) { | |
| const e = String(t || "").replace(/\D/g, "").slice(0, 11), o = []; | |
| e.length > 0 && o.push(e.slice(0, 3)), e.length > 3 && o.push(e.slice(3, 6)), e.length > 6 && o.push(e.slice(6, 9)); | |
| let s = o.join("."); | |
| return e.length > 9 && (s += `-${e.slice(9, 11)}`), s; | |
| } | |
| setSubmitLabel(t) { | |
| const e = t === "CARD" ? '<i class="fas fa-credit-card mr-2"></i> Pagar com Cartão' : '<i class="fas fa-qrcode mr-2"></i> Pagar com PIX'; | |
| this.$submitButton.html(e); | |
| } | |
| setSubmitLoading(t, e) { | |
| if (t) { | |
| this.$submitButton.prop("disabled", !0).html('<i class="fas fa-spinner fa-spin mr-2"></i> Processando...'); | |
| return; | |
| } | |
| this.$submitButton.prop("disabled", !1), this.setSubmitLabel(e); | |
| } | |
| setCouponLoading(t) { | |
| if (t) { | |
| this.$couponButton.prop("disabled", !0).html('<i class="fas fa-spinner fa-spin mr-2"></i> Validando...'); | |
| return; | |
| } | |
| this.$couponButton.prop("disabled", !1).html('<i class="fas fa-ticket mr-2"></i> Aplicar'); | |
| } | |
| showMessage(t, e) { | |
| this.messageTimer && (clearTimeout(this.messageTimer), this.messageTimer = null), this.$message.removeClass("hidden bg-green-100 text-green-700 bg-red-100 text-red-700").addClass(t === "success" ? "bg-green-100 text-green-700" : "bg-red-100 text-red-700").text(e), this.messageTimer = setTimeout(() => { | |
| this.hideMessage(); | |
| }, 3500); | |
| } | |
| hideMessage() { | |
| this.messageTimer && (clearTimeout(this.messageTimer), this.messageTimer = null), this.$message.addClass("hidden").text(""); | |
| } | |
| setCouponStatus(t) { | |
| if (!t) { | |
| this.$couponStatus.addClass("hidden").text("").removeClass("text-green-700 text-red-600"); | |
| return; | |
| } | |
| this.$couponStatus.removeClass("hidden text-green-700 text-red-600").addClass(t.type === "success" ? "text-green-700" : "text-red-600").text(t.text); | |
| } | |
| resetForm() { | |
| const t = $("#checkout-form")[0]; | |
| t && t.reset(), this.setSubmitLabel("PIX"), this.setCouponStatus(null); | |
| } | |
| }, N = class { | |
| constructor() { | |
| this.$pixModal = $("#pix-modal"), this.$pixPanel = $("#pix-modal-panel"), this.$cardModal = $("#card-modal"), this.$cardPanel = $("#card-modal-panel"); | |
| } | |
| showFromPaymentResponse(t) { | |
| const e = t?.data?.payment || {}; | |
| if (e?.qr_code) { | |
| this.#t(e); | |
| return; | |
| } | |
| this.#e(e); | |
| } | |
| #t(t) { | |
| const e = t?.qr_code || {}; | |
| let o = e.image || ""; | |
| o && !String(o).startsWith("data:") && !String(o).startsWith("http") && (o = `data:image/png;base64,${o}`), this.$pixPanel.html(` | |
| <div class="mb-5"> | |
| <i class="fas fa-qrcode text-4xl text-[#c8502a] mb-3 block"></i> | |
| <h3 class="text-xl font-bold text-[#1a1714]">Pagamento PIX</h3> | |
| <p class="text-[#6b6560] text-sm mt-1">Escaneie o QR Code com seu banco.</p> | |
| </div> | |
| ${o ? `<img src="${r(o)}" alt="QR Code PIX" class="w-48 h-48 mx-auto mb-4 rounded-xl border-2 border-[#e8e4df] p-2">` : ""} | |
| ${e.base_64 ? ` | |
| <div class="flex gap-2 mb-4"> | |
| <input id="pix-code" readonly value="${r(e.base_64)}" class="flex-1 px-3 py-2 bg-[#f8f7f4] border border-[#e8e4df] rounded-lg text-xs font-mono min-w-0" /> | |
| <button id="pix-copy" class="px-3 py-2 bg-[#1a1714] text-white rounded-lg hover:bg-[#c8502a] transition-colors shrink-0" title="Copiar codigo PIX"> | |
| <i class="fas fa-copy"></i> | |
| </button> | |
| </div> | |
| ` : ""} | |
| <button id="pix-close" class="w-full py-3 border-2 border-[#e8e4df] text-[#6b6560] font-semibold rounded-xl hover:border-[#1a1714] hover:text-[#1a1714] transition-all"> | |
| Concluir | |
| </button> | |
| `), d(this.$pixModal, !0), $("#pix-copy").off("click").on("click", async () => { | |
| try { | |
| await navigator.clipboard.writeText(String(e.base_64 || "")); | |
| const s = $("#pix-copy"); | |
| s.html('<i class="fas fa-check"></i>'), setTimeout(() => { | |
| s.html('<i class="fas fa-copy"></i>'); | |
| }, l.COPY_FEEDBACK_MS); | |
| } catch { | |
| } | |
| }), $("#pix-close").off("click").on("click", () => { | |
| d(this.$pixModal, !1); | |
| }); | |
| } | |
| #e(t) { | |
| this.$cardPanel.html(` | |
| <div class="text-center p-8 bg-white rounded-[2.5rem] shadow-2xl border border-[#e8e4df]"> | |
| <div class="inline-flex items-center justify-center w-20 h-20 bg-[#1a1714] rounded-full mb-6 shadow-lg"> | |
| <i class="fas fa-credit-card text-2xl text-white"></i> | |
| </div> | |
| <h3 class="text-2xl font-black text-[#1a1714] tracking-tighter mb-2">Pagamento com Cartão</h3> | |
| <p class="text-[#6b6560] text-sm mb-8 leading-relaxed max-w-[240px] mx-auto"> | |
| Método de pagamento: cartão. Clique abaixo para abrir o portal seguro. | |
| </p> | |
| ${t.url ? ` | |
| <a href="${r(t.url)}" | |
| target="_blank" | |
| rel="noopener" | |
| class="block w-full py-5 bg-[#1a1714] text-white font-black rounded-2xl text-center mb-4 hover:bg-[#000000] active:scale-[0.97] transition-all shadow-xl shadow-black/20 uppercase tracking-[0.15em] text-[11px]"> | |
| <span class="text-white !opacity-100">FINALIZAR PAGAMENTO</span> | |
| </a> | |
| ` : ""} | |
| ${t.uuid ? ` | |
| <div class="inline-block bg-[#f8f7f4] rounded-full px-4 py-1.5 mb-8 border border-[#e8e4df]"> | |
| <p class="text-[#6b6560] text-[9px] font-bold tracking-widest uppercase"> | |
| REF: <span class="text-[#1a1714] font-black">${r(t.uuid.split("-")[0])}</span> | |
| </p> | |
| </div> | |
| ` : ""} | |
| <button id="card-close" class="w-full py-3 border-2 border-[#e8e4df] text-[#6b6560] font-semibold rounded-xl hover:border-[#1a1714] hover:text-[#1a1714] transition-all"> | |
| Concluir | |
| </button> | |
| </div> | |
| `), d(this.$cardModal, !0), $("#card-close").off("click").on("click", () => { | |
| d(this.$cardModal, !1); | |
| }); | |
| } | |
| }, D = class { | |
| constructor() { | |
| this.apiService = null, this.cartStorage = new C(), this.productsComponent = null, this.categoriesComponent = null, this.cartDrawer = null, this.checkoutComponent = null, this.paymentModal = new N(), this.appliedCouponCode = null, this.storeId = "", this.currentPage = 1, this.activeCategory = "all"; | |
| } | |
| async init() { | |
| if (!window.jQuery) { | |
| setTimeout(() => this.init(), 80); | |
| return; | |
| } | |
| if (!p) { | |
| setTimeout(() => this.init(), 100); | |
| return; | |
| } | |
| if (this.storeId = String($("meta[name='loja-id']").attr("content") || "").trim(), !this.storeId) { | |
| $("#products-list").html(` | |
| <div class="text-center py-12 text-red-600"> | |
| <i class="fas fa-triangle-exclamation text-4xl mb-3 block"></i> | |
| <p>Meta loja-id nao encontrada no HTML.</p> | |
| </div> | |
| `); | |
| return; | |
| } | |
| this.apiService = new b(p, this.storeId), this.productsComponent = new I({ | |
| onAddToCart: (t) => this.handleAddToCart(t), | |
| onPageChange: (t) => this.handlePageChange(t) | |
| }), this.categoriesComponent = new P({ onCategoryChange: (t) => this.handleCategoryChange(t) }), this.cartDrawer = new T(), this.cartDrawer.bindEvents(), this.checkoutComponent = new E({ | |
| onRemoveItem: (t) => this.handleRemoveItem(t), | |
| onQuantityChange: (t, e) => this.handleQuantityChange(t, e), | |
| onApplyCoupon: async () => { | |
| await this.handleApplyCoupon(); | |
| }, | |
| onSubmit: async () => { | |
| await this.handleCheckoutSubmit(); | |
| }, | |
| onPaymentMethodChange: (t) => { | |
| this.checkoutComponent.setSubmitLabel(t === "CARD" ? "CARD" : "PIX"); | |
| } | |
| }), this.syncCartUI(), await this.loadCategories(), await this.loadProducts(); | |
| } | |
| async loadCategories() { | |
| try { | |
| const t = await this.apiService.getCategories(); | |
| this.categoriesComponent.setCategories(t), this.categoriesComponent.setActiveCategory(this.activeCategory); | |
| } catch { | |
| this.categoriesComponent.setCategories([]), this.categoriesComponent.setActiveCategory("all"); | |
| } | |
| } | |
| async loadProducts(t = 1) { | |
| try { | |
| this.currentPage = t; | |
| const e = await this.apiService.getProducts(t), o = this.cartStorage.getItems(), s = e.products.map((a) => { | |
| const i = o.find((c) => String(c.id) === String(a.id)); | |
| return { | |
| ...a, | |
| inCartQty: i ? i.qty : 0 | |
| }; | |
| }); | |
| this.productsComponent.setProducts({ | |
| ...e, | |
| products: s | |
| }), this.productsComponent.setActiveCategory(this.activeCategory); | |
| } catch (e) { | |
| $("#products-list").html(` | |
| <div class="text-center py-12 text-red-600"> | |
| <i class="fas fa-triangle-exclamation text-4xl mb-3 block"></i> | |
| <p>Falha ao carregar produtos.</p> | |
| <p class="text-sm text-[#6b6560] mt-2">${String(e?.message || "Erro desconhecido")}</p> | |
| </div> | |
| `); | |
| } | |
| } | |
| handlePageChange(t) { | |
| this.loadProducts(t), $("#shop")[0]?.scrollIntoView({ | |
| behavior: "smooth", | |
| block: "start" | |
| }); | |
| } | |
| handleCategoryChange(t) { | |
| this.activeCategory = String(t || "all"), this.productsComponent.setActiveCategory(this.activeCategory); | |
| } | |
| handleAddToCart(t) { | |
| const e = t.stock === null || t.stock === void 0 ? null : Number(t.stock); | |
| return e !== null && e <= 0 ? (this.checkoutComponent.showMessage("error", "Este produto esta sem estoque."), !1) : (this.cartStorage.addProduct(t), this.syncCartUI(), !0); | |
| } | |
| handleRemoveItem(t) { | |
| this.cartStorage.removeProduct(t), this.syncCartUI(); | |
| } | |
| handleQuantityChange(t, e) { | |
| this.cartStorage.changeQuantity(t, e), this.syncCartUI(); | |
| } | |
| syncCartUI() { | |
| const t = this.cartStorage.getItems(); | |
| this.cartDrawer.setCount(this.cartStorage.getTotalItems()), this.checkoutComponent.renderItems(t), this.checkoutComponent.setTotal(this.cartStorage.getTotalPrice()), this.productsComponent.updateButtonsStates(t); | |
| } | |
| async handleApplyCoupon() { | |
| this.checkoutComponent.hideMessage(); | |
| const { coupon: t } = this.checkoutComponent.getFormData(); | |
| if (!t) | |
| return this.appliedCouponCode = null, this.checkoutComponent.setCouponStatus({ | |
| type: "error", | |
| text: "Digite um cupom para aplicar." | |
| }), !1; | |
| this.checkoutComponent.setCouponLoading(!0); | |
| try { | |
| const e = await this.apiService.validateCoupon(t), o = e?.coupon; | |
| if (!e?.status || !o?.code) throw new Error("Cupom invalido ou indisponivel."); | |
| return this.appliedCouponCode = String(o.code), this.checkoutComponent.setCouponStatus({ | |
| type: "success", | |
| text: `Cupom aplicado: ${String(o.code).toUpperCase()} (-${Number(o.discount || 0)}%)` | |
| }), !0; | |
| } catch { | |
| return this.appliedCouponCode = null, this.checkoutComponent.setCouponStatus({ | |
| type: "error", | |
| text: "Cupom invalido, expirado ou indisponivel para esta loja." | |
| }), !1; | |
| } finally { | |
| this.checkoutComponent.setCouponLoading(!1); | |
| } | |
| } | |
| async handleCheckoutSubmit() { | |
| this.checkoutComponent.hideMessage(); | |
| const t = this.cartStorage.getItems(); | |
| if (!w(t)) { | |
| this.checkoutComponent.showMessage("error", "Seu carrinho esta vazio."); | |
| return; | |
| } | |
| const e = this.checkoutComponent.getFormData(); | |
| if (this.checkoutComponent.clearFieldErrors(), !x(e.name)) { | |
| this.checkoutComponent.setFieldError("name", "Informe um nome valido com pelo menos 3 caracteres."), this.checkoutComponent.showMessage("error", "Corrija os campos destacados."); | |
| return; | |
| } | |
| if (!y(e.nickname)) { | |
| this.checkoutComponent.setFieldError("nickname", "O apelido deve ter entre 4 e 32 caracteres."), this.checkoutComponent.showMessage("error", "Corrija os campos destacados."); | |
| return; | |
| } | |
| if (!k(e.email)) { | |
| this.checkoutComponent.setFieldError("email", "Informe um e-mail valido."), this.checkoutComponent.showMessage("error", "Corrija os campos destacados."); | |
| return; | |
| } | |
| if (e.cpf && !v(e.cpf)) { | |
| this.checkoutComponent.setFieldError("cpf", "O CPF deve ter 11 numeros."), this.checkoutComponent.showMessage("error", "Corrija os campos destacados."); | |
| return; | |
| } | |
| if (e.coupon && !this.appliedCouponCode && !await this.handleApplyCoupon()) | |
| return; | |
| e.coupon || (this.appliedCouponCode = null, this.checkoutComponent.setCouponStatus(null)); | |
| const o = e.paymentMethod === "CARD" ? "CARD" : "PIX", s = { | |
| name: e.name, | |
| email: e.email, | |
| cpf: e.cpf || void 0, | |
| gateway: o === "CARD" ? m.CARD : m.PIX, | |
| coupon: this.appliedCouponCode || void 0, | |
| metadata: e.note || e.nickname ? { | |
| ...e.note ? { observation: e.note } : {}, | |
| ...e.nickname ? { nickname: e.nickname } : {} | |
| } : void 0, | |
| items: t.map((a) => ({ | |
| productId: String(a.id), | |
| quantity: Number(a.qty) | |
| })) | |
| }; | |
| this.checkoutComponent.setSubmitLoading(!0, o); | |
| try { | |
| const a = await this.apiService.createPayment(s); | |
| if (!a?.status) throw new Error(a?.message || "Falha ao criar pagamento."); | |
| this.paymentModal.showFromPaymentResponse(a), this.cartStorage.clear(), this.syncCartUI(), this.appliedCouponCode = null, this.checkoutComponent.resetForm(), this.checkoutComponent.showMessage("success", "Pagamento criado com sucesso."); | |
| } catch (a) { | |
| this.checkoutComponent.showMessage("error", String(a?.message || "Erro ao processar pagamento.")); | |
| } finally { | |
| this.checkoutComponent.setSubmitLoading(!1, o); | |
| } | |
| } | |
| }; | |
| new D().init(); | |
| </script> | |
| </head> | |
| <body class="bg-[#f8f7f4] text-[#1a1714] min-h-screen flex flex-col"> | |
| <!-- Navbar --> | |
| <nav class="sticky top-0 z-[200] bg-[#f8f7f4]/95 backdrop-blur-md border-b border-[#e8e4df] shadow-sm"> | |
| <div class="max-w-6xl mx-auto px-4"> | |
| <!-- Toggle --> | |
| <input type="checkbox" id="menu-toggle" class="peer hidden"> | |
| <div class="flex items-center justify-between h-16 md:h-[68px]"> | |
| <!-- Logo --> | |
| <a href="#" class="flex items-center gap-3 hover:opacity-80 transition-opacity"> | |
| <div | |
| class="w-10 h-10 bg-[#1a1714] rounded-xl flex items-center justify-center text-white shadow-md"> | |
| <i class="fas fa-store-alt text-lg"></i> | |
| </div> | |
| <span class="text-lg font-medium tracking-tight text-[#1a1714]"> | |
| Loja <strong class="font-bold text-[#c8502a]">Virtual</strong> | |
| </span> | |
| </a> | |
| <!-- Desktop Menu --> | |
| <ul class="hidden md:flex items-center gap-2 list-none m-0 p-0"> | |
| <li> | |
| <a href="#" | |
| class="group relative flex items-center gap-2 px-4 py-2 rounded-xl text-sm font-medium text-[#6b6560] hover:bg-white hover:text-[#1a1714] transition-all duration-300"> | |
| <i class="fas fa-house text-xs"></i> | |
| Início | |
| <span | |
| class="absolute left-4 bottom-1 w-0 h-[2px] bg-[#c8502a] rounded-full transition-all duration-300 group-hover:w-[55%]"></span> | |
| </a> | |
| </li> | |
| <li> | |
| <a href="#shop" | |
| class="group relative flex items-center gap-2 px-4 py-2 rounded-xl text-sm font-medium text-[#6b6560] hover:bg-white hover:text-[#1a1714] transition-all duration-300"> | |
| <i class="fas fa-store text-xs"></i> | |
| Loja | |
| <span | |
| class="absolute left-4 bottom-1 w-0 h-[2px] bg-[#c8502a] rounded-full transition-all duration-300 group-hover:w-[45%]"></span> | |
| </a> | |
| </li> | |
| <li> | |
| <a href="#" | |
| class="group relative flex items-center gap-2 px-4 py-2 rounded-xl text-sm font-medium text-[#6b6560] hover:bg-white hover:text-[#1a1714] transition-all duration-300"> | |
| <i class="fab fa-discord text-xs"></i> | |
| Discord | |
| <span | |
| class="absolute left-4 bottom-1 w-0 h-[2px] bg-[#c8502a] rounded-full transition-all duration-300 group-hover:w-[65%]"></span> | |
| </a> | |
| </li> | |
| </ul> | |
| <!-- Actions --> | |
| <div class="flex items-center gap-3"> | |
| <!-- Cart --> | |
| <a href="#" id="cart-toggle" aria-label="Abrir carrinho" | |
| class="group relative w-11 h-11 rounded-xl border border-[#e8e4df] bg-white flex items-center justify-center text-[#1a1714] shadow-sm hover:bg-[#1a1714] hover:border-[#1a1714] transition-all duration-300"> | |
| <i | |
| class="fas fa-bag-shopping text-lg transition-colors duration-300 group-hover:text-white"></i> | |
| <span id="cart-count" | |
| class="absolute -top-1 -right-1 min-w-5 h-5 px-1.5 bg-[#c8502a] text-white text-[0.65rem] rounded-full flex items-center justify-center font-bold border-2 border-white"> | |
| 0 | |
| </span> | |
| </a> | |
| <!-- Mobile Button --> | |
| <label for="menu-toggle" | |
| class="md:hidden w-11 h-11 rounded-xl border border-[#e8e4df] bg-white flex items-center justify-center cursor-pointer text-[#1a1714] hover:bg-[#f0ede8] transition-all duration-300"> | |
| <i class="fas fa-bars text-lg"></i> | |
| </label> | |
| </div> | |
| </div> | |
| <!-- Mobile Menu --> | |
| <div class="hidden peer-checked:block md:hidden border-t border-[#e8e4df] py-4"> | |
| <div class="flex flex-col gap-2"> | |
| <a href="#" | |
| class="flex items-center gap-3 px-4 py-3 rounded-xl text-sm font-medium text-[#6b6560] hover:bg-white hover:text-[#1a1714] transition-all"> | |
| <i class="fas fa-house w-4 text-center"></i> | |
| Início | |
| </a> | |
| <a href="#shop" | |
| class="flex items-center gap-3 px-4 py-3 rounded-xl text-sm font-medium text-[#6b6560] hover:bg-white hover:text-[#1a1714] transition-all"> | |
| <i class="fas fa-store w-4 text-center"></i> | |
| Loja | |
| </a> | |
| <a href="#" | |
| class="flex items-center gap-3 px-4 py-3 rounded-xl text-sm font-medium text-[#6b6560] hover:bg-white hover:text-[#1a1714] transition-all"> | |
| <i class="fab fa-discord w-4 text-center"></i> | |
| Discord | |
| </a> | |
| </div> | |
| </div> | |
| </div> | |
| </nav> | |
| <header id="hero" class="relative overflow-hidden py-20 md:py-28 px-4"> | |
| <!-- Background --> | |
| <div class="absolute inset-0 bg-gradient-to-b from-[#f8f7f4] via-[#faf8f6] to-[#f4f1ed] -z-10"></div> | |
| <!-- Blur Effects --> | |
| <div | |
| class="absolute top-[-120px] right-[-80px] w-[320px] h-[320px] bg-[#c8502a]/10 rounded-full blur-3xl -z-10"> | |
| </div> | |
| <div | |
| class="absolute bottom-[-100px] left-[-80px] w-[260px] h-[260px] bg-[#1a1714]/5 rounded-full blur-3xl -z-10"> | |
| </div> | |
| <div class="max-w-7xl mx-auto"> | |
| <div class="grid md:grid-cols-2 gap-14 items-center"> | |
| <!-- Left Content --> | |
| <div> | |
| <!-- Badge --> | |
| <div | |
| class="inline-flex items-center gap-2 px-4 py-2 bg-white border border-[#ebe5df] rounded-full mb-6 shadow-sm"> | |
| <span class="w-2 h-2 bg-[#c8502a] rounded-full animate-pulse"></span> | |
| <span class="text-sm font-medium text-[#4f4a46]"> | |
| Loja online • Entrega expressa | |
| </span> | |
| </div> | |
| <!-- Title --> | |
| <h1 class="text-4xl md:text-6xl leading-[1.05] font-bold tracking-tight text-[#1a1714] mb-6" | |
| style="font-family:'DM Serif Display', serif;"> | |
| Sua loja virtual | |
| <span class="block text-[#c8502a]"> | |
| moderna e completa | |
| </span> | |
| </h1> | |
| <!-- Description --> | |
| <p class="text-lg text-[#6b6560] leading-relaxed max-w-xl mb-8"> | |
| Produtos selecionados, preços acessíveis e uma experiência premium para quem busca | |
| qualidade, velocidade e praticidade. | |
| </p> | |
| <!-- Buttons --> | |
| <div class="flex flex-wrap gap-4 mb-10"> | |
| <!-- Produtos --> | |
| <a href="#shop" | |
| class="group inline-flex items-center gap-3 px-7 py-4 rounded-2xl bg-white border border-[#e8e4df] text-[#1a1714] font-semibold shadow-sm transition-all duration-300 hover:border-[#c8502a] hover:-translate-y-1 hover:shadow-lg"> | |
| <i | |
| class="fas fa-store transition-all duration-300 group-hover:scale-110 group-hover:text-[#c8502a]"></i> | |
| <span class="transition-colors duration-300 group-hover:text-[#c8502a]"> | |
| Ver produtos | |
| </span> | |
| </a> | |
| <!-- Discord --> | |
| <a href="#" | |
| class="group inline-flex items-center gap-3 px-7 py-4 rounded-2xl bg-white border border-[#e8e4df] text-[#1a1714] font-semibold shadow-sm transition-all duration-300 hover:border-[#c8502a] hover:-translate-y-1 hover:shadow-lg"> | |
| <i | |
| class="fab fa-discord transition-all duration-300 group-hover:scale-110 group-hover:text-[#c8502a]"></i> | |
| <span class="transition-colors duration-300 group-hover:text-[#c8502a]"> | |
| Discord | |
| </span> | |
| </a> | |
| </div> | |
| <!-- Stats --> | |
| <div class="flex flex-wrap gap-8"> | |
| <div> | |
| <strong class="block text-2xl font-bold text-[#1a1714]"> | |
| +12k | |
| </strong> | |
| <span class="text-sm text-[#6b6560]"> | |
| Clientes ativos | |
| </span> | |
| </div> | |
| <div> | |
| <strong class="block text-2xl font-bold text-[#1a1714]"> | |
| 24h | |
| </strong> | |
| <span class="text-sm text-[#6b6560]"> | |
| Entrega rápida | |
| </span> | |
| </div> | |
| <div> | |
| <strong class="block text-2xl font-bold text-[#1a1714]"> | |
| 4.9★ | |
| </strong> | |
| <span class="text-sm text-[#6b6560]"> | |
| Avaliação média | |
| </span> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="relative hidden md:block"> | |
| <!-- Fundo decorativo --> | |
| <div class="absolute -top-8 -right-8 w-40 h-40 bg-[#c8502a]/10 rounded-full blur-3xl"> | |
| </div> | |
| <!-- Container da imagem --> | |
| <div | |
| class="relative overflow-hidden rounded-[32px] shadow-[0_35px_80px_rgba(0,0,0,0.14)]"> | |
| <img src="https://blob.cabrapi.com.br/blob/808ff623-b490-414a-8b82-abeadeb87b0d/download" | |
| alt="Produto em destaque" | |
| class="w-full h-[540px] object-cover rounded-[32px] transition-transform duration-500 hover:scale-[1.03]" /> | |
| <!-- Overlay suave --> | |
| <div | |
| class="absolute inset-0 bg-gradient-to-t from-black/10 to-transparent rounded-[32px]"> | |
| </div> | |
| </div> | |
| <!-- Card flutuante --> | |
| <div | |
| class="absolute bottom-6 left-6 bg-white/95 backdrop-blur-md px-5 py-4 rounded-2xl shadow-[0_15px_40px_rgba(0,0,0,0.12)] flex items-center gap-4 border border-[#e8e4df]"> | |
| <div | |
| class="w-14 h-14 bg-[#fef3ec] rounded-2xl flex items-center justify-center flex-shrink-0 shadow-sm"> | |
| <i class="fas fa-bolt text-[#c8502a] text-xl"></i> | |
| </div> | |
| <div> | |
| <strong class="text-sm block text-[#1a1714] font-semibold"> | |
| Entrega instantânea | |
| </strong> | |
| <span class="text-xs text-[#6b6560]"> | |
| Receba em minutos | |
| </span> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </header> | |
| <section class="py-16 px-4 bg-white"> | |
| <div class="max-w-6xl mx-auto"> | |
| <div class="text-center mb-12"> | |
| <p class="text-[#c8502a] text-sm font-semibold uppercase tracking-wider mb-2"><i | |
| class="fas fa-shield-halved mr-2"></i> Diferenciais</p> | |
| <h2 class="text-3xl md:text-4xl font-bold mb-3" style="font-family:'DM Serif Display',serif;"> | |
| Por que comprar aqui?</h2> | |
| <p class="text-[#6b6560]">Segurança, rapidez e confiança em cada pedido</p> | |
| </div> | |
| <div class="grid sm:grid-cols-2 lg:grid-cols-4 gap-6"> | |
| <div class="bg-[#f8f7f4] p-6 rounded-2xl hover:shadow-lg transition-shadow"> | |
| <div class="w-14 h-14 bg-[#fef3ec] rounded-2xl flex items-center justify-center mb-4"><i | |
| class="fas fa-bolt text-[#c8502a] text-2xl"></i></div> | |
| <h3 class="font-bold mb-2">Entrega rápida</h3> | |
| <p class="text-sm text-[#6b6560]">Receba seu produto em minutos ou de forma totalmente | |
| automática após o pagamento.</p> | |
| </div> | |
| <div class="bg-[#f8f7f4] p-6 rounded-2xl hover:shadow-lg transition-shadow"> | |
| <div class="w-14 h-14 bg-[#fef3ec] rounded-2xl flex items-center justify-center mb-4"><i | |
| class="fas fa-lock text-[#c8502a] text-2xl"></i></div> | |
| <h3 class="font-bold mb-2">Pagamento seguro</h3> | |
| <p class="text-sm text-[#6b6560]">Transações protegidas com criptografia e validação em | |
| tempo real.</p> | |
| </div> | |
| <div class="bg-[#f8f7f4] p-6 rounded-2xl hover:shadow-lg transition-shadow"> | |
| <div class="w-14 h-14 bg-[#fef3ec] rounded-2xl flex items-center justify-center mb-4"><i | |
| class="fas fa-headset text-[#c8502a] text-2xl"></i></div> | |
| <h3 class="font-bold mb-2">Suporte ativo</h3> | |
| <p class="text-sm text-[#6b6560]">Atendimento ágil via Discord ou chat para qualquer | |
| dúvida ou problema.</p> | |
| </div> | |
| <div class="bg-[#f8f7f4] p-6 rounded-2xl hover:shadow-lg transition-shadow"> | |
| <div class="w-14 h-14 bg-[#fef3ec] rounded-2xl flex items-center justify-center mb-4"><i | |
| class="fas fa-tag text-[#c8502a] text-2xl"></i></div> | |
| <h3 class="font-bold mb-2">Melhor preço</h3> | |
| <p class="text-sm text-[#6b6560]">Produtos acessíveis com promoções constantes para | |
| economizar sempre.</p> | |
| </div> | |
| </div> | |
| </div> | |
| </section> | |
| <div class="max-w-6xl mx-auto px-4"> | |
| <div class="border-t border-[#e8e4df]"></div> | |
| </div> | |
| <section id="shop" class="py-16 px-4"> | |
| <div class="max-w-6xl mx-auto"> | |
| <div class="flex flex-col md:flex-row md:items-end justify-between mb-10 gap-4"> | |
| <div> | |
| <p class="text-[#c8502a] text-sm font-semibold uppercase tracking-wider mb-2"><i | |
| class="fas fa-store mr-2"></i> Catálogo</p> | |
| <h2 class="text-3xl md:text-4xl font-bold" style="font-family:'DM Serif Display',serif;"> | |
| Nossos produtos</h2> | |
| </div> | |
| </div> | |
| <div id="category-filters" class="flex flex-wrap gap-2 mb-8"></div> | |
| <div id="products-list"> | |
| <div class="text-center py-16 text-[#6b6560]"><i | |
| class="fas fa-spinner fa-spin text-3xl mb-4 block"></i> | |
| <p>Carregando produtos…</p> | |
| </div> | |
| </div> | |
| <div id="products-pagination"></div> | |
| </div> | |
| </section> | |
| <div class="max-w-6xl mx-auto px-4"> | |
| <div class="border-t border-[#e8e4df]"></div> | |
| </div> | |
| <section class="py-16 px-4"> | |
| <div class="max-w-6xl mx-auto"> | |
| <div class="text-center mb-12"> | |
| <p class="text-[#c8502a] text-sm font-semibold uppercase tracking-wider mb-2"><i | |
| class="fas fa-chart-line mr-2"></i> Resultados</p> | |
| <h2 class="text-3xl md:text-4xl font-bold mb-3" style="font-family:'DM Serif Display',serif;"> | |
| Transparência em números</h2> | |
| <p class="text-[#6b6560]">Dados reais de quem já comprou com a gente</p> | |
| </div> | |
| <div class="grid sm:grid-cols-2 lg:grid-cols-4 gap-6"> | |
| <div | |
| class="bg-white p-6 rounded-2xl border border-[#e8e4df] text-center hover:shadow-lg transition-shadow"> | |
| <div | |
| class="w-14 h-14 bg-[#f8f7f4] rounded-2xl flex items-center justify-center mx-auto mb-4"> | |
| <i class="fas fa-shopping-cart text-[#1a1714] text-2xl"></i> | |
| </div> | |
| <div class="text-3xl font-bold">+1.200</div> | |
| <div class="text-sm text-[#6b6560] mt-1">Vendas realizadas</div> | |
| </div> | |
| <div | |
| class="bg-white p-6 rounded-2xl border border-[#e8e4df] text-center hover:shadow-lg transition-shadow"> | |
| <div | |
| class="w-14 h-14 bg-[#f8f7f4] rounded-2xl flex items-center justify-center mx-auto mb-4"> | |
| <i class="fas fa-users text-[#1a1714] text-2xl"></i> | |
| </div> | |
| <div class="text-3xl font-bold">+500</div> | |
| <div class="text-sm text-[#6b6560] mt-1">Clientes ativos</div> | |
| </div> | |
| <div | |
| class="bg-white p-6 rounded-2xl border border-[#e8e4df] text-center hover:shadow-lg transition-shadow"> | |
| <div | |
| class="w-14 h-14 bg-[#f8f7f4] rounded-2xl flex items-center justify-center mx-auto mb-4"> | |
| <i class="fas fa-star text-[#1a1714] text-2xl"></i> | |
| </div> | |
| <div class="text-3xl font-bold">99%</div> | |
| <div class="text-sm text-[#6b6560] mt-1">Satisfação</div> | |
| </div> | |
| <div | |
| class="bg-white p-6 rounded-2xl border border-[#e8e4df] text-center hover:shadow-lg transition-shadow"> | |
| <div | |
| class="w-14 h-14 bg-[#f8f7f4] rounded-2xl flex items-center justify-center mx-auto mb-4"> | |
| <i class="fas fa-headset text-[#1a1714] text-2xl"></i> | |
| </div> | |
| <div class="text-3xl font-bold">24h</div> | |
| <div class="text-sm text-[#6b6560] mt-1">Suporte ativo</div> | |
| </div> | |
| </div> | |
| </div> | |
| </section> | |
| <div class="max-w-6xl mx-auto px-4"> | |
| <div class="border-t border-[#e8e4df]"></div> | |
| </div> | |
| <section class="py-16 px-4"> | |
| <div class="max-w-4xl mx-auto"> | |
| <div class="bg-[#1a1714] rounded-3xl p-10 md:p-14 text-center text-white relative overflow-hidden"> | |
| <div class="absolute inset-0 opacity-5" | |
| style="background-image:radial-gradient(circle at 20% 50%, #c8502a 1px, transparent 1px);background-size:30px 30px;"> | |
| </div> | |
| <p class="text-xs font-bold uppercase tracking-[0.2em] text-[#a09a94] mb-3 relative z-10"> | |
| Atendimento</p> | |
| <h2 class="text-3xl md:text-4xl font-bold mb-4 relative z-10" | |
| style="font-family:'DM Serif Display',serif;">Precisa de ajuda?</h2> | |
| <p class="text-[#a09a94] mb-8 max-w-lg mx-auto relative z-10">Fale com nosso suporte em segundos | |
| — estamos sempre disponíveis.</p> | |
| <a href="#" | |
| class="inline-flex items-center gap-2 px-6 py-3.5 bg-[#5865F2] text-white font-semibold rounded-xl hover:bg-[#4752C4] transition-all relative z-10 shadow-lg"><i | |
| class="fab fa-discord text-lg"></i> Abrir suporte no Discord</a> | |
| </div> | |
| </div> | |
| </section> | |
| <section class="py-16 px-4 bg-white"> | |
| <div class="max-w-3xl mx-auto"> | |
| <div class="text-center mb-12"> | |
| <p class="text-[#c8502a] text-sm font-semibold uppercase tracking-wider mb-2"><i | |
| class="fas fa-circle-question mr-2"></i> Dúvidas</p> | |
| <h2 class="text-3xl md:text-4xl font-bold mb-3" style="font-family:'DM Serif Display',serif;"> | |
| Perguntas frequentes</h2> | |
| <p class="text-[#6b6560]">As respostas que você precisa antes de comprar</p> | |
| </div> | |
| <div class="space-y-3"> | |
| <details class="group bg-[#f8f7f4] rounded-2xl p-5"> | |
| <summary class="flex items-center justify-between cursor-pointer list-none"><span | |
| class="font-semibold"><i | |
| class="fas fa-shopping-cart mr-3 text-[#6b6560]"></i>Como funciona a | |
| compra?</span><i | |
| class="fas fa-chevron-down text-[#6b6560] group-open:rotate-180 transition-transform"></i> | |
| </summary> | |
| <p class="mt-4 text-[#6b6560] text-sm leading-relaxed">Você escolhe o produto, finaliza o | |
| pagamento via PIX e recebe automaticamente as instruções ou acesso no seu e-mail | |
| logo após a confirmação.</p> | |
| </details> | |
| <details class="group bg-[#f8f7f4] rounded-2xl p-5"> | |
| <summary class="flex items-center justify-between cursor-pointer list-none"><span | |
| class="font-semibold"><i | |
| class="fas fa-shield-halved mr-3 text-[#6b6560]"></i>É seguro comprar | |
| aqui?</span><i | |
| class="fas fa-chevron-down text-[#6b6560] group-open:rotate-180 transition-transform"></i> | |
| </summary> | |
| <p class="mt-4 text-[#6b6560] text-sm leading-relaxed">Sim. Utilizamos sistemas seguros de | |
| pagamento e validação para proteger todas as transações. Seus dados são | |
| criptografados.</p> | |
| </details> | |
| <details class="group bg-[#f8f7f4] rounded-2xl p-5"> | |
| <summary class="flex items-center justify-between cursor-pointer list-none"><span | |
| class="font-semibold"><i class="fas fa-clock mr-3 text-[#6b6560]"></i>Quanto | |
| tempo demora para receber?</span><i | |
| class="fas fa-chevron-down text-[#6b6560] group-open:rotate-180 transition-transform"></i> | |
| </summary> | |
| <p class="mt-4 text-[#6b6560] text-sm leading-relaxed">A maioria das entregas é | |
| instantânea ou feita em poucos minutos após a confirmação do pagamento. Produtos | |
| físicos têm prazo estimado no momento da compra.</p> | |
| </details> | |
| <details class="group bg-[#f8f7f4] rounded-2xl p-5"> | |
| <summary class="flex items-center justify-between cursor-pointer list-none"><span | |
| class="font-semibold"><i class="fas fa-headset mr-3 text-[#6b6560]"></i>Como | |
| funciona o suporte?</span><i | |
| class="fas fa-chevron-down text-[#6b6560] group-open:rotate-180 transition-transform"></i> | |
| </summary> | |
| <p class="mt-4 text-[#6b6560] text-sm leading-relaxed">Oferecemos suporte via Discord e | |
| e-mail. Nossa equipe responde rapidamente durante todo o dia para resolver qualquer | |
| dúvida ou problema.</p> | |
| </details> | |
| <details class="group bg-[#f8f7f4] rounded-2xl p-5"> | |
| <summary class="flex items-center justify-between cursor-pointer list-none"><span | |
| class="font-semibold"><i | |
| class="fas fa-rotate-left mr-3 text-[#6b6560]"></i>Posso pedir | |
| reembolso?</span><i | |
| class="fas fa-chevron-down text-[#6b6560] group-open:rotate-180 transition-transform"></i> | |
| </summary> | |
| <p class="mt-4 text-[#6b6560] text-sm leading-relaxed">Sim, em casos de problema no | |
| produto ou não entrega. Entre em contato com nosso suporte e avaliaremos seu caso o | |
| mais rápido possível.</p> | |
| </details> | |
| </div> | |
| </div> | |
| </section> | |
| <div id="checkout" role="dialog" aria-modal="true" aria-label="Carrinho e pagamento" | |
| class="fixed inset-0 z-[300] bg-[#1a1714]/70 backdrop-blur-sm flex items-end md:items-center justify-center p-0 md:p-4 opacity-0 pointer-events-none transition-all duration-300"> | |
| <div id="checkout-panel" | |
| class="bg-white w-full max-w-[860px] rounded-t-3xl md:rounded-3xl max-h-[95vh] md:max-h-[92vh] overflow-y-auto p-4 md:p-8 pb-24 md:pb-8"> | |
| <div class="flex items-center justify-between mb-6 pb-5 border-b border-[#e8e4df]"> | |
| <div> | |
| <h2 class="text-xl font-bold"><i class="fas fa-bag-shopping mr-2"></i> Carrinho e | |
| pagamento</h2> | |
| <p class="text-[#6b6560] text-sm mt-1">Revise seu pedido e finalize via PIX em segundos. | |
| </p> | |
| </div> | |
| <button id="checkout-close" aria-label="Fechar carrinho" | |
| class="w-10 h-10 rounded-xl border border-[#e8e4df] flex items-center justify-center hover:bg-[#f8f7f4] transition-colors"><i | |
| class="fas fa-xmark"></i></button> | |
| </div> | |
| <div id="checkout-message" class="hidden p-3 rounded-xl text-sm mb-4"></div> | |
| <div class="grid md:grid-cols-2 gap-8"> | |
| <div> | |
| <p class="text-sm font-bold uppercase tracking-wider text-[#6b6560] mb-4"><i | |
| class="fas fa-receipt mr-2"></i> Resumo do pedido</p> | |
| <div id="checkout-items" class="flex flex-col gap-3"></div> | |
| <div class="flex justify-between items-center pt-5 mt-5 border-t border-[#e8e4df]"> | |
| <span class="font-semibold">Total</span> | |
| <strong id="checkout-total" class="text-2xl font-bold text-[#c8502a]">R$ | |
| 0,00</strong> | |
| </div> | |
| </div> | |
| <form id="checkout-form" novalidate class="flex flex-col gap-4"> | |
| <div class="flex flex-col gap-1.5"> | |
| <label for="checkout-name" class="text-sm font-semibold"><i | |
| class="fas fa-user mr-2 text-[#6b6560]"></i>Nome completo</label> | |
| <input id="checkout-name" name="name" placeholder="Seu nome completo" | |
| autocomplete="name" | |
| class="px-4 py-3.5 border border-[#e8e4df] rounded-xl focus:ring-2 focus:ring-[#c8502a] focus:border-transparent outline-none transition-all" /> | |
| <p id="checkout-name-error" class="hidden text-xs font-medium text-red-600"></p> | |
| </div> | |
| <div class="flex flex-col gap-1.5"> | |
| <label for="checkout-nickname" class="text-sm font-semibold"><i | |
| class="fas fa-at mr-2 text-[#6b6560]"></i>Nickname <span | |
| class="text-[#a09a94] font-normal">(opcional)</span></label> | |
| <input id="checkout-nickname" name="nickname" placeholder="Seu apelido" | |
| maxlength="32" autocomplete="nickname" | |
| class="px-4 py-3.5 border border-[#e8e4df] rounded-xl focus:ring-2 focus:ring-[#c8502a] focus:border-transparent outline-none transition-all" /> | |
| <p class="text-xs text-[#a09a94]">De 4 a 32 caracteres.</p> | |
| <p id="checkout-nickname-error" class="hidden text-xs font-medium text-red-600"></p> | |
| </div> | |
| <div class="flex flex-col gap-1.5"> | |
| <label for="checkout-email" class="text-sm font-semibold"><i | |
| class="fas fa-envelope mr-2 text-[#6b6560]"></i>E-mail</label> | |
| <input id="checkout-email" name="email" type="email" placeholder="voce@email.com" | |
| autocomplete="email" | |
| class="px-4 py-3.5 border border-[#e8e4df] rounded-xl focus:ring-2 focus:ring-[#c8502a] focus:border-transparent outline-none transition-all" /> | |
| <p id="checkout-email-error" class="hidden text-xs font-medium text-red-600"></p> | |
| </div> | |
| <div class="flex flex-col gap-1.5"> | |
| <label for="checkout-cpf" class="text-sm font-semibold"><i | |
| class="fas fa-id-card mr-2 text-[#6b6560]"></i>CPF <span | |
| class="text-[#a09a94] font-normal">(opcional)</span></label> | |
| <input id="checkout-cpf" name="cpf" placeholder="000.000.000-00" inputmode="numeric" | |
| maxlength="14" | |
| class="px-4 py-3.5 border border-[#e8e4df] rounded-xl focus:ring-2 focus:ring-[#c8502a] focus:border-transparent outline-none transition-all" /> | |
| <p id="checkout-cpf-error" class="hidden text-xs font-medium text-red-600"></p> | |
| </div> | |
| <div class="flex flex-col gap-1.5"> | |
| <label for="checkout-note" class="text-sm font-semibold"><i | |
| class="fas fa-comment mr-2 text-[#6b6560]"></i>Observação <span | |
| class="text-[#a09a94] font-normal">(opcional)</span></label> | |
| <textarea id="checkout-note" name="note" rows="2" placeholder="Algo a informar?" | |
| class="px-4 py-3.5 border border-[#e8e4df] rounded-xl focus:ring-2 focus:ring-[#c8502a] focus:border-transparent outline-none transition-all resize-none"></textarea> | |
| </div> | |
| <div class="flex flex-col gap-1.5"> | |
| <label for="checkout-coupon" class="text-sm font-semibold"><i | |
| class="fas fa-ticket mr-2 text-[#6b6560]"></i>Cupom <span | |
| class="text-[#a09a94] font-normal">(opcional)</span></label> | |
| <div class="flex gap-2"> | |
| <input id="checkout-coupon" name="coupon" placeholder="Ex: BEMVINDO10" | |
| class="flex-1 px-4 py-3.5 border border-[#e8e4df] rounded-xl focus:ring-2 focus:ring-[#c8502a] focus:border-transparent outline-none transition-all" /> | |
| <button id="checkout-apply-coupon" type="button" | |
| class="px-4 py-3 bg-white border border-[#e8e4df] text-[#1a1714] font-semibold rounded-xl hover:border-[#c8502a] hover:text-[#c8502a] disabled:opacity-60 transition-all whitespace-nowrap"> | |
| <i class="fas fa-ticket mr-2"></i> Aplicar | |
| </button> | |
| </div> | |
| <p id="checkout-coupon-status" class="hidden text-xs font-medium"></p> | |
| </div> | |
| <div class="flex flex-col gap-3"> | |
| <label class="text-sm font-semibold"><i | |
| class="fas fa-credit-card mr-2 text-[#6b6560]"></i>Forma de | |
| pagamento</label> | |
| <div class="grid grid-cols-2 gap-3"> | |
| <label class="cursor-pointer"> | |
| <input type="radio" name="payment_method" value="PIX" checked | |
| class="peer sr-only" /> | |
| <div | |
| class="p-3 border-2 border-[#e8e4df] rounded-xl peer-checked:border-[#c8502a] peer-checked:bg-[#fef3ec] hover:border-[#c8502a] transition-all text-center"> | |
| <i class="fas fa-qrcode text-xl text-[#6b6560]"></i> | |
| <p class="font-semibold text-xs mt-1">PIX</p> | |
| </div> | |
| </label> | |
| <label class="cursor-pointer"> | |
| <input type="radio" name="payment_method" value="CARD" | |
| class="peer sr-only" /> | |
| <div | |
| class="p-3 border-2 border-[#e8e4df] rounded-xl peer-checked:border-[#c8502a] peer-checked:bg-[#fef3ec] hover:border-[#c8502a] transition-all text-center"> | |
| <i class="fas fa-credit-card text-xl text-[#6b6560]"></i> | |
| <p class="font-semibold text-xs mt-1">Cartão</p> | |
| </div> | |
| </label> | |
| </div> | |
| </div> | |
| <button id="checkout-submit" type="submit" | |
| class="w-full py-3 bg-[#1a1714] text-white font-semibold rounded-lg hover:bg-[#c8502a] disabled:opacity-50 transition-all shadow-sm"><i | |
| class="fas fa-qrcode mr-2"></i> Pagar com PIX</button> | |
| </form> | |
| </div> | |
| <div id="checkout-result" class="hidden mt-6 pt-5 border-t border-[#e8e4df]"></div> | |
| </div> | |
| </div> | |
| <div id="pix-modal" role="dialog" aria-modal="true" aria-label="Pagamento PIX" | |
| class="fixed inset-0 z-[400] bg-[#1a1714]/80 backdrop-blur-sm flex items-end md:items-center justify-center p-0 md:p-4 opacity-0 pointer-events-none transition-all duration-300"> | |
| <div id="pix-modal-panel" | |
| class="bg-white w-full max-w-sm rounded-t-3xl md:rounded-2xl p-6 md:p-8 text-center pb-20 md:pb-8"> | |
| </div> | |
| </div> | |
| <div id="card-modal" role="dialog" aria-modal="true" aria-label="Pagamento Cartão" | |
| class="fixed inset-0 z-[400] bg-[#1a1714]/80 backdrop-blur-sm flex items-end md:items-center justify-center p-0 md:p-4 opacity-0 pointer-events-none transition-all duration-300"> | |
| <div id="card-modal-panel" | |
| class="bg-white w-full max-w-sm rounded-t-3xl md:rounded-2xl p-6 md:p-8 text-center pb-20 md:pb-8"> | |
| </div> | |
| </div> | |
| <footer class="bg-[#1a1714] text-white py-12 px-4 mt-auto"> | |
| <div class="max-w-6xl mx-auto"> | |
| <div class="flex flex-col md:flex-row justify-between items-center gap-8"> | |
| <div class="flex flex-col items-center md:items-start gap-4"> | |
| <a href="#" class="text-lg font-semibold">Loja <span | |
| class="text-[#c8502a]">Virtual</span></a> | |
| <div | |
| class="flex flex-wrap justify-center md:justify-start gap-4 md:gap-6 text-sm text-[#a09a94]"> | |
| <a href="#" class="hover:text-white transition-colors"><i | |
| class="fas fa-house mr-1"></i> Início</a> | |
| <a href="#shop" class="hover:text-white transition-colors"><i | |
| class="fas fa-store mr-1"></i> Loja</a> | |
| <a href="#" class="hover:text-[#5865F2] transition-all"><i | |
| class="fab fa-discord mr-1"></i> Discord</a> | |
| </div> | |
| </div> | |
| <div class="flex gap-3"> | |
| <a href="#" aria-label="Instagram" | |
| class="w-10 h-10 bg-white/10 rounded-lg flex items-center justify-center text-[#a09a94] hover:text-white hover:bg-white/20 transition-all"><i | |
| class="fab fa-instagram"></i></a> | |
| <a href="#" aria-label="YouTube" | |
| class="w-10 h-10 bg-white/10 rounded-lg flex items-center justify-center text-[#a09a94] hover:text-white hover:bg-white/20 transition-all"><i | |
| class="fab fa-youtube"></i></a> | |
| <a href="#" aria-label="TikTok" | |
| class="w-10 h-10 bg-white/10 rounded-lg flex items-center justify-center text-[#a09a94] hover:text-white hover:bg-white/20 transition-all"><i | |
| class="fab fa-tiktok"></i></a> | |
| <a href="#" aria-label="Discord" | |
| class="w-10 h-10 bg-white/10 rounded-lg flex items-center justify-center text-[#a09a94] hover:text-[#5865F2] hover:bg-white/20 transition-all"><i | |
| class="fab fa-discord"></i></a> | |
| </div> | |
| </div> | |
| <div | |
| class="flex flex-col md:flex-row justify-between items-center gap-3 pt-6 mt-6 border-t border-white/10 text-sm text-[#a09a94]"> | |
| <span>© 2026 Loja Virtual · Todos os direitos reservados</span> | |
| <div class="flex items-center gap-2"><i class="fas fa-code text-xs"></i><span>Powered | |
| by</span><span class="text-[#c8502a] font-semibold">caBRAPI</span></div> | |
| </div> | |
| </div> | |
| </footer> | |
| </body> | |
| </html> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <!DOCTYPE html> | |
| <html lang="pt-br"> | |
| <head> | |
| <meta charset="UTF-8" /> | |
| <meta name="viewport" content="width=device-width, initial-scale=1" /> | |
| <meta name="loja-id" content="ecf68475-0fe1-4224-a2f3-cb1cd3311d84" /> | |
| <!-- HTML Meta Tags --> | |
| <title>Theme Light Shop | Template de Loja Virtual Moderna</title> | |
| <meta name="description" | |
| content="Template moderno para e-commerce com visual claro, performance elevada, SEO otimizado e experiência premium para lojas virtuais."> | |
| <!-- Facebook Meta Tags --> | |
| <meta property="og:url" content="https://demo-theme-light-shop-web.cabrapi.com.br/"> | |
| <meta property="og:type" content="website"> | |
| <meta property="og:title" content="Theme Light Shop | Template de Loja Virtual Moderna"> | |
| <meta property="og:description" | |
| content="Template moderno para e-commerce com visual claro, performance elevada, SEO otimizado e experiência premium para lojas virtuais."> | |
| <meta property="og:image" | |
| content="https://blob.cabrapi.com.br/blob/808ff623-b490-414a-8b82-abeadeb87b0d/download"> | |
| <!-- Twitter Meta Tags --> | |
| <meta name="twitter:card" content="summary_large_image"> | |
| <meta property="twitter:domain" content="demo-theme-light-shop-web.cabrapi.com.br"> | |
| <meta property="twitter:url" content="https://demo-theme-light-shop-web.cabrapi.com.br/"> | |
| <meta name="twitter:title" content="Theme Light Shop | Template de Loja Virtual Moderna"> | |
| <meta name="twitter:description" | |
| content="Template moderno para e-commerce com visual claro, performance elevada, SEO otimizado e experiência premium para lojas virtuais."> | |
| <meta name="twitter:image" | |
| content="https://blob.cabrapi.com.br/blob/808ff623-b490-414a-8b82-abeadeb87b0d/download"> | |
| <link rel="icon" href="https://blob.cabrapi.com.br/blob/808ff623-b490-414a-8b82-abeadeb87b0d/download" | |
| sizes="32x32"> | |
| <link rel="icon" href="https://blob.cabrapi.com.br/blob/808ff623-b490-414a-8b82-abeadeb87b0d/download" | |
| sizes="192x192"> | |
| <link rel="apple-touch-icon" | |
| href="https://blob.cabrapi.com.br/blob/808ff623-b490-414a-8b82-abeadeb87b0d/download"> | |
| <link href="https://fonts.googleapis.com/css2?family=DM+Sans:ital,opsz,wght@0,9..40,300;0,9..40,400;0,9..40,500;0,9..40,600;0,9..40,700;1,9..40,400&family=DM+Serif+Display&display=swap" | |
| rel="stylesheet" /> | |
| <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.0/css/all.min.css" rel="stylesheet" /> | |
| <script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script> | |
| <style> | |
| :root { | |
| --c-bg: #f8f7f4; | |
| --c-surface: #ffffff; | |
| --c-border: #e8e4df; | |
| --c-ink: #1a1714; | |
| --c-ink-muted: #6b6560; | |
| --c-ink-subtle: #a09a94; | |
| --c-accent: #c8502a; | |
| --c-accent-light: #fef3ec; | |
| --c-green: #2d7a4f; | |
| } | |
| *, | |
| *::before, | |
| *::after { | |
| box-sizing: border-box; | |
| } | |
| body { | |
| font-family: 'DM Sans', sans-serif; | |
| background: var(--c-bg); | |
| color: var(--c-ink); | |
| } | |
| a { | |
| text-decoration: none; | |
| color: inherit; | |
| } | |
| img { | |
| max-width: 100%; | |
| height: auto; | |
| } | |
| button { | |
| font-family: inherit; | |
| cursor: pointer; | |
| } | |
| section img { | |
| pointer-events: none; | |
| } | |
| </style> | |
| <script src="https://code.jquery.com/jquery-3.7.1.min.js"></script> | |
| <script type="module"> | |
| import { caBRAPI as p } from "https://cdn.jsdelivr.net/npm/@cabrapi/sdk/dist/index.js"; | |
| var l = { | |
| CART_STORAGE_KEY: "cabrapi_theme_light_shop_cart", | |
| PRODUCTS_PAGE: 1, | |
| PRODUCTS_LIMIT: 3, | |
| PRODUCT_IMAGE_FIT_DEFAULT: "cover", | |
| BUTTON_FEEDBACK_MS: 1400, | |
| COPY_FEEDBACK_MS: 1800 | |
| }, m = { | |
| PIX: "MERCADOPAGO_SERVICE_PIX", | |
| CARD: "MERCADOPAGO_SERVICE_CARD" | |
| }, b = class { | |
| #t; | |
| #e; | |
| constructor(t, e) { | |
| this.#t = new t({ | |
| type: "public", | |
| config: {} | |
| }), this.#e = e; | |
| } | |
| async getProducts(t = l.PRODUCTS_PAGE) { | |
| const e = await this.#t.products.get(this.#e, { | |
| page: t, | |
| limit: l.PRODUCTS_LIMIT | |
| }); | |
| if (!e?.status && e?.error) throw new Error(e?.message || "Erro ao buscar produtos."); | |
| return { | |
| products: Array.isArray(e?.products) ? e.products : [], | |
| pagination: { | |
| page: Number(e?.pagination?.page || t || 1), | |
| limit: Number(e?.pagination?.limit || l.PRODUCTS_LIMIT), | |
| total: Number(e?.pagination?.total || 0), | |
| totalPages: Number(e?.pagination?.totalPages || 1) | |
| } | |
| }; | |
| } | |
| async getCategories() { | |
| const t = await this.#t.categories.get(this.#e, { | |
| page: 1, | |
| limit: 100 | |
| }); | |
| if (!t?.status && t?.error) throw new Error(t?.message || "Erro ao buscar categorias."); | |
| return Array.isArray(t?.categories) ? t.categories : []; | |
| } | |
| async validateCoupon(t) { | |
| return await this.#t.coupons.getByCode(this.#e, t); | |
| } | |
| async createPayment(t) { | |
| return await this.#t.payments.post(this.#e, t); | |
| } | |
| }, C = class { | |
| #t = null; | |
| getItems() { | |
| if (this.#t) return this.#t; | |
| try { | |
| const t = localStorage.getItem(l.CART_STORAGE_KEY); | |
| this.#t = t ? JSON.parse(t) : []; | |
| } catch { | |
| this.#t = []; | |
| } | |
| return this.#t; | |
| } | |
| #e(t) { | |
| this.#t = Array.isArray(t) ? t : [], localStorage.setItem(l.CART_STORAGE_KEY, JSON.stringify(this.#t)); | |
| } | |
| addProduct(t) { | |
| const e = this.getItems(), o = String(t.id), s = e.find((i) => String(i.id) === o), a = t.stock === null || t.stock === void 0 ? null : Number(t.stock); | |
| if (a !== null && a <= 0) return e; | |
| if (s) { | |
| const i = s.stock === null || s.stock === void 0 ? null : Number(s.stock); | |
| if (i !== null && s.qty >= i) return e; | |
| s.qty += 1; | |
| } else e.push({ | |
| id: o, | |
| name: String(t.name || "Produto"), | |
| image: t.image || null, | |
| price: Number(t.price || 0), | |
| qty: 1, | |
| stock: a | |
| }); | |
| return this.#e(e), e; | |
| } | |
| removeProduct(t) { | |
| const e = String(t), o = this.getItems().filter((s) => String(s.id) !== e); | |
| return this.#e(o), o; | |
| } | |
| changeQuantity(t, e) { | |
| const o = String(t), s = this.getItems(), a = s.find((n) => String(n.id) === o); | |
| if (!a) return s; | |
| const i = a.stock === null || a.stock === void 0 ? null : Number(a.stock); | |
| if (e > 0 && i !== null && a.qty >= i) return s; | |
| if (a.qty += e, a.qty <= 0) return this.removeProduct(t); | |
| const c = s.filter((n) => n.qty > 0); | |
| return this.#e(c), c; | |
| } | |
| clear() { | |
| this.#e([]); | |
| } | |
| getTotalItems() { | |
| return this.getItems().reduce((t, e) => t + Number(e.qty || 0), 0); | |
| } | |
| getTotalPrice() { | |
| return this.getItems().reduce((t, e) => t + Number(e.price || 0) * Number(e.qty || 0), 0); | |
| } | |
| }; | |
| function x(t) { | |
| return String(t || "").trim().length >= 3; | |
| } | |
| function y(t) { | |
| const e = String(t || "").trim(); | |
| return e ? e.length >= 4 && e.length <= 32 : !0; | |
| } | |
| function v(t) { | |
| return String(t || "").replace(/\D/g, "").length === 11; | |
| } | |
| function k(t) { | |
| const e = String(t || "").trim(); | |
| return e ? /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(e) : !1; | |
| } | |
| function w(t) { | |
| return Array.isArray(t) && t.length > 0; | |
| } | |
| function S(t, e, o = 1400) { | |
| const s = t.html(); | |
| t.prop("disabled", !0).html(e), setTimeout(() => { | |
| t.prop("disabled", !1).html(s); | |
| }, o); | |
| } | |
| function d(t, e) { | |
| if (e) { | |
| t.removeClass("opacity-0 pointer-events-none"); | |
| return; | |
| } | |
| t.addClass("opacity-0 pointer-events-none"); | |
| } | |
| function r(t) { | |
| return String(t || "").replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/\"/g, """).replace(/'/g, "'"); | |
| } | |
| var P = class { | |
| constructor({ onCategoryChange: t }) { | |
| this.$filters = $("#category-filters"), this.onCategoryChange = t, this.categories = [], this.activeCategory = "all", this.#t(); | |
| } | |
| #t() { | |
| $(document).on("click", ".category-filter-btn", (t) => { | |
| const e = String($(t.currentTarget).data("category") || "all"); | |
| e !== this.activeCategory && (this.activeCategory = e, this.render(), typeof this.onCategoryChange == "function" && this.onCategoryChange(e)); | |
| }); | |
| } | |
| setCategories(t) { | |
| this.categories = (Array.isArray(t) ? t : []).filter((e) => e?.name).map((e) => ({ | |
| id: String(e.id || e.name), | |
| name: String(e.name) | |
| })), this.render(); | |
| } | |
| setActiveCategory(t) { | |
| this.activeCategory = String(t || "all"), this.render(); | |
| } | |
| render() { | |
| const t = [`<button class="category-filter-btn px-4 py-2 rounded-full text-sm font-medium transition-all ${this.activeCategory === "all" ? "bg-[#c8502a] text-white" : "bg-white text-[#6b6560] border border-[#e8e4df]"}" data-category="all">Todos</button>`]; | |
| for (const e of this.categories) { | |
| const o = this.activeCategory === e.name ? "bg-[#c8502a] text-white" : "bg-white text-[#6b6560] border border-[#e8e4df] hover:border-[#c8502a] hover:text-[#c8502a]"; | |
| t.push(`<button class="category-filter-btn px-4 py-2 rounded-full text-sm font-medium transition-all ${o}" data-category="${r(e.name)}">${r(e.name)}</button>`); | |
| } | |
| this.$filters.html(t.join("")); | |
| } | |
| }; | |
| function h(t) { | |
| return new Intl.NumberFormat("pt-BR", { | |
| style: "currency", | |
| currency: "BRL" | |
| }).format(Number(t || 0)); | |
| } | |
| function A(t = "Produto") { | |
| return `https://placehold.co/600x420/F0EDE8/9CA3AF?text=${encodeURIComponent(t)}`; | |
| } | |
| var I = class { | |
| constructor({ onAddToCart: t, onPageChange: e }) { | |
| this.$list = $("#products-list"), this.$pagination = $("#products-pagination"), this.onAddToCart = t, this.onPageChange = e, this.products = [], this.activeCategory = "all", this.pagination = { | |
| page: 1, | |
| totalPages: 1, | |
| total: 0 | |
| }, this.#t(); | |
| } | |
| #t() { | |
| $(document).on("click", ".product-add-btn", (t) => { | |
| const e = $(t.currentTarget); | |
| if (e.prop("disabled") || e.hasClass("cursor-not-allowed")) return; | |
| const o = String(e.data("id")), s = this.products.find((a) => String(a.id) === o); | |
| s && this.onAddToCart(s) !== !1 && S(e, '<i class="fas fa-check mr-2"></i> Adicionado', l.BUTTON_FEEDBACK_MS); | |
| }), $(document).on("click", ".products-page-btn", (t) => { | |
| const e = Number($(t.currentTarget).data("page")); | |
| !e || e === this.pagination.page || typeof this.onPageChange == "function" && this.onPageChange(e); | |
| }); | |
| } | |
| #e() { | |
| this.$list.find(".product-card-image").each((t, e) => { | |
| $(e).css({ | |
| width: "100%", | |
| height: "100%", | |
| "object-fit": "cover", | |
| "object-position": "center", | |
| display: "block" | |
| }); | |
| }); | |
| } | |
| setProducts(t) { | |
| const e = Array.isArray(t?.products) ? t.products : []; | |
| this.pagination = { | |
| page: Number(t?.pagination?.page || 1), | |
| totalPages: Number(t?.pagination?.totalPages || 1), | |
| total: Number(t?.pagination?.total || e.length) | |
| }, this.products = e.filter((o) => !o.disabled), this.#o(), this.#a(); | |
| } | |
| setActiveCategory(t) { | |
| this.activeCategory = String(t || "all"), this.#o(); | |
| } | |
| #s() { | |
| return this.activeCategory === "all" ? this.products : this.products.filter((t) => (t.categories || []).some((e) => String(e.name) === this.activeCategory)); | |
| } | |
| #o() { | |
| const t = this.#s(); | |
| if (!t.length) { | |
| this.$list.html(` | |
| <div class="col-span-full text-center py-20 text-[#6b6560]"> | |
| <i class="fas fa-box-open text-5xl mb-4 block opacity-20"></i> | |
| <p>Nenhum produto encontrado.</p> | |
| </div> | |
| `); | |
| return; | |
| } | |
| const e = t.map((o) => { | |
| const s = r(o.image || A(o.name)), a = Number(o.stock), i = !(!Number.isNaN(a) && a > 0); | |
| return ` | |
| <article class="group bg-white rounded-3xl border border-[#e8e4df] overflow-hidden hover:shadow-xl transition-all duration-300 flex flex-col h-full"> | |
| <div class="product-card-image-frame relative overflow-hidden bg-[#f8f7f4]" style="aspect-ratio: 4/3; width: 100%;"> | |
| <img src="${s}" | |
| alt="${r(o.name)}" | |
| class="product-card-image transition-transform duration-700 group-hover:scale-110" | |
| style="width: 100% !important; height: 100% !important; object-fit: cover !important; object-position: center !important; display: block !important;" | |
| /> | |
| <div class="absolute inset-0 bg-gradient-to-t from-[#1a1714]/10 to-transparent pointer-events-none"></div> | |
| </div> | |
| <div class="p-5 flex flex-col flex-1"> | |
| <div class="flex-1"> | |
| <h3 class="font-bold text-[#1a1714] text-lg mb-1 line-clamp-2 leading-tight"> | |
| ${r(o.name)} | |
| </h3> | |
| <p class="text-sm text-[#6b6560] mb-4 line-clamp-2 leading-relaxed"> | |
| ${r(o.description || "Asset digital exclusivo.")} | |
| </p> | |
| </div> | |
| <div class="mt-auto"> | |
| <div class="mb-4"> | |
| <span class="text-[10px] text-[#6b6560] font-bold uppercase tracking-widest">Valor</span> | |
| <div class="text-2xl text-[#c8502a] font-black leading-none"> | |
| ${h(o.price)} | |
| </div> | |
| </div> | |
| <button class="product-add-btn w-full py-3.5 bg-[#1a1714] text-white font-bold rounded-2xl hover:bg-[#c8502a] transition-all flex items-center justify-center gap-2 shadow-sm disabled:opacity-50 disabled:cursor-not-allowed disabled:hover:bg-[#1a1714]" | |
| ${i ? 'disabled aria-disabled="true"' : ""} | |
| data-id="${r(o.id)}" | |
| data-stock="${r(o.stock)}"> | |
| <i class="fas fa-shopping-bag text-sm"></i> | |
| <span>${i ? "ESGOTADO" : "ADICIONAR"}</span> | |
| </button> | |
| </div> | |
| </div> | |
| </article> | |
| `; | |
| }); | |
| this.$list.html(` | |
| <div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6"> | |
| ${e.join("")} | |
| </div> | |
| `), this.#e(); | |
| } | |
| #a() { | |
| const { page: t, totalPages: e } = this.pagination; | |
| if (e <= 1) { | |
| this.$pagination.html(""); | |
| return; | |
| } | |
| let o = ""; | |
| for (let s = 1; s <= e; s++) s === 1 || s === e || s >= t - 1 && s <= t + 1 ? o += ` | |
| <button class="products-page-btn w-10 h-10 md:w-12 md:h-12 ${s === t ? "flex" : "hidden md:flex"} items-center justify-center rounded-xl border-2 transition-all font-bold ${s === t ? "bg-[#1a1714] border-[#1a1714] text-white active-page shadow-lg" : "border-[#e8e4df] text-[#1a1714] hover:border-[#1a1714]"}" data-page="${s}"> | |
| ${s} | |
| </button> | |
| ` : (s === t - 2 || s === t + 2) && (o += '<span class="text-[#e8e4df] hidden md:inline">...</span>'); | |
| this.$pagination.html(` | |
| <div class="flex items-center justify-between gap-2 mt-12 mb-8 p-3 md:p-6 bg-white rounded-2xl md:rounded-[2rem] border border-[#e8e4df] mx-2"> | |
| <button class="products-page-btn flex items-center justify-center w-10 h-10 md:w-auto md:px-6 md:py-3 rounded-xl font-bold border-2 border-[#e8e4df] transition-all ${t <= 1 ? "opacity-20 cursor-not-allowed" : "text-[#1a1714] hover:bg-[#f8f7f4]"}" | |
| ${t <= 1 ? "disabled" : ""} data-page="${t - 1}"> | |
| <i class="fas fa-chevron-left text-xs"></i> | |
| <span class="hidden md:inline ml-2">Anterior</span> | |
| </button> | |
| <div class="flex items-center gap-1 md:gap-2"> | |
| ${o} | |
| <span class="md:hidden text-xs font-bold text-[#6b6560] ml-2">de ${e}</span> | |
| </div> | |
| <button class="products-page-btn flex items-center justify-center w-10 h-10 md:w-auto md:px-6 md:py-3 rounded-xl font-bold border-2 border-[#e8e4df] transition-all ${t >= e ? "opacity-20 cursor-not-allowed" : "text-[#1a1714] hover:bg-[#f8f7f4]"}" | |
| ${t >= e ? "disabled" : ""} data-page="${t + 1}"> | |
| <span class="hidden md:inline mr-2">Próxima</span> | |
| <i class="fas fa-chevron-right text-xs"></i> | |
| </button> | |
| </div> | |
| `); | |
| } | |
| updateButtonsStates(t) { | |
| $(".product-add-btn").each((e, o) => { | |
| const s = $(o), a = s.data("id"), i = t.find((f) => String(f.id) === String(a)), c = Number(s.data("stock")), n = i ? i.stock : isNaN(c) ? null : c, g = i ? i.qty : 0, u = n !== null && n <= 0 || n > 0 && g >= n; | |
| u ? s.prop("disabled", !0).attr("disabled", "disabled").addClass("opacity-50 cursor-not-allowed") : s.prop("disabled", !1).removeAttr("disabled").removeClass("opacity-50 cursor-not-allowed"), s.find("span").text(u ? "ESGOTADO" : "ADICIONAR"); | |
| }); | |
| } | |
| }, T = class { | |
| constructor() { | |
| this.$drawer = $("#checkout"), this.$openButton = $("#cart-toggle"), this.$closeButton = $("#checkout-close"), this.$count = $("#cart-count"); | |
| } | |
| bindEvents() { | |
| this.$openButton.on("click", (t) => { | |
| t.preventDefault(), this.open(); | |
| }), this.$closeButton.on("click", () => this.close()), this.$drawer.on("click", (t) => { | |
| $(t.target).is(this.$drawer) && this.close(); | |
| }); | |
| } | |
| open() { | |
| d(this.$drawer, !0); | |
| } | |
| close() { | |
| d(this.$drawer, !1); | |
| } | |
| setCount(t) { | |
| this.$count.text(String(Number(t || 0))); | |
| } | |
| }, E = class { | |
| constructor(t) { | |
| this.handlers = t, this.$items = $("#checkout-items"), this.$total = $("#checkout-total"), this.$message = $("#checkout-message"), this.$couponStatus = $("#checkout-coupon-status"), this.$couponInput = $("#checkout-coupon"), this.$cpfInput = $("#checkout-cpf"), this.$submitButton = $("#checkout-submit"), this.$couponButton = $("#checkout-apply-coupon"), this.$fieldErrors = { | |
| name: $("#checkout-name-error"), | |
| cpf: $("#checkout-cpf-error"), | |
| email: $("#checkout-email-error"), | |
| nickname: $("#checkout-nickname-error") | |
| }, this.#t(); | |
| } | |
| #t() { | |
| this.$items.on("click", ".checkout-remove-btn", (t) => { | |
| const e = String($(t.currentTarget).data("id")); | |
| this.handlers.onRemoveItem(e); | |
| }), this.$items.on("click", ".checkout-qty-btn", (t) => { | |
| const e = $(t.currentTarget), o = String(e.data("id")), s = Number(e.data("delta")); | |
| this.handlers.onQuantityChange(o, s); | |
| }), this.$couponButton.on("click", async () => { | |
| await this.handlers.onApplyCoupon(); | |
| }), this.$couponInput.on("input", () => { | |
| this.setCouponStatus(null); | |
| }), this.$cpfInput.on("input", (t) => { | |
| const e = $(t.currentTarget), o = this.#e(e.val()); | |
| e.val() !== o && e.val(o); | |
| }), $('input[name="payment_method"]').on("change", (t) => { | |
| this.handlers.onPaymentMethodChange(String($(t.currentTarget).val())); | |
| }), $("#checkout-form").on("submit", async (t) => { | |
| t.preventDefault(), await this.handlers.onSubmit(); | |
| }); | |
| } | |
| renderItems(t) { | |
| if (!t.length) { | |
| this.$items.html('<p class="text-center py-8 text-[#6b6560]">Carrinho vazio</p>'); | |
| return; | |
| } | |
| const e = t.map((o) => ` | |
| <div class="flex items-center gap-2 p-2 bg-[#f8f7f4] rounded-xl"> | |
| <img src="${r(o.image || "https://placehold.co/64x64/F0EDE8/9CA3AF")}" alt="${r(o.name)}" class="w-12 h-12 rounded-lg object-cover shrink-0" /> | |
| <div class="flex-1 min-w-0"> | |
| <p class="font-medium text-xs text-[#1a1714] truncate">${r(o.name)}</p> | |
| <p class="text-[#6b6560] text-xs">${h(o.price)}</p> | |
| </div> | |
| <div class="flex items-center gap-1 shrink-0"> | |
| <button class="checkout-qty-btn w-7 h-7 rounded-lg bg-white border border-[#e8e4df] text-[#1a1714] hover:bg-[#f8f7f4] disabled:opacity-50 disabled:cursor-not-allowed" ${Number(o.qty) <= 1 ? "disabled" : ""} data-id="${r(o.id)}" data-delta="-1"> | |
| <i class="fas fa-minus text-xs"></i> | |
| </button> | |
| <span class="w-6 text-center text-sm font-bold">${Number(o.qty)}</span> | |
| <button class="checkout-qty-btn w-7 h-7 rounded-lg bg-white border border-[#e8e4df] text-[#1a1714] hover:bg-[#f8f7f4] disabled:opacity-50 disabled:cursor-not-allowed" ${o.stock !== null && Number(o.stock) > 0 && Number(o.qty) >= Number(o.stock) ? "disabled" : ""} data-id="${r(o.id)}" data-delta="1"> | |
| <i class="fas fa-plus text-xs"></i> | |
| </button> | |
| </div> | |
| <button class="checkout-remove-btn text-red-500 hover:text-red-700 p-1 shrink-0 disabled:opacity-50 disabled:cursor-not-allowed" data-id="${r(o.id)}"> | |
| <i class="fas fa-trash text-xs"></i> | |
| </button> | |
| </div> | |
| `).join(""); | |
| this.$items.html(e); | |
| } | |
| setTotal(t) { | |
| this.$total.text(h(t)); | |
| } | |
| getFormData() { | |
| return { | |
| name: String($("#checkout-name").val() || "").trim(), | |
| nickname: String($("#checkout-nickname").val() || "").trim(), | |
| email: String($("#checkout-email").val() || "").trim(), | |
| cpf: String($("#checkout-cpf").val() || "").replace(/\D/g, ""), | |
| note: String($("#checkout-note").val() || "").trim(), | |
| coupon: String($("#checkout-coupon").val() || "").trim(), | |
| paymentMethod: String($('input[name="payment_method"]:checked').val() || "PIX") | |
| }; | |
| } | |
| setFieldError(t, e) { | |
| const o = this.$fieldErrors[t]; | |
| if (!(!o || !o.length)) { | |
| if (!e) { | |
| o.addClass("hidden").text(""); | |
| return; | |
| } | |
| o.removeClass("hidden").text(e); | |
| } | |
| } | |
| clearFieldErrors() { | |
| Object.keys(this.$fieldErrors).forEach((t) => { | |
| this.setFieldError(t, ""); | |
| }); | |
| } | |
| #e(t) { | |
| const e = String(t || "").replace(/\D/g, "").slice(0, 11), o = []; | |
| e.length > 0 && o.push(e.slice(0, 3)), e.length > 3 && o.push(e.slice(3, 6)), e.length > 6 && o.push(e.slice(6, 9)); | |
| let s = o.join("."); | |
| return e.length > 9 && (s += `-${e.slice(9, 11)}`), s; | |
| } | |
| setSubmitLabel(t) { | |
| const e = t === "CARD" ? '<i class="fas fa-credit-card mr-2"></i> Pagar com Cartão' : '<i class="fas fa-qrcode mr-2"></i> Pagar com PIX'; | |
| this.$submitButton.html(e); | |
| } | |
| setSubmitLoading(t, e) { | |
| if (t) { | |
| this.$submitButton.prop("disabled", !0).html('<i class="fas fa-spinner fa-spin mr-2"></i> Processando...'); | |
| return; | |
| } | |
| this.$submitButton.prop("disabled", !1), this.setSubmitLabel(e); | |
| } | |
| setCouponLoading(t) { | |
| if (t) { | |
| this.$couponButton.prop("disabled", !0).html('<i class="fas fa-spinner fa-spin mr-2"></i> Validando...'); | |
| return; | |
| } | |
| this.$couponButton.prop("disabled", !1).html('<i class="fas fa-ticket mr-2"></i> Aplicar'); | |
| } | |
| showMessage(t, e) { | |
| this.messageTimer && (clearTimeout(this.messageTimer), this.messageTimer = null), this.$message.removeClass("hidden bg-green-100 text-green-700 bg-red-100 text-red-700").addClass(t === "success" ? "bg-green-100 text-green-700" : "bg-red-100 text-red-700").text(e), this.messageTimer = setTimeout(() => { | |
| this.hideMessage(); | |
| }, 3500); | |
| } | |
| hideMessage() { | |
| this.messageTimer && (clearTimeout(this.messageTimer), this.messageTimer = null), this.$message.addClass("hidden").text(""); | |
| } | |
| setCouponStatus(t) { | |
| if (!t) { | |
| this.$couponStatus.addClass("hidden").text("").removeClass("text-green-700 text-red-600"); | |
| return; | |
| } | |
| this.$couponStatus.removeClass("hidden text-green-700 text-red-600").addClass(t.type === "success" ? "text-green-700" : "text-red-600").text(t.text); | |
| } | |
| resetForm() { | |
| const t = $("#checkout-form")[0]; | |
| t && t.reset(), this.setSubmitLabel("PIX"), this.setCouponStatus(null); | |
| } | |
| }, N = class { | |
| constructor() { | |
| this.$pixModal = $("#pix-modal"), this.$pixPanel = $("#pix-modal-panel"), this.$cardModal = $("#card-modal"), this.$cardPanel = $("#card-modal-panel"); | |
| } | |
| showFromPaymentResponse(t) { | |
| const e = t?.data?.payment || {}; | |
| if (e?.qr_code) { | |
| this.#t(e); | |
| return; | |
| } | |
| this.#e(e); | |
| } | |
| #t(t) { | |
| const e = t?.qr_code || {}; | |
| let o = e.image || ""; | |
| o && !String(o).startsWith("data:") && !String(o).startsWith("http") && (o = `data:image/png;base64,${o}`), this.$pixPanel.html(` | |
| <div class="mb-5"> | |
| <i class="fas fa-qrcode text-4xl text-[#c8502a] mb-3 block"></i> | |
| <h3 class="text-xl font-bold text-[#1a1714]">Pagamento PIX</h3> | |
| <p class="text-[#6b6560] text-sm mt-1">Escaneie o QR Code com seu banco.</p> | |
| </div> | |
| ${o ? `<img src="${r(o)}" alt="QR Code PIX" class="w-48 h-48 mx-auto mb-4 rounded-xl border-2 border-[#e8e4df] p-2">` : ""} | |
| ${e.base_64 ? ` | |
| <div class="flex gap-2 mb-4"> | |
| <input id="pix-code" readonly value="${r(e.base_64)}" class="flex-1 px-3 py-2 bg-[#f8f7f4] border border-[#e8e4df] rounded-lg text-xs font-mono min-w-0" /> | |
| <button id="pix-copy" class="px-3 py-2 bg-[#1a1714] text-white rounded-lg hover:bg-[#c8502a] transition-colors shrink-0" title="Copiar codigo PIX"> | |
| <i class="fas fa-copy"></i> | |
| </button> | |
| </div> | |
| ` : ""} | |
| <button id="pix-close" class="w-full py-3 border-2 border-[#e8e4df] text-[#6b6560] font-semibold rounded-xl hover:border-[#1a1714] hover:text-[#1a1714] transition-all"> | |
| Concluir | |
| </button> | |
| `), d(this.$pixModal, !0), $("#pix-copy").off("click").on("click", async () => { | |
| try { | |
| await navigator.clipboard.writeText(String(e.base_64 || "")); | |
| const s = $("#pix-copy"); | |
| s.html('<i class="fas fa-check"></i>'), setTimeout(() => { | |
| s.html('<i class="fas fa-copy"></i>'); | |
| }, l.COPY_FEEDBACK_MS); | |
| } catch { | |
| } | |
| }), $("#pix-close").off("click").on("click", () => { | |
| d(this.$pixModal, !1); | |
| }); | |
| } | |
| #e(t) { | |
| this.$cardPanel.html(` | |
| <div class="text-center p-8 bg-white rounded-[2.5rem] shadow-2xl border border-[#e8e4df]"> | |
| <div class="inline-flex items-center justify-center w-20 h-20 bg-[#1a1714] rounded-full mb-6 shadow-lg"> | |
| <i class="fas fa-credit-card text-2xl text-white"></i> | |
| </div> | |
| <h3 class="text-2xl font-black text-[#1a1714] tracking-tighter mb-2">Pagamento com Cartão</h3> | |
| <p class="text-[#6b6560] text-sm mb-8 leading-relaxed max-w-[240px] mx-auto"> | |
| Método de pagamento: cartão. Clique abaixo para abrir o portal seguro. | |
| </p> | |
| ${t.url ? ` | |
| <a href="${r(t.url)}" | |
| target="_blank" | |
| rel="noopener" | |
| class="block w-full py-5 bg-[#1a1714] text-white font-black rounded-2xl text-center mb-4 hover:bg-[#000000] active:scale-[0.97] transition-all shadow-xl shadow-black/20 uppercase tracking-[0.15em] text-[11px]"> | |
| <span class="text-white !opacity-100">FINALIZAR PAGAMENTO</span> | |
| </a> | |
| ` : ""} | |
| ${t.uuid ? ` | |
| <div class="inline-block bg-[#f8f7f4] rounded-full px-4 py-1.5 mb-8 border border-[#e8e4df]"> | |
| <p class="text-[#6b6560] text-[9px] font-bold tracking-widest uppercase"> | |
| REF: <span class="text-[#1a1714] font-black">${r(t.uuid.split("-")[0])}</span> | |
| </p> | |
| </div> | |
| ` : ""} | |
| <button id="card-close" class="w-full py-3 border-2 border-[#e8e4df] text-[#6b6560] font-semibold rounded-xl hover:border-[#1a1714] hover:text-[#1a1714] transition-all"> | |
| Concluir | |
| </button> | |
| </div> | |
| `), d(this.$cardModal, !0), $("#card-close").off("click").on("click", () => { | |
| d(this.$cardModal, !1); | |
| }); | |
| } | |
| }, D = class { | |
| constructor() { | |
| this.apiService = null, this.cartStorage = new C(), this.productsComponent = null, this.categoriesComponent = null, this.cartDrawer = null, this.checkoutComponent = null, this.paymentModal = new N(), this.appliedCouponCode = null, this.storeId = "", this.currentPage = 1, this.activeCategory = "all"; | |
| } | |
| async init() { | |
| if (!window.jQuery) { | |
| setTimeout(() => this.init(), 80); | |
| return; | |
| } | |
| if (!p) { | |
| setTimeout(() => this.init(), 100); | |
| return; | |
| } | |
| if (this.storeId = String($("meta[name='loja-id']").attr("content") || "").trim(), !this.storeId) { | |
| $("#products-list").html(` | |
| <div class="text-center py-12 text-red-600"> | |
| <i class="fas fa-triangle-exclamation text-4xl mb-3 block"></i> | |
| <p>Meta loja-id nao encontrada no HTML.</p> | |
| </div> | |
| `); | |
| return; | |
| } | |
| this.apiService = new b(p, this.storeId), this.productsComponent = new I({ | |
| onAddToCart: (t) => this.handleAddToCart(t), | |
| onPageChange: (t) => this.handlePageChange(t) | |
| }), this.categoriesComponent = new P({ onCategoryChange: (t) => this.handleCategoryChange(t) }), this.cartDrawer = new T(), this.cartDrawer.bindEvents(), this.checkoutComponent = new E({ | |
| onRemoveItem: (t) => this.handleRemoveItem(t), | |
| onQuantityChange: (t, e) => this.handleQuantityChange(t, e), | |
| onApplyCoupon: async () => { | |
| await this.handleApplyCoupon(); | |
| }, | |
| onSubmit: async () => { | |
| await this.handleCheckoutSubmit(); | |
| }, | |
| onPaymentMethodChange: (t) => { | |
| this.checkoutComponent.setSubmitLabel(t === "CARD" ? "CARD" : "PIX"); | |
| } | |
| }), this.syncCartUI(), await this.loadCategories(), await this.loadProducts(); | |
| } | |
| async loadCategories() { | |
| try { | |
| const t = await this.apiService.getCategories(); | |
| this.categoriesComponent.setCategories(t), this.categoriesComponent.setActiveCategory(this.activeCategory); | |
| } catch { | |
| this.categoriesComponent.setCategories([]), this.categoriesComponent.setActiveCategory("all"); | |
| } | |
| } | |
| async loadProducts(t = 1) { | |
| try { | |
| this.currentPage = t; | |
| const e = await this.apiService.getProducts(t), o = this.cartStorage.getItems(), s = e.products.map((a) => { | |
| const i = o.find((c) => String(c.id) === String(a.id)); | |
| return { | |
| ...a, | |
| inCartQty: i ? i.qty : 0 | |
| }; | |
| }); | |
| this.productsComponent.setProducts({ | |
| ...e, | |
| products: s | |
| }), this.productsComponent.setActiveCategory(this.activeCategory); | |
| } catch (e) { | |
| $("#products-list").html(` | |
| <div class="text-center py-12 text-red-600"> | |
| <i class="fas fa-triangle-exclamation text-4xl mb-3 block"></i> | |
| <p>Falha ao carregar produtos.</p> | |
| <p class="text-sm text-[#6b6560] mt-2">${String(e?.message || "Erro desconhecido")}</p> | |
| </div> | |
| `); | |
| } | |
| } | |
| handlePageChange(t) { | |
| this.loadProducts(t), $("#shop")[0]?.scrollIntoView({ | |
| behavior: "smooth", | |
| block: "start" | |
| }); | |
| } | |
| handleCategoryChange(t) { | |
| this.activeCategory = String(t || "all"), this.productsComponent.setActiveCategory(this.activeCategory); | |
| } | |
| handleAddToCart(t) { | |
| const e = t.stock === null || t.stock === void 0 ? null : Number(t.stock); | |
| return e !== null && e <= 0 ? (this.checkoutComponent.showMessage("error", "Este produto esta sem estoque."), !1) : (this.cartStorage.addProduct(t), this.syncCartUI(), !0); | |
| } | |
| handleRemoveItem(t) { | |
| this.cartStorage.removeProduct(t), this.syncCartUI(); | |
| } | |
| handleQuantityChange(t, e) { | |
| this.cartStorage.changeQuantity(t, e), this.syncCartUI(); | |
| } | |
| syncCartUI() { | |
| const t = this.cartStorage.getItems(); | |
| this.cartDrawer.setCount(this.cartStorage.getTotalItems()), this.checkoutComponent.renderItems(t), this.checkoutComponent.setTotal(this.cartStorage.getTotalPrice()), this.productsComponent.updateButtonsStates(t); | |
| } | |
| async handleApplyCoupon() { | |
| this.checkoutComponent.hideMessage(); | |
| const { coupon: t } = this.checkoutComponent.getFormData(); | |
| if (!t) | |
| return this.appliedCouponCode = null, this.checkoutComponent.setCouponStatus({ | |
| type: "error", | |
| text: "Digite um cupom para aplicar." | |
| }), !1; | |
| this.checkoutComponent.setCouponLoading(!0); | |
| try { | |
| const e = await this.apiService.validateCoupon(t), o = e?.coupon; | |
| if (!e?.status || !o?.code) throw new Error("Cupom invalido ou indisponivel."); | |
| return this.appliedCouponCode = String(o.code), this.checkoutComponent.setCouponStatus({ | |
| type: "success", | |
| text: `Cupom aplicado: ${String(o.code).toUpperCase()} (-${Number(o.discount || 0)}%)` | |
| }), !0; | |
| } catch { | |
| return this.appliedCouponCode = null, this.checkoutComponent.setCouponStatus({ | |
| type: "error", | |
| text: "Cupom invalido, expirado ou indisponivel para esta loja." | |
| }), !1; | |
| } finally { | |
| this.checkoutComponent.setCouponLoading(!1); | |
| } | |
| } | |
| async handleCheckoutSubmit() { | |
| this.checkoutComponent.hideMessage(); | |
| const t = this.cartStorage.getItems(); | |
| if (!w(t)) { | |
| this.checkoutComponent.showMessage("error", "Seu carrinho esta vazio."); | |
| return; | |
| } | |
| const e = this.checkoutComponent.getFormData(); | |
| if (this.checkoutComponent.clearFieldErrors(), !x(e.name)) { | |
| this.checkoutComponent.setFieldError("name", "Informe um nome valido com pelo menos 3 caracteres."), this.checkoutComponent.showMessage("error", "Corrija os campos destacados."); | |
| return; | |
| } | |
| if (!y(e.nickname)) { | |
| this.checkoutComponent.setFieldError("nickname", "O apelido deve ter entre 4 e 32 caracteres."), this.checkoutComponent.showMessage("error", "Corrija os campos destacados."); | |
| return; | |
| } | |
| if (!k(e.email)) { | |
| this.checkoutComponent.setFieldError("email", "Informe um e-mail valido."), this.checkoutComponent.showMessage("error", "Corrija os campos destacados."); | |
| return; | |
| } | |
| if (e.cpf && !v(e.cpf)) { | |
| this.checkoutComponent.setFieldError("cpf", "O CPF deve ter 11 numeros."), this.checkoutComponent.showMessage("error", "Corrija os campos destacados."); | |
| return; | |
| } | |
| if (e.coupon && !this.appliedCouponCode && !await this.handleApplyCoupon()) | |
| return; | |
| e.coupon || (this.appliedCouponCode = null, this.checkoutComponent.setCouponStatus(null)); | |
| const o = e.paymentMethod === "CARD" ? "CARD" : "PIX", s = { | |
| name: e.name, | |
| email: e.email, | |
| cpf: e.cpf || void 0, | |
| gateway: o === "CARD" ? m.CARD : m.PIX, | |
| coupon: this.appliedCouponCode || void 0, | |
| metadata: e.note || e.nickname ? { | |
| ...e.note ? { observation: e.note } : {}, | |
| ...e.nickname ? { nickname: e.nickname } : {} | |
| } : void 0, | |
| items: t.map((a) => ({ | |
| productId: String(a.id), | |
| quantity: Number(a.qty) | |
| })) | |
| }; | |
| this.checkoutComponent.setSubmitLoading(!0, o); | |
| try { | |
| const a = await this.apiService.createPayment(s); | |
| if (!a?.status) throw new Error(a?.message || "Falha ao criar pagamento."); | |
| this.paymentModal.showFromPaymentResponse(a), this.cartStorage.clear(), this.syncCartUI(), this.appliedCouponCode = null, this.checkoutComponent.resetForm(), this.checkoutComponent.showMessage("success", "Pagamento criado com sucesso."); | |
| } catch (a) { | |
| this.checkoutComponent.showMessage("error", String(a?.message || "Erro ao processar pagamento.")); | |
| } finally { | |
| this.checkoutComponent.setSubmitLoading(!1, o); | |
| } | |
| } | |
| }; | |
| new D().init(); | |
| </script> | |
| </head> | |
| <body class="bg-[#f8f7f4] text-[#1a1714] min-h-screen flex flex-col"> | |
| <!-- Navbar --> | |
| <nav class="sticky top-0 z-[200] bg-[#f8f7f4]/95 backdrop-blur-md border-b border-[#e8e4df] shadow-sm"> | |
| <div class="max-w-6xl mx-auto px-4"> | |
| <!-- Toggle --> | |
| <input type="checkbox" id="menu-toggle" class="peer hidden"> | |
| <div class="flex items-center justify-between h-16 md:h-[68px]"> | |
| <!-- Logo --> | |
| <a href="#" class="flex items-center gap-3 hover:opacity-80 transition-opacity"> | |
| <div | |
| class="w-10 h-10 bg-[#1a1714] rounded-xl flex items-center justify-center text-white shadow-md"> | |
| <i class="fas fa-store-alt text-lg"></i> | |
| </div> | |
| <span class="text-lg font-medium tracking-tight text-[#1a1714]"> | |
| Loja <strong class="font-bold text-[#c8502a]">Virtual</strong> | |
| </span> | |
| </a> | |
| <!-- Desktop Menu --> | |
| <ul class="hidden md:flex items-center gap-2 list-none m-0 p-0"> | |
| <li> | |
| <a href="#" | |
| class="group relative flex items-center gap-2 px-4 py-2 rounded-xl text-sm font-medium text-[#6b6560] hover:bg-white hover:text-[#1a1714] transition-all duration-300"> | |
| <i class="fas fa-house text-xs"></i> | |
| Início | |
| <span | |
| class="absolute left-4 bottom-1 w-0 h-[2px] bg-[#c8502a] rounded-full transition-all duration-300 group-hover:w-[55%]"></span> | |
| </a> | |
| </li> | |
| <li> | |
| <a href="#shop" | |
| class="group relative flex items-center gap-2 px-4 py-2 rounded-xl text-sm font-medium text-[#6b6560] hover:bg-white hover:text-[#1a1714] transition-all duration-300"> | |
| <i class="fas fa-store text-xs"></i> | |
| Loja | |
| <span | |
| class="absolute left-4 bottom-1 w-0 h-[2px] bg-[#c8502a] rounded-full transition-all duration-300 group-hover:w-[45%]"></span> | |
| </a> | |
| </li> | |
| <li> | |
| <a href="#" | |
| class="group relative flex items-center gap-2 px-4 py-2 rounded-xl text-sm font-medium text-[#6b6560] hover:bg-white hover:text-[#1a1714] transition-all duration-300"> | |
| <i class="fab fa-discord text-xs"></i> | |
| Discord | |
| <span | |
| class="absolute left-4 bottom-1 w-0 h-[2px] bg-[#c8502a] rounded-full transition-all duration-300 group-hover:w-[65%]"></span> | |
| </a> | |
| </li> | |
| </ul> | |
| <!-- Actions --> | |
| <div class="flex items-center gap-3"> | |
| <!-- Cart --> | |
| <a href="#" id="cart-toggle" aria-label="Abrir carrinho" | |
| class="group relative w-11 h-11 rounded-xl border border-[#e8e4df] bg-white flex items-center justify-center text-[#1a1714] shadow-sm hover:bg-[#1a1714] hover:border-[#1a1714] transition-all duration-300"> | |
| <i | |
| class="fas fa-bag-shopping text-lg transition-colors duration-300 group-hover:text-white"></i> | |
| <span id="cart-count" | |
| class="absolute -top-1 -right-1 min-w-5 h-5 px-1.5 bg-[#c8502a] text-white text-[0.65rem] rounded-full flex items-center justify-center font-bold border-2 border-white"> | |
| 0 | |
| </span> | |
| </a> | |
| <!-- Mobile Button --> | |
| <label for="menu-toggle" | |
| class="md:hidden w-11 h-11 rounded-xl border border-[#e8e4df] bg-white flex items-center justify-center cursor-pointer text-[#1a1714] hover:bg-[#f0ede8] transition-all duration-300"> | |
| <i class="fas fa-bars text-lg"></i> | |
| </label> | |
| </div> | |
| </div> | |
| <!-- Mobile Menu --> | |
| <div class="hidden peer-checked:block md:hidden border-t border-[#e8e4df] py-4"> | |
| <div class="flex flex-col gap-2"> | |
| <a href="#" | |
| class="flex items-center gap-3 px-4 py-3 rounded-xl text-sm font-medium text-[#6b6560] hover:bg-white hover:text-[#1a1714] transition-all"> | |
| <i class="fas fa-house w-4 text-center"></i> | |
| Início | |
| </a> | |
| <a href="#shop" | |
| class="flex items-center gap-3 px-4 py-3 rounded-xl text-sm font-medium text-[#6b6560] hover:bg-white hover:text-[#1a1714] transition-all"> | |
| <i class="fas fa-store w-4 text-center"></i> | |
| Loja | |
| </a> | |
| <a href="#" | |
| class="flex items-center gap-3 px-4 py-3 rounded-xl text-sm font-medium text-[#6b6560] hover:bg-white hover:text-[#1a1714] transition-all"> | |
| <i class="fab fa-discord w-4 text-center"></i> | |
| Discord | |
| </a> | |
| </div> | |
| </div> | |
| </div> | |
| </nav> | |
| <header id="hero" class="relative overflow-hidden py-20 md:py-28 px-4"> | |
| <!-- Background --> | |
| <div class="absolute inset-0 bg-gradient-to-b from-[#f8f7f4] via-[#faf8f6] to-[#f4f1ed] -z-10"></div> | |
| <!-- Blur Effects --> | |
| <div | |
| class="absolute top-[-120px] right-[-80px] w-[320px] h-[320px] bg-[#c8502a]/10 rounded-full blur-3xl -z-10"> | |
| </div> | |
| <div | |
| class="absolute bottom-[-100px] left-[-80px] w-[260px] h-[260px] bg-[#1a1714]/5 rounded-full blur-3xl -z-10"> | |
| </div> | |
| <div class="max-w-7xl mx-auto"> | |
| <div class="grid md:grid-cols-2 gap-14 items-center"> | |
| <!-- Left Content --> | |
| <div> | |
| <!-- Badge --> | |
| <div | |
| class="inline-flex items-center gap-2 px-4 py-2 bg-white border border-[#ebe5df] rounded-full mb-6 shadow-sm"> | |
| <span class="w-2 h-2 bg-[#c8502a] rounded-full animate-pulse"></span> | |
| <span class="text-sm font-medium text-[#4f4a46]"> | |
| Loja online • Entrega expressa | |
| </span> | |
| </div> | |
| <!-- Title --> | |
| <h1 class="text-4xl md:text-6xl leading-[1.05] font-bold tracking-tight text-[#1a1714] mb-6" | |
| style="font-family:'DM Serif Display', serif;"> | |
| Sua loja virtual | |
| <span class="block text-[#c8502a]"> | |
| moderna e completa | |
| </span> | |
| </h1> | |
| <!-- Description --> | |
| <p class="text-lg text-[#6b6560] leading-relaxed max-w-xl mb-8"> | |
| Produtos selecionados, preços acessíveis e uma experiência premium para quem busca | |
| qualidade, velocidade e praticidade. | |
| </p> | |
| <!-- Buttons --> | |
| <div class="flex flex-wrap gap-4 mb-10"> | |
| <!-- Produtos --> | |
| <a href="#shop" | |
| class="group inline-flex items-center gap-3 px-7 py-4 rounded-2xl bg-white border border-[#e8e4df] text-[#1a1714] font-semibold shadow-sm transition-all duration-300 hover:border-[#c8502a] hover:-translate-y-1 hover:shadow-lg"> | |
| <i | |
| class="fas fa-store transition-all duration-300 group-hover:scale-110 group-hover:text-[#c8502a]"></i> | |
| <span class="transition-colors duration-300 group-hover:text-[#c8502a]"> | |
| Ver produtos | |
| </span> | |
| </a> | |
| <!-- Discord --> | |
| <a href="#" | |
| class="group inline-flex items-center gap-3 px-7 py-4 rounded-2xl bg-white border border-[#e8e4df] text-[#1a1714] font-semibold shadow-sm transition-all duration-300 hover:border-[#c8502a] hover:-translate-y-1 hover:shadow-lg"> | |
| <i | |
| class="fab fa-discord transition-all duration-300 group-hover:scale-110 group-hover:text-[#c8502a]"></i> | |
| <span class="transition-colors duration-300 group-hover:text-[#c8502a]"> | |
| Discord | |
| </span> | |
| </a> | |
| </div> | |
| <!-- Stats --> | |
| <div class="flex flex-wrap gap-8"> | |
| <div> | |
| <strong class="block text-2xl font-bold text-[#1a1714]"> | |
| +12k | |
| </strong> | |
| <span class="text-sm text-[#6b6560]"> | |
| Clientes ativos | |
| </span> | |
| </div> | |
| <div> | |
| <strong class="block text-2xl font-bold text-[#1a1714]"> | |
| 24h | |
| </strong> | |
| <span class="text-sm text-[#6b6560]"> | |
| Entrega rápida | |
| </span> | |
| </div> | |
| <div> | |
| <strong class="block text-2xl font-bold text-[#1a1714]"> | |
| 4.9★ | |
| </strong> | |
| <span class="text-sm text-[#6b6560]"> | |
| Avaliação média | |
| </span> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="relative hidden md:block"> | |
| <!-- Fundo decorativo --> | |
| <div class="absolute -top-8 -right-8 w-40 h-40 bg-[#c8502a]/10 rounded-full blur-3xl"> | |
| </div> | |
| <!-- Container da imagem --> | |
| <div | |
| class="relative overflow-hidden rounded-[32px] shadow-[0_35px_80px_rgba(0,0,0,0.14)]"> | |
| <img src="https://blob.cabrapi.com.br/blob/808ff623-b490-414a-8b82-abeadeb87b0d/download" | |
| alt="Produto em destaque" | |
| class="w-full h-[540px] object-cover rounded-[32px] transition-transform duration-500 hover:scale-[1.03]" /> | |
| <!-- Overlay suave --> | |
| <div | |
| class="absolute inset-0 bg-gradient-to-t from-black/10 to-transparent rounded-[32px]"> | |
| </div> | |
| </div> | |
| <!-- Card flutuante --> | |
| <div | |
| class="absolute bottom-6 left-6 bg-white/95 backdrop-blur-md px-5 py-4 rounded-2xl shadow-[0_15px_40px_rgba(0,0,0,0.12)] flex items-center gap-4 border border-[#e8e4df]"> | |
| <div | |
| class="w-14 h-14 bg-[#fef3ec] rounded-2xl flex items-center justify-center flex-shrink-0 shadow-sm"> | |
| <i class="fas fa-bolt text-[#c8502a] text-xl"></i> | |
| </div> | |
| <div> | |
| <strong class="text-sm block text-[#1a1714] font-semibold"> | |
| Entrega instantânea | |
| </strong> | |
| <span class="text-xs text-[#6b6560]"> | |
| Receba em minutos | |
| </span> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </header> | |
| <section class="py-16 px-4 bg-white"> | |
| <div class="max-w-6xl mx-auto"> | |
| <div class="text-center mb-12"> | |
| <p class="text-[#c8502a] text-sm font-semibold uppercase tracking-wider mb-2"><i | |
| class="fas fa-shield-halved mr-2"></i> Diferenciais</p> | |
| <h2 class="text-3xl md:text-4xl font-bold mb-3" style="font-family:'DM Serif Display',serif;"> | |
| Por que comprar aqui?</h2> | |
| <p class="text-[#6b6560]">Segurança, rapidez e confiança em cada pedido</p> | |
| </div> | |
| <div class="grid sm:grid-cols-2 lg:grid-cols-4 gap-6"> | |
| <div class="bg-[#f8f7f4] p-6 rounded-2xl hover:shadow-lg transition-shadow"> | |
| <div class="w-14 h-14 bg-[#fef3ec] rounded-2xl flex items-center justify-center mb-4"><i | |
| class="fas fa-bolt text-[#c8502a] text-2xl"></i></div> | |
| <h3 class="font-bold mb-2">Entrega rápida</h3> | |
| <p class="text-sm text-[#6b6560]">Receba seu produto em minutos ou de forma totalmente | |
| automática após o pagamento.</p> | |
| </div> | |
| <div class="bg-[#f8f7f4] p-6 rounded-2xl hover:shadow-lg transition-shadow"> | |
| <div class="w-14 h-14 bg-[#fef3ec] rounded-2xl flex items-center justify-center mb-4"><i | |
| class="fas fa-lock text-[#c8502a] text-2xl"></i></div> | |
| <h3 class="font-bold mb-2">Pagamento seguro</h3> | |
| <p class="text-sm text-[#6b6560]">Transações protegidas com criptografia e validação em | |
| tempo real.</p> | |
| </div> | |
| <div class="bg-[#f8f7f4] p-6 rounded-2xl hover:shadow-lg transition-shadow"> | |
| <div class="w-14 h-14 bg-[#fef3ec] rounded-2xl flex items-center justify-center mb-4"><i | |
| class="fas fa-headset text-[#c8502a] text-2xl"></i></div> | |
| <h3 class="font-bold mb-2">Suporte ativo</h3> | |
| <p class="text-sm text-[#6b6560]">Atendimento ágil via Discord ou chat para qualquer | |
| dúvida ou problema.</p> | |
| </div> | |
| <div class="bg-[#f8f7f4] p-6 rounded-2xl hover:shadow-lg transition-shadow"> | |
| <div class="w-14 h-14 bg-[#fef3ec] rounded-2xl flex items-center justify-center mb-4"><i | |
| class="fas fa-tag text-[#c8502a] text-2xl"></i></div> | |
| <h3 class="font-bold mb-2">Melhor preço</h3> | |
| <p class="text-sm text-[#6b6560]">Produtos acessíveis com promoções constantes para | |
| economizar sempre.</p> | |
| </div> | |
| </div> | |
| </div> | |
| </section> | |
| <div class="max-w-6xl mx-auto px-4"> | |
| <div class="border-t border-[#e8e4df]"></div> | |
| </div> | |
| <section id="shop" class="py-16 px-4"> | |
| <div class="max-w-6xl mx-auto"> | |
| <div class="flex flex-col md:flex-row md:items-end justify-between mb-10 gap-4"> | |
| <div> | |
| <p class="text-[#c8502a] text-sm font-semibold uppercase tracking-wider mb-2"><i | |
| class="fas fa-store mr-2"></i> Catálogo</p> | |
| <h2 class="text-3xl md:text-4xl font-bold" style="font-family:'DM Serif Display',serif;"> | |
| Nossos produtos</h2> | |
| </div> | |
| </div> | |
| <div id="category-filters" class="flex flex-wrap gap-2 mb-8"></div> | |
| <div id="products-list"> | |
| <div class="text-center py-16 text-[#6b6560]"><i | |
| class="fas fa-spinner fa-spin text-3xl mb-4 block"></i> | |
| <p>Carregando produtos…</p> | |
| </div> | |
| </div> | |
| <div id="products-pagination"></div> | |
| </div> | |
| </section> | |
| <div class="max-w-6xl mx-auto px-4"> | |
| <div class="border-t border-[#e8e4df]"></div> | |
| </div> | |
| <section class="py-16 px-4"> | |
| <div class="max-w-6xl mx-auto"> | |
| <div class="text-center mb-12"> | |
| <p class="text-[#c8502a] text-sm font-semibold uppercase tracking-wider mb-2"><i | |
| class="fas fa-chart-line mr-2"></i> Resultados</p> | |
| <h2 class="text-3xl md:text-4xl font-bold mb-3" style="font-family:'DM Serif Display',serif;"> | |
| Transparência em números</h2> | |
| <p class="text-[#6b6560]">Dados reais de quem já comprou com a gente</p> | |
| </div> | |
| <div class="grid sm:grid-cols-2 lg:grid-cols-4 gap-6"> | |
| <div | |
| class="bg-white p-6 rounded-2xl border border-[#e8e4df] text-center hover:shadow-lg transition-shadow"> | |
| <div | |
| class="w-14 h-14 bg-[#f8f7f4] rounded-2xl flex items-center justify-center mx-auto mb-4"> | |
| <i class="fas fa-shopping-cart text-[#1a1714] text-2xl"></i> | |
| </div> | |
| <div class="text-3xl font-bold">+1.200</div> | |
| <div class="text-sm text-[#6b6560] mt-1">Vendas realizadas</div> | |
| </div> | |
| <div | |
| class="bg-white p-6 rounded-2xl border border-[#e8e4df] text-center hover:shadow-lg transition-shadow"> | |
| <div | |
| class="w-14 h-14 bg-[#f8f7f4] rounded-2xl flex items-center justify-center mx-auto mb-4"> | |
| <i class="fas fa-users text-[#1a1714] text-2xl"></i> | |
| </div> | |
| <div class="text-3xl font-bold">+500</div> | |
| <div class="text-sm text-[#6b6560] mt-1">Clientes ativos</div> | |
| </div> | |
| <div | |
| class="bg-white p-6 rounded-2xl border border-[#e8e4df] text-center hover:shadow-lg transition-shadow"> | |
| <div | |
| class="w-14 h-14 bg-[#f8f7f4] rounded-2xl flex items-center justify-center mx-auto mb-4"> | |
| <i class="fas fa-star text-[#1a1714] text-2xl"></i> | |
| </div> | |
| <div class="text-3xl font-bold">99%</div> | |
| <div class="text-sm text-[#6b6560] mt-1">Satisfação</div> | |
| </div> | |
| <div | |
| class="bg-white p-6 rounded-2xl border border-[#e8e4df] text-center hover:shadow-lg transition-shadow"> | |
| <div | |
| class="w-14 h-14 bg-[#f8f7f4] rounded-2xl flex items-center justify-center mx-auto mb-4"> | |
| <i class="fas fa-headset text-[#1a1714] text-2xl"></i> | |
| </div> | |
| <div class="text-3xl font-bold">24h</div> | |
| <div class="text-sm text-[#6b6560] mt-1">Suporte ativo</div> | |
| </div> | |
| </div> | |
| </div> | |
| </section> | |
| <div class="max-w-6xl mx-auto px-4"> | |
| <div class="border-t border-[#e8e4df]"></div> | |
| </div> | |
| <section class="py-16 px-4"> | |
| <div class="max-w-4xl mx-auto"> | |
| <div class="bg-[#1a1714] rounded-3xl p-10 md:p-14 text-center text-white relative overflow-hidden"> | |
| <div class="absolute inset-0 opacity-5" | |
| style="background-image:radial-gradient(circle at 20% 50%, #c8502a 1px, transparent 1px);background-size:30px 30px;"> | |
| </div> | |
| <p class="text-xs font-bold uppercase tracking-[0.2em] text-[#a09a94] mb-3 relative z-10"> | |
| Atendimento</p> | |
| <h2 class="text-3xl md:text-4xl font-bold mb-4 relative z-10" | |
| style="font-family:'DM Serif Display',serif;">Precisa de ajuda?</h2> | |
| <p class="text-[#a09a94] mb-8 max-w-lg mx-auto relative z-10">Fale com nosso suporte em segundos | |
| — estamos sempre disponíveis.</p> | |
| <a href="#" | |
| class="inline-flex items-center gap-2 px-6 py-3.5 bg-[#5865F2] text-white font-semibold rounded-xl hover:bg-[#4752C4] transition-all relative z-10 shadow-lg"><i | |
| class="fab fa-discord text-lg"></i> Abrir suporte no Discord</a> | |
| </div> | |
| </div> | |
| </section> | |
| <section class="py-16 px-4 bg-white"> | |
| <div class="max-w-3xl mx-auto"> | |
| <div class="text-center mb-12"> | |
| <p class="text-[#c8502a] text-sm font-semibold uppercase tracking-wider mb-2"><i | |
| class="fas fa-circle-question mr-2"></i> Dúvidas</p> | |
| <h2 class="text-3xl md:text-4xl font-bold mb-3" style="font-family:'DM Serif Display',serif;"> | |
| Perguntas frequentes</h2> | |
| <p class="text-[#6b6560]">As respostas que você precisa antes de comprar</p> | |
| </div> | |
| <div class="space-y-3"> | |
| <details class="group bg-[#f8f7f4] rounded-2xl p-5"> | |
| <summary class="flex items-center justify-between cursor-pointer list-none"><span | |
| class="font-semibold"><i | |
| class="fas fa-shopping-cart mr-3 text-[#6b6560]"></i>Como funciona a | |
| compra?</span><i | |
| class="fas fa-chevron-down text-[#6b6560] group-open:rotate-180 transition-transform"></i> | |
| </summary> | |
| <p class="mt-4 text-[#6b6560] text-sm leading-relaxed">Você escolhe o produto, finaliza o | |
| pagamento via PIX e recebe automaticamente as instruções ou acesso no seu e-mail | |
| logo após a confirmação.</p> | |
| </details> | |
| <details class="group bg-[#f8f7f4] rounded-2xl p-5"> | |
| <summary class="flex items-center justify-between cursor-pointer list-none"><span | |
| class="font-semibold"><i | |
| class="fas fa-shield-halved mr-3 text-[#6b6560]"></i>É seguro comprar | |
| aqui?</span><i | |
| class="fas fa-chevron-down text-[#6b6560] group-open:rotate-180 transition-transform"></i> | |
| </summary> | |
| <p class="mt-4 text-[#6b6560] text-sm leading-relaxed">Sim. Utilizamos sistemas seguros de | |
| pagamento e validação para proteger todas as transações. Seus dados são | |
| criptografados.</p> | |
| </details> | |
| <details class="group bg-[#f8f7f4] rounded-2xl p-5"> | |
| <summary class="flex items-center justify-between cursor-pointer list-none"><span | |
| class="font-semibold"><i class="fas fa-clock mr-3 text-[#6b6560]"></i>Quanto | |
| tempo demora para receber?</span><i | |
| class="fas fa-chevron-down text-[#6b6560] group-open:rotate-180 transition-transform"></i> | |
| </summary> | |
| <p class="mt-4 text-[#6b6560] text-sm leading-relaxed">A maioria das entregas é | |
| instantânea ou feita em poucos minutos após a confirmação do pagamento. Produtos | |
| físicos têm prazo estimado no momento da compra.</p> | |
| </details> | |
| <details class="group bg-[#f8f7f4] rounded-2xl p-5"> | |
| <summary class="flex items-center justify-between cursor-pointer list-none"><span | |
| class="font-semibold"><i class="fas fa-headset mr-3 text-[#6b6560]"></i>Como | |
| funciona o suporte?</span><i | |
| class="fas fa-chevron-down text-[#6b6560] group-open:rotate-180 transition-transform"></i> | |
| </summary> | |
| <p class="mt-4 text-[#6b6560] text-sm leading-relaxed">Oferecemos suporte via Discord e | |
| e-mail. Nossa equipe responde rapidamente durante todo o dia para resolver qualquer | |
| dúvida ou problema.</p> | |
| </details> | |
| <details class="group bg-[#f8f7f4] rounded-2xl p-5"> | |
| <summary class="flex items-center justify-between cursor-pointer list-none"><span | |
| class="font-semibold"><i | |
| class="fas fa-rotate-left mr-3 text-[#6b6560]"></i>Posso pedir | |
| reembolso?</span><i | |
| class="fas fa-chevron-down text-[#6b6560] group-open:rotate-180 transition-transform"></i> | |
| </summary> | |
| <p class="mt-4 text-[#6b6560] text-sm leading-relaxed">Sim, em casos de problema no | |
| produto ou não entrega. Entre em contato com nosso suporte e avaliaremos seu caso o | |
| mais rápido possível.</p> | |
| </details> | |
| </div> | |
| </div> | |
| </section> | |
| <div id="checkout" role="dialog" aria-modal="true" aria-label="Carrinho e pagamento" | |
| class="fixed inset-0 z-[300] bg-[#1a1714]/70 backdrop-blur-sm flex items-end md:items-center justify-center p-0 md:p-4 opacity-0 pointer-events-none transition-all duration-300"> | |
| <div id="checkout-panel" | |
| class="bg-white w-full max-w-[860px] rounded-t-3xl md:rounded-3xl max-h-[95vh] md:max-h-[92vh] overflow-y-auto p-4 md:p-8 pb-24 md:pb-8"> | |
| <div class="flex items-center justify-between mb-6 pb-5 border-b border-[#e8e4df]"> | |
| <div> | |
| <h2 class="text-xl font-bold"><i class="fas fa-bag-shopping mr-2"></i> Carrinho e | |
| pagamento</h2> | |
| <p class="text-[#6b6560] text-sm mt-1">Revise seu pedido e finalize via PIX em segundos. | |
| </p> | |
| </div> | |
| <button id="checkout-close" aria-label="Fechar carrinho" | |
| class="w-10 h-10 rounded-xl border border-[#e8e4df] flex items-center justify-center hover:bg-[#f8f7f4] transition-colors"><i | |
| class="fas fa-xmark"></i></button> | |
| </div> | |
| <div id="checkout-message" class="hidden p-3 rounded-xl text-sm mb-4"></div> | |
| <div class="grid md:grid-cols-2 gap-8"> | |
| <div> | |
| <p class="text-sm font-bold uppercase tracking-wider text-[#6b6560] mb-4"><i | |
| class="fas fa-receipt mr-2"></i> Resumo do pedido</p> | |
| <div id="checkout-items" class="flex flex-col gap-3"></div> | |
| <div class="flex justify-between items-center pt-5 mt-5 border-t border-[#e8e4df]"> | |
| <span class="font-semibold">Total</span> | |
| <strong id="checkout-total" class="text-2xl font-bold text-[#c8502a]">R$ | |
| 0,00</strong> | |
| </div> | |
| </div> | |
| <form id="checkout-form" novalidate class="flex flex-col gap-4"> | |
| <div class="flex flex-col gap-1.5"> | |
| <label for="checkout-name" class="text-sm font-semibold"><i | |
| class="fas fa-user mr-2 text-[#6b6560]"></i>Nome completo</label> | |
| <input id="checkout-name" name="name" placeholder="Seu nome completo" | |
| autocomplete="name" | |
| class="px-4 py-3.5 border border-[#e8e4df] rounded-xl focus:ring-2 focus:ring-[#c8502a] focus:border-transparent outline-none transition-all" /> | |
| <p id="checkout-name-error" class="hidden text-xs font-medium text-red-600"></p> | |
| </div> | |
| <div class="flex flex-col gap-1.5"> | |
| <label for="checkout-nickname" class="text-sm font-semibold"><i | |
| class="fas fa-at mr-2 text-[#6b6560]"></i>Nickname <span | |
| class="text-[#a09a94] font-normal">(opcional)</span></label> | |
| <input id="checkout-nickname" name="nickname" placeholder="Seu apelido" | |
| maxlength="32" autocomplete="nickname" | |
| class="px-4 py-3.5 border border-[#e8e4df] rounded-xl focus:ring-2 focus:ring-[#c8502a] focus:border-transparent outline-none transition-all" /> | |
| <p class="text-xs text-[#a09a94]">De 4 a 32 caracteres.</p> | |
| <p id="checkout-nickname-error" class="hidden text-xs font-medium text-red-600"></p> | |
| </div> | |
| <div class="flex flex-col gap-1.5"> | |
| <label for="checkout-email" class="text-sm font-semibold"><i | |
| class="fas fa-envelope mr-2 text-[#6b6560]"></i>E-mail</label> | |
| <input id="checkout-email" name="email" type="email" placeholder="voce@email.com" | |
| autocomplete="email" | |
| class="px-4 py-3.5 border border-[#e8e4df] rounded-xl focus:ring-2 focus:ring-[#c8502a] focus:border-transparent outline-none transition-all" /> | |
| <p id="checkout-email-error" class="hidden text-xs font-medium text-red-600"></p> | |
| </div> | |
| <div class="flex flex-col gap-1.5"> | |
| <label for="checkout-cpf" class="text-sm font-semibold"><i | |
| class="fas fa-id-card mr-2 text-[#6b6560]"></i>CPF <span | |
| class="text-[#a09a94] font-normal">(opcional)</span></label> | |
| <input id="checkout-cpf" name="cpf" placeholder="000.000.000-00" inputmode="numeric" | |
| maxlength="14" | |
| class="px-4 py-3.5 border border-[#e8e4df] rounded-xl focus:ring-2 focus:ring-[#c8502a] focus:border-transparent outline-none transition-all" /> | |
| <p id="checkout-cpf-error" class="hidden text-xs font-medium text-red-600"></p> | |
| </div> | |
| <div class="flex flex-col gap-1.5"> | |
| <label for="checkout-note" class="text-sm font-semibold"><i | |
| class="fas fa-comment mr-2 text-[#6b6560]"></i>Observação <span | |
| class="text-[#a09a94] font-normal">(opcional)</span></label> | |
| <textarea id="checkout-note" name="note" rows="2" placeholder="Algo a informar?" | |
| class="px-4 py-3.5 border border-[#e8e4df] rounded-xl focus:ring-2 focus:ring-[#c8502a] focus:border-transparent outline-none transition-all resize-none"></textarea> | |
| </div> | |
| <div class="flex flex-col gap-1.5"> | |
| <label for="checkout-coupon" class="text-sm font-semibold"><i | |
| class="fas fa-ticket mr-2 text-[#6b6560]"></i>Cupom <span | |
| class="text-[#a09a94] font-normal">(opcional)</span></label> | |
| <div class="flex gap-2"> | |
| <input id="checkout-coupon" name="coupon" placeholder="Ex: BEMVINDO10" | |
| class="flex-1 px-4 py-3.5 border border-[#e8e4df] rounded-xl focus:ring-2 focus:ring-[#c8502a] focus:border-transparent outline-none transition-all" /> | |
| <button id="checkout-apply-coupon" type="button" | |
| class="px-4 py-3 bg-white border border-[#e8e4df] text-[#1a1714] font-semibold rounded-xl hover:border-[#c8502a] hover:text-[#c8502a] disabled:opacity-60 transition-all whitespace-nowrap"> | |
| <i class="fas fa-ticket mr-2"></i> Aplicar | |
| </button> | |
| </div> | |
| <p id="checkout-coupon-status" class="hidden text-xs font-medium"></p> | |
| </div> | |
| <div class="flex flex-col gap-3"> | |
| <label class="text-sm font-semibold"><i | |
| class="fas fa-credit-card mr-2 text-[#6b6560]"></i>Forma de | |
| pagamento</label> | |
| <div class="grid grid-cols-2 gap-3"> | |
| <label class="cursor-pointer"> | |
| <input type="radio" name="payment_method" value="PIX" checked | |
| class="peer sr-only" /> | |
| <div | |
| class="p-3 border-2 border-[#e8e4df] rounded-xl peer-checked:border-[#c8502a] peer-checked:bg-[#fef3ec] hover:border-[#c8502a] transition-all text-center"> | |
| <i class="fas fa-qrcode text-xl text-[#6b6560]"></i> | |
| <p class="font-semibold text-xs mt-1">PIX</p> | |
| </div> | |
| </label> | |
| <label class="cursor-pointer"> | |
| <input type="radio" name="payment_method" value="CARD" | |
| class="peer sr-only" /> | |
| <div | |
| class="p-3 border-2 border-[#e8e4df] rounded-xl peer-checked:border-[#c8502a] peer-checked:bg-[#fef3ec] hover:border-[#c8502a] transition-all text-center"> | |
| <i class="fas fa-credit-card text-xl text-[#6b6560]"></i> | |
| <p class="font-semibold text-xs mt-1">Cartão</p> | |
| </div> | |
| </label> | |
| </div> | |
| </div> | |
| <button id="checkout-submit" type="submit" | |
| class="w-full py-3 bg-[#1a1714] text-white font-semibold rounded-lg hover:bg-[#c8502a] disabled:opacity-50 transition-all shadow-sm"><i | |
| class="fas fa-qrcode mr-2"></i> Pagar com PIX</button> | |
| </form> | |
| </div> | |
| <div id="checkout-result" class="hidden mt-6 pt-5 border-t border-[#e8e4df]"></div> | |
| </div> | |
| </div> | |
| <div id="pix-modal" role="dialog" aria-modal="true" aria-label="Pagamento PIX" | |
| class="fixed inset-0 z-[400] bg-[#1a1714]/80 backdrop-blur-sm flex items-end md:items-center justify-center p-0 md:p-4 opacity-0 pointer-events-none transition-all duration-300"> | |
| <div id="pix-modal-panel" | |
| class="bg-white w-full max-w-sm rounded-t-3xl md:rounded-2xl p-6 md:p-8 text-center pb-20 md:pb-8"> | |
| </div> | |
| </div> | |
| <div id="card-modal" role="dialog" aria-modal="true" aria-label="Pagamento Cartão" | |
| class="fixed inset-0 z-[400] bg-[#1a1714]/80 backdrop-blur-sm flex items-end md:items-center justify-center p-0 md:p-4 opacity-0 pointer-events-none transition-all duration-300"> | |
| <div id="card-modal-panel" | |
| class="bg-white w-full max-w-sm rounded-t-3xl md:rounded-2xl p-6 md:p-8 text-center pb-20 md:pb-8"> | |
| </div> | |
| </div> | |
| <footer class="bg-[#1a1714] text-white py-12 px-4 mt-auto"> | |
| <div class="max-w-6xl mx-auto"> | |
| <div class="flex flex-col md:flex-row justify-between items-center gap-8"> | |
| <div class="flex flex-col items-center md:items-start gap-4"> | |
| <a href="#" class="text-lg font-semibold">Loja <span | |
| class="text-[#c8502a]">Virtual</span></a> | |
| <div | |
| class="flex flex-wrap justify-center md:justify-start gap-4 md:gap-6 text-sm text-[#a09a94]"> | |
| <a href="#" class="hover:text-white transition-colors"><i | |
| class="fas fa-house mr-1"></i> Início</a> | |
| <a href="#shop" class="hover:text-white transition-colors"><i | |
| class="fas fa-store mr-1"></i> Loja</a> | |
| <a href="#" class="hover:text-[#5865F2] transition-all"><i | |
| class="fab fa-discord mr-1"></i> Discord</a> | |
| </div> | |
| </div> | |
| <div class="flex gap-3"> | |
| <a href="#" aria-label="Instagram" | |
| class="w-10 h-10 bg-white/10 rounded-lg flex items-center justify-center text-[#a09a94] hover:text-white hover:bg-white/20 transition-all"><i | |
| class="fab fa-instagram"></i></a> | |
| <a href="#" aria-label="YouTube" | |
| class="w-10 h-10 bg-white/10 rounded-lg flex items-center justify-center text-[#a09a94] hover:text-white hover:bg-white/20 transition-all"><i | |
| class="fab fa-youtube"></i></a> | |
| <a href="#" aria-label="TikTok" | |
| class="w-10 h-10 bg-white/10 rounded-lg flex items-center justify-center text-[#a09a94] hover:text-white hover:bg-white/20 transition-all"><i | |
| class="fab fa-tiktok"></i></a> | |
| <a href="#" aria-label="Discord" | |
| class="w-10 h-10 bg-white/10 rounded-lg flex items-center justify-center text-[#a09a94] hover:text-[#5865F2] hover:bg-white/20 transition-all"><i | |
| class="fab fa-discord"></i></a> | |
| </div> | |
| </div> | |
| <div | |
| class="flex flex-col md:flex-row justify-between items-center gap-3 pt-6 mt-6 border-t border-white/10 text-sm text-[#a09a94]"> | |
| <span>© 2026 Loja Virtual · Todos os direitos reservados</span> | |
| <div class="flex items-center gap-2"><i class="fas fa-code text-xs"></i><span>Powered | |
| by</span><span class="text-[#c8502a] font-semibold">caBRAPI</span></div> | |
| </div> | |
| </div> | |
| </footer> | |
| </body> | |
| </html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment