O projecto é um site estático puro — sem servidor, sem base de dados, sem framework. Todos os ficheiros estão numa única pasta que pode ser aberta directamente no browser ou publicada num serviço de hosting estático.
| Ficheiro | Responsabilidade | Dependências externas |
|---|---|---|
index.html |
Página principal. Contém a navbar, o cart offcanvas, o hero, a grelha de produtos, as value propositions e a newsletter. | Bootstrap 5.3, Font Awesome 6, Google Fonts, style.css, main.js |
the-*.html |
Cada ficheiro de produto tem: galeria de imagens, seletor de tamanhos, botão add-to-cart, accordion com detalhes, e secção de produtos relacionados. | Idem + Bootstrap accordion JS |
checkout.html |
Fluxo de 3 passos: contacto/morada → método de envio → pagamento. Lê o carrinho do localStorage. Integra Stripe.js para tokenização do cartão. | Idem + Stripe.js v3 de js.stripe.com |
assets/css/style.css |
Define as variáveis CSS (:root), reset, tipografia, navbar, botões, cards de produto, carrinho offcanvas, footer e animações. |
— |
assets/js/main.js |
Módulo IIFE auto-contido. Gere o estado do carrinho em localStorage, o badge de contagem, o render do offcanvas, os botões de tamanho, as animações de scroll e a navegação por produto. | Bootstrap JS (para o offcanvas) |
product.html: Existe também um ficheiro product.html na raiz que serve como template de referência para criar novos produtos. A estrutura é idêntica à dos outros ficheiros de produto.
Todas as cores estão definidas como variáveis CSS no bloco :root no início de assets/css/style.css (linha 7). Para mudar uma cor em todo o site basta alterar a variável — não é necessário procurar instâncias individuais.
| Variável | Valor actual | Amostra | Onde é usada |
|---|---|---|---|
--black |
#000000 |
Fundo do body, fundo de botões sólidos, fundo do hero | |
--dark |
#1a1a1a |
Sidebar do checkout, campos de formulário, cards de produtos relacionados | |
--off-white |
#f4f4f4 |
Cor principal do texto, bordas de botões ghost, fundos de botões sólidos | |
--gray |
#888888 |
Texto secundário, metadados de produto, descrições no rodapé | |
--accent |
#c8a96e |
Cor dourada: eyebrows, divisores, bordas de hover, preços activos, links |
Abre assets/css/style.css e localiza o bloco inicial:
:root {
--black: #000000;
--dark: #1a1a1a;
--dark-soft: #111111;
--off-white: #f4f4f4;
--gray: #888888;
--gray-light: #555555;
--accent: #c8a96e; /* ← muda esta linha para alterar o dourado */
--border: rgba(244, 244, 244, 0.08);
}
Exemplo: para um tema com destaque em cor-de-rosa quente substitui --accent: #c8a96e por --accent: #e84393. A alteração propaga-se automaticamente a todo o site.
--border usa rgba propositadamente — é uma borda semi-transparente pensada para sobrepor fundos escuros. Se mudares o fundo para claro podes ter de a ajustar para algo como rgba(0,0,0,0.12).
| Variável CSS | Fonte | Usada em |
|---|---|---|
--serif |
Playfair Display (Google Fonts) + Georgia, serif | Títulos (h1–h5), preços, nome da marca, citações |
--sans |
Inter (Google Fonts) + system-ui, sans-serif | Corpo, labels, botões, metadados, eyebrows |
Passo 1 — URL do Google Fonts. Em cada ficheiro HTML, no <head>, há uma linha semelhante a esta. Substitui a família pretendida:
<!-- Antes -->
<link href="https://fonts.googleapis.com/css2?family=Playfair+Display:ital,wght@0,400;0,700;0,900;1,400&family=Inter:wght@300;400;500;600&display=swap" rel="stylesheet" />
<!-- Depois (exemplo com EB Garamond + DM Sans) -->
<link href="https://fonts.googleapis.com/css2?family=EB+Garamond:ital,wght@0,400;0,700;1,400&family=DM+Sans:wght@300;400;500&display=swap" rel="stylesheet" />
Passo 2 — Variáveis CSS em style.css. Actualiza os nomes no bloco :root:
--serif: 'EB Garamond', Georgia, serif;
--sans: 'DM Sans', system-ui, sans-serif;
assets/fonts/. Depois usa @font-face no início do style.css em vez do link externo.
Abre o ficheiro do produto pretendido (ex: the-outlaw.html). Os campos editáveis estão na coluna da direita, dentro de <div class="info-col-sticky">:
<!-- Número do modelo -->
<div class="pdp-model-number">No. 01 · The Essential Six</div>
<!-- Nome do produto -->
<h1 class="pdp-title">The Outlaw</h1>
<!-- Preço (alterar aqui E no main.js — ver abaixo) -->
<div class="pdp-price">€485<small>IVA incluído</small></div>
<!-- Descrição curta -->
<p style="font-size:13px;color:var(--gray);line-height:1.9;margin-bottom:0;">
A bota que iniciou tudo. Linhas limpas, biqueira apontada, cano alto.
Full-Grain Italiano curtido em Toscana.
</p>
Os tamanhos são botões dentro de <div class="size-grid">. Adiciona ou remove linhas conforme necessário. A classe unavailable marca um tamanho como esgotado (aparece riscado e não clicável):
<div class="size-grid">
<!-- Esgotado: adiciona classe "unavailable" -->
<button class="size-btn unavailable" data-size="38">38</button>
<!-- Disponível -->
<button class="size-btn" data-size="39">39</button>
<button class="size-btn" data-size="40">40</button>
<!-- Activo por defeito: adiciona classe "active" -->
<button class="size-btn active" data-size="41">41</button>
<button class="size-btn" data-size="42">42</button>
<button class="size-btn" data-size="43">43</button>
</div>
<!-- Input hidden: actualizar o value para o tamanho activo por defeito -->
<input type="hidden" data-size-value data-size-selector="the-outlaw" value="41" />
data-size-selector no <input hidden> deve coincidir exactamente com o data-add-to-cart do botão. Por exemplo, para The Outlaw ambos têm o valor the-outlaw.
Actualmente as imagens são geradas automaticamente por picsum.photos — um serviço que entrega fotografias aleatórias com base numa "seed" (semente). É ideal para protótipos mas deve ser substituído por fotografias reais antes de lançar.
Como funciona a URL actual:
https://picsum.photos/seed/outlaw9A/900/1200?grayscale
↑ seed "outlaw9A" → sempre a mesma foto para este produto
↑ 900/1200 → largura/altura em píxeis
↑ ?grayscale → converte para preto e branco
Como substituir por imagens reais:
assets/img/ (cria a pasta se não existir). Sugestão de estrutura: assets/img/the-outlaw/main.jpg, assets/img/the-outlaw/detail.jpg, etc.src de cada <img>:<!-- Antes -->
<img src="https://picsum.photos/seed/outlaw9A/900/1200?grayscale"
alt="The Outlaw — Vista Principal"
class="gallery-main" />
<!-- Depois -->
<img src="assets/img/the-outlaw/main.jpg"
alt="The Outlaw — Vista Principal"
class="gallery-main" />
Recomendações para fotografias de produto: proporção 3:4 para a imagem principal (900×1200px), 1:1 para as miniaturas (300×300px). Formato .jpg com compressão ~80% para equilíbrio entre qualidade e velocidade.
O preço em main.js é o que é usado para calcular o total do carrinho. É independente do que está escrito no HTML — é aqui que o carrinho lê o valor real. Localiza o objecto MODELS no início do módulo Cart:
// assets/js/main.js — linha 29
const MODELS = {
'the-outlaw': { name: 'The Outlaw', price: 485 },
'the-desperado': { name: 'The Desperado', price: 520 },
'the-maverick': { name: 'The Maverick', price: 495 },
'the-ranger': { name: 'The Ranger', price: 510 },
'the-renegade': { name: 'The Renegade', price: 475 },
'the-vaquero': { name: 'The Vaquero', price: 545 },
};
.pdp-price) e (2) no MODELS do main.js. Se só alterares num, o preço exibido e o preço cobrado no checkout ficarão dessincronizados.
No final de cada ficheiro de produto há uma secção <section id="related"> com uma grelha de 4 cards. Cada card segue este padrão — basta substituir o slug, o nome, o preço e a seed da imagem:
<div class="col-6 col-md-3 product-card-wrap">
<a href="the-desperado.html" class="d-block text-decoration-none">
<div class="product-card">
<img src="https://picsum.photos/seed/desp77A/600/800?grayscale"
alt="The Desperado" class="product-card-img" />
<div class="product-card-number">No. 02</div>
<div class="product-card-overlay">
<div class="product-card-info">
<div class="product-card-name">The Desperado</div>
<div class="product-card-price">€520</div>
</div>
</div>
</div>
<div class="product-card-label">
<span class="product-card-label-name">The Desperado</span>
<span class="product-card-label-price">€520</span>
</div>
</a>
</div>
| Secção | Elemento HTML | O que editar |
|---|---|---|
| Hero | <section id="hero"> |
Tagline principal (.hero-title), subtítulo (.hero-subtitle), eyebrow (.hero-eyebrow), imagem de fundo (.hero-img-placeholder — src), stats (.hero-meta-number) |
| Marquee strip | <div class="marquee-strip"> |
Textos dentro de <template id="marqueeContent"> — cada <span class="marquee-item"> |
| The Essential Six | <section id="collection"> |
Título da secção, descrição. Os cards de produto — ver Secção 3 deste manual. |
| Value Props | <section id="values"> |
Título (.value-title) e texto (.value-text) de cada um dos 3 cards. Ícone (<i class="fa-solid fa-...">) |
| Imagem full-width | <div style="height:60vh..."> |
Imagem de fundo, citação e botão CTA no centro |
| Newsletter / CTA | <section id="cta-section"> |
Título (.cta-title), subtítulo (.cta-subtitle). O formulário não envia email por defeito — ver nota abaixo. |
index.html tem onsubmit="return false;" — não envia email. Para o activar precisas de integrar um serviço externo como Mailchimp, ConvertKit ou Buttondown. Cada um fornece um snippet de formulário HTML para substituir o actual.
A timeline está em <section id="timeline">. Cada entrada é um bloco .timeline-item:
<div class="timeline-item fade-up">
<!-- Ano (muda apenas o texto) -->
<div class="timeline-year">2024</div>
<div class="timeline-content">
<!-- Título do evento -->
<h3>VOLT & LEATHER Nasce</h3>
<!-- Descrição -->
<p>Após dois anos de prototipagem, a marca lança os seis modelos...</p>
</div>
</div>
Para adicionar uma entrada: copia um bloco .timeline-item e cola antes do último </div> da <section id="timeline">. Para remover: apaga o bloco .timeline-item completo.
Em <section id="craft">, cada passo é um .craft-step. O número (.craft-step-number), o título (.craft-step-title) e o texto (.craft-step-text) são todos editáveis livremente.
As informações de contacto estão nos cards à direita do formulário, cada um num bloco .info-card:
<!-- Email -->
<div class="info-card">
<div class="info-card-icon"><i class="fa-solid fa-envelope"></i></div>
<div class="info-card-title">Email</div>
<!-- ↓ Altera aqui -->
<div class="info-card-value">hello@voltandleather.com</div>
<div class="info-card-sub">Resposta em 24 horas úteis</div>
</div>
<!-- Morada -->
<div class="info-card">
<div class="info-card-icon"><i class="fa-solid fa-location-dot"></i></div>
<div class="info-card-title">Atelier</div>
<!-- ↓ Altera aqui -->
<div class="info-card-value">Alcanena, Portugal</div>
<div class="info-card-sub">Visitas mediante marcação prévia.</div>
</div>
O rodapé é repetido em todos os ficheiros HTML. As redes sociais estão em .footer-social no final do <footer>:
<div class="footer-social">
<!-- Substitui os href="#" pelos URLs reais das tuas páginas -->
<a href="https://instagram.com/voltandleather" aria-label="Instagram" target="_blank">
<i class="fa-brands fa-instagram"></i>
</a>
<a href="https://pinterest.com/voltandleather" aria-label="Pinterest" target="_blank">
<i class="fa-brands fa-pinterest"></i>
</a>
<a href="https://tiktok.com/@voltandleather" aria-label="TikTok" target="_blank">
<i class="fa-brands fa-tiktok"></i>
</a>
</div>
index.html, sobre.html, contacto.html, the-outlaw.html, etc. Uma forma mais eficiente é usar um editor com busca e substituição global (ex: VS Code: Ctrl+Shift+H).
O carrinho não precisa de servidor — é guardado localmente no browser do utilizador através da Web Storage API. Os dados persistem entre sessões até o utilizador limpar o histórico do browser.
| Detalhe | Valor |
|---|---|
| Chave localStorage | vl_cart |
| Formato | Array JSON: [{ slug, size, name, price, qty }, ...] |
| Onde é escrito | assets/js/main.js — função save() linha 44 |
| Onde é lido | assets/js/main.js — função load() linha 39; e checkout.html — função loadCart() |
Para inspeccionar o conteúdo do carrinho no browser: abre as Ferramentas de Programador (F12) → aba Application (Chrome) ou Storage (Firefox) → Local Storage → selecciona o domínio → procura a chave vl_cart.
A função clearCart() está definida em checkout.html (linha 833) e é chamada automaticamente após um pagamento bem-sucedido. Podes chamá-la manualmente a partir da consola do browser para testar:
// No ficheiro checkout.html
function clearCart() {
localStorage.removeItem('vl_cart');
}
// Para adicionar um botão "Limpar Carrinho" à interface:
// 1. Adiciona o botão no HTML do offcanvas em qualquer página
<button onclick="localStorage.removeItem('vl_cart'); location.reload();">
Limpar Carrinho
</button>
Os códigos promo estão num objecto simples em checkout.html (linha 826). A chave é o código (em maiúsculas) e o valor é a percentagem de desconto:
// checkout.html — linha 826
const PROMO_CODES = {
'VOLT10': 10, // 10% de desconto
'LEATHER20': 20, // 20% de desconto
// Adiciona mais entradas aqui:
'LAUNCH30': 30, // 30% de desconto de lançamento
'FRIEND15': 15, // 15% para amigos
};
Os preços de envio estão no objecto SHIPPING_PRICES em checkout.html (linha 837). As chaves correspondem ao valor do input[type=radio] em cada opção de envio no HTML:
// checkout.html — linha 837
const SHIPPING_PRICES = {
free: 0, // Standard CTT — grátis
express_pt: 8, // Express DHL Portugal — €8
europe: 15, // Internacional Europa — €15
international:30, // Internacional geral — €30
};
Para adicionar um novo método de envio: adiciona uma entrada ao objecto, e no HTML do Step 2 adiciona uma nova <label class="shipping-option"> com um input[type=radio] cujo value coincida com a nova chave.
A Publishable Key é pública — é seguro colocá-la no frontend. Não confundir com a Secret Key (que nunca deve estar no frontend). Em checkout.html, linha 822:
/* checkout.html — linha 822 */
/* Obtém a tua chave em: https://dashboard.stripe.com/apikeys */
const STRIPE_PUBLISHABLE_KEY = 'pk_live_51AbCdEfGhIjKlMnOpQrStUvWxYz...';
// ↑ Começa sempre com pk_live_ (modo live) ou pk_test_ (modo teste)
Para encontrar a tua chave: Dashboard Stripe → Developers → API keys → copia a "Publishable key".
O fluxo completo do Stripe tem dois passos:
PaymentMethod — os dados sensíveis nunca passam pelo teu servidor.PaymentIntent com o valor exacto. O Stripe retorna um clientSecret. O frontend usa esse clientSecret para confirmar o pagamento.| Opção | Custo | Dificuldade | Quando usar |
|---|---|---|---|
| Netlify Functions | Gratuito (125k req/mês) | Baixa | Site já hospedado no Netlify |
| Vercel Serverless | Gratuito (100GB-h/mês) | Baixa | Site hospedado no Vercel |
| Node.js + Express | Custo do servidor (Railway, Render — gratuito) | Média | Controlo total, lógica complexa |
| Stripe Checkout (hosted) | 0% + taxas Stripe standard | Muito baixa | Preferir a página de checkout do próprio Stripe |
Cria um ficheiro server.js na raiz do projecto e instala as dependências: npm install express stripe cors
// server.js — Endpoint para criar o PaymentIntent
const express = require('express');
const cors = require('cors');
const stripe = require('stripe')('sk_live_SUA_SECRET_KEY_AQUI');
const app = express();
app.use(cors());
app.use(express.json());
app.post('/api/create-payment-intent', async (req, res) => {
const { paymentMethodId, amount, currency, email, items } = req.body;
// Validação básica
if (!paymentMethodId || !amount || amount < 50) {
return res.status(400).json({ error: 'Dados inválidos.' });
}
try {
const paymentIntent = await stripe.paymentIntents.create({
amount: amount, // em cêntimos (ex: 485 euros = 48500)
currency: currency || 'eur',
payment_method: paymentMethodId,
receipt_email: email,
confirm: true,
return_url: 'https://voltandleather.com/checkout.html',
automatic_payment_methods: {
enabled: true,
allow_redirects: 'never'
},
metadata: {
items: JSON.stringify(items)
}
});
res.json({
clientSecret: paymentIntent.client_secret,
status: paymentIntent.status
});
} catch (err) {
res.status(500).json({ error: err.message });
}
});
app.listen(3001, () => console.log('Stripe backend a correr na porta 3001'));
pk_live_.checkout.html, substitui o valor de STRIPE_PUBLISHABLE_KEY.sk_live_....sk_live_...) para um repositório Git público. Usa variáveis de ambiente: no Netlify/Vercel configura STRIPE_SECRET_KEY nas definições do projecto e acede via process.env.STRIPE_SECRET_KEY.
| Número do cartão | Resultado | CVC / Expiração |
|---|---|---|
4242 4242 4242 4242 |
Pagamento bem-sucedido | Qualquer 3 dígitos / qualquer data futura |
4000 0000 0000 0002 |
Cartão recusado (genérico) | Idem |
4000 0027 6000 3184 |
Requer autenticação 3D Secure | Idem |
4000 0000 0000 9995 |
Recusado — sem fundos suficientes | Idem |
ecommerce-template/ (a pasta raiz do projecto) para essa área.https://random-name-123.netlify.app.# Instala o Vercel CLI (só na primeira vez)
npm install -g vercel
# Na pasta do projecto
cd ecommerce-template
vercel deploy
# Responde às perguntas:
# Set up and deploy? Y
# Which scope? (a tua conta)
# Link to existing project? N
# Project name: volt-and-leather (ou o que quiseres)
# In which directory is your code? ./ (a raiz)
# Para deploy em produção (URL fixo):
vercel --prod
volt-and-leather (ou qualquer outro).main.main → Folder: / (root) → Save.https://SEU-USER.github.io/volt-and-leather/.Depois de teres o site no ar num dos serviços acima:
Adiciona estas meta tags dentro do <head> de cada página. São usadas quando o URL é partilhado no Facebook, Instagram, WhatsApp, etc.:
<!-- Coloca dentro do <head> de cada página -->
<!-- SEO básico -->
<meta name="description" content="VOLT & LEATHER — Botas Cowboy Handmade de Portugal. Apenas 6 modelos exclusivos. Couro Italiano. Craftsmanship Português." />
<!-- Open Graph para redes sociais -->
<meta property="og:type" content="website" />
<meta property="og:site_name" content="VOLT & LEATHER" />
<meta property="og:title" content="VOLT & LEATHER — Handmade Cowboy Boots · Portugal" />
<meta property="og:description" content="Seis modelos. Couro Italiano. Feitos à mão em Portugal." />
<meta property="og:image" content="https://voltandleather.com/assets/img/og-cover.jpg" />
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />
<meta property="og:url" content="https://voltandleather.com" />
<!-- Twitter Card -->
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content="VOLT & LEATHER — Handmade Cowboy Boots" />
<meta name="twitter:description" content="Seis modelos. Couro Italiano. Feitos à mão em Portugal." />
<meta name="twitter:image" content="https://voltandleather.com/assets/img/og-cover.jpg" />
A imagem og-cover.jpg deve ter 1200×630px. Usa o Facebook Sharing Debugger (developers.facebook.com/tools/debug) para testar.
Regista-te em analytics.google.com, cria uma propriedade GA4 e obtém o ID de medição (formato G-XXXXXXXXXX). Depois adiciona este snippet no <head> de cada página, antes de fechar a tag:
<!-- Google Analytics 4 — substitui G-XXXXXXXXXX pelo teu ID -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-XXXXXXXXXX"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'G-XXXXXXXXXX');
</script>
Em search.google.com/search-console, adiciona o teu domínio. O método mais simples de verificação é a meta tag HTML — adiciona ao <head> da index.html:
<!-- Google Search Console — substitui XXXXXXXXXXXXXXXXXXXX pelo teu token -->
<meta name="google-site-verification" content="XXXXXXXXXXXXXXXXXXXX" />
Cria um ficheiro sitemap.xml na raiz do projecto. Ajusta o <loc> com o teu domínio real e as datas <lastmod>:
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>https://voltandleather.com/</loc>
<lastmod>2024-01-01</lastmod>
<changefreq>monthly</changefreq>
<priority>1.0</priority>
</url>
<url>
<loc>https://voltandleather.com/sobre.html</loc>
<lastmod>2024-01-01</lastmod>
<changefreq>yearly</changefreq>
<priority>0.7</priority>
</url>
<url>
<loc>https://voltandleather.com/contacto.html</loc>
<lastmod>2024-01-01</lastmod>
<changefreq>yearly</changefreq>
<priority>0.6</priority>
</url>
<url>
<loc>https://voltandleather.com/the-outlaw.html</loc>
<lastmod>2024-01-01</lastmod>
<changefreq>monthly</changefreq>
<priority>0.9</priority>
</url>
<url>
<loc>https://voltandleather.com/the-desperado.html</loc>
<lastmod>2024-01-01</lastmod>
<changefreq>monthly</changefreq>
<priority>0.9</priority>
</url>
<url>
<loc>https://voltandleather.com/the-maverick.html</loc>
<lastmod>2024-01-01</lastmod>
<changefreq>monthly</changefreq>
<priority>0.9</priority>
</url>
<url>
<loc>https://voltandleather.com/the-ranger.html</loc>
<lastmod>2024-01-01</lastmod>
<changefreq>monthly</changefreq>
<priority>0.9</priority>
</url>
<url>
<loc>https://voltandleather.com/the-renegade.html</loc>
<lastmod>2024-01-01</lastmod>
<changefreq>monthly</changefreq>
<priority>0.9</priority>
</url>
<url>
<loc>https://voltandleather.com/the-vaquero.html</loc>
<lastmod>2024-01-01</lastmod>
<changefreq>monthly</changefreq>
<priority>0.9</priority>
</url>
</urlset>
Depois de criar o sitemap.xml, submete-o no Google Search Console: Sitemaps → introduce sitemap.xml → Submit.
O Bootstrap é carregado via CDN (jsDelivr). Para actualizar para uma nova versão, substitui o número da versão nos links de CSS e JS em todos os ficheiros HTML. Actualmente usa a versão 5.3.2:
<!-- CSS — no <head> -->
<!-- Antes: -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet" />
<!-- Depois (exemplo para 5.3.3): -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" />
<!-- JS Bundle — antes de fechar </body> -->
<!-- Antes: -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
<!-- Depois: -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
O Font Awesome é carregado via Cloudflare CDN. Actualmente usa a versão 6.5.0. Substitui nos ficheiros HTML:
<!-- Antes: -->
<link rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.0/css/all.min.css" />
<!-- Depois (ex: 6.6.0): -->
<link rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.6.0/css/all.min.css" />
Verifica a versão mais recente em cdnjs.com/libraries/font-awesome.
O projecto é 100% estático — não há base de dados. O backup consiste simplesmente em copiar a pasta:
ecommerce-template/ para um serviço de cloud storage (Google Drive, Dropbox, OneDrive) ou para um disco externo.# Inicializar repositório Git (só na primeira vez)
git init
git add .
git commit -m "Initial commit — VOLT & LEATHER v1.0"
# Ligar a repositório remoto (GitHub)
git remote add origin https://github.com/SEU-USER/volt-and-leather.git
git push -u origin main
# Guardar alterações futuras
git add .
git commit -m "Actualizar preço The Vaquero para €560"
git push
Antes de tornar o site público, verifica todos os itens abaixo:
VOLT & LEATHER · Manual de Personalização v1.0 · 2024
Projecto estático — Bootstrap 5.3 · Font Awesome 6 · Stripe.js v3