chromacanvas-studio / script.js
vFloorplan's picture
What is our your current Webflow section structure
97f8fdb verified
Raw
History Blame Contribute Delete
10.6 kB
// 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));