E-commerce completo de cosméticos e beleza com vitrine interativa, carrinho de compras, painel administrativo e integração com Supabase. Produtos veganos e cruelty-free.
Produtos organizados em categorias (Maquiagem, Skincare, Perfumes, Kits) com busca e filtros dinâmicos.
Carrinho lateral com controle de quantidade, cálculo de frete grátis acima de R$ 199 e notificação via WhatsApp.
Login seguro com hash SHA-256, dashboard com estatísticas, CRUD completo de produtos e gerenciamento de pedidos.
Schema SQL preparado com tabelas products, orders e profiles, Row Level Security e trigger de auto-cadastro.
Sistema de registro/login com dashboard de histórico de pedidos e dados persistentes em localStorage.
Tema rosa elegante com Tailwind CSS, animações CSS, confetti e layout adaptável para mobile/tablet/desktop.
<!-- Ashley Makeup — Loja Virtual de Cosméticos -->
<!DOCTYPE html>
<html lang="pt-BR">
<head>
<meta charset="UTF-8">
<title>Ashley Makeup</title>
<link href="https://fonts.googleapis.com/css2?family=Playfair+Display:wght@400;500;600;700&family=Poppins:wght@300;400;500;600;700&display=swap" rel="stylesheet">
<script src="https://cdn.tailwindcss.com"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.0/css/all.min.css">
</head>
<body>
<!-- ══ HEADER com logo, busca, icones e navegação ══ -->
<header class="bg-white shadow-sm sticky top-0 z-50">
<div class="max-w-7xl mx-auto px-4 sm:px-6">
<!-- Linha superior: Logo + Busca + Ícones -->
<div class="flex items-center justify-between py-3">
<div class="flex items-center gap-3">
<button onclick="toggleMobileMenu()">
<i class="fas fa-bars text-xl"></i>
</button>
<img src="logo.png" alt="Ashley Makeup" class="h-8 md:h-10">
</div>
<!-- Busca (desktop) -->
<div class="hidden md:block flex-1 max-w-md mx-8">
<input type="text" placeholder="Buscar produtos...">
</div>
<!-- Ícones: Favoritos, Conta, Sacola -->
<div class="flex items-center gap-4">
<button><i class="far fa-heart"></i></button>
<button onclick="openAccount()"><i class="fas fa-user"></i></button>
<button onclick="toggleCart()" class="relative">
<i class="fas fa-shopping-bag text-xl"></i>
<span id="cart-count">0</span>
</button>
</div>
</div>
<!-- Navegação por categorias -->
<nav class="hidden md:block border-t">
<ul>
<li><a>Lançamentos</a></li>
<li><a>Maquiagem</a></li>
<li><a>Skincare</a></li>
<li><a>Kits & Presentes</a></li>
</ul>
</nav>
</div>
</header>
<!-- ══ HERO com gradiente e CTA ══ -->
<section class="bg-gradient-hero text-white min-h-[70vh] flex items-center">
<h1>Descubra sua <span>Beleza</span> Interior</h1>
<p>Maquiagem premium que realça sua essência.</p>
<button>Ver Coleção</button>
</section>
<!-- ══ PRODUTOS com filtros ══ -->
<section id="products">
<div class="flex gap-2 mb-6" id="category-filters">
<button class="filter-btn active" data-cat="todos">Todos</button>
<button class="filter-btn" data-cat="maquiagem">Maquiagem</button>
<button class="filter-btn" data-cat="skincare">Skincare</button>
<button class="filter-btn" data-cat="perfumes">Perfumes</button>
<button class="filter-btn" data-cat="kits">Kits</button>
</div>
<div id="products-grid" class="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4">
<!-- Renderizado via JavaScript -->
</div>
</section>
<!-- ══ CARRINHO LATERAL ══ -->
<div id="cart-sidebar" class="fixed right-0 top-0 h-full w-96 bg-white shadow-xl z-50 transform translate-x-full transition-transform">
<div class="p-6">
<h3>Sacola de Compras</h3>
<div id="cart-items"></div>
<div id="cart-total"></div>
<button onclick="checkout()">Finalizar Pedido</button>
</div>
</div>
<!-- ══ PAINEL ADMIN ══ -->
<div id="admin-panel" class="hidden">
<!-- Dashboard com estatísticas, CRUD de produtos e pedidos -->
</div>
</body>
</html>
// ══ Ashley Makeup — JavaScript (Single Page App) ══
// ── Configuração Supabase ──
const SUPABASE_URL = 'https://seu-projeto.supabase.co';
const SUPABASE_ANON_KEY = 'sua-chave-anon';
// ── Estado Global ──
let products = [];
let cart = [];
let currentUser = null;
let currentCategory = 'todos';
// ── Produtos Padrão (12 itens em 4 categorias) ──
const DEFAULT_PRODUCTS = [
{
id: '1',
name: 'Batom Líquido Matte',
price: 59.90,
category: 'maquiagem',
stock: 50,
image: 'https://images.unsplash.com/photo-1586495777744-4413f21062fa?w=400',
description: 'Batom líquido matte de alta duração.',
color: '#dc2626'
},
// ... +11 produtos (maquiagem, skincare, perfumes, kits)
];
// ── Inicialização ──
function init() {
loadProducts();
loadCart();
renderProducts();
renderCart();
checkAuth();
setupEventListeners();
}
// ── Renderizar Produtos com Filtro ──
function renderProducts() {
const grid = document.getElementById('products-grid');
const filtered = currentCategory === 'todos'
? products
: products.filter(p => p.category === currentCategory);
grid.innerHTML = filtered.map(p => `
<div class="product-card">
<img src="${p.image}" alt="${p.name}">
<h4>${p.name}</h4>
<p class="price">R$ ${p.price.toFixed(2)}</p>
<button onclick="addToCart('${p.id}')">Adicionar</button>
</div>
`).join('');
}
// ── Carrinho ──
function addToCart(productId) {
const product = products.find(p => p.id === productId);
const existing = cart.find(item => item.id === productId);
if (existing) {
existing.quantity++;
} else {
cart.push({ ...product, quantity: 1 });
}
saveCart();
renderCart();
showToast('✨ Produto adicionado à sacola!');
}
function checkout() {
if (cart.length === 0) return;
const orderNumber = 'ASH-' + Date.now().toString(36).toUpperCase();
const subtotal = cart.reduce((acc, item) => acc + item.price * item.quantity, 0);
const shipping = subtotal >= 199 ? 0 : 14.90;
const total = subtotal + shipping;
// Salva pedido
const order = {
id: orderNumber,
items: [...cart],
subtotal, shipping, total,
date: new Date().toISOString(),
status: 'confirmado'
};
saveOrder(order);
cart = [];
saveCart();
renderCart();
// Notificação WhatsApp
const msg = `Olá! Pedido ${orderNumber} confirmado!\nTotal: R$ ${total.toFixed(2)}`;
window.open(`https://wa.me/5511940313138?text=${encodeURIComponent(msg)}`, '_blank');
showToast(`🎉 Pedido ${orderNumber} confirmado!`);
triggerConfetti();
}
// ── Painel Admin ──
async function adminLogin(user, pass) {
const hash = await sha256(pass);
const stored = localStorage.getItem('admin_hash');
if (hash === stored) {
sessionStorage.setItem('admin_session', 'true');
showAdminDashboard();
}
}
function showAdminDashboard() {
// Exibe estatísticas: produtos, pedidos, receita, clientes
// CRUD de produtos com modal de criação/edição
// Visualização de pedidos recebidos
}
// ── Utilitários ──
function showToast(msg) { /* Toast notification animado */ }
function triggerConfetti() { /* Confetti ao finalizar pedido */ }
async function sha256(str) { /* Web Crypto API hash */ }
// ── Inicializar na carga da página ──
document.addEventListener('DOMContentLoaded', init);
-- Supabase Schema — Ashley Makeup
-- Tabelas, RLS Policies e Triggers
-- Produtos
CREATE TABLE products (
id TEXT PRIMARY KEY,
name TEXT NOT NULL,
price NUMERIC(10,2) NOT NULL,
category TEXT NOT NULL,
stock INTEGER DEFAULT 0,
description TEXT,
image TEXT,
color TEXT DEFAULT '#ec4899',
featured BOOLEAN DEFAULT FALSE,
created_at TIMESTAMPTZ DEFAULT now()
);
-- Pedidos
CREATE TABLE orders (
id TEXT PRIMARY KEY,
user_id UUID REFERENCES auth.users NOT NULL,
user_email TEXT,
user_name TEXT,
items JSONB NOT NULL,
subtotal NUMERIC(10,2),
shipping NUMERIC(10,2),
total NUMERIC(10,2),
status TEXT DEFAULT 'pendente',
date TIMESTAMPTZ DEFAULT now()
);
-- Perfis de usuário
CREATE TABLE profiles (
id UUID PRIMARY KEY REFERENCES auth.users ON DELETE CASCADE,
name TEXT,
email TEXT,
is_admin BOOLEAN DEFAULT FALSE,
created_at TIMESTAMPTZ DEFAULT now()
);
-- 🔒 Row Level Security
ALTER TABLE products ENABLE ROW LEVEL SECURITY;
ALTER TABLE orders ENABLE ROW LEVEL SECURITY;
ALTER TABLE profiles ENABLE ROW LEVEL SECURITY;
-- Produtos: qualquer um pode ler, só admin pode escrever
CREATE POLICY products_select ON products FOR SELECT USING (TRUE);
CREATE POLICY products_insert ON products FOR INSERT WITH CHECK (
EXISTS (SELECT 1 FROM profiles WHERE id = auth.uid() AND is_admin = TRUE)
);
-- Pedidos: usuários veem apenas os próprios pedidos
CREATE POLICY orders_select ON orders FOR SELECT USING (user_id = auth.uid());
CREATE POLICY orders_insert ON orders FOR INSERT WITH CHECK (user_id = auth.uid());
-- Trigger: criar perfil automaticamente no cadastro
CREATE FUNCTION handle_new_user()
RETURNS TRIGGER AS $$
BEGIN
INSERT INTO profiles (id, name, email)
VALUES (NEW.id, NEW.raw_user_meta_data->>'name', NEW.email);
RETURN NEW;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;
CREATE TRIGGER on_auth_user_created
AFTER INSERT ON auth.users
FOR EACH ROW
EXECUTE FUNCTION handle_new_user();