557 lines
19 KiB
HTML
557 lines
19 KiB
HTML
<!doctype html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
<meta name="description" content="Shop all products - Sky Art Shop" />
|
|
<title>Shop - Sky Art Shop</title>
|
|
|
|
<!-- Fonts -->
|
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
|
<link
|
|
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Poppins:wght@600;700;800&display=swap"
|
|
rel="stylesheet"
|
|
/>
|
|
|
|
<!-- Icons -->
|
|
<link
|
|
rel="stylesheet"
|
|
href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css"
|
|
/>
|
|
|
|
<!-- Modern Theme CSS -->
|
|
<link
|
|
rel="stylesheet"
|
|
href="/assets/css/modern-theme.css?v=20260118drawer"
|
|
/>
|
|
<link
|
|
rel="stylesheet"
|
|
href="/assets/css/mobile-fixes.css?v=20260119touch"
|
|
/>
|
|
</head>
|
|
<body>
|
|
<!-- Navigation -->
|
|
<header class="nav-wrapper">
|
|
<nav class="navbar">
|
|
<a href="/home" class="nav-brand">
|
|
<img
|
|
src="/uploads/cat-png-1767324141436-368259437.png"
|
|
alt="Sky Art Shop Logo"
|
|
/>
|
|
<span>Sky Art Shop</span>
|
|
</a>
|
|
|
|
<ul class="nav-menu">
|
|
<li><a href="/home" class="nav-link">Home</a></li>
|
|
<li><a href="/shop" class="nav-link active">Shop</a></li>
|
|
<li><a href="/portfolio" class="nav-link">Portfolio</a></li>
|
|
<li><a href="/blog" class="nav-link">Blog</a></li>
|
|
<li><a href="/about" class="nav-link">About</a></li>
|
|
<li><a href="/contact" class="nav-link">Contact</a></li>
|
|
</ul>
|
|
|
|
<div class="nav-actions">
|
|
<a href="/signin" class="nav-icon-btn" title="Sign In">
|
|
<i class="bi bi-person"></i>
|
|
</a>
|
|
<button class="nav-icon-btn wishlist-btn-nav" title="Wishlist">
|
|
<i class="bi bi-heart"></i>
|
|
<span class="badge wishlist-count" style="display: none">0</span>
|
|
</button>
|
|
<button class="nav-icon-btn cart-btn" title="Cart">
|
|
<i class="bi bi-bag"></i>
|
|
<span class="badge cart-count" style="display: none">0</span>
|
|
</button>
|
|
<button class="nav-mobile-toggle" aria-label="Toggle menu">
|
|
<span></span>
|
|
<span></span>
|
|
<span></span>
|
|
</button>
|
|
</div>
|
|
</nav>
|
|
</header>
|
|
|
|
<!-- Page Content -->
|
|
<main class="page-content">
|
|
<!-- Page Header -->
|
|
<div class="page-header">
|
|
<div class="container">
|
|
<h1>Shop All Products</h1>
|
|
<p>
|
|
Explore our complete collection of stationery and crafting supplies
|
|
</p>
|
|
<div class="breadcrumb">
|
|
<a href="/home">Home</a>
|
|
<span>/</span>
|
|
<span>Shop</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Shop Content -->
|
|
<section class="section">
|
|
<div class="container">
|
|
<div class="shop-layout">
|
|
<!-- Sidebar Filters -->
|
|
<aside class="shop-sidebar">
|
|
<!-- Search -->
|
|
<div class="filter-card">
|
|
<h3 class="filter-title">Search</h3>
|
|
<div class="search-box" style="position: relative">
|
|
<input
|
|
type="text"
|
|
id="searchInput"
|
|
placeholder="Search products..."
|
|
style="
|
|
width: 100%;
|
|
padding: 12px 40px 12px 16px;
|
|
border: 2px solid var(--border-light);
|
|
border-radius: var(--radius-md);
|
|
font-size: 0.95rem;
|
|
"
|
|
/>
|
|
<i
|
|
class="bi bi-search"
|
|
style="
|
|
position: absolute;
|
|
right: 14px;
|
|
top: 50%;
|
|
transform: translateY(-50%);
|
|
color: var(--text-light);
|
|
"
|
|
></i>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Categories -->
|
|
<div class="filter-card">
|
|
<h3 class="filter-title">Categories</h3>
|
|
<div class="filter-options" id="categoryFilters">
|
|
<label class="filter-option">
|
|
<input type="checkbox" value="all" checked />
|
|
<span>All Products</span>
|
|
</label>
|
|
<!-- Categories loaded via JavaScript -->
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Price Range -->
|
|
<div class="filter-card">
|
|
<h3 class="filter-title">Price Range</h3>
|
|
<div class="filter-options">
|
|
<label class="filter-option">
|
|
<input type="checkbox" name="price" value="0-10" />
|
|
<span>Under $10</span>
|
|
</label>
|
|
<label class="filter-option">
|
|
<input type="checkbox" name="price" value="10-25" />
|
|
<span>$10 - $25</span>
|
|
</label>
|
|
<label class="filter-option">
|
|
<input type="checkbox" name="price" value="25-50" />
|
|
<span>$25 - $50</span>
|
|
</label>
|
|
<label class="filter-option">
|
|
<input type="checkbox" name="price" value="50+" />
|
|
<span>$50 & Above</span>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Availability -->
|
|
<div class="filter-card">
|
|
<h3 class="filter-title">Availability</h3>
|
|
<div class="filter-options">
|
|
<label class="filter-option">
|
|
<input type="checkbox" name="stock" value="in-stock" />
|
|
<span>In Stock</span>
|
|
</label>
|
|
<label class="filter-option">
|
|
<input type="checkbox" name="stock" value="featured" />
|
|
<span>Featured</span>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
</aside>
|
|
|
|
<!-- Products Grid -->
|
|
<div class="shop-main">
|
|
<div class="shop-header">
|
|
<div class="shop-results">
|
|
<span id="productCount">Loading products...</span>
|
|
</div>
|
|
<div class="shop-sort">
|
|
<select id="sortSelect">
|
|
<option value="newest">Newest First</option>
|
|
<option value="price-low">Price: Low to High</option>
|
|
<option value="price-high">Price: High to Low</option>
|
|
<option value="name-az">Name: A-Z</option>
|
|
<option value="name-za">Name: Z-A</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="products-grid" id="productsGrid">
|
|
<div
|
|
class="loading-spinner"
|
|
style="grid-column: 1/-1; margin: 40px auto"
|
|
></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
</main>
|
|
|
|
<!-- Footer -->
|
|
<footer class="footer">
|
|
<div class="container">
|
|
<div class="footer-grid">
|
|
<div class="footer-about">
|
|
<div class="footer-brand">
|
|
<img
|
|
src="/uploads/cat-png-1767324141436-368259437.png"
|
|
alt="Sky Art Shop"
|
|
/>
|
|
<span>Sky Art Shop</span>
|
|
</div>
|
|
<p>
|
|
Your one-stop shop for scrapbooking, journaling, cardmaking, and
|
|
collaging stationery. Quality products for all your creative
|
|
needs.
|
|
</p>
|
|
<div class="footer-social">
|
|
<a href="#" class="social-link"><i class="bi bi-facebook"></i></a>
|
|
<a href="#" class="social-link"
|
|
><i class="bi bi-instagram"></i
|
|
></a>
|
|
<a href="#" class="social-link"
|
|
><i class="bi bi-pinterest"></i
|
|
></a>
|
|
<a href="#" class="social-link"><i class="bi bi-youtube"></i></a>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="footer-column">
|
|
<h4>Quick Links</h4>
|
|
<ul class="footer-links">
|
|
<li><a href="/home">Home</a></li>
|
|
<li><a href="/shop">Shop</a></li>
|
|
<li><a href="/portfolio">Portfolio</a></li>
|
|
<li><a href="/blog">Blog</a></li>
|
|
<li><a href="/about">About Us</a></li>
|
|
<li><a href="/contact">Contact</a></li>
|
|
</ul>
|
|
</div>
|
|
|
|
<div class="footer-column">
|
|
<h4>Customer Service</h4>
|
|
<ul class="footer-links">
|
|
<li><a href="/faq">FAQ</a></li>
|
|
<li><a href="/shipping-info">Shipping Info</a></li>
|
|
<li><a href="/returns">Returns & Refunds</a></li>
|
|
<li><a href="/privacy">Privacy Policy</a></li>
|
|
</ul>
|
|
</div>
|
|
|
|
<div class="footer-column">
|
|
<h4>Contact Us</h4>
|
|
<ul class="footer-links">
|
|
<li><i class="bi bi-envelope"></i> hello@skyartshop.com</li>
|
|
<li><i class="bi bi-telephone"></i> (555) 123-4567</li>
|
|
<li><i class="bi bi-geo-alt"></i> 123 Creative Lane</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="footer-bottom">
|
|
<p>© 2026 Sky Art Shop. All rights reserved.</p>
|
|
<p>
|
|
Made with
|
|
<i class="bi bi-heart-fill" style="color: var(--primary-pink)"></i>
|
|
for creative souls
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</footer>
|
|
|
|
<!-- Cart Drawer -->
|
|
<div class="cart-overlay"></div>
|
|
<div class="cart-drawer">
|
|
<div class="cart-header">
|
|
<h3>Shopping Cart</h3>
|
|
<button class="cart-close"><i class="bi bi-x"></i></button>
|
|
</div>
|
|
<div class="cart-items"></div>
|
|
<div class="cart-footer">
|
|
<div class="cart-total">
|
|
<span>Total:</span>
|
|
<span class="cart-total-amount">$0.00</span>
|
|
</div>
|
|
<a href="/checkout" class="btn btn-primary cart-checkout-btn"
|
|
>Checkout</a
|
|
>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Wishlist Drawer -->
|
|
<div class="wishlist-overlay"></div>
|
|
<div class="wishlist-drawer">
|
|
<div class="wishlist-header">
|
|
<h3><i class="bi bi-heart"></i> My Wishlist</h3>
|
|
<button class="wishlist-close"><i class="bi bi-x"></i></button>
|
|
</div>
|
|
<div class="wishlist-items"></div>
|
|
<div class="wishlist-footer">
|
|
<a href="/shop" class="btn btn-outline">Continue Shopping</a>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Scripts -->
|
|
<script src="/assets/js/mobile-touch-fix.js"></script>
|
|
<script src="/assets/js/modern-theme.js?v=20260119touch"></script>
|
|
<script src="/assets/js/customer-auth.js"></script>
|
|
<script>
|
|
let allProducts = [];
|
|
let filteredProducts = [];
|
|
|
|
document.addEventListener("DOMContentLoaded", async () => {
|
|
// Load all products
|
|
allProducts = await API.loadAllProducts();
|
|
filteredProducts = [...allProducts];
|
|
|
|
// Load categories
|
|
const categories = await API.loadCategories();
|
|
const categoryFilters = document.getElementById("categoryFilters");
|
|
if (categoryFilters && categories.length > 0) {
|
|
categories.forEach((cat) => {
|
|
const label = document.createElement("label");
|
|
label.className = "filter-option";
|
|
label.innerHTML = `
|
|
<input type="checkbox" name="category" value="${cat}">
|
|
<span>${cat}</span>
|
|
`;
|
|
categoryFilters.appendChild(label);
|
|
});
|
|
}
|
|
|
|
// Render products
|
|
renderProducts();
|
|
|
|
// Setup filters
|
|
setupFilters();
|
|
|
|
// Setup product card click to navigate to product page
|
|
document.addEventListener("click", (e) => {
|
|
const card = e.target.closest(".product-card");
|
|
// Don't navigate if clicking add to cart or wishlist buttons
|
|
if (
|
|
card &&
|
|
!e.target.closest(".add-to-cart-btn") &&
|
|
!e.target.closest(".wishlist-btn") &&
|
|
!e.target.closest(".quick-view-btn")
|
|
) {
|
|
e.preventDefault();
|
|
// Use slug from data attribute, fallback to product lookup
|
|
const slug = card.dataset.productSlug;
|
|
if (slug) {
|
|
window.location.href = `/product/${slug}`;
|
|
} else {
|
|
const productId = card.dataset.productId;
|
|
const product = allProducts.find(
|
|
(p) => p.id === productId || p.id === parseInt(productId),
|
|
);
|
|
if (product) {
|
|
window.location.href = `/product/${product.slug || product.id}`;
|
|
}
|
|
}
|
|
}
|
|
});
|
|
});
|
|
|
|
function renderProducts() {
|
|
const grid = document.getElementById("productsGrid");
|
|
const countEl = document.getElementById("productCount");
|
|
|
|
if (filteredProducts.length === 0) {
|
|
grid.innerHTML =
|
|
'<p class="text-center" style="grid-column: 1/-1; padding: 40px;">No products found matching your criteria.</p>';
|
|
countEl.textContent = "0 products";
|
|
return;
|
|
}
|
|
|
|
ProductRenderer.renderProducts(grid, filteredProducts);
|
|
countEl.textContent = `${filteredProducts.length} product${
|
|
filteredProducts.length !== 1 ? "s" : ""
|
|
}`;
|
|
}
|
|
|
|
function setupFilters() {
|
|
// Search
|
|
const searchInput = document.getElementById("searchInput");
|
|
let searchTimeout;
|
|
searchInput.addEventListener("input", () => {
|
|
clearTimeout(searchTimeout);
|
|
searchTimeout = setTimeout(applyFilters, 300);
|
|
});
|
|
|
|
// Category checkboxes
|
|
document.querySelectorAll('input[name="category"]').forEach((cb) => {
|
|
cb.addEventListener("change", applyFilters);
|
|
});
|
|
|
|
// Price checkboxes
|
|
document.querySelectorAll('input[name="price"]').forEach((cb) => {
|
|
cb.addEventListener("change", applyFilters);
|
|
});
|
|
|
|
// Stock checkboxes
|
|
document.querySelectorAll('input[name="stock"]').forEach((cb) => {
|
|
cb.addEventListener("change", applyFilters);
|
|
});
|
|
|
|
// Sort
|
|
document
|
|
.getElementById("sortSelect")
|
|
.addEventListener("change", applyFilters);
|
|
}
|
|
|
|
function applyFilters() {
|
|
const searchTerm = document
|
|
.getElementById("searchInput")
|
|
.value.toLowerCase();
|
|
const selectedCategories = Array.from(
|
|
document.querySelectorAll('input[name="category"]:checked'),
|
|
).map((cb) => cb.value);
|
|
const selectedPrices = Array.from(
|
|
document.querySelectorAll('input[name="price"]:checked'),
|
|
).map((cb) => cb.value);
|
|
const stockFilters = Array.from(
|
|
document.querySelectorAll('input[name="stock"]:checked'),
|
|
).map((cb) => cb.value);
|
|
const sortBy = document.getElementById("sortSelect").value;
|
|
|
|
filteredProducts = allProducts.filter((product) => {
|
|
// Search filter
|
|
if (
|
|
searchTerm &&
|
|
!product.name.toLowerCase().includes(searchTerm) &&
|
|
!(product.shortdescription || "").toLowerCase().includes(searchTerm)
|
|
) {
|
|
return false;
|
|
}
|
|
|
|
// Category filter
|
|
if (
|
|
selectedCategories.length > 0 &&
|
|
!selectedCategories.includes(product.category)
|
|
) {
|
|
return false;
|
|
}
|
|
|
|
// Price filter
|
|
if (selectedPrices.length > 0) {
|
|
const price = parseFloat(product.price);
|
|
const priceMatch = selectedPrices.some((range) => {
|
|
if (range === "0-10") return price < 10;
|
|
if (range === "10-25") return price >= 10 && price < 25;
|
|
if (range === "25-50") return price >= 25 && price < 50;
|
|
if (range === "50+") return price >= 50;
|
|
return true;
|
|
});
|
|
if (!priceMatch) return false;
|
|
}
|
|
|
|
// Stock filters
|
|
if (stockFilters.includes("in-stock") && product.stockquantity <= 0)
|
|
return false;
|
|
if (stockFilters.includes("featured") && !product.isfeatured)
|
|
return false;
|
|
|
|
return true;
|
|
});
|
|
|
|
// Sort
|
|
filteredProducts.sort((a, b) => {
|
|
switch (sortBy) {
|
|
case "price-low":
|
|
return parseFloat(a.price) - parseFloat(b.price);
|
|
case "price-high":
|
|
return parseFloat(b.price) - parseFloat(a.price);
|
|
case "name-az":
|
|
return a.name.localeCompare(b.name);
|
|
case "name-za":
|
|
return b.name.localeCompare(a.name);
|
|
default:
|
|
return 0; // newest - already sorted from API
|
|
}
|
|
});
|
|
|
|
renderProducts();
|
|
}
|
|
|
|
// Collapsible Filters for Mobile/Tablet
|
|
function initCollapsibleFilters() {
|
|
const isMobile = window.innerWidth <= 992;
|
|
const filterCards = document.querySelectorAll(".filter-card");
|
|
|
|
filterCards.forEach((card, index) => {
|
|
// Skip the search filter (first one)
|
|
if (index === 0) return;
|
|
|
|
const title = card.querySelector(".filter-title");
|
|
if (!title) return;
|
|
|
|
// Start collapsed on mobile (except search)
|
|
if (isMobile) {
|
|
card.classList.add("collapsed");
|
|
}
|
|
|
|
// Toggle on click
|
|
title.addEventListener("click", (e) => {
|
|
e.stopPropagation();
|
|
|
|
// Close other open dropdowns first
|
|
filterCards.forEach((otherCard, otherIndex) => {
|
|
if (otherIndex !== 0 && otherCard !== card) {
|
|
otherCard.classList.add("collapsed");
|
|
}
|
|
});
|
|
|
|
card.classList.toggle("collapsed");
|
|
});
|
|
});
|
|
|
|
// Close dropdowns when clicking outside
|
|
document.addEventListener("click", (e) => {
|
|
if (window.innerWidth <= 992 && !e.target.closest(".filter-card")) {
|
|
filterCards.forEach((card, index) => {
|
|
if (index > 0) {
|
|
card.classList.add("collapsed");
|
|
}
|
|
});
|
|
}
|
|
});
|
|
|
|
// Handle resize
|
|
window.addEventListener("resize", () => {
|
|
const nowMobile = window.innerWidth <= 992;
|
|
filterCards.forEach((card, index) => {
|
|
if (index === 0) return;
|
|
if (nowMobile) {
|
|
card.classList.add("collapsed");
|
|
} else {
|
|
card.classList.remove("collapsed");
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
// Initialize collapsible filters when DOM is ready
|
|
document.addEventListener("DOMContentLoaded", initCollapsibleFilters);
|
|
</script>
|
|
<script src="/assets/js/accessibility.js"></script>
|
|
</body>
|
|
</html>
|