chore: clean publish artifacts and add sources
This commit is contained in:
155
wwwroot/assets/js/admin.js
Executable file
155
wwwroot/assets/js/admin.js
Executable file
@@ -0,0 +1,155 @@
|
||||
// Sky Art Shop - Admin Panel Functions
|
||||
|
||||
// Delete confirmation with fetch
|
||||
function deleteWithConfirmation(url, itemName, redirectUrl) {
|
||||
if (!confirm(`Are you sure you want to delete ${itemName}?`)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
fetch(url, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
})
|
||||
.then((response) => {
|
||||
if (response.ok) {
|
||||
window.location.href = redirectUrl || window.location.href;
|
||||
} else {
|
||||
alert("Delete failed. Please try again.");
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
alert("Error: " + error.message);
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Image upload with preview
|
||||
function uploadImageWithPreview(fileInputId, previewId, urlInputId) {
|
||||
const input = document.getElementById(fileInputId);
|
||||
const file = input.files[0];
|
||||
|
||||
if (!file) {
|
||||
alert("Please select a file");
|
||||
return;
|
||||
}
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append("file", file);
|
||||
|
||||
fetch("/admin/upload/image", {
|
||||
method: "POST",
|
||||
body: formData,
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then((result) => {
|
||||
if (result.success) {
|
||||
document.getElementById(urlInputId).value = result.url;
|
||||
const preview = document.getElementById(previewId);
|
||||
if (preview) {
|
||||
preview.src = result.url;
|
||||
preview.style.display = "block";
|
||||
}
|
||||
showAdminNotification("Image uploaded successfully!", "success");
|
||||
} else {
|
||||
showAdminNotification("Upload failed: " + result.message, "error");
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
showAdminNotification("Upload error: " + error.message, "error");
|
||||
});
|
||||
}
|
||||
|
||||
// Show admin notification
|
||||
function showAdminNotification(message, type = "success") {
|
||||
const notification = document.createElement("div");
|
||||
notification.className = `alert alert-${
|
||||
type === "success" ? "success" : "danger"
|
||||
} alert-dismissible fade show`;
|
||||
notification.style.cssText =
|
||||
"position: fixed; top: 20px; right: 20px; z-index: 9999; min-width: 300px;";
|
||||
notification.innerHTML = `
|
||||
${message}
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
||||
`;
|
||||
|
||||
document.body.appendChild(notification);
|
||||
|
||||
setTimeout(() => {
|
||||
notification.classList.remove("show");
|
||||
setTimeout(() => notification.remove(), 150);
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
// Copy to clipboard
|
||||
function copyToClipboard(text) {
|
||||
navigator.clipboard
|
||||
.writeText(text)
|
||||
.then(() => {
|
||||
showAdminNotification("Copied to clipboard!", "success");
|
||||
})
|
||||
.catch(() => {
|
||||
showAdminNotification("Failed to copy", "error");
|
||||
});
|
||||
}
|
||||
|
||||
// Auto-generate slug from title
|
||||
function generateSlugFromTitle(titleInputId, slugInputId) {
|
||||
const titleInput = document.getElementById(titleInputId);
|
||||
const slugInput = document.getElementById(slugInputId);
|
||||
|
||||
if (titleInput && slugInput) {
|
||||
titleInput.addEventListener("input", function () {
|
||||
if (slugInput.value === "" || slugInput.dataset.auto === "true") {
|
||||
slugInput.value = titleInput.value
|
||||
.toLowerCase()
|
||||
.replace(/[^a-z0-9]+/g, "-")
|
||||
.replace(/(^-|-$)/g, "");
|
||||
slugInput.dataset.auto = "true";
|
||||
}
|
||||
});
|
||||
|
||||
slugInput.addEventListener("input", function () {
|
||||
slugInput.dataset.auto = "false";
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Form validation helper
|
||||
function validateForm(formId) {
|
||||
const form = document.getElementById(formId);
|
||||
if (!form) return true;
|
||||
|
||||
const requiredFields = form.querySelectorAll("[required]");
|
||||
let isValid = true;
|
||||
|
||||
requiredFields.forEach((field) => {
|
||||
if (!field.value.trim()) {
|
||||
field.classList.add("is-invalid");
|
||||
isValid = false;
|
||||
} else {
|
||||
field.classList.remove("is-invalid");
|
||||
}
|
||||
});
|
||||
|
||||
if (!isValid) {
|
||||
showAdminNotification("Please fill in all required fields", "error");
|
||||
}
|
||||
|
||||
return isValid;
|
||||
}
|
||||
|
||||
// Initialize tooltips
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
// Bootstrap tooltips
|
||||
var tooltipTriggerList = [].slice.call(
|
||||
document.querySelectorAll('[data-bs-toggle="tooltip"]')
|
||||
);
|
||||
if (typeof bootstrap !== "undefined") {
|
||||
tooltipTriggerList.map(function (tooltipTriggerEl) {
|
||||
return new bootstrap.Tooltip(tooltipTriggerEl);
|
||||
});
|
||||
}
|
||||
});
|
||||
378
wwwroot/assets/js/cart.js
Executable file
378
wwwroot/assets/js/cart.js
Executable file
@@ -0,0 +1,378 @@
|
||||
// Sky Art Shop - Shopping Cart Functions
|
||||
|
||||
// Add item to cart
|
||||
function addToCart(id, name, price, imageUrl = null) {
|
||||
// Get existing cart from localStorage
|
||||
let cart = JSON.parse(localStorage.getItem("cart") || "[]");
|
||||
|
||||
// Check if item already exists
|
||||
const existingItem = cart.find((item) => item.id === id);
|
||||
|
||||
if (existingItem) {
|
||||
existingItem.quantity++;
|
||||
// Update imageUrl if it was null before
|
||||
if (!existingItem.imageUrl && imageUrl) {
|
||||
existingItem.imageUrl = imageUrl;
|
||||
}
|
||||
} else {
|
||||
cart.push({ id, name, price, quantity: 1, imageUrl });
|
||||
}
|
||||
|
||||
// Save cart
|
||||
localStorage.setItem("cart", JSON.stringify(cart));
|
||||
console.log("Cart updated:", cart);
|
||||
|
||||
// Show confirmation
|
||||
showCartNotification(`${name} added to cart!`);
|
||||
updateCartCount();
|
||||
}
|
||||
|
||||
// Remove item from cart
|
||||
function removeFromCart(id) {
|
||||
let cart = JSON.parse(localStorage.getItem("cart") || "[]");
|
||||
cart = cart.filter((item) => item.id !== id);
|
||||
localStorage.setItem("cart", JSON.stringify(cart));
|
||||
updateCartCount();
|
||||
}
|
||||
|
||||
// Update cart item quantity
|
||||
function updateCartQuantity(id, quantity) {
|
||||
let cart = JSON.parse(localStorage.getItem("cart") || "[]");
|
||||
const item = cart.find((item) => item.id === id);
|
||||
if (item) {
|
||||
item.quantity = quantity;
|
||||
if (quantity <= 0) {
|
||||
cart = cart.filter((item) => item.id !== id);
|
||||
}
|
||||
}
|
||||
localStorage.setItem("cart", JSON.stringify(cart));
|
||||
updateCartCount();
|
||||
}
|
||||
|
||||
// Get cart items
|
||||
function getCart() {
|
||||
return JSON.parse(localStorage.getItem("cart") || "[]");
|
||||
}
|
||||
|
||||
// Get cart total
|
||||
function getCartTotal() {
|
||||
const cart = getCart();
|
||||
return cart.reduce((total, item) => total + item.price * item.quantity, 0);
|
||||
}
|
||||
|
||||
// Update cart count badge
|
||||
function updateCartCount() {
|
||||
const cart = getCart();
|
||||
const count = cart.reduce((total, item) => total + item.quantity, 0);
|
||||
|
||||
// Update old badge (if exists)
|
||||
const badge = document.getElementById("cart-count");
|
||||
if (badge) {
|
||||
badge.textContent = count;
|
||||
badge.style.display = count > 0 ? "inline" : "none";
|
||||
}
|
||||
|
||||
// Update navbar cart badge
|
||||
const navCartBadge = document.querySelector("#cartBtn .badge");
|
||||
if (navCartBadge) {
|
||||
navCartBadge.textContent = count;
|
||||
navCartBadge.style.display = count > 0 ? "block" : "none";
|
||||
}
|
||||
}
|
||||
|
||||
// Show cart notification
|
||||
function showCartNotification(message) {
|
||||
const notification = document.createElement("div");
|
||||
notification.className = "cart-notification";
|
||||
notification.textContent = message;
|
||||
notification.style.cssText = `
|
||||
position: fixed;
|
||||
top: 80px;
|
||||
right: 20px;
|
||||
background: #4CAF50;
|
||||
color: white;
|
||||
padding: 15px 25px;
|
||||
border-radius: 5px;
|
||||
box-shadow: 0 4px 6px rgba(0,0,0,0.2);
|
||||
z-index: 10000;
|
||||
animation: slideInFromTop 0.3s ease;
|
||||
`;
|
||||
|
||||
document.body.appendChild(notification);
|
||||
|
||||
setTimeout(() => {
|
||||
notification.style.animation = "slideOut 0.3s ease";
|
||||
setTimeout(() => notification.remove(), 300);
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
// Clear entire cart
|
||||
function clearCart() {
|
||||
localStorage.removeItem("cart");
|
||||
updateCartCount();
|
||||
}
|
||||
|
||||
// ====================================
|
||||
// Wishlist Functions
|
||||
// ====================================
|
||||
|
||||
// Add item to wishlist
|
||||
function addToWishlist(id, name, price, imageUrl) {
|
||||
let wishlist = JSON.parse(localStorage.getItem("wishlist") || "[]");
|
||||
|
||||
const existingItem = wishlist.find((item) => item.id === id);
|
||||
|
||||
if (existingItem) {
|
||||
showWishlistNotification(`${name} is already in your wishlist!`);
|
||||
return;
|
||||
}
|
||||
|
||||
wishlist.push({ id, name, price, imageUrl });
|
||||
localStorage.setItem("wishlist", JSON.stringify(wishlist));
|
||||
console.log("Wishlist updated:", wishlist);
|
||||
|
||||
showWishlistNotification(`${name} added to wishlist!`);
|
||||
updateWishlistCount();
|
||||
}
|
||||
|
||||
// Remove item from wishlist
|
||||
function removeFromWishlist(id) {
|
||||
let wishlist = JSON.parse(localStorage.getItem("wishlist") || "[]");
|
||||
wishlist = wishlist.filter((item) => item.id !== id);
|
||||
localStorage.setItem("wishlist", JSON.stringify(wishlist));
|
||||
updateWishlistCount();
|
||||
}
|
||||
|
||||
// Get wishlist items
|
||||
function getWishlist() {
|
||||
return JSON.parse(localStorage.getItem("wishlist") || "[]");
|
||||
}
|
||||
|
||||
// Update wishlist count badge
|
||||
function updateWishlistCount() {
|
||||
const wishlist = getWishlist();
|
||||
const count = wishlist.length;
|
||||
|
||||
const navWishlistBadge = document.querySelector("#wishlistBtn .badge");
|
||||
const wishlistIcon = document.querySelector("#wishlistBtn i");
|
||||
|
||||
if (navWishlistBadge) {
|
||||
navWishlistBadge.textContent = count;
|
||||
navWishlistBadge.style.display = count > 0 ? "block" : "none";
|
||||
}
|
||||
|
||||
// Change heart icon based on wishlist status
|
||||
if (wishlistIcon) {
|
||||
if (count > 0) {
|
||||
wishlistIcon.className = "bi bi-heart-fill";
|
||||
wishlistIcon.style.color = "#e74c3c";
|
||||
} else {
|
||||
wishlistIcon.className = "bi bi-heart";
|
||||
wishlistIcon.style.color = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Show wishlist notification
|
||||
function showWishlistNotification(message) {
|
||||
const notification = document.createElement("div");
|
||||
notification.className = "wishlist-notification";
|
||||
notification.textContent = message;
|
||||
notification.style.cssText = `
|
||||
position: fixed;
|
||||
top: 80px;
|
||||
right: 20px;
|
||||
background: #E91E63;
|
||||
color: white;
|
||||
padding: 15px 25px;
|
||||
border-radius: 5px;
|
||||
box-shadow: 0 4px 6px rgba(0,0,0,0.2);
|
||||
z-index: 10000;
|
||||
animation: slideInFromTop 0.3s ease;
|
||||
`;
|
||||
|
||||
document.body.appendChild(notification);
|
||||
|
||||
setTimeout(() => {
|
||||
notification.style.animation = "slideOut 0.3s ease";
|
||||
setTimeout(() => notification.remove(), 300);
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
// Clear entire wishlist
|
||||
function clearWishlist() {
|
||||
localStorage.removeItem("wishlist");
|
||||
updateWishlistCount();
|
||||
}
|
||||
|
||||
// ====================================
|
||||
// Dropdown Functions
|
||||
// ====================================
|
||||
// Render cart dropdown
|
||||
function renderCartDropdown() {
|
||||
const cart = getCart();
|
||||
const cartItems = document.getElementById("cartItems");
|
||||
const cartTotal = document.getElementById("cartTotal");
|
||||
|
||||
if (!cartItems) return;
|
||||
|
||||
if (cart.length === 0) {
|
||||
cartItems.innerHTML = '<p class="empty-message">Your cart is empty</p>';
|
||||
if (cartTotal) cartTotal.textContent = "$0.00";
|
||||
return;
|
||||
}
|
||||
|
||||
console.log("Rendering cart:", cart);
|
||||
|
||||
cartItems.innerHTML = cart
|
||||
.map((item) => {
|
||||
const imgSrc = item.imageUrl || "/assets/images/placeholder.jpg";
|
||||
console.log("Cart item image URL:", imgSrc);
|
||||
return `
|
||||
<div class="dropdown-item">
|
||||
<img src="${imgSrc}" alt="${
|
||||
item.name
|
||||
}" class="dropdown-item-image" onerror="this.src='/assets/images/placeholder.jpg'">
|
||||
<div class="dropdown-item-info">
|
||||
<div class="dropdown-item-name">${item.name}</div>
|
||||
<div class="dropdown-item-details">
|
||||
<span class="dropdown-item-quantity">Qty: ${
|
||||
item.quantity
|
||||
}</span>
|
||||
<span class="dropdown-item-price">$${(
|
||||
item.price * item.quantity
|
||||
).toFixed(2)}</span>
|
||||
</div>
|
||||
</div>
|
||||
<button class="dropdown-item-remove" onclick="removeFromCartDropdown('${
|
||||
item.id
|
||||
}')">
|
||||
<i class="bi bi-x"></i>
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
})
|
||||
.join("");
|
||||
|
||||
if (cartTotal) {
|
||||
const total = getCartTotal();
|
||||
cartTotal.textContent = `$${total.toFixed(2)}`;
|
||||
}
|
||||
}
|
||||
|
||||
// Render wishlist dropdown
|
||||
function renderWishlistDropdown() {
|
||||
const wishlist = getWishlist();
|
||||
const wishlistItems = document.getElementById("wishlistItems");
|
||||
|
||||
if (!wishlistItems) return;
|
||||
|
||||
if (wishlist.length === 0) {
|
||||
wishlistItems.innerHTML =
|
||||
'<p class="empty-message">Your wishlist is empty</p>';
|
||||
return;
|
||||
}
|
||||
|
||||
console.log("Rendering wishlist:", wishlist);
|
||||
|
||||
wishlistItems.innerHTML = wishlist
|
||||
.map((item) => {
|
||||
const imgSrc = item.imageUrl || "/assets/images/placeholder.jpg";
|
||||
console.log("Wishlist item image URL:", imgSrc);
|
||||
return `
|
||||
<div class="dropdown-item">
|
||||
<img src="${imgSrc}" alt="${
|
||||
item.name
|
||||
}" class="dropdown-item-image" onerror="this.src='/assets/images/placeholder.jpg'">
|
||||
<div class="dropdown-item-info">
|
||||
<div class="dropdown-item-name">${item.name}</div>
|
||||
<div class="dropdown-item-details">
|
||||
<span class="dropdown-item-price">$${item.price.toFixed(
|
||||
2
|
||||
)}</span>
|
||||
</div>
|
||||
</div>
|
||||
<button class="dropdown-item-remove" onclick="removeFromWishlistDropdown('${
|
||||
item.id
|
||||
}')">
|
||||
<i class="bi bi-x"></i>
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
})
|
||||
.join("");
|
||||
}
|
||||
|
||||
// Remove from cart via dropdown
|
||||
function removeFromCartDropdown(id) {
|
||||
removeFromCart(id);
|
||||
renderCartDropdown();
|
||||
updateCartCount();
|
||||
}
|
||||
|
||||
// Remove from wishlist via dropdown
|
||||
function removeFromWishlistDropdown(id) {
|
||||
removeFromWishlist(id);
|
||||
renderWishlistDropdown();
|
||||
updateWishlistCount();
|
||||
}
|
||||
|
||||
// Toggle dropdown visibility
|
||||
function toggleDropdown(dropdownId) {
|
||||
const dropdown = document.getElementById(dropdownId);
|
||||
if (!dropdown) return;
|
||||
|
||||
// Close other dropdowns
|
||||
document.querySelectorAll(".icon-dropdown").forEach((d) => {
|
||||
if (d.id !== dropdownId) {
|
||||
d.classList.remove("show");
|
||||
}
|
||||
});
|
||||
|
||||
dropdown.classList.toggle("show");
|
||||
|
||||
// Render content when opening
|
||||
if (dropdown.classList.contains("show")) {
|
||||
if (dropdownId === "cartDropdown") {
|
||||
renderCartDropdown();
|
||||
} else if (dropdownId === "wishlistDropdown") {
|
||||
renderWishlistDropdown();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Close cart/wishlist dropdowns when clicking outside
|
||||
document.addEventListener("click", function (e) {
|
||||
if (
|
||||
!e.target.closest(".dropdown-container") &&
|
||||
!e.target.closest(".nav-toggle")
|
||||
) {
|
||||
document.querySelectorAll(".icon-dropdown").forEach((d) => {
|
||||
d.classList.remove("show");
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Initialize cart and wishlist count on page load
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
updateCartCount();
|
||||
updateWishlistCount();
|
||||
|
||||
// Add click handlers for dropdown toggles
|
||||
const cartBtn = document.getElementById("cartBtn");
|
||||
const wishlistBtn = document.getElementById("wishlistBtn");
|
||||
|
||||
if (cartBtn) {
|
||||
cartBtn.addEventListener("click", function (e) {
|
||||
e.preventDefault();
|
||||
toggleDropdown("cartDropdown");
|
||||
});
|
||||
}
|
||||
|
||||
if (wishlistBtn) {
|
||||
wishlistBtn.addEventListener("click", function (e) {
|
||||
e.preventDefault();
|
||||
toggleDropdown("wishlistDropdown");
|
||||
});
|
||||
}
|
||||
});
|
||||
427
wwwroot/assets/js/main.js
Executable file
427
wwwroot/assets/js/main.js
Executable file
@@ -0,0 +1,427 @@
|
||||
// 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! 🎨");
|
||||
Reference in New Issue
Block a user