// Links matching one or more entries in the list below can be opened without link protection.
82e00de
verified
| // Main JavaScript for RoseRadiance Design Showcase | |
| class RoseRadianceApp { | |
| constructor() { | |
| this.init(); | |
| } | |
| init() { | |
| console.log('RoseRadiance Design Showcase initialized'); | |
| this.setupEventListeners(); | |
| this.enhanceUI(); | |
| this.loadDynamicContent(); | |
| this.initializeComponents(); | |
| } | |
| setupEventListeners() { | |
| // Smooth scroll for all anchor links | |
| document.addEventListener('click', (e) => { | |
| const link = e.target.closest('a'); | |
| if (link && link.hash && link.pathname === window.location.pathname) { | |
| e.preventDefault(); | |
| const target = document.querySelector(link.hash); | |
| if (target) { | |
| target.scrollIntoView({ behavior: 'smooth' }); | |
| } | |
| } | |
| }); | |
| // Back to top button | |
| window.addEventListener('scroll', this.debounce(() => { | |
| this.toggleBackToTopButton(); | |
| }, 100)); | |
| // Responsive image loading | |
| window.addEventListener('load', () => { | |
| this.lazyLoadImages(); | |
| }); | |
| // Theme support (future dark mode) | |
| window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', e => { | |
| console.log('Theme preference changed to:', e.matches ? 'dark' : 'light'); | |
| }); | |
| } | |
| enhanceUI() { | |
| // Add hover effects to cards | |
| document.querySelectorAll('.hover-card').forEach(card => { | |
| card.addEventListener('mouseenter', () => { | |
| card.classList.add('shadow-xl', 'border-rose-200'); | |
| }); | |
| card.addEventListener('mouseleave', () => { | |
| card.classList.remove('shadow-xl', 'border-rose-200'); | |
| }); | |
| }); | |
| // Add click ripple effect to buttons | |
| document.querySelectorAll('button, a[role="button"]').forEach(button => { | |
| button.addEventListener('click', (e) => { | |
| this.createRippleEffect(e, button); | |
| }); | |
| }); | |
| } | |
| createRippleEffect(event, element) { | |
| const ripple = document.createElement('span'); | |
| const rect = element.getBoundingClientRect(); | |
| const size = Math.max(rect.width, rect.height); | |
| const x = event.clientX - rect.left - size / 2; | |
| const y = event.clientY - rect.top - size / 2; | |
| ripple.style.cssText = ` | |
| position: absolute; | |
| border-radius: 50%; | |
| background: rgba(244, 63, 94, 0.3); | |
| transform: scale(0); | |
| animation: ripple-animation 600ms linear; | |
| width: ${size}px; | |
| height: ${size}px; | |
| top: ${y}px; | |
| left: ${x}px; | |
| pointer-events: none; | |
| `; | |
| // Add CSS animation if not exists | |
| if (!document.querySelector('#ripple-styles')) { | |
| const style = document.createElement('style'); | |
| style.id = 'ripple-styles'; | |
| style.textContent = ` | |
| @keyframes ripple-animation { | |
| to { | |
| transform: scale(4); | |
| opacity: 0; | |
| } | |
| } | |
| `; | |
| document.head.appendChild(style); | |
| } | |
| element.style.position = 'relative'; | |
| element.style.overflow = 'hidden'; | |
| element.appendChild(ripple); | |
| setTimeout(() => { | |
| ripple.remove(); | |
| }, 600); | |
| } | |
| loadDynamicContent() { | |
| // This could be expanded to load content from APIs | |
| console.log('Loading dynamic content...'); | |
| // Example: Load featured designs | |
| this.loadFeaturedDesigns(); | |
| } | |
| loadFeaturedDesigns() { | |
| // Simulating API call | |
| setTimeout(() => { | |
| const designs = [ | |
| { id: 1, title: "Minimal Dashboard", category: "UI Design", likes: 42 }, | |
| { id: 2, title: "E-commerce Redesign", category: "Web Design", likes: 87 }, | |
| { id: 3, title: "Mobile App Icons", category: "App Design", likes: 63 } | |
| ]; | |
| console.log('Featured designs loaded:', designs); | |
| }, 1000); | |
| } | |
| lazyLoadImages() { | |
| const images = document.querySelectorAll('img[data-src]'); | |
| const observer = new IntersectionObserver((entries) => { | |
| entries.forEach(entry => { | |
| if (entry.isIntersecting) { | |
| const img = entry.target; | |
| img.src = img.dataset.src; | |
| img.removeAttribute('data-src'); | |
| observer.unobserve(img); | |
| } | |
| }); | |
| }); | |
| images.forEach(img => observer.observe(img)); | |
| } | |
| toggleBackToTopButton() { | |
| const scrollTop = window.pageYOffset || document.documentElement.scrollTop; | |
| const backToTop = document.querySelector('#back-to-top'); | |
| if (!backToTop) return; | |
| if (scrollTop > 300) { | |
| backToTop.classList.remove('opacity-0', 'invisible'); | |
| backToTop.classList.add('opacity-100', 'visible'); | |
| } else { | |
| backToTop.classList.remove('opacity-100', 'visible'); | |
| backToTop.classList.add('opacity-0', 'invisible'); | |
| } | |
| } | |
| initializeComponents() { | |
| // Initialize any custom components here | |
| this.initImageLightbox(); | |
| this.initSmoothTransitions(); | |
| } | |
| initImageLightbox() { | |
| // This would be expanded for a proper lightbox implementation | |
| console.log('Image lightbox ready'); | |
| } | |
| initSmoothTransitions() { | |
| // Add smooth transitions to elements | |
| document.querySelectorAll('.transition-element').forEach(element => { | |
| element.style.transition = 'all 0.3s cubic-bezier(0.4, 0, 0.2, 1)'; | |
| }); | |
| } | |
| debounce(func, wait) { | |
| let timeout; | |
| return function executedFunction(...args) { | |
| const later = () => { | |
| clearTimeout(timeout); | |
| func(...args); | |
| }; | |
| clearTimeout(timeout); | |
| timeout = setTimeout(later, wait); | |
| }; | |
| } | |
| // Utility function for toast notifications | |
| showToast(message, type = 'success') { | |
| const toast = document.createElement('div'); | |
| toast.className = `fixed bottom-4 right-4 px-6 py-3 rounded-lg shadow-xl transform transition-all duration-300 translate-x-full ${this.getToastClass(type)}`; | |
| toast.textContent = message; | |
| document.body.appendChild(toast); | |
| setTimeout(() => { | |
| toast.classList.remove('translate-x-full'); | |
| }, 10); | |
| setTimeout(() => { | |
| toast.classList.add('translate-x-full'); | |
| setTimeout(() => toast.remove(), 300); | |
| }, 3000); | |
| } | |
| getToastClass(type) { | |
| const classes = { | |
| success: 'bg-gradient-to-r from-rose-100 to-pink-100 border border-rose-200 text-rose-700', | |
| error: 'bg-red-50 border border-red-200 text-red-700', | |
| info: 'bg-blue-50 border border-blue-200 text-blue-700', | |
| warning: 'bg-yellow-50 border border-yellow-200 text-yellow-700' | |
| }; | |
| return classes[type] || classes.info; | |
| } | |
| // Analytics tracking | |
| trackEvent(event, data = {}) { | |
| console.log(`Event tracked: ${event}`, data); | |
| // Here you would integrate with Google Analytics or similar | |
| } | |
| } | |
| // Initialize the app when DOM is ready | |
| document.addEventListener('DOMContentLoaded', () => { | |
| const app = new RoseRadianceApp(); | |
| // Make app available globally for debugging | |
| window.roseRadianceApp = app; | |
| }); | |
| // Service Worker Registration (optional) | |
| if ('serviceWorker' in navigator) { | |
| window.addEventListener('load', () => { | |
| navigator.serviceWorker.register('/sw.js').then(registration => { | |
| console.log('SW registered:', registration); | |
| }).catch(registrationError => { | |
| console.log('SW registration failed:', registrationError); | |
| }); | |
| }); | |
| } | |
| // Image Gallery Helper Function | |
| function loadGalleryImages(category = 'all') { | |
| return fetch(`https://api.example.com/gallery/${category}`) | |
| .then(response => response.json()) | |
| .catch(error => { | |
| console.error('Error loading gallery images:', error); | |
| return []; | |
| }); | |
| } | |
| // Form Validation Helper | |
| function validateForm(form) { | |
| let isValid = true; | |
| const inputs = form.querySelectorAll('input[required], textarea[required]'); | |
| inputs.forEach(input => { | |
| if (!input.value.trim()) { | |
| isValid = false; | |
| input.classList.add('border-red-500'); | |
| input.classList.remove('border-rose-200'); | |
| } else { | |
| input.classList.remove('border-red-500'); | |
| input.classList.add('border-rose-200'); | |
| } | |
| }); | |
| return isValid; | |
| } |