anycoder-e74f9146 / index.html
Lucasrds's picture
Upload folder using huggingface_hub
84a8c4d verified
Raw
History Blame Contribute Delete
34.3 kB
<!DOCTYPE html>
<html lang="pt-BR">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Obramax Flyer Gen - Gerador de Flyers de Promoções</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js"></script>
<style>
:root {
--primary: #e63946;
--secondary: #f4a261;
--accent: #2a9d8f;
--dark: #1d3557;
--light: #f1faee;
--bg: #f8f9fa;
--glass: rgba(255, 255, 255, 0.85);
--shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
--radius: 16px;
--transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', system-ui, -apple-system, sans-serif;
background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
min-height: 100vh;
color: var(--dark);
}
/* Header */
.header {
background: linear-gradient(90deg, var(--dark) 0%, #2c3e50 100%);
color: white;
padding: 1rem 2rem;
display: flex;
justify-content: space-between;
align-items: center;
box-shadow: 0 4px 20px rgba(0,0,0,0.15);
position: sticky;
top: 0;
z-index: 100;
flex-wrap: wrap;
gap: 1rem;
}
.header-brand {
display: flex;
align-items: center;
gap: 12px;
font-size: 1.5rem;
font-weight: 800;
letter-spacing: -0.5px;
}
.header-brand i {
color: var(--secondary);
font-size: 1.8rem;
}
.header-link {
color: rgba(255,255,255,0.85);
text-decoration: none;
font-size: 0.85rem;
font-weight: 500;
padding: 6px 12px;
border: 1px solid rgba(255,255,255,0.3);
border-radius: 20px;
transition: var(--transition);
}
.header-link:hover {
background: rgba(255,255,255,0.15);
color: white;
transform: translateY(-1px);
}
/* Layout Principal */
.app-container {
display: grid;
grid-template-columns: 380px 1fr;
max-width: 1400px;
margin: 2rem auto;
padding: 0 1.5rem;
gap: 2rem;
min-height: calc(100vh - 100px);
}
/* Painel de Controle */
.controls-panel {
background: var(--glass);
backdrop-filter: blur(12px);
-webkit-backdrop-filter: blur(12px);
border-radius: var(--radius);
padding: 1.5rem;
box-shadow: var(--shadow);
border: 1px solid rgba(255,255,255,0.5);
height: fit-content;
position: sticky;
top: 90px;
overflow-y: auto;
max-height: calc(100vh - 110px);
}
.panel-title {
font-size: 1.25rem;
font-weight: 700;
margin-bottom: 1.5rem;
display: flex;
align-items: center;
gap: 8px;
color: var(--dark);
padding-bottom: 0.75rem;
border-bottom: 2px solid var(--secondary);
}
.form-group {
margin-bottom: 1.25rem;
}
.form-group label {
display: block;
font-weight: 600;
font-size: 0.85rem;
margin-bottom: 0.5rem;
color: var(--dark);
opacity: 0.9;
}
.form-control {
width: 100%;
padding: 0.75rem 1rem;
border: 2px solid #e2e8f0;
border-radius: 10px;
font-family: inherit;
font-size: 0.9rem;
transition: var(--transition);
background: rgba(255,255,255,0.9);
}
.form-control:focus {
outline: none;
border-color: var(--accent);
box-shadow: 0 0 0 3px rgba(42, 157, 143, 0.15);
}
input[type="color"].form-control {
height: 42px;
padding: 4px;
cursor: pointer;
}
.color-row {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 1rem;
}
.btn {
display: inline-flex;
align-items: center;
justify-content: center;
gap: 8px;
padding: 0.75rem 1.25rem;
border: none;
border-radius: 10px;
font-family: inherit;
font-weight: 600;
font-size: 0.9rem;
cursor: pointer;
transition: var(--transition);
}
.btn-primary {
background: linear-gradient(135deg, var(--primary), #d62839);
color: white;
box-shadow: 0 4px 15px rgba(230, 57, 70, 0.3);
width: 100%;
margin-top: 0.5rem;
}
.btn-primary:hover {
transform: translateY(-2px);
box-shadow: 0 6px 20px rgba(230, 57, 70, 0.4);
}
.btn-secondary {
background: linear-gradient(135deg, var(--dark), #2c3e50);
color: white;
width: 100%;
margin-top: 1rem;
padding: 1rem;
font-size: 1rem;
}
.btn-secondary:hover {
transform: translateY(-2px);
box-shadow: 0 6px 20px rgba(29, 53, 87, 0.3);
}
.btn-small {
padding: 0.4rem 0.8rem;
font-size: 0.8rem;
background: var(--primary);
color: white;
border-radius: 6px;
}
.btn-danger {
background: #e63946;
color: white;
padding: 0.4rem;
border-radius: 6px;
width: 32px;
height: 32px;
}
/* Lista de Produtos no Painel */
.products-list {
display: flex;
flex-direction: column;
gap: 1rem;
margin-top: 1rem;
}
.product-editor {
background: white;
border: 2px solid #edf2f7;
border-radius: 12px;
padding: 1rem;
position: relative;
transition: var(--transition);
}
.product-editor:hover {
border-color: var(--secondary);
box-shadow: 0 4px 12px rgba(0,0,0,0.05);
}
.product-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 0.75rem;
}
.product-header span {
font-weight: 700;
font-size: 0.85rem;
color: var(--dark);
}
.product-fields {
display: grid;
gap: 0.5rem;
}
.layout-selector {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 0.75rem;
margin-top: 0.5rem;
}
.layout-option {
border: 2px solid #e2e8f0;
border-radius: 10px;
padding: 0.75rem;
text-align: center;
cursor: pointer;
transition: var(--transition);
background: white;
}
.layout-option.active {
border-color: var(--accent);
background: rgba(42, 157, 143, 0.05);
color: var(--accent);
}
.layout-option:hover:not(.active) {
border-color: #cbd5e0;
}
.layout-option i {
font-size: 1.25rem;
margin-bottom: 4px;
display: block;
}
.layout-option span {
font-size: 0.75rem;
font-weight: 600;
}
/* Preview Area */
.preview-area {
display: flex;
flex-direction: column;
align-items: center;
gap: 1.5rem;
}
.preview-wrapper {
background: white;
padding: 2rem;
border-radius: var(--radius);
box-shadow: var(--shadow);
width: 100%;
max-width: 600px;
display: flex;
justify-content: center;
align-items: flex-start;
position: relative;
overflow: hidden;
}
/* O Flyer em si */
#flyer-canvas {
width: 100%;
max-width: 550px;
aspect-ratio: 3/4;
background: white;
position: relative;
overflow: hidden;
box-shadow: 0 20px 60px rgba(0,0,0,0.15);
display: flex;
flex-direction: column;
}
/* Flyer Header */
.flyer-header {
padding: 2rem;
text-align: center;
position: relative;
overflow: hidden;
}
.flyer-header::before {
content: '';
position: absolute;
top: -50%;
left: -50%;
width: 200%;
height: 200%;
background: radial-gradient(circle, rgba(255,255,255,0.2) 0%, transparent 60%);
pointer-events: none;
}
.flyer-logo {
font-size: 2rem;
font-weight: 900;
letter-spacing: 2px;
margin-bottom: 0.5rem;
position: relative;
z-index: 1;
text-transform: uppercase;
}
.flyer-title {
font-size: 2.5rem;
font-weight: 900;
margin-bottom: 0.5rem;
position: relative;
z-index: 1;
line-height: 1.1;
text-transform: uppercase;
letter-spacing: -1px;
}
.flyer-subtitle {
font-size: 1.1rem;
font-weight: 600;
opacity: 0.95;
position: relative;
z-index: 1;
}
/* Flyer Body */
.flyer-body {
flex: 1;
padding: 1.5rem;
display: grid;
gap: 1rem;
align-content: start;
overflow: hidden;
}
.flyer-body.grid-layout {
grid-template-columns: repeat(2, 1fr);
}
.flyer-body.list-layout {
grid-template-columns: 1fr;
}
/* Product Card */
.flyer-product {
background: white;
border-radius: 12px;
overflow: hidden;
box-shadow: 0 4px 15px rgba(0,0,0,0.08);
display: flex;
flex-direction: column;
position: relative;
border: 2px solid transparent;
transition: transform 0.2s;
}
.grid-layout .flyer-product {
aspect-ratio: 1/1.2;
}
.list-layout .flyer-product {
flex-direction: row;
align-items: center;
height: 120px;
}
.flyer-product:hover {
transform: scale(1.02);
}
.product-badge {
position: absolute;
top: 8px;
right: 8px;
background: #e63946;
color: white;
font-weight: 800;
font-size: 0.75rem;
padding: 4px 8px;
border-radius: 20px;
z-index: 2;
box-shadow: 0 2px 8px rgba(0,0,0,0.15);
}
.product-image {
width: 100%;
height: 60%;
object-fit: cover;
background: #f1f5f9;
display: flex;
align-items: center;
justify-content: center;
color: #94a3b8;
font-size: 2.5rem;
}
.list-layout .product-image {
width: 120px;
height: 100%;
}
.product-info {
padding: 0.75rem;
flex: 1;
display: flex;
flex-direction: column;
justify-content: center;
}
.product-name {
font-weight: 700;
font-size: 0.9rem;
color: #1e293b;
margin-bottom: 0.25rem;
line-height: 1.2;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
}
.list-layout .product-name {
font-size: 1.1rem;
-webkit-line-clamp: 1;
}
.prices {
display: flex;
align-items: baseline;
gap: 0.5rem;
flex-wrap: wrap;
}
.old-price {
text-decoration: line-through;
color: #94a3b8;
font-size: 0.8rem;
}
.new-price {
font-size: 1.3rem;
font-weight: 900;
color: #e63946;
}
.list-layout .new-price {
font-size: 1.5rem;
}
.discount-tag {
display: inline-block;
background: #dcfce7;
color: #166534;
font-size: 0.7rem;
font-weight: 700;
padding: 2px 6px;
border-radius: 4px;
}
/* Flyer Footer */
.flyer-footer {
padding: 1.25rem;
text-align: center;
font-weight: 700;
color: white;
font-size: 1rem;
position: relative;
}
.flyer-footer::before {
content: '';
position: absolute;
inset: 0;
background: url("data:image/svg+xml,%3Csvg width='20' height='20' viewBox='0 0 20 20' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='%23ffffff' fill-opacity='0.1' fill-rule='evenodd'%3E%3Ccircle cx='3' cy='3' r='3'/%3E%3Ccircle cx='13' cy='13' r='3'/%3E%3C/g%3E%3C/svg%3E");
opacity: 0.3;
}
.flyer-footer span {
position: relative;
z-index: 1;
}
/* Decorative elements */
.deco-circle {
position: absolute;
border-radius: 50%;
opacity: 0.15;
pointer-events: none;
}
/* Responsividade */
@media (max-width: 968px) {
.app-container {
grid-template-columns: 1fr;
max-width: 700px;
}
.controls-panel {
position: relative;
top: 0;
max-height: none;
order: 2;
}
.preview-area {
order: 1;
}
#flyer-canvas {
max-width: 100%;
}
}
@media (max-width: 480px) {
.header {
padding: 1rem;
}
.header-brand {
font-size: 1.2rem;
}
.preview-wrapper {
padding: 1rem;
}
.flyer-title {
font-size: 1.8rem;
}
.flyer-header {
padding: 1.5rem;
}
.flyer-body {
padding: 1rem;
}
}
/* Loading e Toast */
.toast {
position: fixed;
bottom: 2rem;
right: 2rem;
background: var(--dark);
color: white;
padding: 1rem 1.5rem;
border-radius: 12px;
box-shadow: 0 10px 30px rgba(0,0,0,0.2);
transform: translateY(150%);
transition: transform 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275);
z-index: 1000;
font-weight: 600;
display: flex;
align-items: center;
gap: 0.75rem;
}
.toast.show {
transform: translateY(0);
}
.loading-overlay {
position: absolute;
inset: 0;
background: rgba(255,255,255,0.9);
display: flex;
align-items: center;
justify-content: center;
z-index: 50;
border-radius: var(--radius);
opacity: 0;
pointer-events: none;
transition: opacity 0.3s;
}
.loading-overlay.active {
opacity: 1;
pointer-events: all;
}
.spinner {
width: 40px;
height: 40px;
border: 4px solid #e2e8f0;
border-top-color: var(--accent);
border-radius: 50%;
animation: spin 0.8s linear infinite;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
/* Scrollbar customizada */
.controls-panel::-webkit-scrollbar {
width: 6px;
}
.controls-panel::-webkit-scrollbar-track {
background: transparent;
}
.controls-panel::-webkit-scrollbar-thumb {
background-color: #cbd5e0;
border-radius: 20px;
}
/* Animations */
@keyframes float {
0%, 100% { transform: translateY(0px); }
50% { transform: translateY(-10px); }
}
.animate-float {
animation: float 6s ease-in-out infinite;
}
.section-divider {
height: 1px;
background: linear-gradient(90deg, transparent, #e2e8f0, transparent);
margin: 1.5rem 0;
}
</style>
</head>
<body>
<header class="header">
<div class="header-brand">
<i class="fa-solid fa-bullhorn"></i>
<span>Obramax Flyer Gen</span>
</div>
<a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank" class="header-link">
<i class="fa-solid fa-code"></i> Built with anycoder
</a>
</header>
<main class="app-container">
<!-- Painel de Controles -->
<aside class="controls-panel">
<div class="panel-title">
<i class="fa-solid fa-sliders"></i>
Configurações do Flyer
</div>
<div class="form-group">
<label>Título da Promoção</label>
<input type="text" class="form-control" id="input-title" value="MEGA PROMOÇÃO" maxlength="25">
</div>
<div class="form-group">
<label>Subtítulo / Descrição</label>
<input type="text" class="form-control" id="input-subtitle" value="Ofertas imperdíveis para você!" maxlength="40">
</div>
<div class="form-group">
<label>Validade da Oferta</label>
<input type="text" class="form-control" id="input-validity" value="Válido até 30/12/2024" maxlength="30">
</div>
<div class="color-row">
<div class="form-group" style="margin-bottom:0">
<label>Cor Principal</label>
<input type="color" class="form-control" id="input-primary" value="#e63946">
</div>
<div class="form-group" style="margin-bottom:0">
<label>Cor Secundária</label>
<input type="color" class="form-control" id="input-secondary" value="#f4a261">
</div>
</div>
<div class="section-divider"></div>
<div class="form-group">
<label>Layout dos Produtos</label>
<div class="layout-selector">
<div class="layout-option active" data-layout="grid" onclick="setLayout('grid')">
<i class="fa-solid fa-border-all"></i>
<span>Grade</span>
</div>
<div class="layout-option" data-layout="list" onclick="setLayout('list')">
<i class="fa-solid fa-list"></i>
<span>Lista</span>
</div>
</div>
</div>
<div class="section-divider"></div>
<div style="display:flex; justify-content:space-between; align-items:center; margin-bottom:0.5rem">
<label style="margin:0">Produtos</label>
<span style="font-size:0.8rem; color:#64748b" id="product-count">3/6</span>
</div>
<div class="products-list" id="products-list">
<!-- Produtos inseridos via JS -->
</div>
<button class="btn btn-primary" onclick="addProduct()" id="btn-add-product">
<i class="fa-solid fa-plus"></i> Adicionar Produto
</button>
<div class="section-divider"></div>
<button class="btn btn-secondary" onclick="downloadFlyer()">
<i class="fa-solid fa-download"></i> Baixar Flyer (PNG)
</button>
</aside>
<!-- Área de Preview -->
<section class="preview-area">
<div class="preview-wrapper" id="preview-wrapper">
<div class="loading-overlay" id="loading-overlay">
<div class="spinner"></div>
</div>
<!-- O Flyer -->
<div id="flyer-canvas">
<div class="flyer-header" id="flyer-header">
<div class="deco-circle animate-float" style="width:120px;height:120px;background:white;top:-20px;left:-20px;"></div>
<div class="deco-circle" style="width:80px;height:80px;background:white;opacity:0.1;bottom:10px;right:20px;"></div>
<div class="flyer-logo">obramax.com.br</div>
<div class="flyer-title" id="flyer-title">MEGA PROMOÇÃO</div>
<div class="flyer-subtitle" id="flyer-subtitle">Ofertas imperdíveis para você!</div>
</div>
<div class="flyer-body grid-layout" id="flyer-body">
<!-- Produtos no flyer -->
</div>
<div class="flyer-footer" id="flyer-footer">
<span><i class="fa-solid fa-clock" style="margin-right:6px"></i> <span id="flyer-validity">Válido até 30/12/2024</span></span>
</div>
</div>
</div>
<p style="color:#64748b; font-size:0.85rem; text-align:center; max-width:500px">
<i class="fa-solid fa-circle-info"></i> O preview atualiza automaticamente. Clique em "Baixar Flyer" para exportar em alta resolução.
</p>
</section>
</main>
<div class="toast" id="toast">
<i class="fa-solid fa-check-circle"></i>
<span id="toast-message">Flyer baixado com sucesso!</span>
</div>
<script>
// Estado da aplicação
const state = {
title: 'MEGA PROMOÇÃO',
subtitle: 'Ofertas imperdíveis para você!',
validity: 'Válido até 30/12/2024',
primary: '#e63946',
secondary: '#f4a261',
layout: 'grid',
products: [
{ id: 1, name: 'Cimento CP II 50kg', oldPrice: 'R$ 39,90', newPrice: 'R$ 29,90', image: 'https://images.unsplash.com/photo-1530124566582-a618bc2615dc?w=400&h=400&fit=crop' },
{ id: 2, name: 'Tinta Acrílica 18L', oldPrice: 'R$ 189,00', newPrice: 'R$ 149,00', image: 'https://images.unsplash.com/photo-1589939705384-5185137a7f0f?w=400&h=400&fit=crop' },
{ id: 3, name: 'Furadeira 650W', oldPrice: 'R$ 259,00', newPrice: 'R$ 199,00', image: 'https://images.unsplash.com/photo-1504148455328-c376907d081c?w=400&h=400&fit=crop' }
]
};
let nextId = 4;
// Referências DOM
const els = {
inputTitle: document.getElementById('input-title'),
inputSubtitle: document.getElementById('input-subtitle'),
inputValidity: document.getElementById('input-validity'),
inputPrimary: document.getElementById('input-primary'),
inputSecondary: document.getElementById('input-secondary'),
productsList: document.getElementById('products-list'),
flyerTitle: document.getElementById('flyer-title'),
flyerSubtitle: document.getElementById('flyer-subtitle'),
flyerValidity: document.getElementById('flyer-validity'),
flyerBody: document.getElementById('flyer-body'),
flyerHeader: document.getElementById('flyer-header'),
flyerFooter: document.getElementById('flyer-footer'),
toast: document.getElementById('toast'),
toastMsg: document.getElementById('toast-message'),
loading: document.getElementById('loading-overlay'),
productCount: document.getElementById('product-count'),
btnAdd: document.getElementById('btn-add-product')
};
// Inicialização
function init() {
bindEvents();
renderProductEditors();
updateFlyer();
}
function bindEvents() {
els.inputTitle.addEventListener('input', (e) => { state.title = e.target.value; updateFlyer(); });
els.inputSubtitle.addEventListener('input', (e) => { state.subtitle = e.target.value; updateFlyer(); });
els.inputValidity.addEventListener('input', (e) => { state.validity = e.target.value; updateFlyer(); });
els.inputPrimary.addEventListener('input', (e) => { state.primary = e.target.value; updateFlyer(); });
els.inputSecondary.addEventListener('input', (e) => { state.secondary = e.target.value; updateFlyer(); });
}
function setLayout(layout) {
state.layout = layout;
document.querySelectorAll('.layout-option').forEach(el => {
el.classList.toggle('active', el.dataset.layout === layout);
});
updateFlyer();
}
function addProduct() {
if (state.products.length >= 6) {
showToast('Limite máximo de 6 produtos atingido!', 'warning');
return;
}
state.products.push({
id: nextId++,
name: 'Novo Produto',
oldPrice: 'R$ 0,00',
newPrice: 'R$ 0,00',
image: ''
});
renderProductEditors();
updateFlyer();
}
function removeProduct(id) {
if (state.products.length <= 1) {
showToast('Adicione pelo menos 1 produto!', 'warning');
return;
}
state.products = state.products.filter(p => p.id !== id);
renderProductEditors();
updateFlyer();
}
function updateProduct(id, field, value) {
const product = state.products.find(p => p.id === id);
if (product) {
product[field] = value;
updateFlyer();
}
}
function renderProductEditors() {
els.productsList.innerHTML = '';
els.productCount.textContent = `${state.products.length}/6`;
els.btnAdd.disabled = state.products.length >= 6;
els.btnAdd.style.opacity = state.products.length >= 6 ? '0.5' : '1';
state.products.forEach((p, index) => {
const div = document.createElement('div');
div.className = 'product-editor';
div.innerHTML = `
<div class="product-header">
<span><i class="fa-solid fa-tag" style="color:var(--secondary); margin-right:4px"></i> Produto ${index + 1}</span>
<button class="btn btn-danger" onclick="removeProduct(${p.id})" title="Remover">
<i class="fa-solid fa-trash"></i>
</button>
</div>
<div class="product-fields">
<input type="text" class="form-control" placeholder="Nome do produto" value="${p.name}"
oninput="updateProduct(${p.id}, 'name', this.value)" maxlength="30">
<div style="display:grid; grid-template-columns: 1fr 1fr; gap:0.5rem">
<input type="text" class="form-control" placeholder="Preço antigo" value="${p.oldPrice}"
oninput="updateProduct(${p.id}, 'oldPrice', this.value)">
<input type="text" class="form-control" placeholder="Preço novo" value="${p.newPrice}"
oninput="updateProduct(${p.id}, 'newPrice', this.value)">
</div>
<input type="text" class="form-control" placeholder="URL da imagem (opcional)" value="${p.image}"
oninput="updateProduct(${p.id}, 'image', this.value)">
</div>
`;
els.productsList.appendChild(div);
});
}
function calcDiscount(oldP, newP) {
try {
const oldVal = parseFloat(oldP.replace(/[^0-9,]/g, '').replace(',', '.'));
const newVal = parseFloat(newP.replace(/[^0-9,]/g, '').replace(',', '.'));
if (oldVal && newVal && oldVal > newVal) {
return Math.round((1 - newVal / oldVal) * 100) + '% OFF';
}
} catch(e) {}
return '';
}
function updateFlyer() {
// Atualizar textos
els.flyerTitle.textContent = state.title || 'PROMOÇÃO';
els.flyerSubtitle.textContent = state.subtitle;
els.flyerValidity.textContent = state.validity;
// Aplicar cores
els.flyerHeader.style.background = `linear-gradient(135deg, ${state.primary}, ${state.secondary})`;
els.flyerHeader.style.color = 'white';
els.flyerFooter.style.background = state.dark || '#1d3557';
els.flyerFooter.style.background = `linear-gradient(90deg, ${state.primary}, ${adjustColor(state.primary, -20)})`;
// Layout
els.flyerBody.className = `flyer-body ${state.layout}-layout`;
// Renderizar produtos no flyer
els.flyerBody.innerHTML = state.products.map(p => {
const discount = calcDiscount(p.oldPrice, p.newPrice);
const imgContent = p.image
? `<img src="${p.image}" class="product-image" alt="" onerror="this.style.display='none'; this.nextElementSibling.style.display='flex';">
<div class="product-image" style="display:none"><i class="fa-solid fa-box-open"></i></div>`
: `<div class="product-image"><i class="fa-solid fa-box-open"></i></div>`;
return `
<div class="flyer-product">
${discount ? `<div class="product-badge">${discount}</div>` : ''}
${imgContent}
<div class="product-info">
<div class="product-name">${p.name}</div>
<div class="prices">
<span class="old-price">${p.oldPrice}</span>
<span class="new-price">${p.newPrice}</span>
</div>
</div>
</div>
`;
}).join('');
}
function adjustColor(hex, amount) {
// Função simples para escurecer/clarear cor hex
let color = hex.replace('#', '');
if (color.length === 3) color = color.split('').map(c => c+c).join('');
const num = parseInt(color, 16);
let r = (num >> 16) + amount;
let g = ((num >> 8) & 0x00FF) + amount;
let b = (num & 0x00FF) + amount;
r = r < 0 ? 0 : r > 255 ? 255 : r;
g = g < 0 ? 0 : g > 255 ? 255 : g;
b = b < 0 ? 0 : b > 255 ? 255 : b;
return `rgb(${r},${g},${b})`;
}
async function downloadFlyer() {
els.loading.classList.add('active');
try {
const canvas = await html2canvas(document.getElementById('flyer-canvas'), {
scale: 2,
useCORS: true,
allowTaint: true,
backgroundColor: '#ffffff',
logging: false
});
const link = document.createElement('a');
link.download = `obramax-flyer-${Date.now()}.png`;
link.href = canvas.toDataURL('image/png');
link.click();
showToast('Flyer baixado com sucesso!');
} catch (err) {
console.error(err);
showToast('Erro ao gerar imagem. Tente novamente.', 'error');
} finally {
setTimeout(() => els.loading.classList.remove('active'), 500);
}
}
function showToast(msg, type = 'success') {
els.toastMsg.textContent = msg;
const icon = els.toast.querySelector('i');
if (type === 'error') {
icon.className = 'fa-solid fa-circle-xmark';
els.toast.style.background = '#e63946';
} else if (type === 'warning') {
icon.className = 'fa-solid fa-triangle-exclamation';
els.toast.style.background = '#f4a261';
} else {
icon.className = 'fa-solid fa-check-circle';
els.toast.style.background = '#1d3557';
}
els.toast.classList.add('show');
setTimeout(() => els.toast.classList.remove('show'), 3000);
}
// Iniciar app
init();
</script>
</body>
</html>