chore: clean publish artifacts and add sources

This commit is contained in:
2025-12-09 16:53:34 -06:00
parent 6138c0a60c
commit 673fa06d1e
62 changed files with 9137 additions and 0 deletions

4223
wwwroot/assets/css/main.css Executable file

File diff suppressed because it is too large Load Diff

BIN
wwwroot/assets/images/about-1.jpg Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

BIN
wwwroot/assets/images/about-2.jpg Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

155
wwwroot/assets/js/admin.js Executable file
View 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
View 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
View 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! 🎨");