1. Prerequisites
Before starting, make sure you have:
- Basic knowledge of HTML, CSS, and JavaScript.
- A Firebase project with Firestore enabled.
- A Cloudinary account with an unsigned upload preset.
- Local development environment (e.g., Live Server).
2. Firebase Setup
Steps to configure Firebase Firestore:
- Go to Firebase Console and create a new project.
- Register a web app in your project and copy the Firebase config object:
const firebaseConfig = {
apiKey: "AIzaSyCUad2MwdykedKqSWG7AOx9iIN5ePYxDg8",
authDomain: "ecommerce-products-573ce.firebaseapp.com",
projectId: "ecommerce-products-573ce",
storageBucket: "ecommerce-products-573ce.firebasestorage.app",
messagingSenderId: "875506405938",
appId: "1:875506405938:web:815042d0daf81941ae622b",
measurementId: "G-LTEMTLNB9E"
};
- Enable Cloud Firestore in test mode to allow writing data during development.
3. Shop Product Template
Combine the HTML, CSS, and JS above into a single HTML file for immediate use in development. This template is ready to drop into Live Server and start uploading products.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Shop</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
/* Products Section */
.container-products {
max-width: 1200px;
margin: 0 auto;
padding: 40px 20px;
}
.section-title-products {
text-align: center;
font-size: 2.5rem;
font-weight: 300;
letter-spacing: 2px;
margin-bottom: 50px;
color: #222;
position: relative;
}
.section-title-products::after {
content: '';
position: absolute;
bottom: -15px;
left: 50%;
transform: translateX(-50%);
width: 80px;
height: 2px;
background-color: #d4af37;
}
.collections-grid {
display: grid;
grid-template-columns: repeat(1, 1fr);
gap: 30px;
}
.all-btn {
text-align: center;
margin-top: 30px;
}
@media (min-width: 768px) {
.collections-grid {
grid-template-columns: repeat(2, 1fr);
}
}
@media (min-width: 1024px) {
.collections-grid {
grid-template-columns: repeat(3, 1fr);
}
}
.product-card {
background: white;
border-radius: 8px;
overflow: hidden;
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.08);
transition: transform 0.3s ease, box-shadow 0.3s ease;
position: relative;
}
.product-card:hover {
transform: translateY(-5px);
box-shadow: 0 15px 30px rgba(0, 0, 0, 0.15);
}
.product-image {
padding: 10px;
width: 100%;
height: 280px;
object-fit: contain;
display: block;
}
.divider {
height: 1px;
background-color: #d4af37;
width: 100%;
margin: 0;
}
.product-info {
padding: 20px;
}
.product-name {
font-size: 1.2rem;
font-weight: 500;
margin-bottom: 8px;
color: #222;
}
.product-price {
font-size: 1.1rem;
font-weight: 600;
color: #d4af37;
}
.overlay-products {
position: absolute;
bottom: 0;
left: 0;
right: 0;
background-color: rgba(0, 0, 0, 0.7);
overflow: hidden;
width: 100%;
height: 0;
transition: height 0.3s ease;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
gap: 15px;
}
/* Show overlay when hovering on product card */
.product-card:hover .overlay-products {
height: 100%;
}
.view-details-btn {
background-color: transparent;
border: 2px solid white;
color: white;
padding: 12px 25px;
font-size: 0.9rem;
cursor: pointer;
border-radius: 4px;
transition: all 0.3s ease;
letter-spacing: 1px;
font-weight: 500;
text-decoration: none;
}
.view-details-btn:hover {
background-color: white;
color: #222;
transform: scale(1.05);
}
.cart-icon {
color: white;
font-size: 1.5rem;
cursor: pointer;
transition: all 0.3s ease;
background: rgba(255, 255, 255, 0.2);
width: 50px;
height: 50px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
}
.cart-icon:hover {
background: rgba(255, 255, 255, 0.3);
transform: scale(1.1);
}
.notification {
position: fixed;
top: 20px;
right: 20px;
background: #222;
color: white;
padding: 15px 25px;
border-radius: 4px;
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2);
transform: translateX(150%);
transition: transform 0.4s ease;
z-index: 1000;
}
.notification.show {
transform: translateX(0);
}
</style>
</head>
<body>
<!-- Products -->
<div class="container-products">
<h1 class="section-title-products">Product Collections</h1>
<div class="collections-grid" id="productsGrid">
<!-- Product cards will be appended here dynamically -->
</div>
</div>
<!-- Font Awesome for cart icons -->
<script src="https://kit.fontawesome.com/a076d05399.js" crossorigin="anonymous"></script>
<script type="module">
import { initializeApp } from "https://www.gstatic.com/firebasejs/10.12.0/firebase-app.js";
import { getFirestore, collection, getDocs } from "https://www.gstatic.com/firebasejs/10.12.0/firebase-firestore.js";
const firebaseConfig = {
apiKey: "AIzaSyCUad2MwdykedKqSWG7AOx9iIN5ePYxDg8",
authDomain: "ecommerce-products-573ce.firebaseapp.com",
projectId: "ecommerce-products-573ce",
storageBucket: "ecommerce-products-573ce.firebasestorage.app",
messagingSenderId: "875506405938",
appId: "1:875506405938:web:815042d0daf81941ae622b",
measurementId: "G-LTEMTLNB9E"
};
const app = initializeApp(firebaseConfig);
const db = getFirestore(app);
const productsGrid = document.getElementById("productsGrid");
async function fetchProducts() {
try {
const querySnapshot = await getDocs(collection(db, "products"));
querySnapshot.forEach(doc => {
const product = doc.data();
const card = document.createElement("div");
card.classList.add("product-card");
card.innerHTML = `
<img src="${product.mainImage}" alt="${product.name}" class="product-image">
<div class="divider"></div>
<div class="product-info">
<h3 class="product-name">${product.name}</h3>
<p class="product-price">Ksh ${product.price}</p>
</div>
<div class="overlay-products">
<a href="product.html?id=${doc.id}" class="view-details-btn">VIEW DETAILS</a>
<div class="cart-icon" data-product="${product.name}">
<i class="fas fa-shopping-cart"></i>
</div>
</div>
`;
productsGrid.appendChild(card);
});
} catch (err) {
console.error("Error fetching products:", err);
productsGrid.innerHTML = "<p>Failed to load products. Please try again later.</p>";
}
}
fetchProducts();
</script>
</body>
</html>
All code blocks above are fully copyable. Follow the Firebase and Cloudinary setup carefully to ensure uploads work correctly.