Ashley Makeup — Loja Virtual

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.

HTML5CSS3Tailwind CSSJavaScriptSupabaselocalStorage

Vitrine Interativa

Produtos organizados em categorias (Maquiagem, Skincare, Perfumes, Kits) com busca e filtros dinâmicos.

Carrinho de Compras

Carrinho lateral com controle de quantidade, cálculo de frete grátis acima de R$ 199 e notificação via WhatsApp.

Painel Admin

Login seguro com hash SHA-256, dashboard com estatísticas, CRUD completo de produtos e gerenciamento de pedidos.

Supabase Ready

Schema SQL preparado com tabelas products, orders e profiles, Row Level Security e trigger de auto-cadastro.

Cadastro de Usuários

Sistema de registro/login com dashboard de histórico de pedidos e dados persistentes em localStorage.

Design Responsivo

Tema rosa elegante com Tailwind CSS, animações CSS, confetti e layout adaptável para mobile/tablet/desktop.

Pré-visualização da Loja

Ashley Makeup
💄
Batom Líquido Matte
R$ 59,90
Maquiagem
🧴
Sérum Facial Vit C
R$ 89,90
Skincare
🌸
Perfume Floral
R$ 149,90
Perfumes
🎁
Kit Glow Essencial
R$ 199,90
Kits
👁️
Paleta Sombras
R$ 79,90
Maquiagem
🧖
Máscara Facial
R$ 45,90
Skincare

Código do Projeto

index.html
JavaScript
Supabase Schema
<!-- 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();