Files
SkyArtShop/website/public/shop.html

557 lines
19 KiB
HTML
Raw Normal View History

2026-01-18 02:22:05 -06:00
<!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>
2026-01-18 02:22:05 -06:00
<!-- Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
2026-01-18 02:22:05 -06:00
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Poppins:wght@600;700;800&display=swap"
rel="stylesheet"
/>
2026-01-18 02:22:05 -06:00
<!-- Icons -->
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css"
/>
2026-01-18 02:22:05 -06:00
<!-- Modern Theme CSS -->
<link
rel="stylesheet"
2026-01-18 02:22:05 -06:00
href="/assets/css/modern-theme.css?v=20260118drawer"
/>
<link
rel="stylesheet"
href="/assets/css/mobile-fixes.css?v=20260119touch"
/>
</head>
2025-12-19 20:44:46 -06:00
<body>
2026-01-18 02:22:05 -06:00
<!-- 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>
2026-01-01 22:24:30 -06:00
</div>
2026-01-18 02:22:05 -06:00
</div>
</div>
2025-12-19 20:44:46 -06:00
2026-01-18 02:22:05 -06:00
<!-- 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>
2026-01-01 22:24:30 -06:00
</div>
2026-01-18 02:22:05 -06:00
</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 -->
2026-01-01 22:24:30 -06:00
</div>
2026-01-18 02:22:05 -06:00
</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>
2026-01-01 22:24:30 -06:00
</div>
2025-12-19 20:44:46 -06:00
</div>
2026-01-01 22:24:30 -06:00
2026-01-18 02:22:05 -06:00
<!-- 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>
2026-01-01 22:24:30 -06:00
</div>
2026-01-18 02:22:05 -06:00
</div>
</aside>
<!-- Products Grid -->
<div class="shop-main">
<div class="shop-header">
<div class="shop-results">
<span id="productCount">Loading products...</span>
2026-01-01 22:24:30 -06:00
</div>
2026-01-18 02:22:05 -06:00
<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>
2026-01-01 22:24:30 -06:00
</div>
2025-12-19 20:44:46 -06:00
</div>
2026-01-18 02:22:05 -06:00
<div class="products-grid" id="productsGrid">
<div
class="loading-spinner"
style="grid-column: 1/-1; margin: 40px auto"
></div>
</div>
2025-12-19 20:44:46 -06:00
</div>
</div>
</div>
2026-01-18 02:22:05 -06:00
</section>
</main>
<!-- Footer -->
<footer class="footer">
<div class="container">
2025-12-19 20:44:46 -06:00
<div class="footer-grid">
2026-01-18 02:22:05 -06:00
<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.
2025-12-19 20:44:46 -06:00
</p>
2026-01-18 02:22:05 -06:00
<div class="footer-social">
2025-12-19 20:44:46 -06:00
<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>
2026-01-18 02:22:05 -06:00
<a href="#" class="social-link"><i class="bi bi-youtube"></i></a>
</div>
</div>
2026-01-18 02:22:05 -06:00
<div class="footer-column">
<h4>Quick Links</h4>
2025-12-19 20:44:46 -06:00
<ul class="footer-links">
2026-01-18 02:22:05 -06:00
<li><a href="/home">Home</a></li>
<li><a href="/shop">Shop</a></li>
2026-01-01 22:24:30 -06:00
<li><a href="/portfolio">Portfolio</a></li>
<li><a href="/blog">Blog</a></li>
2026-01-18 02:22:05 -06:00
<li><a href="/about">About Us</a></li>
2026-01-01 22:24:30 -06:00
<li><a href="/contact">Contact</a></li>
</ul>
</div>
2026-01-18 02:22:05 -06:00
<div class="footer-column">
<h4>Customer Service</h4>
2025-12-19 20:44:46 -06:00
<ul class="footer-links">
2026-01-01 22:24:30 -06:00
<li><a href="/faq">FAQ</a></li>
2026-01-18 02:22:05 -06:00
<li><a href="/shipping-info">Shipping Info</a></li>
<li><a href="/returns">Returns & Refunds</a></li>
2026-01-01 22:24:30 -06:00
<li><a href="/privacy">Privacy Policy</a></li>
2025-12-19 20:44:46 -06:00
</ul>
</div>
2026-01-18 02:22:05 -06:00
<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>
2026-01-18 02:22:05 -06:00
<div class="footer-bottom">
2026-01-18 02:22:05 -06:00
<p>&copy; 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>
2026-01-18 02:22:05 -06:00
<!-- 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>
2025-12-19 20:44:46 -06:00
2026-01-18 02:22:05 -06:00
<!-- 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>
2025-12-19 20:44:46 -06:00
2026-01-18 02:22:05 -06:00
<!-- 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 = [];
2025-12-19 20:44:46 -06:00
let filteredProducts = [];
2026-01-18 02:22:05 -06:00
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);
});
2026-01-01 22:24:30 -06:00
}
2026-01-18 02:22:05 -06:00
// 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}`;
2026-01-01 22:24:30 -06:00
} else {
2026-01-18 02:22:05 -06:00
const productId = card.dataset.productId;
const product = allProducts.find(
(p) => p.id === productId || p.id === parseInt(productId),
2026-01-01 22:24:30 -06:00
);
2026-01-18 02:22:05 -06:00
if (product) {
window.location.href = `/product/${product.slug || product.id}`;
}
2026-01-01 22:24:30 -06:00
}
}
2026-01-18 02:22:05 -06:00
});
});
2026-01-01 22:24:30 -06:00
2026-01-18 02:22:05 -06:00
function renderProducts() {
const grid = document.getElementById("productsGrid");
const countEl = document.getElementById("productCount");
2026-01-01 22:24:30 -06:00
2026-01-18 02:22:05 -06:00
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;
2026-01-01 22:24:30 -06:00
}
2026-01-18 02:22:05 -06:00
ProductRenderer.renderProducts(grid, filteredProducts);
countEl.textContent = `${filteredProducts.length} product${
filteredProducts.length !== 1 ? "s" : ""
}`;
2026-01-01 22:24:30 -06:00
}
2026-01-18 02:22:05 -06:00
function setupFilters() {
// Search
const searchInput = document.getElementById("searchInput");
let searchTimeout;
searchInput.addEventListener("input", () => {
clearTimeout(searchTimeout);
searchTimeout = setTimeout(applyFilters, 300);
});
2026-01-01 22:24:30 -06:00
2026-01-18 02:22:05 -06:00
// Category checkboxes
document.querySelectorAll('input[name="category"]').forEach((cb) => {
cb.addEventListener("change", applyFilters);
});
2026-01-18 02:22:05 -06:00
// Price checkboxes
document.querySelectorAll('input[name="price"]').forEach((cb) => {
cb.addEventListener("change", applyFilters);
});
2026-01-18 02:22:05 -06:00
// Stock checkboxes
document.querySelectorAll('input[name="stock"]').forEach((cb) => {
cb.addEventListener("change", applyFilters);
});
2026-01-01 22:24:30 -06:00
2026-01-18 02:22:05 -06:00
// 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;
}
2025-12-24 00:13:23 -06:00
2026-01-18 02:22:05 -06:00
// Category filter
if (
selectedCategories.length > 0 &&
!selectedCategories.includes(product.category)
) {
return false;
}
2025-12-24 00:13:23 -06:00
2026-01-18 02:22:05 -06:00
// 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;
}
2026-01-18 02:22:05 -06:00
// Stock filters
if (stockFilters.includes("in-stock") && product.stockquantity <= 0)
return false;
if (stockFilters.includes("featured") && !product.isfeatured)
return false;
2026-01-18 02:22:05 -06:00
return true;
});
2026-01-18 02:22:05 -06:00
// 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
}
2025-12-19 20:44:46 -06:00
});
2026-01-18 02:22:05 -06:00
renderProducts();
}
2025-12-19 20:44:46 -06:00
2026-01-18 02:22:05 -06:00
// Collapsible Filters for Mobile/Tablet
function initCollapsibleFilters() {
const isMobile = window.innerWidth <= 992;
const filterCards = document.querySelectorAll(".filter-card");
2025-12-19 20:44:46 -06:00
2026-01-18 02:22:05 -06:00
filterCards.forEach((card, index) => {
// Skip the search filter (first one)
if (index === 0) return;
2025-12-19 20:44:46 -06:00
2026-01-18 02:22:05 -06:00
const title = card.querySelector(".filter-title");
if (!title) return;
2026-01-01 22:24:30 -06:00
2026-01-18 02:22:05 -06:00
// Start collapsed on mobile (except search)
if (isMobile) {
card.classList.add("collapsed");
}
2025-12-19 20:44:46 -06:00
2026-01-18 02:22:05 -06:00
// Toggle on click
title.addEventListener("click", (e) => {
e.stopPropagation();
2026-01-01 22:24:30 -06:00
2026-01-18 02:22:05 -06:00
// Close other open dropdowns first
filterCards.forEach((otherCard, otherIndex) => {
if (otherIndex !== 0 && otherCard !== card) {
otherCard.classList.add("collapsed");
}
});
2025-12-19 20:44:46 -06:00
2026-01-18 02:22:05 -06:00
card.classList.toggle("collapsed");
});
});
2025-12-19 20:44:46 -06:00
2026-01-18 02:22:05 -06:00
// 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");
}
});
2025-12-19 20:44:46 -06:00
}
2026-01-18 02:22:05 -06:00
});
2025-12-19 20:44:46 -06:00
2026-01-18 02:22:05 -06:00
// 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");
}
});
2025-12-19 20:44:46 -06:00
});
2026-01-18 02:22:05 -06:00
}
2026-01-18 02:22:05 -06:00
// Initialize collapsible filters when DOM is ready
document.addEventListener("DOMContentLoaded", initCollapsibleFilters);
</script>
2026-01-18 02:22:05 -06:00
<script src="/assets/js/accessibility.js"></script>
2025-12-19 20:44:46 -06:00
</body>
</html>