Spaces:
Running
Running
| // Main JavaScript for ChromaCanvas Studio | |
| // API Configuration | |
| const UNSPLASH_API_KEY = 'YOUR_UNSPLASH_ACCESS_KEY'; // Replace with your Unsplash Access Key | |
| const UNSPLASH_BASE_URL = 'https://api.unsplash.com'; | |
| const ARTWORKS_PER_PAGE = 6; | |
| // Featured artworks data (fallback if API fails) | |
| const featuredArtworksFallback = [ | |
| { | |
| id: 1, | |
| title: "Neon Dreams", | |
| artist: "Alex Chen", | |
| image: "https://static.photos/abstract/640x360/1", | |
| likes: 245, | |
| category: "Abstract" | |
| }, | |
| { | |
| id: 2, | |
| title: "Digital Waves", | |
| artist: "Maya Rodriguez", | |
| image: "https://static.photos/blue/640x360/2", | |
| likes: 189, | |
| category: "Digital" | |
| }, | |
| { | |
| id: 3, | |
| title: "Color Symphony", | |
| artist: "James Wilson", | |
| image: "https://static.photos/gradient/640x360/3", | |
| likes: 312, | |
| category: "Gradient" | |
| }, | |
| { | |
| id: 4, | |
| title: "Urban Echoes", | |
| artist: "Sarah Kim", | |
| image: "https://static.photos/cityscape/640x360/4", | |
| likes: 156, | |
| category: "Cityscape" | |
| }, | |
| { | |
| id: 5, | |
| title: "Cosmic Dance", | |
| artist: "David Park", | |
| image: "https://static.photos/technology/640x360/5", | |
| likes: 278, | |
| category: "Sci-Fi" | |
| }, | |
| { | |
| id: 6, | |
| title: "Serene Moments", | |
| artist: "Emma Thompson", | |
| image: "https://static.photos/nature/640x360/6", | |
| likes: 194, | |
| category: "Nature" | |
| } | |
| ]; | |
| // Load featured artworks | |
| async function loadFeaturedArtworks() { | |
| const container = document.getElementById('featured-artworks'); | |
| if (!container) return; | |
| try { | |
| // Try to fetch from Unsplash API | |
| const response = await fetch( | |
| `${UNSPLASH_BASE_URL}/photos/random?count=${ARTWORKS_PER_PAGE}&query=abstract,art,digital,colorful&client_id=${UNSPLASH_API_KEY}` | |
| ); | |
| if (!response.ok) throw new Error('API request failed'); | |
| const data = await response.json(); | |
| container.innerHTML = data.map((photo, index) => ` | |
| <div class="art-card group cursor-pointer"> | |
| <div class="relative overflow-hidden rounded-2xl mb-4"> | |
| <img | |
| src="${photo.urls.regular}" | |
| alt="${photo.alt_description || 'Digital artwork'}" | |
| class="w-full h-64 object-cover image-zoom group-hover:scale-105 transition-transform duration-500" | |
| loading="lazy" | |
| > | |
| <div class="absolute inset-0 bg-gradient-to-t from-black/60 to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-300"></div> | |
| <div class="absolute bottom-4 left-4 right-4 text-white opacity-0 group-hover:opacity-100 transition-opacity duration-300"> | |
| <div class="flex justify-between items-center"> | |
| <span class="px-3 py-1 bg-white/20 backdrop-blur-sm rounded-full text-sm">${photo.tags?.[0]?.title || 'Art'}</span> | |
| <button class="like-btn p-2 rounded-full bg-white/20 backdrop-blur-sm hover:bg-white/30 transition-colors" data-id="${photo.id}"> | |
| <i data-feather="heart" class="w-4 h-4"></i> | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| <h3 class="font-display font-semibold text-lg mb-1">${photo.user.name || 'Unknown Artist'}</h3> | |
| <p class="text-gray-600 text-sm">${photo.description?.substring(0, 50) || 'Beautiful digital artwork'}...</p> | |
| <div class="flex items-center justify-between mt-3"> | |
| <span class="text-primary-600 font-medium">$${Math.floor(Math.random() * 500) + 50}</span> | |
| <div class="flex items-center gap-2 text-gray-500"> | |
| <i data-feather="eye" class="w-4 h-4"></i> | |
| <span class="text-sm">${photo.views || Math.floor(Math.random() * 1000)}</span> | |
| </div> | |
| </div> | |
| </div> | |
| `).join(''); | |
| } catch (error) { | |
| console.log('Using fallback data:', error); | |
| // Use fallback data | |
| container.innerHTML = featuredArtworksFallback.map(art => ` | |
| <div class="art-card group cursor-pointer"> | |
| <div class="relative overflow-hidden rounded-2xl mb-4"> | |
| <img | |
| src="${art.image}" | |
| alt="${art.title}" | |
| class="w-full h-64 object-cover image-zoom group-hover:scale-105 transition-transform duration-500" | |
| loading="lazy" | |
| > | |
| <div class="absolute inset-0 bg-gradient-to-t from-black/60 to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-300"></div> | |
| <div class="absolute bottom-4 left-4 right-4 text-white opacity-0 group-hover:opacity-100 transition-opacity duration-300"> | |
| <div class="flex justify-between items-center"> | |
| <span class="px-3 py-1 bg-white/20 backdrop-blur-sm rounded-full text-sm">${art.category}</span> | |
| <button class="like-btn p-2 rounded-full bg-white/20 backdrop-blur-sm hover:bg-white/30 transition-colors" data-id="${art.id}"> | |
| <i data-feather="heart" class="w-4 h-4"></i> | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| <h3 class="font-display font-semibold text-lg mb-1">${art.title}</h3> | |
| <p class="text-gray-600 text-sm">By ${art.artist}</p> | |
| <div class="flex items-center justify-between mt-3"> | |
| <span class="text-primary-600 font-medium">$${Math.floor(Math.random() * 500) + 50}</span> | |
| <div class="flex items-center gap-2 text-gray-500"> | |
| <i data-feather="heart" class="w-4 h-4"></i> | |
| <span class="text-sm">${art.likes}</span> | |
| </div> | |
| </div> | |
| </div> | |
| `).join(''); | |
| } | |
| // Re-initialize feather icons | |
| feather.replace(); | |
| // Add event listeners for like buttons | |
| document.querySelectorAll('.like-btn').forEach(btn => { | |
| btn.addEventListener('click', function(e) { | |
| e.stopPropagation(); | |
| const icon = this.querySelector('i'); | |
| const isLiked = icon.getAttribute('data-feather') === 'heart'; | |
| if (isLiked) { | |
| icon.setAttribute('data-feather', 'heart'); | |
| this.classList.remove('text-red-500'); | |
| } else { | |
| icon.setAttribute('data-feather', 'heart'); | |
| this.classList.add('text-red-500'); | |
| } | |
| feather.replace(); | |
| }); | |
| }); | |
| } | |
| // Initialize theme (light/dark mode) | |
| function initTheme() { | |
| const themeToggle = document.getElementById('theme-toggle'); | |
| if (!themeToggle) return; | |
| // Check for saved theme preference or default to light | |
| const currentTheme = localStorage.getItem('theme') || 'light'; | |
| if (currentTheme === 'dark') { | |
| document.documentElement.classList.add('dark'); | |
| themeToggle.innerHTML = '<i data-feather="sun"></i>'; | |
| } else { | |
| document.documentElement.classList.remove('dark'); | |
| themeToggle.innerHTML = '<i data-feather="moon"></i>'; | |
| } | |
| themeToggle.addEventListener('click', () => { | |
| if (document.documentElement.classList.contains('dark')) { | |
| document.documentElement.classList.remove('dark'); | |
| localStorage.setItem('theme', 'light'); | |
| themeToggle.innerHTML = '<i data-feather="moon"></i>'; | |
| } else { | |
| document.documentElement.classList.add('dark'); | |
| localStorage.setItem('theme', 'dark'); | |
| themeToggle.innerHTML = '<i data-feather="sun"></i>'; | |
| } | |
| feather.replace(); | |
| }); | |
| } | |
| // Mobile menu toggle | |
| function initMobileMenu() { | |
| const mobileMenuBtn = document.getElementById('mobile-menu-btn'); | |
| const mobileMenu = document.getElementById('mobile-menu'); | |
| if (mobileMenuBtn && mobileMenu) { | |
| mobileMenuBtn.addEventListener('click', () => { | |
| mobileMenu.classList.toggle('hidden'); | |
| const icon = mobileMenuBtn.querySelector('i'); | |
| if (mobileMenu.classList.contains('hidden')) { | |
| icon.setAttribute('data-feather', 'menu'); | |
| } else { | |
| icon.setAttribute('data-feather', 'x'); | |
| } | |
| feather.replace(); | |
| }); | |
| } | |
| } | |
| // Smooth scroll for anchor links | |
| function initSmoothScroll() { | |
| document.querySelectorAll('a[href^="#"]').forEach(anchor => { | |
| anchor.addEventListener('click', function (e) { | |
| const href = this.getAttribute('href'); | |
| if (href === '#') return; | |
| e.preventDefault(); | |
| const target = document.querySelector(href); | |
| if (target) { | |
| target.scrollIntoView({ | |
| behavior: 'smooth', | |
| block: 'start' | |
| }); | |
| } | |
| }); | |
| }); | |
| } | |
| // Initialize all functions when DOM is loaded | |
| document.addEventListener('DOMContentLoaded', () => { | |
| initTheme(); | |
| initMobileMenu(); | |
| initSmoothScroll(); | |
| // Check if we're on homepage to load artworks | |
| if (window.location.pathname.endsWith('index.html') || window.location.pathname === '/') { | |
| loadFeaturedArtworks(); | |
| } | |
| }); | |
| // Debounce function for performance | |
| function debounce(func, wait) { | |
| let timeout; | |
| return function executedFunction(...args) { | |
| const later = () => { | |
| clearTimeout(timeout); | |
| func(...args); | |
| }; | |
| clearTimeout(timeout); | |
| timeout = setTimeout(later, wait); | |
| }; | |
| } | |
| // Handle window resize with debounce | |
| window.addEventListener('resize', debounce(() => { | |
| // Handle responsive behaviors | |
| const mobileMenu = document.getElementById('mobile-menu'); | |
| if (window.innerWidth >= 768 && mobileMenu) { | |
| mobileMenu.classList.add('hidden'); | |
| const menuBtn = document.getElementById('mobile-menu-btn'); | |
| if (menuBtn) { | |
| menuBtn.querySelector('i').setAttribute('data-feather', 'menu'); | |
| feather.replace(); | |
| } | |
| } | |
| }, 250)); |