428 lines
13 KiB
JavaScript
428 lines
13 KiB
JavaScript
|
|
// Sky Art Shop - Main JavaScript File
|
||
|
|
|
||
|
|
// ====================================
|
||
|
|
// Mobile Navigation Toggle
|
||
|
|
// ====================================
|
||
|
|
document.addEventListener("DOMContentLoaded", function () {
|
||
|
|
const navToggle = document.querySelector(".nav-toggle");
|
||
|
|
const navMenu = document.querySelector("#navDropdown");
|
||
|
|
|
||
|
|
if (navToggle && navMenu) {
|
||
|
|
// Hover to open dropdown
|
||
|
|
navToggle.addEventListener("mouseenter", function () {
|
||
|
|
navMenu.classList.add("active");
|
||
|
|
this.setAttribute("aria-expanded", "true");
|
||
|
|
|
||
|
|
const spans = this.querySelectorAll("span");
|
||
|
|
spans[0].style.transform = "rotate(45deg) translate(7px, 7px)";
|
||
|
|
spans[1].style.opacity = "0";
|
||
|
|
spans[2].style.transform = "rotate(-45deg) translate(7px, -7px)";
|
||
|
|
});
|
||
|
|
|
||
|
|
// Keep dropdown open when hovering over it
|
||
|
|
navMenu.addEventListener("mouseenter", function () {
|
||
|
|
this.classList.add("active");
|
||
|
|
});
|
||
|
|
|
||
|
|
// Close when mouse leaves both hamburger and dropdown
|
||
|
|
navToggle.addEventListener("mouseleave", function (e) {
|
||
|
|
// Delay closing to allow moving to dropdown
|
||
|
|
setTimeout(() => {
|
||
|
|
if (!navMenu.matches(":hover") && !navToggle.matches(":hover")) {
|
||
|
|
navMenu.classList.remove("active");
|
||
|
|
navToggle.setAttribute("aria-expanded", "false");
|
||
|
|
|
||
|
|
const spans = navToggle.querySelectorAll("span");
|
||
|
|
spans[0].style.transform = "none";
|
||
|
|
spans[1].style.opacity = "1";
|
||
|
|
spans[2].style.transform = "none";
|
||
|
|
}
|
||
|
|
}, 200);
|
||
|
|
});
|
||
|
|
|
||
|
|
navMenu.addEventListener("mouseleave", function () {
|
||
|
|
setTimeout(() => {
|
||
|
|
if (!navMenu.matches(":hover") && !navToggle.matches(":hover")) {
|
||
|
|
navMenu.classList.remove("active");
|
||
|
|
navToggle.setAttribute("aria-expanded", "false");
|
||
|
|
|
||
|
|
const spans = navToggle.querySelectorAll("span");
|
||
|
|
spans[0].style.transform = "none";
|
||
|
|
spans[1].style.opacity = "1";
|
||
|
|
spans[2].style.transform = "none";
|
||
|
|
}
|
||
|
|
}, 200);
|
||
|
|
});
|
||
|
|
|
||
|
|
// Click to toggle (for mobile/touch)
|
||
|
|
navToggle.addEventListener("click", function (e) {
|
||
|
|
e.stopPropagation();
|
||
|
|
const isActive = navMenu.classList.toggle("active");
|
||
|
|
this.setAttribute("aria-expanded", isActive ? "true" : "false");
|
||
|
|
|
||
|
|
// Animate hamburger menu
|
||
|
|
const spans = this.querySelectorAll("span");
|
||
|
|
if (isActive) {
|
||
|
|
spans[0].style.transform = "rotate(45deg) translate(7px, 7px)";
|
||
|
|
spans[1].style.opacity = "0";
|
||
|
|
spans[2].style.transform = "rotate(-45deg) translate(7px, -7px)";
|
||
|
|
} else {
|
||
|
|
spans[0].style.transform = "none";
|
||
|
|
spans[1].style.opacity = "1";
|
||
|
|
spans[2].style.transform = "none";
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
// Close dropdown when clicking on a link
|
||
|
|
const dropdownLinks = navMenu.querySelectorAll("a");
|
||
|
|
dropdownLinks.forEach((link) => {
|
||
|
|
link.addEventListener("click", function () {
|
||
|
|
navMenu.classList.remove("active");
|
||
|
|
navToggle.setAttribute("aria-expanded", "false");
|
||
|
|
const spans = navToggle.querySelectorAll("span");
|
||
|
|
spans[0].style.transform = "none";
|
||
|
|
spans[1].style.opacity = "1";
|
||
|
|
spans[2].style.transform = "none";
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
// Close dropdown when clicking outside
|
||
|
|
document.addEventListener("click", function (event) {
|
||
|
|
// Don't close if clicking on cart/wishlist dropdowns
|
||
|
|
if (
|
||
|
|
event.target.closest(".dropdown-container") ||
|
||
|
|
event.target.closest(".icon-dropdown")
|
||
|
|
) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
const isClickInside =
|
||
|
|
navToggle.contains(event.target) || navMenu.contains(event.target);
|
||
|
|
if (!isClickInside && navMenu.classList.contains("active")) {
|
||
|
|
navMenu.classList.remove("active");
|
||
|
|
navToggle.setAttribute("aria-expanded", "false");
|
||
|
|
const spans = navToggle.querySelectorAll("span");
|
||
|
|
spans[0].style.transform = "none";
|
||
|
|
spans[1].style.opacity = "1";
|
||
|
|
spans[2].style.transform = "none";
|
||
|
|
}
|
||
|
|
});
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
// ====================================
|
||
|
|
// Smooth Scrolling for Anchor Links
|
||
|
|
// ====================================
|
||
|
|
document.querySelectorAll('a[href^="#"]').forEach((anchor) => {
|
||
|
|
anchor.addEventListener("click", function (e) {
|
||
|
|
const href = this.getAttribute("href");
|
||
|
|
if (href !== "#" && href !== "#instagram" && href !== "#wishlist") {
|
||
|
|
e.preventDefault();
|
||
|
|
const target = document.querySelector(href);
|
||
|
|
if (target) {
|
||
|
|
target.scrollIntoView({
|
||
|
|
behavior: "smooth",
|
||
|
|
block: "start",
|
||
|
|
});
|
||
|
|
}
|
||
|
|
}
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
// ====================================
|
||
|
|
// Shop Page Filtering
|
||
|
|
// ====================================
|
||
|
|
const categoryFilter = document.getElementById("category-filter");
|
||
|
|
const sortFilter = document.getElementById("sort-filter");
|
||
|
|
|
||
|
|
if (categoryFilter) {
|
||
|
|
categoryFilter.addEventListener("change", function () {
|
||
|
|
const selectedCategory = this.value;
|
||
|
|
const productCards = document.querySelectorAll(".product-card");
|
||
|
|
|
||
|
|
productCards.forEach((card) => {
|
||
|
|
if (selectedCategory === "all") {
|
||
|
|
card.style.display = "block";
|
||
|
|
} else {
|
||
|
|
const cardCategory = card.getAttribute("data-category");
|
||
|
|
if (cardCategory === selectedCategory) {
|
||
|
|
card.style.display = "block";
|
||
|
|
} else {
|
||
|
|
card.style.display = "none";
|
||
|
|
}
|
||
|
|
}
|
||
|
|
});
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
if (sortFilter) {
|
||
|
|
sortFilter.addEventListener("change", function () {
|
||
|
|
const sortValue = this.value;
|
||
|
|
const productsGrid = document.querySelector(".products-grid");
|
||
|
|
const productCards = Array.from(document.querySelectorAll(".product-card"));
|
||
|
|
|
||
|
|
if (sortValue === "price-low") {
|
||
|
|
productCards.sort((a, b) => {
|
||
|
|
const priceA = parseFloat(
|
||
|
|
a.querySelector(".price").textContent.replace("$", "")
|
||
|
|
);
|
||
|
|
const priceB = parseFloat(
|
||
|
|
b.querySelector(".price").textContent.replace("$", "")
|
||
|
|
);
|
||
|
|
return priceA - priceB;
|
||
|
|
});
|
||
|
|
} else if (sortValue === "price-high") {
|
||
|
|
productCards.sort((a, b) => {
|
||
|
|
const priceA = parseFloat(
|
||
|
|
a.querySelector(".price").textContent.replace("$", "")
|
||
|
|
);
|
||
|
|
const priceB = parseFloat(
|
||
|
|
b.querySelector(".price").textContent.replace("$", "")
|
||
|
|
);
|
||
|
|
return priceB - priceA;
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
// Re-append sorted cards
|
||
|
|
productCards.forEach((card) => {
|
||
|
|
productsGrid.appendChild(card);
|
||
|
|
});
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
// ====================================
|
||
|
|
// Add to Cart Functionality (Basic)
|
||
|
|
// ====================================
|
||
|
|
document.querySelectorAll(".product-card .btn").forEach((button) => {
|
||
|
|
button.addEventListener("click", function (e) {
|
||
|
|
e.preventDefault();
|
||
|
|
|
||
|
|
// Get product details
|
||
|
|
const productCard = this.closest(".product-card");
|
||
|
|
const productName = productCard.querySelector("h3").textContent;
|
||
|
|
const productPrice = productCard.querySelector(".price").textContent;
|
||
|
|
|
||
|
|
// Show notification
|
||
|
|
showNotification(`${productName} added to cart!`);
|
||
|
|
|
||
|
|
// You can expand this to actually store cart items
|
||
|
|
// For example, using localStorage or sending to a server
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
// ====================================
|
||
|
|
// Contact Form Handling
|
||
|
|
// ====================================
|
||
|
|
const contactForm = document.getElementById("contactForm");
|
||
|
|
|
||
|
|
if (contactForm) {
|
||
|
|
contactForm.addEventListener("submit", function (e) {
|
||
|
|
e.preventDefault();
|
||
|
|
|
||
|
|
// Get form values
|
||
|
|
const name = document.getElementById("name").value;
|
||
|
|
const email = document.getElementById("email").value;
|
||
|
|
const phone = document.getElementById("phone").value;
|
||
|
|
const subject = document.getElementById("subject").value;
|
||
|
|
const message = document.getElementById("message").value;
|
||
|
|
|
||
|
|
// Basic validation
|
||
|
|
if (!name || !email || !subject || !message) {
|
||
|
|
showNotification("Please fill in all required fields!", "error");
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Email validation
|
||
|
|
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
||
|
|
if (!emailRegex.test(email)) {
|
||
|
|
showNotification("Please enter a valid email address!", "error");
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Here you would typically send the form data to a server
|
||
|
|
// For now, we'll just show a success message
|
||
|
|
showNotification(
|
||
|
|
"Thank you! Your message has been sent. We'll get back to you soon.",
|
||
|
|
"success"
|
||
|
|
);
|
||
|
|
|
||
|
|
// Reset form
|
||
|
|
contactForm.reset();
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
// ====================================
|
||
|
|
// Notification System
|
||
|
|
// ====================================
|
||
|
|
function showNotification(message, type = "success") {
|
||
|
|
// Create notification element
|
||
|
|
const notification = document.createElement("div");
|
||
|
|
notification.className = `notification notification-${type}`;
|
||
|
|
notification.textContent = message;
|
||
|
|
|
||
|
|
// Style the notification
|
||
|
|
notification.style.cssText = `
|
||
|
|
position: fixed;
|
||
|
|
top: 100px;
|
||
|
|
right: 20px;
|
||
|
|
background-color: ${type === "success" ? "#4CAF50" : "#F44336"};
|
||
|
|
color: white;
|
||
|
|
padding: 15px 25px;
|
||
|
|
border-radius: 5px;
|
||
|
|
box-shadow: 0 4px 6px rgba(0,0,0,0.1);
|
||
|
|
z-index: 10000;
|
||
|
|
animation: slideIn 0.3s ease-out;
|
||
|
|
`;
|
||
|
|
|
||
|
|
// Add animation
|
||
|
|
const style = document.createElement("style");
|
||
|
|
style.textContent = `
|
||
|
|
@keyframes slideIn {
|
||
|
|
from {
|
||
|
|
transform: translateX(400px);
|
||
|
|
opacity: 0;
|
||
|
|
}
|
||
|
|
to {
|
||
|
|
transform: translateX(0);
|
||
|
|
opacity: 1;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
@keyframes slideOut {
|
||
|
|
from {
|
||
|
|
transform: translateX(0);
|
||
|
|
opacity: 1;
|
||
|
|
}
|
||
|
|
to {
|
||
|
|
transform: translateX(400px);
|
||
|
|
opacity: 0;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
`;
|
||
|
|
document.head.appendChild(style);
|
||
|
|
|
||
|
|
// Add to page
|
||
|
|
document.body.appendChild(notification);
|
||
|
|
|
||
|
|
// Remove after 3 seconds
|
||
|
|
setTimeout(() => {
|
||
|
|
notification.style.animation = "slideOut 0.3s ease-out";
|
||
|
|
setTimeout(() => {
|
||
|
|
notification.remove();
|
||
|
|
}, 300);
|
||
|
|
}, 3000);
|
||
|
|
}
|
||
|
|
|
||
|
|
// ====================================
|
||
|
|
// Image Lazy Loading (Optional Enhancement)
|
||
|
|
// ====================================
|
||
|
|
if ("IntersectionObserver" in window) {
|
||
|
|
const imageObserver = new IntersectionObserver((entries, observer) => {
|
||
|
|
entries.forEach((entry) => {
|
||
|
|
if (entry.isIntersecting) {
|
||
|
|
const img = entry.target;
|
||
|
|
img.src = img.dataset.src || img.src;
|
||
|
|
img.classList.add("loaded");
|
||
|
|
observer.unobserve(img);
|
||
|
|
}
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
document.querySelectorAll("img").forEach((img) => {
|
||
|
|
imageObserver.observe(img);
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
// ====================================
|
||
|
|
// Scroll to Top Button
|
||
|
|
// ====================================
|
||
|
|
function createScrollToTopButton() {
|
||
|
|
const button = document.createElement("button");
|
||
|
|
button.innerHTML = "↑";
|
||
|
|
button.className = "scroll-to-top";
|
||
|
|
button.style.cssText = `
|
||
|
|
position: fixed;
|
||
|
|
bottom: 30px;
|
||
|
|
right: 30px;
|
||
|
|
width: 50px;
|
||
|
|
height: 50px;
|
||
|
|
background-color: #6B4E9B;
|
||
|
|
color: white;
|
||
|
|
border: none;
|
||
|
|
border-radius: 50%;
|
||
|
|
font-size: 24px;
|
||
|
|
cursor: pointer;
|
||
|
|
display: none;
|
||
|
|
z-index: 1000;
|
||
|
|
transition: all 0.3s ease;
|
||
|
|
box-shadow: 0 4px 6px rgba(0,0,0,0.1);
|
||
|
|
`;
|
||
|
|
|
||
|
|
document.body.appendChild(button);
|
||
|
|
|
||
|
|
// Show/hide button based on scroll position
|
||
|
|
window.addEventListener("scroll", () => {
|
||
|
|
if (window.pageYOffset > 300) {
|
||
|
|
button.style.display = "block";
|
||
|
|
} else {
|
||
|
|
button.style.display = "none";
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
// Scroll to top when clicked
|
||
|
|
button.addEventListener("click", () => {
|
||
|
|
window.scrollTo({
|
||
|
|
top: 0,
|
||
|
|
behavior: "smooth",
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
// Hover effect
|
||
|
|
button.addEventListener("mouseenter", () => {
|
||
|
|
button.style.backgroundColor = "#5a3e82";
|
||
|
|
button.style.transform = "translateY(-3px)";
|
||
|
|
});
|
||
|
|
|
||
|
|
button.addEventListener("mouseleave", () => {
|
||
|
|
button.style.backgroundColor = "#6B4E9B";
|
||
|
|
button.style.transform = "translateY(0)";
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
// Initialize scroll to top button
|
||
|
|
createScrollToTopButton();
|
||
|
|
|
||
|
|
// ====================================
|
||
|
|
// Portfolio Gallery Hover Effects
|
||
|
|
// ====================================
|
||
|
|
document.querySelectorAll(".portfolio-category").forEach((category) => {
|
||
|
|
category.addEventListener("mouseenter", function () {
|
||
|
|
this.style.transition = "all 0.3s ease";
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
// ====================================
|
||
|
|
// Active Navigation Link Highlighting
|
||
|
|
// ====================================
|
||
|
|
function highlightActiveNavLink() {
|
||
|
|
const currentPage = window.location.pathname.split("/").pop() || "index.html";
|
||
|
|
const navLinks = document.querySelectorAll(".nav-menu a");
|
||
|
|
|
||
|
|
navLinks.forEach((link) => {
|
||
|
|
const linkPage = link.getAttribute("href").split("/").pop().split("#")[0];
|
||
|
|
if (linkPage === currentPage) {
|
||
|
|
link.classList.add("active");
|
||
|
|
}
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
highlightActiveNavLink();
|
||
|
|
|
||
|
|
// ====================================
|
||
|
|
// Print console message
|
||
|
|
// ====================================
|
||
|
|
console.log(
|
||
|
|
"%c Sky Art Shop Website ",
|
||
|
|
"background: #6B4E9B; color: white; font-size: 20px; padding: 10px;"
|
||
|
|
);
|
||
|
|
console.log("Welcome to Sky Art Shop! 🎨");
|