Animations can transform a static interface into an engaging experience. Reveal animations, in particular, add a touch of elegance and surprise to UI elements.
In this article, we will explore 10 stunning reveal animation examples that can elevate your design projects. Each example showcases unique techniques to captivate users and enhance interactivity.
CODE1
Here's the code:
CODETEXT1
CODE2
Here's the code:
CODETEXT2
CODE3
Here's the code:
CODETEXT3
CODE4
Here's the code:
CODETEXT4
CODE5
Here's the code:
CODETEXT5
Subframe's drag-and-drop interface and intuitive, responsive canvas make designing pixel-perfect reveal animations a breeze. Loved by designers and developers alike, it ensures your UI is stunning every time.
Start for free and elevate your design projects today!
CODE6
Here's the code:
CODETEXT6
CODE7
Here's the code:
CODETEXT7
CODE8
Here's the code:
CODETEXT8
CODE9
Here's the code:
CODETEXT9
CODE10
Here's the code:
CODETEXT10
Ready to elevate your UI design game? With Subframe, you can create pixel-perfect interfaces and stunning reveal animations effortlessly. Our drag-and-drop editor ensures efficiency and precision.
Don't wait—start for free and begin designing beautiful UIs immediately. Join the community of designers and developers who trust Subframe for their projects.
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Luminous - Premium Lighting Collection</title> <style> :root { --primary: #f5f5f5; --secondary: #333333; --accent: #ff6b6b; --neutral-light: #e0e0e0; --neutral-dark: #707070; --spacing-xs: 8px; --spacing-sm: 16px; --spacing-md: 24px; --spacing-lg: 32px; --spacing-xl: 48px; --font-primary: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif; --transition-slow: 0.6s cubic-bezier(0.16, 1, 0.3, 1); --transition-medium: 0.4s cubic-bezier(0.16, 1, 0.3, 1); --transition-fast: 0.2s cubic-bezier(0.16, 1, 0.3, 1); } * { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: var(--font-primary); background-color: var(--primary); color: var(--secondary); line-height: 1.6; overflow-x: hidden; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } .container { max-width: 700px; margin: 0 auto; padding: var(--spacing-md); height: 700px; overflow-y: auto; scrollbar-width: thin; scrollbar-color: var(--neutral-dark) var(--primary); } .container::-webkit-scrollbar { width: 6px; } .container::-webkit-scrollbar-track { background: var(--primary); } .container::-webkit-scrollbar-thumb { background-color: var(--neutral-dark); border-radius: 6px; } header { padding: var(--spacing-md) 0; position: sticky; top: 0; background-color: rgba(245, 245, 245, 0.9); backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px); z-index: 100; border-bottom: 1px solid var(--neutral-light); } .header-inner { display: flex; justify-content: space-between; align-items: center; } .logo { font-size: 1.4rem; font-weight: 700; letter-spacing: -0.02em; color: var(--secondary); } .logo span { color: var(--accent); } .product-grid { margin-top: var(--spacing-lg); display: grid; grid-template-columns: 1fr; gap: var(--spacing-xl); } .product-card { position: relative; opacity: 0; transform: translateY(30px); transition: opacity var(--transition-medium), transform var(--transition-medium); } .product-card.visible { opacity: 1; transform: translateY(0); } .product-image { aspect-ratio: 4/3; background-color: var(--neutral-light); border-radius: 8px; overflow: hidden; position: relative; } .product-image img { width: 100%; height: 100%; object-fit: cover; transition: transform var(--transition-medium); } .product-image::after { content: ''; position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: linear-gradient(to bottom, rgba(0,0,0,0) 70%, rgba(0,0,0,0.1) 100%); opacity: 0; transition: opacity var(--transition-medium); } .product-card:hover .product-image::after { opacity: 1; } .product-card:hover .product-image img { transform: scale(1.05); } .product-content { margin-top: var(--spacing-sm); } .product-title { font-size: 1.2rem; font-weight: 600; margin-bottom: var(--spacing-xs); position: relative; display: inline-block; } .product-title::after { content: ''; position: absolute; bottom: -2px; left: 0; width: 0; height: 2px; background-color: var(--accent); transition: width var(--transition-medium); } .product-card:hover .product-title::after { width: 100%; } .product-desc { font-size: 0.9rem; color: var(--neutral-dark); margin-bottom: var(--spacing-sm); line-height: 1.5; } .product-meta { display: flex; justify-content: space-between; align-items: center; font-size: 0.9rem; } .product-price { font-weight: 600; } .product-cta { display: inline-flex; align-items: center; gap: var(--spacing-xs); color: var(--accent); font-weight: 500; cursor: pointer; transition: transform var(--transition-fast); } .product-cta:hover { transform: translateX(4px); } .product-cta svg { width: 16px; height: 16px; transition: transform var(--transition-fast); } .product-cta:hover svg { transform: translateX(2px); } .product-badge { position: absolute; top: var(--spacing-sm); right: var(--spacing-sm); background-color: var(--accent); color: white; padding: 4px 8px; font-size: 0.7rem; font-weight: 600; border-radius: 4px; z-index: 10; opacity: 0; transform: translateY(-10px); transition: opacity var(--transition-medium), transform var(--transition-medium); } .product-card.visible .product-badge { opacity: 1; transform: translateY(0); transition-delay: 0.2s; } .product-specs { margin-top: var(--spacing-sm); padding: var(--spacing-sm); background-color: var(--neutral-light); border-radius: 8px; font-size: 0.85rem; opacity: 0; transform: scaleY(0.9); transform-origin: top; height: 0; overflow: hidden; transition: opacity var(--transition-medium), transform var(--transition-medium), height var(--transition-medium); } .product-card.expanded .product-specs { opacity: 1; transform: scaleY(1); height: auto; padding: var(--spacing-sm); margin-top: var(--spacing-sm); } .specs-title { font-weight: 600; margin-bottom: var(--spacing-xs); } .specs-list { display: grid; grid-template-columns: 1fr 1fr; gap: var(--spacing-xs); } .specs-item { display: flex; align-items: center; gap: var(--spacing-xs); } .specs-item-label { color: var(--neutral-dark); } .progress-bar { position: fixed; top: 0; left: 0; width: 0%; height: 3px; background-color: var(--accent); z-index: 1000; } .quick-view { position: fixed; top: 0; left: 0; width: 100%; height: 100%; display: flex; align-items: center; justify-content: center; background-color: rgba(0, 0, 0, 0.8); opacity: 0; pointer-events: none; transition: opacity var(--transition-medium); z-index: 1000; } .quick-view.active { opacity: 1; pointer-events: all; } .quick-view-content { background-color: var(--primary); width: 90%; max-width: 600px; border-radius: 8px; padding: var(--spacing-lg); position: relative; opacity: 0; transform: translateY(20px); transition: opacity var(--transition-medium), transform var(--transition-medium); transition-delay: 0.1s; } .quick-view.active .quick-view-content { opacity: 1; transform: translateY(0); } .quick-view-close { position: absolute; top: var(--spacing-md); right: var(--spacing-md); width: 24px; height: 24px; cursor: pointer; opacity: 0.7; transition: opacity var(--transition-fast); } .quick-view-close:hover { opacity: 1; } .quick-view-gallery { display: grid; grid-template-columns: 1fr 1fr; gap: var(--spacing-md); margin-bottom: var(--spacing-md); } .quick-view-gallery img { width: 100%; aspect-ratio: 1; object-fit: cover; border-radius: 4px; } .quick-view-title { font-size: 1.5rem; font-weight: 600; margin-bottom: var(--spacing-sm); } .quick-view-desc { margin-bottom: var(--spacing-md); color: var(--neutral-dark); } .quick-view-price { font-size: 1.3rem; font-weight: 600; margin-bottom: var(--spacing-md); } .quick-view-actions { display: flex; gap: var(--spacing-md); margin-top: var(--spacing-md); } .quick-view-btn { padding: var(--spacing-sm) var(--spacing-md); border-radius: 4px; font-weight: 500; font-size: 0.9rem; cursor: pointer; transition: all var(--transition-fast); } .primary-btn { background-color: var(--accent); color: white; border: none; flex: 2; } .primary-btn:hover { background-color: #ff5252; } .secondary-btn { background-color: transparent; color: var(--secondary); border: 1px solid var(--neutral-dark); flex: 1; } .secondary-btn:hover { background-color: var(--neutral-light); } .footer { margin-top: var(--spacing-xl); padding: var(--spacing-md) 0; border-top: 1px solid var(--neutral-light); text-align: center; font-size: 0.8rem; color: var(--neutral-dark); } @media (max-width: 600px) { .product-meta { flex-direction: column; align-items: flex-start; gap: var(--spacing-xs); } .specs-list { grid-template-columns: 1fr; } .quick-view-gallery { grid-template-columns: 1fr; } .quick-view-actions { flex-direction: column; } } </style> </head> <body> <div class="progress-bar"></div> <div class="container"> <header> <div class="header-inner"> <div class="logo">Luminous<span>.</span></div> <div class="cart-count">Cart (0)</div> </div> </header> <div class="product-grid"> <div class="product-card" data-id="1"> <div class="product-badge">NEW ARRIVAL</div> <div class="product-image"> <img src="https://images.unsplash.com/photo-1540932239986-30128078f3c5?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=774&q=80" alt="Halo Pendant Light"> </div> <div class="product-content"> <h3 class="product-title">Halo Pendant Light</h3> <p class="product-desc">Minimalist halo-shaped LED pendant with adjustable height and dimmable warm lighting. Perfect for dining spaces.</p> <div class="product-meta"> <div class="product-price">$189.00</div> <div class="product-cta">View details <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor"> <path fill-rule="evenodd" d="M12.293 5.293a1 1 0 011.414 0l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414-1.414L14.586 11H3a1 1 0 110-2h11.586l-2.293-2.293a1 1 0 010-1.414z" clip-rule="evenodd" /> </svg> </div> </div> </div> <div class="product-specs"> <div class="specs-title">Specifications</div> <div class="specs-list"> <div class="specs-item"> <span class="specs-item-label">Material:</span> <span>Aluminum, Acrylic</span> </div> <div class="specs-item"> <span class="specs-item-label">Diameter:</span> <span>45 cm</span> </div> <div class="specs-item"> <span class="specs-item-label">Max Height:</span> <span>120 cm</span> </div> <div class="specs-item"> <span class="specs-item-label">Light Source:</span> <span>LED 18W</span> </div> </div> </div> </div> <div class="product-card" data-id="2"> <div class="product-badge">BESTSELLER</div> <div class="product-image"> <img src="https://images.unsplash.com/photo-1513506003901-1e6a229e2d15?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=1770&q=80" alt="Aria Floor Lamp"> </div> <div class="product-content"> <h3 class="product-title">Aria Floor Lamp</h3> <p class="product-desc">Sculptural floor lamp with brass accents and a linen shade. Features 3-way lighting control for ambient to task illumination.</p> <div class="product-meta"> <div class="product-price">$249.00</div> <div class="product-cta">View details <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor"> <path fill-rule="evenodd" d="M12.293 5.293a1 1 0 011.414 0l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414-1.414L14.586 11H3a1 1 0 110-2h11.586l-2.293-2.293a1 1 0 010-1.414z" clip-rule="evenodd" /> </svg> </div> </div> </div> <div class="product-specs"> <div class="specs-title">Specifications</div> <div class="specs-list"> <div class="specs-item"> <span class="specs-item-label">Material:</span> <span>Brass, Linen, Marble</span> </div> <div class="specs-item"> <span class="specs-item-label">Height:</span> <span>160 cm</span> </div> <div class="specs-item"> <span class="specs-item-label">Shade Diameter:</span> <span>35 cm</span> </div> <div class="specs-item"> <span class="specs-item-label">Bulb Type:</span> <span>E27, max 60W</span> </div> </div> </div> </div> <div class="product-card" data-id="3"> <div class="product-image"> <img src="https://images.unsplash.com/photo-1507473885765-e6ed057f782c?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=1770&q=80" alt="Nova Table Lamp"> </div> <div class="product-content"> <h3 class="product-title">Nova Table Lamp</h3> <p class="product-desc">Compact concrete base table lamp with an articulating arm. Features touch-sensitive dimming and USB charging port.</p> <div class="product-meta"> <div class="product-price">$129.00</div> <div class="product-cta">View details <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor"> <path fill-rule="evenodd" d="M12.293 5.293a1 1 0 011.414 0l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414-1.414L14.586 11H3a1 1 0 110-2h11.586l-2.293-2.293a1 1 0 010-1.414z" clip-rule="evenodd" /> </svg> </div> </div> </div> <div class="product-specs"> <div class="specs-title">Specifications</div> <div class="specs-list"> <div class="specs-item"> <span class="specs-item-label">Material:</span> <span>Concrete, Aluminum</span> </div> <div class="specs-item"> <span class="specs-item-label">Height:</span> <span>38 cm</span> </div> <div class="specs-item"> <span class="specs-item-label">Base Diameter:</span> <span>12 cm</span> </div> <div class="specs-item"> <span class="specs-item-label">Light Source:</span> <span>LED 8W integrated</span> </div> </div> </div> </div> <div class="product-card" data-id="4"> <div class="product-badge">LIMITED EDITION</div> <div class="product-image"> <img src="https://images.unsplash.com/photo-1517991104123-1d56a6e81ed9?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=1770&q=80" alt="Orb Ceiling Light"> </div> <div class="product-content"> <h3 class="product-title">Orb Ceiling Light</h3> <p class="product-desc">Floating glass orb design with hand-blown glass and brass details. Creates a stunning reflective light pattern.</p> <div class="product-meta"> <div class="product-price">$349.00</div> <div class="product-cta">View details <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor"> <path fill-rule="evenodd" d="M12.293 5.293a1 1 0 011.414 0l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414-1.414L14.586 11H3a1 1 0 110-2h11.586l-2.293-2.293a1 1 0 010-1.414z" clip-rule="evenodd" /> </svg> </div> </div> </div> <div class="product-specs"> <div class="specs-title">Specifications</div> <div class="specs-list"> <div class="specs-item"> <span class="specs-item-label">Material:</span> <span>Blown Glass, Brass</span> </div> <div class="specs-item"> <span class="specs-item-label">Diameter:</span> <span>30 cm</span> </div> <div class="specs-item"> <span class="specs-item-label">Cord Length:</span> <span>150 cm (adjustable)</span> </div> <div class="specs-item"> <span class="specs-item-label">Bulb Type:</span> <span>G9, max 40W</span> </div> </div> </div> </div> </div> <div class="footer"> <p>© 2023 Luminous Lighting. Premium light fixtures for modern living.</p> </div> </div> <div class="quick-view"> <div class="quick-view-content"> <div class="quick-view-close"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor"> <path fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd" /> </svg> </div> <div class="quick-view-gallery"> <img id="qv-img-1" src="" alt=""> <img id="qv-img-2" src="" alt=""> </div> <h2 class="quick-view-title" id="qv-title"></h2> <p class="quick-view-desc" id="qv-desc"></p> <div class="quick-view-price" id="qv-price"></div> <div class="quick-view-actions"> <button class="quick-view-btn primary-btn">Add to Cart</button> <button class="quick-view-btn secondary-btn">Save</button> </div> </div> </div> <script> document.addEventListener('DOMContentLoaded', function() { const container = document.querySelector('.container'); const productCards = document.querySelectorAll('.product-card'); const progressBar = document.querySelector('.progress-bar'); const quickView = document.querySelector('.quick-view'); const quickViewClose = document.querySelector('.quick-view-close'); const quickViewTitle = document.getElementById('qv-title'); const quickViewDesc = document.getElementById('qv-desc'); const quickViewPrice = document.getElementById('qv-price'); const quickViewImg1 = document.getElementById('qv-img-1'); const quickViewImg2 = document.getElementById('qv-img-2'); // Product data - in a real app, this would come from an API const products = { 1: { title: "Halo Pendant Light", desc: "The Halo Pendant Light redefines modern ceiling lighting with its minimalist design and sophisticated functionality. The circular LED strip creates a floating ring of light that casts both direct and ambient illumination, perfect for creating a focal point over dining tables or in living spaces. Height-adjustable cords allow for versatile installation in rooms with different ceiling heights.", price: "$189.00", img1: "https://images.unsplash.com/photo-1540932239986-30128078f3c5?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=774&q=80", img2: "https://images.unsplash.com/photo-1565814329452-e1efa11c5b89?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=774&q=80" }, 2: { title: "Aria Floor Lamp", desc: "The Aria Floor Lamp combines form and function with its sculptural silhouette and versatile lighting options. The brass stem creates a graceful arc that positions the linen shade perfectly for reading or ambient lighting. A marble base provides stability while adding a touch of luxury. Three-way lighting allows you to adjust brightness to suit any moment, from quiet reading to entertaining.", price: "$249.00", img1: "https://images.unsplash.com/photo-1513506003901-1e6a229e2d15?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=1770&q=80", img2: "https://images.unsplash.com/photo-1567459169668-95d355371bda?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=774&q=80" }, 3: { title: "Nova Table Lamp", desc: "The Nova Table Lamp balances industrial aesthetics with modern convenience. Its solid concrete base provides a sturdy foundation for the articulating arm that puts light exactly where you need it. The integrated touch dimmer lets you control brightness with a simple tap, while the USB port keeps your devices charged. Ideal for bedside tables, desks, or any small space needing flexible lighting.", price: "$129.00", img1: "https://images.unsplash.com/photo-1507473885765-e6ed057f782c?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=1770&q=80", img2: "https://images.unsplash.com/photo-1530603907829-659ab5ec057b?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=774&q=80" }, 4: { title: "Orb Ceiling Light", desc: "The Orb Ceiling Light is a statement piece that transforms any space with its mesmerizing play of light and reflection. Each sphere is individually hand-blown by master craftsmen, ensuring unique variations in the glass. When illuminated, the fixture creates captivating light patterns on surrounding surfaces while providing a warm, diffused glow. Limited production makes each piece a collector's item for design enthusiasts.", price: "$349.00", img1: "https://images.unsplash.com/photo-1517991104123-1d56a6e81ed9?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=1770&q=80", img2: "https://images.unsplash.com/photo-1519710164239-da123dc03ef4?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=774&q=80" } }; // Check if product cards are in viewport and reveal them function checkVisibility() { productCards.forEach(card => { const rect = card.getBoundingClientRect(); const isInViewport = ( rect.top >= 0 && rect.left >= 0 && rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && rect.right <= (window.innerWidth || document.documentElement.clientWidth) ); if (isInViewport) { card.classList.add('visible'); } }); } // Update progress bar based on scroll position function updateProgressBar() { const scrollPosition = container.scrollTop; const scrollHeight = container.scrollHeight - container.clientHeight; const scrollPercentage = (scrollPosition / scrollHeight) * 100; progressBar.style.width = `${scrollPercentage}%`; } // Initialize visibility check checkVisibility(); // Event listeners for scroll container.addEventListener('scroll', () => { checkVisibility(); updateProgressBar(); }); // Product detail view toggle document.querySelectorAll('.product-cta').forEach(cta => { cta.addEventListener('click', function(e) { e.preventDefault(); const card = this.closest('.product-card'); const productId = card.dataset.id; // Populate quick view with product data const product = products[productId]; quickViewTitle.textContent = product.title; quickViewDesc.textContent = product.desc; quickViewPrice.textContent = product.price; quickViewImg1.src = product.img1; quickViewImg2.src = product.img2; // Show quick view quickView.classList.add('active'); }); }); // Close quick view quickViewClose.addEventListener('click', function() { quickView.classList.remove('active'); }); // Close quick view when clicking outside content quickView.addEventListener('click', function(e) { if (e.target === quickView) { quickView.classList.remove('active'); } }); // Toggle product specs document.querySelectorAll('.product-title').forEach(title => { title.addEventListener('click', function() { const card = this.closest('.product-card'); card.classList.toggle('expanded'); }); }); // Prevent actual form submission document.querySelectorAll('button').forEach(button => { button.addEventListener('click', function(e) { e.preventDefault(); }); }); }); </script> </body> </html>
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>MetricVision Dashboard</title> <style> :root { --primary-color: #1a2b47; --secondary-color: #0a5bf5; --accent-color: #00e6c3; --text-color: #e0e5ec; --dark-text: #213547; --grid-line: rgba(255, 255, 255, 0.1); --card-bg: rgba(26, 43, 71, 0.85); --card-hover: rgba(10, 91, 245, 0.1); --success-color: #00e676; --warning-color: #ffab00; --error-color: #ff5252; } * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; } body { background-color: var(--primary-color); color: var(--text-color); overflow-x: hidden; height: 100%; background-image: radial-gradient(circle at 15% 50%, rgba(10, 91, 245, 0.1) 0%, transparent 25%), radial-gradient(circle at 85% 30%, rgba(0, 230, 195, 0.1) 0%, transparent 30%); } .dashboard-container { max-width: 700px; height: 700px; margin: 0 auto; padding: 20px; display: grid; grid-template-rows: auto 1fr; gap: 20px; overflow-y: auto; position: relative; } .dashboard-container::before { content: ''; position: absolute; top: 0; left: 0; width: 100%; height: 100%; background-image: linear-gradient(rgba(10, 91, 245, 0.05) 1px, transparent 1px), linear-gradient(90deg, rgba(10, 91, 245, 0.05) 1px, transparent 1px); background-size: 20px 20px; z-index: -1; } .header { display: flex; justify-content: space-between; align-items: center; border-bottom: 1px solid var(--grid-line); padding-bottom: 15px; } .logo { display: flex; align-items: center; gap: 10px; } .logo-icon { width: 30px; height: 30px; background: var(--accent-color); border-radius: 6px; display: grid; place-items: center; transform: rotate(45deg); } .logo-text { font-weight: 700; font-size: 18px; letter-spacing: 0.5px; } .date-selector { padding: 8px 16px; border-radius: 50px; border: 1px solid var(--grid-line); background: transparent; color: var(--text-color); font-size: 14px; cursor: pointer; transition: all 0.3s ease; } .date-selector:hover { background: rgba(255, 255, 255, 0.1); } .metrics-grid { display: grid; grid-template-columns: repeat(6, 1fr); grid-template-rows: auto; gap: 20px; grid-template-areas: "kpi1 kpi1 kpi2 kpi2 kpi3 kpi3" "chart1 chart1 chart1 chart2 chart2 chart2" "chart3 chart3 chart3 chart3 chart3 chart3"; } .metric-card { background: var(--card-bg); border-radius: 12px; padding: 20px; backdrop-filter: blur(10px); border: 1px solid var(--grid-line); transition: all 0.4s cubic-bezier(0.16, 1, 0.3, 1); transform: translateY(20px); opacity: 0; position: relative; overflow: hidden; } .metric-card::before { content: ''; position: absolute; top: 0; left: 0; width: 100%; height: 4px; background: linear-gradient(90deg, var(--secondary-color), var(--accent-color)); transform: scaleX(0); transform-origin: left; transition: transform 0.6s ease-out; } .metric-card:hover::before { transform: scaleX(1); } .metric-card:hover { box-shadow: 0 8px 32px rgba(0, 0, 0, 0.2); transform: translateY(0) scale(1.02); border-color: rgba(255, 255, 255, 0.2); background: var(--card-hover); } .kpi-card { display: flex; flex-direction: column; justify-content: space-between; } .kpi-title { font-size: 14px; font-weight: 500; color: rgba(255, 255, 255, 0.7); margin-bottom: 10px; } .kpi-value { font-size: 28px; font-weight: 700; margin-bottom: 5px; } .kpi-change { font-size: 13px; display: flex; align-items: center; gap: 5px; } .up { color: var(--success-color); } .down { color: var(--error-color); } .metric-icon { position: absolute; top: 20px; right: 20px; width: 30px; height: 30px; display: grid; place-items: center; border-radius: 50%; background: rgba(255, 255, 255, 0.1); } .chart-container { position: relative; height: 100%; width: 100%; min-height: 200px; } .chart-title { margin-bottom: 15px; font-weight: 600; font-size: 16px; display: flex; justify-content: space-between; align-items: center; } .legend { display: flex; gap: 15px; margin-top: 5px; font-size: 12px; } .legend-item { display: flex; align-items: center; gap: 5px; } .legend-color { width: 10px; height: 10px; border-radius: 50%; } #kpi1 { grid-area: kpi1; } #kpi2 { grid-area: kpi2; } #kpi3 { grid-area: kpi3; } #chart1 { grid-area: chart1; } #chart2 { grid-area: chart2; } #chart3 { grid-area: chart3; } canvas { max-width: 100%; } .chart-tooltip { position: absolute; background: rgba(20, 27, 43, 0.95); border: 1px solid var(--grid-line); padding: 10px; border-radius: 6px; font-size: 12px; pointer-events: none; opacity: 0; transition: opacity 0.3s; z-index: 10; box-shadow: 0 4px 20px rgba(0, 0, 0, 0.2); backdrop-filter: blur(10px); } @media (max-width: 600px) { .metrics-grid { grid-template-columns: 1fr; grid-template-areas: "kpi1" "kpi2" "kpi3" "chart1" "chart2" "chart3"; } .chart-container { min-height: 180px; } } /* Pulse animation for metrics */ @keyframes pulse { 0% { transform: scale(1); } 50% { transform: scale(1.05); } 100% { transform: scale(1); } } .pulse { animation: pulse 1.5s ease infinite; } /* Shimmer effect for loading state */ .shimmer { background: linear-gradient(90deg, var(--card-bg) 0%, rgba(40, 60, 100, 0.8) 50%, var(--card-bg) 100%); background-size: 200% 100%; animation: shimmer 2s infinite; } @keyframes shimmer { 0% { background-position: -200% 0; } 100% { background-position: 200% 0; } } .badge { font-size: 11px; padding: 3px 8px; border-radius: 20px; background: rgba(0, 230, 195, 0.2); color: var(--accent-color); } .tooltip-title { font-weight: 600; margin-bottom: 5px; color: var(--accent-color); } .tooltip-value { font-size: 14px; font-weight: 700; margin-bottom: 5px; } .tooltip-date { opacity: 0.7; font-size: 11px; } .data-point { cursor: pointer; transition: all 0.3s ease; } .data-point:hover { transform: scale(1.2); } </style> </head> <body> <div class="dashboard-container"> <div class="header"> <div class="logo"> <div class="logo-icon"> <svg width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M3 9L12 4.5L21 9L12 13.5L3 9Z" stroke="#1a2b47" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> <path d="M21 9V15L12 19.5L3 15V9" stroke="#1a2b47" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> </svg> </div> <div class="logo-text">MetricVision</div> </div> <select class="date-selector"> <option value="7d">Last 7 days</option> <option value="30d" selected>Last 30 days</option> <option value="90d">Last 90 days</option> <option value="1y">Last year</option> </select> </div> <div class="metrics-grid"> <div id="kpi1" class="metric-card kpi-card"> <div> <div class="kpi-title">Active Users</div> <div class="kpi-value">47,582</div> <div class="kpi-change up"> <svg width="12" height="12" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M12 5L12 19M12 5L18 11M12 5L6 11" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> </svg> +12.8% from last period </div> </div> <div class="metric-icon"> <svg width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M17 21V19C17 17.9391 16.5786 16.9217 15.8284 16.1716C15.0783 15.4214 14.0609 15 13 15H5C3.93913 15 2.92172 15.4214 2.17157 16.1716C1.42143 16.9217 1 17.9391 1 19V21" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> <path d="M9 11C11.2091 11 13 9.20914 13 7C13 4.79086 11.2091 3 9 3C6.79086 3 5 4.79086 5 7C5 9.20914 6.79086 11 9 11Z" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> <path d="M23 21V19C22.9993 18.1137 22.7044 17.2528 22.1614 16.5523C21.6184 15.8519 20.8581 15.3516 20 15.13" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> <path d="M16 3.13C16.8604 3.35031 17.623 3.85071 18.1676 4.55232C18.7122 5.25392 19.0078 6.11683 19.0078 7.005C19.0078 7.89318 18.7122 8.75608 18.1676 9.45769C17.623 10.1593 16.8604 10.6597 16 10.88" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> </svg> </div> </div> <div id="kpi2" class="metric-card kpi-card"> <div> <div class="kpi-title">Conversion Rate</div> <div class="kpi-value">8.2%</div> <div class="kpi-change up"> <svg width="12" height="12" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M12 5L12 19M12 5L18 11M12 5L6 11" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> </svg> +1.4% from last period </div> </div> <div class="metric-icon"> <svg width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M16 8.0001V3.0001M16 3.0001H11M16 3.0001L7 12.0001M3 21H8.5L20.5 9.00005C21.0304 8.46962 21.3284 7.7502 21.3284 7.00005C21.3284 6.2499 21.0304 5.53049 20.5 5.00005C19.9696 4.46962 19.2501 4.17163 18.5 4.17163C17.7499 4.17163 17.0304 4.46962 16.5 5.00005L4.5 17.0001V21.0001L3 21Z" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> </svg> </div> </div> <div id="kpi3" class="metric-card kpi-card"> <div> <div class="kpi-title">Revenue</div> <div class="kpi-value">$328,491</div> <div class="kpi-change down"> <svg width="12" height="12" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M12 19L12 5M12 19L6 13M12 19L18 13" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> </svg> -3.2% from last period </div> </div> <div class="metric-icon"> <svg width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M12 1V23" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> <path d="M17 5H9.5C8.57174 5 7.6815 5.36875 7.02513 6.02513C6.36875 6.6815 6 7.57174 6 8.5C6 9.42826 6.36875 10.3185 7.02513 10.9749C7.6815 11.6313 8.57174 12 9.5 12H14.5C15.4283 12 16.3185 12.3687 16.9749 13.0251C17.6313 13.6815 18 14.5717 18 15.5C18 16.4283 17.6313 17.3185 16.9749 17.9749C16.3185 18.6313 15.4283 19 14.5 19H6" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> </svg> </div> </div> <div id="chart1" class="metric-card"> <div class="chart-title"> User Engagement <span class="badge">Real-time</span> </div> <div class="chart-container"> <canvas id="engagementChart"></canvas> </div> <div class="legend"> <div class="legend-item"> <div class="legend-color" style="background: rgba(10, 91, 245, 0.7)"></div> <span>Sessions</span> </div> <div class="legend-item"> <div class="legend-color" style="background: rgba(0, 230, 195, 0.7)"></div> <span>Interactions</span> </div> </div> </div> <div id="chart2" class="metric-card"> <div class="chart-title">Traffic Sources</div> <div class="chart-container"> <canvas id="sourcesChart"></canvas> </div> </div> <div id="chart3" class="metric-card"> <div class="chart-title">Performance Metrics</div> <div class="chart-container"> <canvas id="performanceChart"></canvas> </div> <div class="legend"> <div class="legend-item"> <div class="legend-color" style="background: rgba(10, 91, 245, 0.7)"></div> <span>Page Load</span> </div> <div class="legend-item"> <div class="legend-color" style="background: rgba(0, 230, 195, 0.7)"></div> <span>Response Time</span> </div> <div class="legend-item"> <div class="legend-color" style="background: rgba(255, 171, 0, 0.7)"></div> <span>Errors</span> </div> </div> </div> </div> <div class="chart-tooltip" id="chartTooltip"> <div class="tooltip-title">User Sessions</div> <div class="tooltip-value">3,245</div> <div class="tooltip-date">Oct 15, 2023</div> </div> </div> <script src="https://cdn.jsdelivr.net/npm/chart.js"></script> <script> // Animation timing function function staggerAnimation() { const elements = document.querySelectorAll('.metric-card'); elements.forEach((el, index) => { setTimeout(() => { el.style.opacity = 1; el.style.transform = 'translateY(0)'; }, 150 * index); }); } // Custom chart tooltip const tooltip = document.getElementById('chartTooltip'); function showTooltip(x, y, title, value, date) { tooltip.style.opacity = 1; tooltip.style.left = `${x}px`; tooltip.style.top = `${y}px`; tooltip.innerHTML = ` <div class="tooltip-title">${title}</div> <div class="tooltip-value">${value}</div> <div class="tooltip-date">${date}</div> `; } function hideTooltip() { tooltip.style.opacity = 0; } // Initialize charts function initCharts() { // Engagement Chart const engagementCtx = document.getElementById('engagementChart').getContext('2d'); const engagementChart = new Chart(engagementCtx, { type: 'line', data: { labels: ['Aug 1', 'Aug 8', 'Aug 15', 'Aug 22', 'Aug 29', 'Sep 5', 'Sep 12', 'Sep 19', 'Sep 26'], datasets: [ { label: 'Sessions', data: [5200, 5800, 6400, 7500, 7200, 8100, 8700, 9500, 9800], borderColor: 'rgba(10, 91, 245, 0.7)', backgroundColor: 'rgba(10, 91, 245, 0.1)', borderWidth: 2, fill: true, tension: 0.4, pointRadius: 3, pointBackgroundColor: 'rgba(10, 91, 245, 1)', pointHoverRadius: 5, pointHoverBackgroundColor: '#fff', pointHoverBorderWidth: 2, pointHoverBorderColor: 'rgba(10, 91, 245, 1)' }, { label: 'Interactions', data: [3700, 4200, 4900, 6000, 5800, 6500, 7100, 7800, 8200], borderColor: 'rgba(0, 230, 195, 0.7)', backgroundColor: 'rgba(0, 230, 195, 0.1)', borderWidth: 2, fill: true, tension: 0.4, pointRadius: 3, pointBackgroundColor: 'rgba(0, 230, 195, 1)', pointHoverRadius: 5, pointHoverBackgroundColor: '#fff', pointHoverBorderWidth: 2, pointHoverBorderColor: 'rgba(0, 230, 195, 1)' } ] }, options: { responsive: true, maintainAspectRatio: false, animation: { duration: 1500, easing: 'easeOutQuart' }, scales: { y: { beginAtZero: true, grid: { color: 'rgba(255, 255, 255, 0.05)' }, ticks: { color: 'rgba(255, 255, 255, 0.7)' } }, x: { grid: { color: 'rgba(255, 255, 255, 0.05)' }, ticks: { color: 'rgba(255, 255, 255, 0.7)' } } }, plugins: { legend: { display: false }, tooltip: { enabled: false, external: function(context) { const element = context.chart.canvas; const position = context.chart.canvas.getBoundingClientRect(); if (context.tooltip.opacity === 0) { hideTooltip(); return; } const label = context.tooltip.dataPoints[0].label; const datasetLabel = context.tooltip.dataPoints[0].dataset.label; const value = context.tooltip.dataPoints[0].formattedValue; const x = position.left + context.tooltip.caretX; const y = position.top + context.tooltip.caretY; showTooltip(x, y, datasetLabel, value, label); } } }, interaction: { mode: 'nearest', intersect: false }, elements: { point: { radius: 0, hoverRadius: 6 } } } }); // Sources Chart const sourcesCtx = document.getElementById('sourcesChart').getContext('2d'); const sourcesChart = new Chart(sourcesCtx, { type: 'doughnut', data: { labels: ['Organic Search', 'Direct', 'Social', 'Referral', 'Email'], datasets: [{ data: [42, 23, 18, 12, 5], backgroundColor: [ 'rgba(10, 91, 245, 0.7)', 'rgba(0, 230, 195, 0.7)', 'rgba(255, 171, 0, 0.7)', 'rgba(82, 82, 255, 0.7)', 'rgba(255, 82, 82, 0.7)' ], borderColor: [ 'rgba(10, 91, 245, 1)', 'rgba(0, 230, 195, 1)', 'rgba(255, 171, 0, 1)', 'rgba(82, 82, 255, 1)', 'rgba(255, 82, 82, 1)' ], borderWidth: 2 }] }, options: { responsive: true, maintainAspectRatio: false, cutout: '70%', animations: { animateRotate: true, animateScale: true }, plugins: { legend: { position: 'right', labels: { color: 'rgba(255, 255, 255, 0.7)', padding: 10, font: { size: 11 }, usePointStyle: true, pointStyle: 'circle' } }, tooltip: { backgroundColor: 'rgba(20, 27, 43, 0.9)', titleColor: 'rgba(0, 230, 195, 1)', bodyColor: 'rgba(255, 255, 255, 0.9)', borderColor: 'rgba(255, 255, 255, 0.1)', borderWidth: 1, padding: 10, cornerRadius: 6, displayColors: true, usePointStyle: true, callbacks: { label: function(context) { const label = context.label || ''; const value = context.formattedValue || ''; return `${label}: ${value}%`; } } } } } }); // Performance Chart const performanceCtx = document.getElementById('performanceChart').getContext('2d'); const performanceChart = new Chart(performanceCtx, { type: 'bar', data: { labels: ['Aug 1', 'Aug 8', 'Aug 15', 'Aug 22', 'Aug 29', 'Sep 5', 'Sep 12', 'Sep 19', 'Sep 26'], datasets: [ { label: 'Page Load (ms)', data: [420, 380, 410, 390, 360, 340, 320, 310, 300], backgroundColor: 'rgba(10, 91, 245, 0.7)', borderColor: 'rgba(10, 91, 245, 1)', borderWidth: 1, borderRadius: 4 }, { label: 'Response Time (ms)', data: [150, 145, 140, 135, 130, 125, 120, 115, 110], backgroundColor: 'rgba(0, 230, 195, 0.7)', borderColor: 'rgba(0, 230, 195, 1)', borderWidth: 1, borderRadius: 4 }, { label: 'Errors (%)', data: [2.1, 1.9, 1.8, 1.5, 1.3, 1.1, 0.9, 0.8, 0.6], backgroundColor: 'rgba(255, 171, 0, 0.7)', borderColor: 'rgba(255, 171, 0, 1)', borderWidth: 1, borderRadius: 4 } ] }, options: { responsive: true, maintainAspectRatio: false, animation: { delay: function(context) { return context.dataIndex * 50; } }, scales: { y: { beginAtZero: true, grid: { color: 'rgba(255, 255, 255, 0.05)' }, ticks: { color: 'rgba(255, 255, 255, 0.7)' } }, x: { grid: { display: false }, ticks: { color: 'rgba(255, 255, 255, 0.7)' } } }, plugins: { legend: { display: false }, tooltip: { backgroundColor: 'rgba(20, 27, 43, 0.9)', titleColor: 'rgba(0, 230, 195, 1)', bodyColor: 'rgba(255, 255, 255, 0.9)', borderColor: 'rgba(255, 255, 255, 0.1)', borderWidth: 1, padding: 10, cornerRadius: 6, displayColors: true, usePointStyle: true } } } }); // Unique hover effect on charts const dataPoints = document.querySelectorAll('.data-point'); dataPoints.forEach(point => { point.addEventListener('mouseenter', function() { this.classList.add('pulse'); }); point.addEventListener('mouseleave', function() { this.classList.remove('pulse'); }); }); } // Handle date selector change document.querySelector('.date-selector').addEventListener('change', function(e) { const selectedOption = e.target.value; // Simulate loading state with shimmer const cards = document.querySelectorAll('.metric-card'); cards.forEach(card => { card.classList.add('shimmer'); card.style.opacity = 0.7; }); // Mock API call delay setTimeout(() => { cards.forEach(card => { card.classList.remove('shimmer'); card.style.opacity = 1; }); // Update chart data based on selected time period // In a real app, this would fetch new data from the backend // For demo purposes, we'll just refresh the animations staggerAnimation(); }, 800); }); // Initialize on load window.addEventListener('DOMContentLoaded', () => { staggerAnimation(); initCharts(); }); </script> </body> </html>
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Quantum Physics: Wave-Particle Duality</title> <style> :root { --primary: #6a75ca; --secondary: #f0b9c3; --tertiary: #a0e4cb; --light: #f3f6ff; --dark: #2d3142; --correct: #7bce99; --incorrect: #e66767; --neutral: #e9ecef; --progress: #a0e4cb; } * { box-sizing: border-box; margin: 0; padding: 0; } body { font-family: 'Nunito', -apple-system, BlinkMacSystemFont, sans-serif; background-color: var(--light); color: var(--dark); line-height: 1.6; overflow-x: hidden; max-width: 700px; height: 700px; margin: 0 auto; display: flex; flex-direction: column; } h1, h2, h3 { font-family: 'Poppins', sans-serif; font-weight: 700; margin-bottom: 1rem; color: var(--dark); } h1 { font-size: 1.8rem; background: linear-gradient(90deg, var(--primary), var(--secondary)); -webkit-background-clip: text; -webkit-text-fill-color: transparent; text-align: center; margin-top: 1.5rem; } h2 { font-size: 1.3rem; color: var(--primary); margin-top: 1.5rem; } h3 { font-size: 1.1rem; color: var(--primary); margin-top: 1rem; } p { margin-bottom: 1rem; font-size: 1rem; opacity: 0; transform: translateY(20px); transition: opacity 0.5s ease, transform 0.5s ease; } p.visible { opacity: 1; transform: translateY(0); } .container { padding: 1.5rem; flex: 1; overflow-y: auto; position: relative; scroll-behavior: smooth; } .progress-container { width: 100%; height: 8px; background: var(--neutral); position: sticky; top: 0; z-index: 10; border-radius: 4px; overflow: hidden; margin-bottom: 1rem; } .progress-bar { height: 100%; width: 0; background: linear-gradient(90deg, var(--primary), var(--tertiary)); transition: width 0.5s ease; border-radius: 4px; } .section { margin-bottom: 2rem; opacity: 0; transform: translateY(30px); transition: opacity 0.8s ease, transform 0.8s ease; padding: 1.2rem; border-radius: 12px; background: white; box-shadow: 0 4px 15px rgba(0, 0, 0, 0.05); position: relative; overflow: hidden; } .section::before { content: ''; position: absolute; top: 0; left: 0; width: 4px; height: 100%; background: linear-gradient(to bottom, var(--primary), var(--tertiary)); border-radius: 4px 0 0 4px; } .section.visible { opacity: 1; transform: translateY(0); } .quiz-container { margin-top: 2rem; opacity: 0; transform: translateY(30px); transition: opacity 0.8s ease, transform 0.8s ease; background: white; border-radius: 12px; padding: 1.5rem; box-shadow: 0 8px 20px rgba(0, 0, 0, 0.08); } .quiz-container.visible { opacity: 1; transform: translateY(0); } .question { margin-bottom: 1.5rem; font-weight: 600; color: var(--primary); } .options { display: grid; grid-template-columns: 1fr; gap: 0.8rem; } .option { padding: 1rem; background-color: var(--neutral); border-radius: 8px; cursor: pointer; transition: all 0.3s ease; display: flex; align-items: center; position: relative; overflow: hidden; border: 2px solid transparent; } .option:hover { transform: translateY(-3px); box-shadow: 0 4px 10px rgba(0, 0, 0, 0.05); border-color: var(--tertiary); } .option.correct { background-color: var(--correct); color: white; border-color: var(--correct); } .option.incorrect { background-color: var(--incorrect); color: white; border-color: var(--incorrect); } .option::before { content: ''; position: absolute; top: 50%; left: 50%; width: 0; height: 0; background: rgba(255, 255, 255, 0.2); border-radius: 50%; transform: translate(-50%, -50%); transition: width 0.5s ease, height 0.5s ease; } .option:active::before { width: 300px; height: 300px; } .option-letter { display: inline-flex; align-items: center; justify-content: center; width: 28px; height: 28px; background-color: var(--primary); color: white; border-radius: 50%; margin-right: 1rem; font-weight: bold; flex-shrink: 0; } .next-button { display: none; background: linear-gradient(45deg, var(--primary), var(--tertiary)); color: white; border: none; padding: 0.8rem 1.5rem; border-radius: 8px; font-weight: 600; margin-top: 1.5rem; cursor: pointer; transition: all 0.3s ease; box-shadow: 0 4px 12px rgba(106, 117, 202, 0.3); } .next-button:hover { transform: translateY(-3px); box-shadow: 0 8px 15px rgba(106, 117, 202, 0.4); } .next-button.visible { display: block; animation: pulse 2s infinite; } @keyframes pulse { 0% { box-shadow: 0 4px 12px rgba(106, 117, 202, 0.3); } 50% { box-shadow: 0 8px 20px rgba(106, 117, 202, 0.5); } 100% { box-shadow: 0 4px 12px rgba(106, 117, 202, 0.3); } } .feedback { margin-top: 1rem; padding: 1rem; border-radius: 8px; font-weight: 600; text-align: center; opacity: 0; transform: translateY(20px); transition: all 0.5s ease; display: none; } .feedback.visible { opacity: 1; transform: translateY(0); display: block; } .feedback.correct { background-color: rgba(123, 206, 153, 0.2); color: var(--correct); } .feedback.incorrect { background-color: rgba(230, 103, 103, 0.2); color: var(--incorrect); } .formula { font-family: 'Times New Roman', serif; font-style: italic; padding: 1rem; background-color: rgba(160, 228, 203, 0.1); border-left: 3px solid var(--tertiary); margin: 1rem 0; border-radius: 4px; display: flex; align-items: center; justify-content: center; font-size: 1.1rem; } .key-term { font-weight: 700; color: var(--primary); border-bottom: 2px dotted var(--tertiary); padding-bottom: 2px; cursor: help; position: relative; } .key-term:hover::after { content: attr(data-definition); position: absolute; bottom: 100%; left: 50%; transform: translateX(-50%); background: var(--dark); color: white; padding: 0.5rem; border-radius: 4px; width: max-content; max-width: 200px; z-index: 10; font-weight: normal; font-size: 0.8rem; box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2); } .image-container { width: 100%; text-align: center; margin: 1.5rem 0; overflow: hidden; border-radius: 8px; box-shadow: 0 4px 15px rgba(0, 0, 0, 0.08); } .image-container img { max-width: 100%; border-radius: 8px; transform: scale(0.95); transition: transform 0.3s ease; } .image-container:hover img { transform: scale(1); } .image-caption { font-size: 0.85rem; color: var(--dark); opacity: 0.8; padding: 0.5rem; background: rgba(255, 255, 255, 0.8); border-radius: 0 0 8px 8px; margin-top: -4px; } @media (max-width: 600px) { .container { padding: 1rem; } h1 { font-size: 1.5rem; } h2 { font-size: 1.2rem; } p { font-size: 0.95rem; } } .completion-message { text-align: center; padding: 2rem; background: linear-gradient(45deg, var(--primary), var(--tertiary)); color: white; border-radius: 12px; margin-top: 2rem; box-shadow: 0 8px 25px rgba(106, 117, 202, 0.4); opacity: 0; transform: translateY(30px); transition: opacity 0.8s ease, transform 0.8s ease; display: none; } .completion-message.visible { opacity: 1; transform: translateY(0); display: block; } .completion-icon { font-size: 3rem; margin-bottom: 1rem; display: inline-block; animation: bounce 2s infinite; } @keyframes bounce { 0%, 20%, 50%, 80%, 100% { transform: translateY(0); } 40% { transform: translateY(-20px); } 60% { transform: translateY(-10px); } } .chip { display: inline-block; padding: 0.3rem 0.8rem; background: rgba(255, 255, 255, 0.2); border-radius: 20px; font-size: 0.8rem; margin-right: 0.5rem; margin-bottom: 0.5rem; } .interactive-demo { background: rgba(160, 228, 203, 0.1); border-radius: 8px; padding: 1rem; margin: 1.5rem 0; text-align: center; } .wave-container { height: 100px; width: 100%; position: relative; margin: 1rem 0; overflow: hidden; } .wave { position: absolute; height: 60px; width: 100%; background: linear-gradient(90deg, var(--primary), var(--tertiary)); border-radius: 100%; opacity: 0.2; animation: waveMotion 5s infinite linear; transform-origin: center; } .wave:nth-child(2) { animation-delay: 0.5s; opacity: 0.3; } .wave:nth-child(3) { animation-delay: 1s; opacity: 0.4; } @keyframes waveMotion { 0% { transform: scale(0) translateX(-50%); } 50% { transform: scale(1) translateX(0); } 100% { transform: scale(0) translateX(50%); } } .particle { width: 10px; height: 10px; background-color: var(--primary); border-radius: 50%; position: absolute; top: 45px; left: 50%; transform: translateX(-50%); animation: particleMotion 5s infinite linear; } @keyframes particleMotion { 0% { left: 10%; background-color: var(--primary); } 50% { left: 90%; background-color: var(--secondary); } 100% { left: 10%; background-color: var(--primary); } } .scroll-prompt { text-align: center; padding: 1rem; color: var(--primary); opacity: 1; animation: fadeInOut 2s infinite; font-size: 0.9rem; font-weight: 600; margin-top: 1rem; } @keyframes fadeInOut { 0%, 100% { opacity: 0.3; } 50% { opacity: 1; } } </style> </head> <body> <div class="container"> <div class="progress-container"> <div class="progress-bar" id="progressBar"></div> </div> <h1>Quantum Physics: Wave-Particle Duality</h1> <div class="section" id="section1"> <h2>Introduction to Wave-Particle Duality</h2> <p>One of the most fascinating concepts in quantum physics is the idea that particles like electrons and photons can exhibit both particle-like and wave-like behavior—a phenomenon known as <span class="key-term" data-definition="The concept that matter and energy can display properties of both waves and particles.">wave-particle duality</span>.</p> <p>This fundamental principle challenges our classical intuition about the nature of reality and forms the cornerstone of quantum mechanics.</p> <p>In this lesson, we'll explore the historical experiments that led to this revolutionary concept and understand its implications in modern physics.</p> <div class="scroll-prompt">Scroll to continue</div> </div> <div class="section" id="section2"> <h2>The Double-Slit Experiment</h2> <p>The most iconic demonstration of wave-particle duality is the <span class="key-term" data-definition="An experiment where particles pass through two slits and create an interference pattern, demonstrating wave-like behavior.">double-slit experiment</span>, first conducted with light by Thomas Young in 1801.</p> <div class="image-container"> <img src="https://upload.wikimedia.org/wikipedia/commons/thumb/c/cd/Double-slit_experiment_results_Tanamura_2.jpg/600px-Double-slit_experiment_results_Tanamura_2.jpg" alt="Double-slit experiment interference pattern"> <div class="image-caption">Interference pattern from the double-slit experiment with electrons</div> </div> <p>When light passes through two closely spaced slits, it creates an interference pattern on the screen behind—a characteristic of waves. However, when individual photons are sent one at a time, they still gradually build up the same interference pattern!</p> <p>This suggests each photon somehow passes through both slits simultaneously and interferes with itself—a pure quantum phenomenon with no classical explanation.</p> </div> <div class="section" id="section3"> <h2>Mathematical Description</h2> <p>The wave nature of particles is described by the <span class="key-term" data-definition="A mathematical equation that describes how the quantum state of a physical system changes over time.">Schrödinger equation</span>, which represents particles as wave functions (Ψ).</p> <div class="formula"> iℏ ∂Ψ/∂t = -ℏ²/2m ∇²Ψ + VΨ </div> <p>The <span class="key-term" data-definition="The square of the amplitude of the wave function, giving the probability of finding a particle at a specific position.">probability density</span> |Ψ|² gives us the likelihood of finding a particle at a particular location when measured.</p> <p>This probabilistic nature is key to understanding quantum behavior—we can only predict the probability of finding a particle, not its exact path or position before measurement.</p> </div> <div class="section" id="section4"> <h2>Interactive Demonstration</h2> <p>Below is a simplified visualization of wave-particle duality. The waves represent the probability distribution, while the particle represents what we might observe upon measurement.</p> <div class="interactive-demo"> <div class="wave-container"> <div class="wave"></div> <div class="wave"></div> <div class="wave"></div> <div class="particle"></div> </div> <p>The particle's position is uncertain until measured, following the probability distribution of the wave function.</p> </div> <p>This illustrates <span class="key-term" data-definition="The principle that certain pairs of physical properties cannot be simultaneously known with arbitrary precision.">Heisenberg's uncertainty principle</span>—the more precisely we know a particle's position, the less precisely we can know its momentum, and vice versa.</p> </div> <div class="quiz-container" id="quiz1"> <h3>Knowledge Check</h3> <div class="question">What phenomenon demonstrates that light can behave both as a wave and a particle?</div> <div class="options"> <div class="option" data-correct="true"> <span class="option-letter">A</span> <span>The double-slit experiment</span> </div> <div class="option" data-correct="false"> <span class="option-letter">B</span> <span>The photoelectric effect</span> </div> <div class="option" data-correct="false"> <span class="option-letter">C</span> <span>Brownian motion</span> </div> <div class="option" data-correct="false"> <span class="option-letter">D</span> <span>Compton scattering</span> </div> </div> <div class="feedback"></div> <button class="next-button" id="next1">Continue</button> </div> <div class="section" id="section5"> <h2>Implications of Wave-Particle Duality</h2> <p>Wave-particle duality has profound implications for our understanding of reality:</p> <p>• It suggests that the classical distinction between waves and particles breaks down at the quantum level.</p> <p>• It forms the basis for quantum technologies like quantum computing and quantum cryptography.</p> <p>• It challenges our intuitive understanding of causality and determinism.</p> <p>In the words of Richard Feynman, "If you think you understand quantum mechanics, you don't understand quantum mechanics." This humbling statement reflects the counterintuitive nature of quantum phenomena.</p> </div> <div class="quiz-container" id="quiz2"> <h3>Final Challenge</h3> <div class="question">According to the Heisenberg uncertainty principle, what happens when we measure a particle's position with high precision?</div> <div class="options"> <div class="option" data-correct="false"> <span class="option-letter">A</span> <span>The particle's energy becomes precisely known</span> </div> <div class="option" data-correct="false"> <span class="option-letter">B</span> <span>The particle disappears from observation</span> </div> <div class="option" data-correct="true"> <span class="option-letter">C</span> <span>The particle's momentum becomes more uncertain</span> </div> <div class="option" data-correct="false"> <span class="option-letter">D</span> <span>The particle splits into multiple identical copies</span> </div> </div> <div class="feedback"></div> <button class="next-button" id="next2">Complete Lesson</button> </div> <div class="completion-message" id="completionMessage"> <div class="completion-icon">🎓</div> <h2>Congratulations!</h2> <p>You've completed the introduction to Wave-Particle Duality.</p> <div> <span class="chip">Quantum Physics</span> <span class="chip">Wave-Particle Duality</span> <span class="chip">Double-Slit Experiment</span> </div> <p style="margin-top: 1rem;">Ready to dive deeper into quantum mechanics?</p> </div> </div> <script> document.addEventListener('DOMContentLoaded', function() { const sections = document.querySelectorAll('.section'); const paragraphs = document.querySelectorAll('p'); const quizContainers = document.querySelectorAll('.quiz-container'); const progressBar = document.getElementById('progressBar'); const completionMessage = document.getElementById('completionMessage'); // Initialize visibility tracking let visibleSections = 0; const totalSections = sections.length + quizContainers.length; // Function to check if element is in viewport function isInViewport(element) { const rect = element.getBoundingClientRect(); return ( rect.top >= 0 && rect.top <= (window.innerHeight || document.documentElement.clientHeight) * 0.6 ); } // Function to update progress bar function updateProgressBar() { const progress = (visibleSections / totalSections) * 100; progressBar.style.width = `${progress}%`; } // Function to reveal sections when scrolled into view function revealSections() { sections.forEach(section => { if (isInViewport(section) && !section.classList.contains('visible')) { section.classList.add('visible'); visibleSections++; updateProgressBar(); // Reveal paragraphs within the section const sectionParagraphs = section.querySelectorAll('p'); sectionParagraphs.forEach((paragraph, index) => { setTimeout(() => { paragraph.classList.add('visible'); }, 200 * index); }); } }); quizContainers.forEach(quiz => { if (isInViewport(quiz) && !quiz.classList.contains('visible')) { quiz.classList.add('visible'); } }); } // Reveal sections on scroll document.querySelector('.container').addEventListener('scroll', revealSections); // Initial reveal for visible sections setTimeout(revealSections, 500); // Quiz interaction document.querySelectorAll('.option').forEach(option => { option.addEventListener('click', function() { const parent = this.closest('.quiz-container'); const options = parent.querySelectorAll('.option'); const feedback = parent.querySelector('.feedback'); const nextButton = parent.querySelector('.next-button'); // If already answered, do nothing if (options[0].classList.contains('correct') || options[0].classList.contains('incorrect')) { return; } const isCorrect = this.getAttribute('data-correct') === 'true'; options.forEach(opt => { opt.classList.remove('correct', 'incorrect'); if (opt.getAttribute('data-correct') === 'true') { opt.classList.add('correct'); } else if (opt === this && !isCorrect) { opt.classList.add('incorrect'); } }); feedback.textContent = isCorrect ? "Correct! That's the right answer." : "Not quite. The correct answer is highlighted."; feedback.className = `feedback ${isCorrect ? 'correct' : 'incorrect'} visible`; nextButton.classList.add('visible'); // Update progress for quizzes if (!parent.hasAttribute('data-counted')) { visibleSections++; updateProgressBar(); parent.setAttribute('data-counted', 'true'); } }); }); // Next button handlers document.getElementById('next1').addEventListener('click', function() { document.getElementById('section5').scrollIntoView({ behavior: 'smooth' }); }); document.getElementById('next2').addEventListener('click', function() { completionMessage.classList.add('visible'); completionMessage.scrollIntoView({ behavior: 'smooth' }); progressBar.style.width = '100%'; }); // Ensure all paragraphs eventually become visible for accessibility setTimeout(() => { paragraphs.forEach(p => { if (!p.classList.contains('visible')) { p.classList.add('visible'); } }); }, 8000); }); </script> </body> </html>
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Corporate Timeline</title> <style> @import url('https://fonts.googleapis.com/css2?family=Playfair+Display:wght@400;700&family=Source+Sans+Pro:wght@300;400;600&display=swap'); * { margin: 0; padding: 0; box-sizing: border-box; } :root { --primary: #2c3e50; --secondary: #34495e; --accent: #3498db; --light: #ecf0f1; --light-grey: #f5f7fa; --timeline-color: #bdc3c7; --success: #27ae60; } body { font-family: 'Source Sans Pro', sans-serif; background-color: var(--light); color: var(--primary); overflow-x: hidden; width: 100%; height: 100%; max-width: 700px; margin: 0 auto; } .timeline-container { width: 100%; max-width: 700px; height: 700px; padding: 40px 20px; overflow-y: auto; position: relative; scrollbar-width: thin; scrollbar-color: var(--secondary) var(--light-grey); } .timeline-container::-webkit-scrollbar { width: 6px; } .timeline-container::-webkit-scrollbar-track { background: var(--light-grey); } .timeline-container::-webkit-scrollbar-thumb { background: var(--timeline-color); border-radius: 3px; } .header { text-align: center; margin-bottom: 40px; opacity: 0; transform: translateY(30px); transition: opacity 0.8s ease, transform 0.8s ease; } .header h1 { font-family: 'Playfair Display', serif; font-size: 32px; margin-bottom: 12px; color: var(--primary); letter-spacing: 0.5px; } .header p { font-size: 16px; line-height: 1.6; color: var(--secondary); max-width: 560px; margin: 0 auto; } .timeline { position: relative; margin: 60px 0; padding-left: 40px; } .timeline::before { content: ''; position: absolute; left: 15px; top: 0; width: 3px; height: 0; background: var(--timeline-color); transition: height 2s ease; } .timeline-item { position: relative; margin-bottom: 60px; opacity: 0; transform: translateX(50px); transition: opacity 0.6s ease, transform 0.6s ease; } .timeline-item:last-child { margin-bottom: 0; } .timeline-item::before { content: ''; position: absolute; left: -46px; top: 0; width: 14px; height: 14px; border-radius: 50%; border: 3px solid var(--timeline-color); background: var(--light); transform: scale(0); transition: transform 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275), background-color 0.3s ease, border-color 0.3s ease; } .timeline-item.active::before { transform: scale(1); background: var(--light); border-color: var(--accent); } .timeline-item.completed::before { background: var(--success); border-color: var(--success); } .timeline-date { font-family: 'Playfair Display', serif; font-size: 18px; font-weight: 700; margin-bottom: 8px; color: var(--accent); } .timeline-title { font-family: 'Playfair Display', serif; font-size: 24px; margin-bottom: 12px; color: var(--primary); } .timeline-content { background: white; padding: 25px; border-radius: 6px; box-shadow: 0 5px 15px rgba(0, 0, 0, 0.05); position: relative; transition: transform 0.3s ease, box-shadow 0.3s ease; } .timeline-content:hover { transform: translateY(-5px); box-shadow: 0 8px 25px rgba(0, 0, 0, 0.08); } .timeline-content p { font-size: 15px; line-height: 1.6; color: var(--secondary); margin-bottom: 15px; } .timeline-stats { display: flex; flex-wrap: wrap; gap: 15px; margin-top: 20px; } .stat { background: var(--light-grey); padding: 10px 15px; border-radius: 4px; font-size: 14px; transition: background 0.3s ease; } .stat:hover { background: rgba(52, 152, 219, 0.1); } .stat-value { font-weight: 600; color: var(--primary); margin-right: 5px; } .progress-line { height: 4px; background: var(--light-grey); margin-top: 20px; border-radius: 2px; overflow: hidden; } .progress-line .fill { height: 100%; width: 0; background: var(--accent); transition: width 1.2s ease-in-out; } .timeline-badges { display: flex; gap: 10px; margin-top: 15px; } .badge { font-size: 13px; padding: 4px 10px; border-radius: 30px; background: rgba(52, 152, 219, 0.1); color: var(--accent); border: 1px solid rgba(52, 152, 219, 0.2); } .counter-container { display: flex; justify-content: space-between; margin-top: 30px; } .counter-item { text-align: center; flex: 1; } .counter { font-family: 'Playfair Display', serif; font-size: 36px; color: var(--primary); margin-bottom: 5px; } .counter-label { font-size: 14px; color: var(--secondary); } @media (max-width: 500px) { .header h1 { font-size: 26px; } .timeline { padding-left: 30px; } .timeline-item::before { left: -36px; } .timeline-title { font-size: 20px; } .timeline-content { padding: 20px; } .counter { font-size: 28px; } } /* Animation classes */ .fade-in { opacity: 1; transform: translateY(0); } .slide-in { opacity: 1; transform: translateX(0); } /* Custom cursor */ .timeline-container { cursor: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='20' height='20' viewBox='0 0 24 24' fill='none' stroke='%232c3e50' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'%3E%3C/circle%3E%3Cpolyline points='12 6 12 12 16 14'%3E%3C/polyline%3E%3C/svg%3E"), auto; } </style> </head> <body> <div class="timeline-container"> <div class="header"> <h1>Our Journey to Excellence</h1> <p>Scroll through the defining moments that have shaped Spectra Technologies into the innovation powerhouse it is today.</p> </div> <div class="timeline"> <div class="timeline-item" data-year="2008"> <div class="timeline-date">2008</div> <div class="timeline-content"> <h2 class="timeline-title">Company Founding</h2> <p>Spectra Technologies was founded by Dr. Eleanor Chen and Michael Rodriguez in a small office in San Francisco with just 4 team members and a vision to revolutionize enterprise software solutions.</p> <div class="timeline-stats"> <div class="stat"><span class="stat-value">4</span>Employees</div> <div class="stat"><span class="stat-value">$250K</span>Seed Funding</div> </div> <div class="timeline-badges"> <span class="badge">Silicon Valley</span> <span class="badge">Founding</span> </div> </div> </div> <div class="timeline-item" data-year="2010"> <div class="timeline-date">2010</div> <div class="timeline-content"> <h2 class="timeline-title">First Product Launch</h2> <p>We launched our flagship product, SpectraCore 1.0, an integrated enterprise resource management solution that exceeded industry benchmarks for efficiency by 34%.</p> <div class="progress-line"> <div class="fill" data-width="25"></div> </div> <div class="timeline-stats"> <div class="stat"><span class="stat-value">12</span>Employees</div> <div class="stat"><span class="stat-value">8</span>Enterprise Clients</div> </div> <div class="timeline-badges"> <span class="badge">Product Launch</span> <span class="badge">Enterprise Software</span> </div> </div> </div> <div class="timeline-item" data-year="2013"> <div class="timeline-date">2013</div> <div class="timeline-content"> <h2 class="timeline-title">Series A Funding</h2> <p>Secured $4.2M in Series A funding led by Accel Partners, valuing the company at $18M. This investment accelerated our R&D capabilities and allowed expansion into European markets.</p> <div class="progress-line"> <div class="fill" data-width="45"></div> </div> <div class="timeline-stats"> <div class="stat"><span class="stat-value">28</span>Employees</div> <div class="stat"><span class="stat-value">$4.2M</span>Funding</div> </div> <div class="timeline-badges"> <span class="badge">Series A</span> <span class="badge">International Expansion</span> </div> </div> </div> <div class="timeline-item" data-year="2015"> <div class="timeline-date">2015</div> <div class="timeline-content"> <h2 class="timeline-title">Cloud Platform Innovation</h2> <p>Launched SpectraCloud, our revolutionary cloud-native solution that reduced deployment time by 78% and operational costs by 42% for enterprise clients, setting a new industry standard.</p> <div class="progress-line"> <div class="fill" data-width="65"></div> </div> <div class="timeline-stats"> <div class="stat"><span class="stat-value">62</span>Employees</div> <div class="stat"><span class="stat-value">147</span>Global Clients</div> </div> <div class="timeline-badges"> <span class="badge">Innovation</span> <span class="badge">Cloud Computing</span> </div> </div> </div> <div class="timeline-item" data-year="2018"> <div class="timeline-date">2018</div> <div class="timeline-content"> <h2 class="timeline-title">Quantum Computing Division</h2> <p>Established the Quantum Computing Division with a team of 15 specialized engineers to explore next-generation computational approaches for enterprise applications and data security.</p> <div class="progress-line"> <div class="fill" data-width="80"></div> </div> <div class="timeline-stats"> <div class="stat"><span class="stat-value">124</span>Employees</div> <div class="stat"><span class="stat-value">3</span>Research Centers</div> </div> <div class="timeline-badges"> <span class="badge">Research</span> <span class="badge">Quantum Computing</span> </div> </div> </div> <div class="timeline-item" data-year="2021"> <div class="timeline-date">2021</div> <div class="timeline-content"> <h2 class="timeline-title">Carbon Neutral Certification</h2> <p>Achieved carbon neutrality across all operations by implementing sustainable practices and investing $5.7M in renewable energy infrastructure, becoming the first in our sector to do so.</p> <div class="progress-line"> <div class="fill" data-width="90"></div> </div> <div class="timeline-stats"> <div class="stat"><span class="stat-value">215</span>Employees</div> <div class="stat"><span class="stat-value">100%</span>Renewable Energy</div> </div> <div class="timeline-badges"> <span class="badge">Sustainability</span> <span class="badge">Corporate Responsibility</span> </div> </div> </div> <div class="timeline-item" data-year="2023"> <div class="timeline-date">2023</div> <div class="timeline-content"> <h2 class="timeline-title">Present Day & Future Vision</h2> <p>Today, Spectra Technologies is a global leader with operations in 18 countries. Our roadmap includes advancing quantum-secured cloud infrastructure and democratizing enterprise AI solutions by 2025.</p> <div class="progress-line"> <div class="fill" data-width="100"></div> </div> <div class="counter-container"> <div class="counter-item"> <div class="counter" data-target="280">0</div> <div class="counter-label">Team Members</div> </div> <div class="counter-item"> <div class="counter" data-target="18">0</div> <div class="counter-label">Countries</div> </div> <div class="counter-item"> <div class="counter" data-target="450">0</div> <div class="counter-label">Global Clients</div> </div> </div> <div class="timeline-badges"> <span class="badge">Global Presence</span> <span class="badge">Future Vision</span> </div> </div> </div> </div> </div> <script> document.addEventListener('DOMContentLoaded', () => { // Initialize animation on load setTimeout(() => { document.querySelector('.header').classList.add('fade-in'); }, 300); // Set the timeline height after a short delay setTimeout(() => { const timeline = document.querySelector('.timeline'); timeline.style.setProperty('--timeline-height', timeline.scrollHeight + 'px'); document.querySelector('.timeline::before').style.height = '100%'; }, 500); // Get all timeline items const timelineItems = document.querySelectorAll('.timeline-item'); const timeline = document.querySelector('.timeline'); // Initialize timeline line timeline.querySelector('::before'); // Function to check if an element is in viewport const isInViewport = (el, offset = 0) => { const rect = el.getBoundingClientRect(); return ( rect.top <= (window.innerHeight || document.documentElement.clientHeight) - offset && rect.bottom >= 0 ); }; // Function to animate timeline items const animateTimelineItems = () => { let delay = 0; timeline.style.setProperty('--timeline-height', document.querySelector('.timeline').scrollHeight + 'px'); // Set the height of the timeline line const scrollPosition = document.querySelector('.timeline-container').scrollTop; const totalHeight = timeline.scrollHeight; const viewportHeight = document.querySelector('.timeline-container').clientHeight; const scrollPercentage = Math.min( (scrollPosition / (totalHeight - viewportHeight)) * 100, 100 ); timeline.style.setProperty('--scroll-percentage', scrollPercentage + '%'); const timelineLine = document.querySelector('.timeline::before'); if (timelineLine) { timelineLine.style.height = scrollPercentage + '%'; } // Animate the progress fill document.querySelectorAll('.progress-line .fill').forEach(fill => { if (isInViewport(fill.parentElement, 100)) { setTimeout(() => { fill.style.width = fill.getAttribute('data-width') + '%'; }, 300); } }); // Animate timeline items timelineItems.forEach((item, index) => { if (isInViewport(item, 150)) { setTimeout(() => { item.classList.add('slide-in'); item.classList.add('active'); }, delay); // Animate counters inside the item if (item.querySelector('.counter-container')) { setTimeout(() => { animateCounters(item); }, delay + 300); } delay += 200; // Mark previous items as completed if (index > 0) { for (let i = 0; i < index; i++) { timelineItems[i].classList.add('completed'); } } } else { if (!item.classList.contains('slide-in')) { item.classList.remove('active'); } } }); }; // Function to animate counters const animateCounters = (container) => { const counters = container.querySelectorAll('.counter'); const speed = 200; // Lower is faster counters.forEach(counter => { const target = +counter.getAttribute('data-target'); const count = +counter.innerText; const inc = Math.ceil(target / speed); if (count < target) { counter.innerText = count + inc; setTimeout(() => animateCounters(container), 20); } else { counter.innerText = target; } }); }; // Set the initial timeline height timeline.style.height = '100%'; // Initial check for items in viewport setTimeout(animateTimelineItems, 800); // Listen for scroll events document.querySelector('.timeline-container').addEventListener('scroll', animateTimelineItems); // Handle the line animation window.addEventListener('load', () => { setTimeout(() => { const timelineLine = document.querySelector('.timeline::before'); if (timelineLine) { timelineLine.style.height = '100%'; } }, 500); }); // Add subtle parallax effect on mouse move document.querySelector('.timeline-container').addEventListener('mousemove', (e) => { const moveX = (e.clientX - window.innerWidth / 2) * 0.01; const moveY = (e.clientY - window.innerHeight / 2) * 0.01; document.querySelectorAll('.timeline-content').forEach(content => { content.style.transform = `translateX(${moveX}px) translateY(${moveY}px)`; }); }); }); </script> </body> </html>
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Interactive Portfolio Reveal</title> <style> @import url('https://fonts.googleapis.com/css2?family=Manrope:wght@200;300;400;500;600;700;800&display=swap'); :root { --primary-color: #121212; --secondary-color: #222222; --text-color: #f0f0f0; --accent-color: #ff3e55; --accent-secondary: #4d5bff; --transition-slow: 0.8s cubic-bezier(0.165, 0.84, 0.44, 1); --transition-medium: 0.5s cubic-bezier(0.165, 0.84, 0.44, 1); --transition-fast: 0.3s cubic-bezier(0.165, 0.84, 0.44, 1); } * { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: 'Manrope', sans-serif; background-color: var(--primary-color); color: var(--text-color); overflow-x: hidden; line-height: 1.6; } .container { max-width: 700px; height: 700px; margin: 0 auto; padding: 20px; overflow-y: auto; scrollbar-width: thin; scrollbar-color: var(--accent-color) var(--primary-color); } .container::-webkit-scrollbar { width: 4px; } .container::-webkit-scrollbar-track { background: var(--primary-color); } .container::-webkit-scrollbar-thumb { background-color: var(--accent-color); border-radius: 20px; } header { padding: 10px 0 30px; position: relative; opacity: 0; transform: translateY(20px); animation: fadeInUp 0.8s cubic-bezier(0.165, 0.84, 0.44, 1) forwards; } .logo { font-size: 26px; font-weight: 800; letter-spacing: -1px; display: inline-block; position: relative; } .logo::after { content: ''; position: absolute; width: 6px; height: 6px; border-radius: 50%; background-color: var(--accent-color); bottom: 8px; right: -10px; } nav { margin-top: 15px; display: flex; align-items: center; justify-content: space-between; } .menu ul { display: flex; list-style: none; gap: 20px; } .menu li a { color: var(--text-color); text-decoration: none; font-size: 14px; font-weight: 500; position: relative; transition: color var(--transition-fast); } .menu li a::after { content: ''; position: absolute; bottom: -4px; left: 0; width: 0; height: 1px; background-color: var(--accent-color); transition: width var(--transition-fast); } .menu li a:hover { color: var(--accent-color); } .menu li a:hover::after { width: 100%; } .intro { margin: 40px 0; opacity: 0; transform: translateY(30px); animation: fadeInUp 0.8s cubic-bezier(0.165, 0.84, 0.44, 1) 0.2s forwards; } .intro h1 { font-size: 42px; font-weight: 800; margin-bottom: 15px; line-height: 1.2; letter-spacing: -1px; } .intro h1 span { position: relative; display: inline-block; } .intro h1 span::after { content: ''; position: absolute; bottom: 4px; left: 0; width: 100%; height: 6px; background-color: var(--accent-color); opacity: 0.3; z-index: -1; } .intro p { font-size: 16px; max-width: 600px; margin-top: 20px; color: rgba(240, 240, 240, 0.7); } .portfolio-grid { display: grid; grid-template-columns: repeat(6, 1fr); gap: 20px; margin-top: 40px; } .portfolio-item { border-radius: 4px; overflow: hidden; position: relative; background-color: var(--secondary-color); opacity: 0; transform: translateY(40px); box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1); cursor: pointer; transition: transform var(--transition-medium); } .portfolio-item:hover { transform: translateY(-5px) scale(1.02); } .portfolio-item:nth-child(odd) { animation: fadeInSlideLeft 0.7s cubic-bezier(0.165, 0.84, 0.44, 1) forwards; } .portfolio-item:nth-child(even) { animation: fadeInSlideRight 0.7s cubic-bezier(0.165, 0.84, 0.44, 1) forwards; } .portfolio-item:nth-child(1) { grid-column: span 3; grid-row: span 2; animation-delay: 0.3s; } .portfolio-item:nth-child(2) { grid-column: span 3; grid-row: span 3; animation-delay: 0.4s; } .portfolio-item:nth-child(3) { grid-column: span 2; grid-row: span 2; animation-delay: 0.5s; } .portfolio-item:nth-child(4) { grid-column: span 4; grid-row: span 2; animation-delay: 0.6s; } .portfolio-item:nth-child(5) { grid-column: span 6; grid-row: span 2; animation-delay: 0.7s; } .portfolio-item-img { width: 100%; height: 100%; object-fit: cover; transition: transform var(--transition-medium), filter var(--transition-medium); } .portfolio-item:hover .portfolio-item-img { transform: scale(1.05); filter: brightness(0.8); } .portfolio-item-overlay { position: absolute; bottom: 0; left: 0; width: 100%; padding: 20px; background: linear-gradient(to top, rgba(0, 0, 0, 0.9), transparent); transform: translateY(100%); transition: transform var(--transition-medium); } .portfolio-item:hover .portfolio-item-overlay { transform: translateY(0); } .portfolio-item-category { font-size: 12px; color: var(--accent-color); font-weight: 600; margin-bottom: 5px; letter-spacing: 1px; text-transform: uppercase; } .portfolio-item-title { font-size: 18px; font-weight: 700; margin-bottom: 10px; } .portfolio-item-description { font-size: 14px; color: rgba(240, 240, 240, 0.8); display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; } .modal { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(0, 0, 0, 0.9); display: flex; align-items: center; justify-content: center; z-index: 1000; opacity: 0; pointer-events: none; transition: opacity var(--transition-medium); } .modal.show { opacity: 1; pointer-events: auto; } .modal-content { position: relative; width: 90%; max-width: 650px; max-height: 90vh; background-color: var(--secondary-color); border-radius: 6px; overflow: hidden; transform: scale(0.9); opacity: 0; transition: transform var(--transition-medium), opacity var(--transition-medium); } .modal.show .modal-content { transform: scale(1); opacity: 1; } .modal-close { position: absolute; top: 15px; right: 15px; width: 30px; height: 30px; border-radius: 50%; background-color: rgba(0, 0, 0, 0.3); display: flex; align-items: center; justify-content: center; cursor: pointer; z-index: 1; } .modal-close::before, .modal-close::after { content: ''; position: absolute; width: 15px; height: 2px; background-color: white; } .modal-close::before { transform: rotate(45deg); } .modal-close::after { transform: rotate(-45deg); } .modal-img { width: 100%; height: 300px; object-fit: cover; } .modal-details { padding: 25px; } .modal-category { display: inline-block; background-color: var(--accent-color); color: white; font-size: 12px; font-weight: 600; padding: 5px 10px; border-radius: 3px; margin-bottom: 15px; } .modal-title { font-size: 24px; font-weight: 700; margin-bottom: 15px; } .modal-description { margin-bottom: 20px; color: rgba(240, 240, 240, 0.9); } .modal-meta { display: flex; gap: 25px; margin-top: 20px; font-size: 14px; } .modal-meta-item { opacity: 0.7; } .modal-meta-item span { font-weight: 600; opacity: 1; color: var(--accent-color); } .progress-bar { position: fixed; top: 0; left: 0; width: 0; height: 3px; background-color: var(--accent-color); z-index: 100; transition: width var(--transition-slow); } .cursor { position: fixed; width: 20px; height: 20px; border-radius: 50%; background-color: rgba(255, 62, 85, 0.2); transform: translate(-50%, -50%); pointer-events: none; z-index: 9999; transition: transform 0.1s ease, width 0.3s ease, height 0.3s ease, background-color 0.3s ease; mix-blend-mode: difference; } .cursor-dot { position: fixed; width: 6px; height: 6px; border-radius: 50%; background-color: var(--accent-color); transform: translate(-50%, -50%); pointer-events: none; z-index: 9999; transition: width 0.3s ease, height 0.3s ease, background-color 0.3s ease; } .cursor-grow { transform: translate(-50%, -50%) scale(3); background-color: rgba(255, 62, 85, 0.1); mix-blend-mode: difference; } @keyframes fadeInUp { from { opacity: 0; transform: translateY(30px); } to { opacity: 1; transform: translateY(0); } } @keyframes fadeInSlideLeft { from { opacity: 0; transform: translateX(-30px); } to { opacity: 1; transform: translateX(0); } } @keyframes fadeInSlideRight { from { opacity: 0; transform: translateX(30px); } to { opacity: 1; transform: translateX(0); } } @media (max-width: 700px) { .intro h1 { font-size: 32px; } .portfolio-grid { grid-template-columns: repeat(2, 1fr); } .portfolio-item:nth-child(1), .portfolio-item:nth-child(2), .portfolio-item:nth-child(3), .portfolio-item:nth-child(4), .portfolio-item:nth-child(5) { grid-column: span 2; grid-row: span 1; } .menu ul { gap: 15px; } .menu li a { font-size: 13px; } } </style> </head> <body> <div class="progress-bar"></div> <div class="cursor"></div> <div class="cursor-dot"></div> <div class="container"> <header> <div class="logo">MONO.</div> <nav> <div class="menu"> <ul> <li><a href="#" class="menu-link">About</a></li> <li><a href="#" class="menu-link">Work</a></li> <li><a href="#" class="menu-link">Process</a></li> <li><a href="#" class="menu-link">Contact</a></li> </ul> </div> </nav> </header> <section class="intro"> <h1>Crafting <span>digital</span> experiences with motion</h1> <p>A curated selection of projects where animation and interaction design elevate user experiences. Each piece demonstrates the power of thoughtful motion design in the digital landscape.</p> </section> <div class="portfolio-grid"> <div class="portfolio-item" data-category="UX Motion" data-title="Fintech Dashboard Animation Flow" data-year="2023" data-client="Blueshift Capital"> <img src="https://images.unsplash.com/photo-1551288049-bebda4e38f71?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=1500&q=80" alt="Fintech Dashboard Animation Flow" class="portfolio-item-img"> <div class="portfolio-item-overlay"> <div class="portfolio-item-category">UX Motion</div> <h3 class="portfolio-item-title">Fintech Dashboard Animation Flow</h3> <p class="portfolio-item-description">Series of micro-interactions that guide users through complex financial data visualization with ease.</p> </div> </div> <div class="portfolio-item" data-category="Interactive Design" data-title="Architectural Portfolio Reveal" data-year="2022" data-client="Studio Meridian"> <img src="https://images.unsplash.com/photo-1487958449943-2429e8be8625?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=1500&q=80" alt="Architectural Portfolio Reveal" class="portfolio-item-img"> <div class="portfolio-item-overlay"> <div class="portfolio-item-category">Interactive Design</div> <h3 class="portfolio-item-title">Architectural Portfolio Reveal</h3> <p class="portfolio-item-description">Parallax-based scroll animations that showcase architectural projects with depth and perspective shifts.</p> </div> </div> <div class="portfolio-item" data-category="Interaction Design" data-title="E-commerce Product Showcase" data-year="2023" data-client="Obsidian Apparel"> <img src="https://images.unsplash.com/photo-1523381294911-8d3cead13475?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=1500&q=80" alt="E-commerce Product Showcase" class="portfolio-item-img"> <div class="portfolio-item-overlay"> <div class="portfolio-item-category">Interaction Design</div> <h3 class="portfolio-item-title">E-commerce Product Showcase</h3> <p class="portfolio-item-description">Animated product cards with reveal effects to enhance user engagement and conversion rates.</p> </div> </div> <div class="portfolio-item" data-category="Motion Design" data-title="Digital Magazine Transitions" data-year="2023" data-client="Prism Publications"> <img src="https://images.unsplash.com/photo-1496171367470-9ed9a91ea931?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=1500&q=80" alt="Digital Magazine Transitions" class="portfolio-item-img"> <div class="portfolio-item-overlay"> <div class="portfolio-item-category">Motion Design</div> <h3 class="portfolio-item-title">Digital Magazine Transitions</h3> <p class="portfolio-item-description">Smooth page transitions and article reveals for an immersive digital reading experience.</p> </div> </div> <div class="portfolio-item" data-category="UI Animation" data-title="Healthcare App Onboarding" data-year="2022" data-client="Vital Health"> <img src="https://images.unsplash.com/photo-1581287053822-fd7bf4f4bfec?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=1500&q=80" alt="Healthcare App Onboarding" class="portfolio-item-img"> <div class="portfolio-item-overlay"> <div class="portfolio-item-category">UI Animation</div> <h3 class="portfolio-item-title">Healthcare App Onboarding</h3> <p class="portfolio-item-description">Sequential animations that guide new users through complex healthcare features with clarity and engagement.</p> </div> </div> </div> </div> <div class="modal"> <div class="modal-content"> <div class="modal-close"></div> <img src="" alt="" class="modal-img"> <div class="modal-details"> <div class="modal-category"></div> <h2 class="modal-title"></h2> <p class="modal-description"></p> <div class="modal-meta"> <div class="modal-meta-item">Year: <span class="modal-year"></span></div> <div class="modal-meta-item">Client: <span class="modal-client"></span></div> </div> </div> </div> </div> <script> document.addEventListener('DOMContentLoaded', () => { // Custom cursor const cursor = document.querySelector('.cursor'); const cursorDot = document.querySelector('.cursor-dot'); document.addEventListener('mousemove', (e) => { cursor.style.left = e.clientX + 'px'; cursor.style.top = e.clientY + 'px'; cursorDot.style.left = e.clientX + 'px'; cursorDot.style.top = e.clientY + 'px'; }); const links = document.querySelectorAll('a, .portfolio-item, .modal-close'); links.forEach(link => { link.addEventListener('mouseenter', () => { cursor.classList.add('cursor-grow'); }); link.addEventListener('mouseleave', () => { cursor.classList.remove('cursor-grow'); }); }); // Scroll progress bar const progressBar = document.querySelector('.progress-bar'); window.addEventListener('scroll', () => { const scrollTop = document.documentElement.scrollTop || document.body.scrollTop; const scrollHeight = document.documentElement.scrollHeight - document.documentElement.clientHeight; const progress = (scrollTop / scrollHeight) * 100; progressBar.style.width = progress + '%'; }); // Portfolio item modal const portfolioItems = document.querySelectorAll('.portfolio-item'); const modal = document.querySelector('.modal'); const modalImg = document.querySelector('.modal-img'); const modalCategory = document.querySelector('.modal-category'); const modalTitle = document.querySelector('.modal-title'); const modalDescription = document.querySelector('.modal-description'); const modalYear = document.querySelector('.modal-year'); const modalClient = document.querySelector('.modal-client'); const modalClose = document.querySelector('.modal-close'); const projectDescriptions = { "Fintech Dashboard Animation Flow": "A comprehensive animation system designed for complex financial data visualization. This project focused on creating smooth transitions between dashboard states, incorporating meaningful micro-interactions that guide users through data analysis. The animations serve both functional and aesthetic purposes, highlighting changes in data while maintaining context.", "Architectural Portfolio Reveal": "A unique approach to showcasing architectural works through sequenced reveal animations. Each project unfolds through carefully timed transitions that highlight spatial relationships and design details. The scroll-triggered animations create a narrative experience, allowing visitors to appreciate the architectural projects in a more immersive way than static presentations.", "E-commerce Product Showcase": "An innovative product card system with staggered animation sequences that improve product discovery and conversion. Each interaction was designed to emphasize product features while maintaining a clean, distraction-free browsing experience. The motion design creates visual hierarchy and guides attention to key purchasing decision points.", "Digital Magazine Transitions": "A complete reimagining of the digital reading experience through choreographed page transitions and content reveals. The animations maintain reading flow while creating distinct sections and article boundaries. Special attention was given to typography animations that enhance readability and content consumption.", "Healthcare App Onboarding": "A series of educational animations designed to improve user comprehension of complex healthcare features. The onboarding sequence uses motion to explain relationships between data points and user actions. The animations were carefully optimized for performance while maintaining clarity and engagement through the entire user journey." }; portfolioItems.forEach(item => { item.addEventListener('click', () => { const img = item.querySelector('img').src; const category = item.dataset.category; const title = item.dataset.title; const year = item.dataset.year; const client = item.dataset.client; modalImg.src = img; modalImg.alt = title; modalCategory.textContent = category; modalTitle.textContent = title; modalDescription.textContent = projectDescriptions[title]; modalYear.textContent = year; modalClient.textContent = client; modal.classList.add('show'); document.body.style.overflow = 'hidden'; }); }); modalClose.addEventListener('click', () => { modal.classList.remove('show'); document.body.style.overflow = 'auto'; }); modal.addEventListener('click', (e) => { if (e.target === modal) { modal.classList.remove('show'); document.body.style.overflow = 'auto'; } }); // Staggered animation for portfolio items on scroll const observerOptions = { threshold: 0.1 }; const observer = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { entry.target.style.animationPlayState = 'running'; observer.unobserve(entry.target); } }); }, observerOptions); portfolioItems.forEach(item => { item.style.animationPlayState = 'paused'; observer.observe(item); }); }); </script> </body> </html>
<html> <head> <style> * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Rajdhani', sans-serif; } body { background-color: #0a0a1a; color: #fff; overflow-x: hidden; display: flex; justify-content: center; align-items: center; min-height: 700px; width: 100%; max-width: 700px; margin: 0 auto; padding: 20px; } @font-face { font-family: 'Rajdhani'; font-style: normal; font-weight: 500; src: url(https://fonts.gstatic.com/s/rajdhani/v15/LDI2apCSOBg7S-QT7pb0EPOqeef2kg.woff2) format('woff2'); } @font-face { font-family: 'Rajdhani'; font-style: normal; font-weight: 700; src: url(https://fonts.gstatic.com/s/rajdhani/v15/LDI2apCSOBg7S-QT7pa8FvOqeef2kg.woff2) format('woff2'); } .container { width: 100%; max-width: 650px; position: relative; background: rgba(15, 15, 30, 0.8); border-radius: 12px; padding: 5px; box-shadow: 0 0 30px rgba(0, 225, 255, 0.2); overflow: hidden; } .container::before { content: ''; position: absolute; top: -2px; left: -2px; right: -2px; bottom: -2px; background: linear-gradient(45deg, #ff00e5, #00e1ff, #00ff8f, #ff00e5); z-index: -1; border-radius: 14px; animation: animate 10s linear infinite; background-size: 400%; } @keyframes animate { 0% { background-position: 0 0; } 50% { background-position: 300% 0; } 100% { background-position: 0 0; } } .header { text-align: center; padding: 20px 0; position: relative; border-bottom: 1px solid rgba(0, 225, 255, 0.3); } .header h1 { font-size: 2.5rem; font-weight: 700; margin-bottom: 5px; color: #fff; text-transform: uppercase; letter-spacing: 2px; text-shadow: 0 0 10px #00e1ff, 0 0 20px #00e1ff, 0 0 40px #00e1ff; opacity: 0; transform: translateY(-20px); animation: fadeIn 0.5s ease forwards 0.2s; } .header p { color: #00e1ff; font-size: 1.1rem; margin-bottom: 10px; opacity: 0; transform: translateY(-10px); animation: fadeIn 0.5s ease forwards 0.4s; } .tournament-info { display: flex; justify-content: space-between; padding: 10px 20px; font-size: 0.95rem; color: #aaa; background: rgba(0, 0, 0, 0.3); margin-bottom: 10px; opacity: 0; transform: translateY(-10px); animation: fadeIn 0.5s ease forwards 0.6s; } .leaderboard { padding: 0 15px; margin-bottom: 20px; } .leaderboard-header { display: grid; grid-template-columns: 0.5fr 2fr 1fr 1fr 1fr; padding: 10px 15px; font-weight: bold; color: #00e1ff; border-bottom: 1px solid rgba(0, 225, 255, 0.2); font-size: 0.95rem; opacity: 0; transform: translateY(-10px); animation: fadeIn 0.5s ease forwards 0.8s; } .player-card { display: grid; grid-template-columns: 0.5fr 2fr 1fr 1fr 1fr; padding: 12px 15px; margin: 8px 0; background: rgba(0, 0, 0, 0.2); border-radius: 8px; box-shadow: 0 0 10px rgba(0, 225, 255, 0.1); cursor: pointer; transition: all 0.3s ease; position: relative; overflow: hidden; opacity: 0; transform: translateX(-20px); } .rank { font-weight: bold; font-size: 1.2rem; display: flex; align-items: center; justify-content: center; } .rank-1 { color: #ffdc73; text-shadow: 0 0 5px #ffdc73; } .rank-2 { color: #c0c0c0; text-shadow: 0 0 5px #c0c0c0; } .rank-3 { color: #cd7f32; text-shadow: 0 0 5px #cd7f32; } .player { display: flex; align-items: center; gap: 10px; } .player-avatar { width: 35px; height: 35px; border-radius: 50%; background-size: cover; background-position: center; border: 2px solid #00e1ff; box-shadow: 0 0 10px rgba(0, 225, 255, 0.5); } .player-name { font-weight: 500; font-size: 1.1rem; } .player-tag { font-size: 0.8rem; color: #888; } .score, .kills, .accuracy { display: flex; align-items: center; justify-content: center; font-weight: 500; font-size: 1.1rem; } .player-card::before { content: ''; position: absolute; top: 0; left: -100%; width: 100%; height: 100%; background: linear-gradient(90deg, transparent, rgba(0, 225, 255, 0.2), transparent); transition: 0.5s; } .player-card:hover::before { left: 100%; } .player-card:hover { transform: translateY(-2px); box-shadow: 0 5px 15px rgba(0, 225, 255, 0.2); background: rgba(0, 0, 0, 0.4); } .player-detail { display: none; grid-template-columns: 1fr 1fr; grid-gap: 10px; padding: 15px; background: rgba(0, 0, 0, 0.3); border-radius: 8px; margin-top: 5px; border: 1px solid rgba(0, 225, 255, 0.3); animation: detailFadeIn 0.4s ease forwards; } .detail-item { display: flex; flex-direction: column; padding: 10px; background: rgba(0, 0, 0, 0.4); border-radius: 6px; } .detail-label { font-size: 0.85rem; color: #888; margin-bottom: 5px; } .detail-value { font-size: 1.1rem; font-weight: 500; color: #00e1ff; } .controls { padding: 0 15px 15px; display: flex; justify-content: space-between; opacity: 0; transform: translateY(10px); animation: fadeIn 0.5s ease forwards 1.8s; } button { background: transparent; border: 1px solid #00e1ff; color: #00e1ff; padding: 8px 16px; border-radius: 4px; cursor: pointer; font-weight: 500; font-size: 0.9rem; transition: all 0.3s ease; outline: none; position: relative; overflow: hidden; z-index: 1; } button::before { content: ''; position: absolute; top: 0; left: 0; width: 0; height: 100%; background: rgba(0, 225, 255, 0.2); transition: all 0.3s ease; z-index: -1; } button:hover::before { width: 100%; } select { background: rgba(0, 0, 0, 0.5); border: 1px solid #00e1ff; color: #fff; padding: 8px 16px; border-radius: 4px; cursor: pointer; font-size: 0.9rem; outline: none; } .pulse { animation: pulse 1.5s infinite; } @keyframes pulse { 0% { box-shadow: 0 0 0 0 rgba(0, 225, 255, 0.7); } 70% { box-shadow: 0 0 0 10px rgba(0, 225, 255, 0); } 100% { box-shadow: 0 0 0 0 rgba(0, 225, 255, 0); } } @keyframes fadeIn { to { opacity: 1; transform: translateY(0) translateX(0); } } @keyframes detailFadeIn { from { opacity: 0; transform: scaleY(0.8); transform-origin: top; } to { opacity: 1; transform: scaleY(1); transform-origin: top; } } .loader { position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: rgba(10, 10, 26, 0.95); z-index: 10; display: flex; justify-content: center; align-items: center; flex-direction: column; transition: all 0.4s ease; } .loader.hidden { opacity: 0; pointer-events: none; } .loading-text { color: #00e1ff; font-size: 1.5rem; margin-top: 20px; text-transform: uppercase; letter-spacing: 3px; animation: blink 1s infinite; } .spinner { width: 50px; height: 50px; border: 5px solid rgba(0, 225, 255, 0.3); border-radius: 50%; border-top-color: #00e1ff; animation: spin 1s linear infinite; } @keyframes spin { to { transform: rotate(360deg); } } @keyframes blink { 0%, 100% { opacity: 1; } 50% { opacity: 0.5; } } @media (max-width: 600px) { .header h1 { font-size: 2rem; } .leaderboard-header, .player-card { grid-template-columns: 0.5fr 2fr 1fr 0.8fr; } .accuracy { display: none; } .leaderboard-header > div:last-child { display: none; } .player-detail { grid-template-columns: 1fr; } .controls { flex-direction: column; gap: 10px; } select, button { width: 100%; } } </style> </head> <body> <div class="container"> <div class="loader"> <div class="spinner"></div> <div class="loading-text">Loading leaderboard</div> </div> <div class="header"> <h1>Nova Strike</h1> <p>Season 4 - Operation Twilight</p> </div> <div class="tournament-info"> <div>Players: 1,246</div> <div>Last Updated: 3 mins ago</div> </div> <div class="leaderboard"> <div class="leaderboard-header"> <div>Rank</div> <div>Player</div> <div>Score</div> <div>Kills</div> <div>Accuracy</div> </div> <div id="leaderboard-content"></div> </div> <div class="controls"> <select id="filter-region"> <option value="all">All Regions</option> <option value="na">North America</option> <option value="eu">Europe</option> <option value="asia">Asia</option> <option value="oce">Oceania</option> </select> <button id="refresh-btn" class="pulse">Refresh Leaderboard</button> </div> </div> <script> // Sample player data const players = [ { id: 1, name: "ShadowByte", tag: "SBY", avatar: "https://i.pravatar.cc/150?img=33", score: 9784, kills: 342, accuracy: "94%", region: "na", details: { kdRatio: "3.8", winRate: "68%", headshots: "43%", playtime: "187h", longestStreak: "17", favoriteWeapon: "Quantum Rifle" } }, { id: 2, name: "NeonViper", tag: "NVP", avatar: "https://i.pravatar.cc/150?img=32", score: 9653, kills: 301, accuracy: "91%", region: "eu", details: { kdRatio: "3.6", winRate: "72%", headshots: "38%", playtime: "163h", longestStreak: "14", favoriteWeapon: "Plasma Cannon" } }, { id: 3, name: "Cyberslash", tag: "CYS", avatar: "https://i.pravatar.cc/150?img=11", score: 9427, kills: 289, accuracy: "89%", region: "asia", details: { kdRatio: "3.2", winRate: "65%", headshots: "45%", playtime: "201h", longestStreak: "13", favoriteWeapon: "Void Dagger" } }, { id: 4, name: "Pixelstorm", tag: "PXS", avatar: "https://i.pravatar.cc/150?img=23", score: 9215, kills: 277, accuracy: "87%", region: "na", details: { kdRatio: "3.1", winRate: "63%", headshots: "36%", playtime: "172h", longestStreak: "12", favoriteWeapon: "Lightning SMG" } }, { id: 5, name: "ElectroFrost", tag: "EFT", avatar: "https://i.pravatar.cc/150?img=15", score: 9011, kills: 264, accuracy: "90%", region: "eu", details: { kdRatio: "2.9", winRate: "61%", headshots: "41%", playtime: "156h", longestStreak: "11", favoriteWeapon: "Ice Launcher" } }, { id: 6, name: "QuantumKnight", tag: "QKT", avatar: "https://i.pravatar.cc/150?img=59", score: 8832, kills: 251, accuracy: "86%", region: "asia", details: { kdRatio: "2.8", winRate: "58%", headshots: "37%", playtime: "189h", longestStreak: "10", favoriteWeapon: "Energy Sword" } }, { id: 7, name: "VirtualGhost", tag: "VGT", avatar: "https://i.pravatar.cc/150?img=53", score: 8713, kills: 242, accuracy: "84%", region: "oce", details: { kdRatio: "2.7", winRate: "56%", headshots: "35%", playtime: "143h", longestStreak: "9", favoriteWeapon: "Stealth Pistol" } }, { id: 8, name: "CodeRipper", tag: "CRP", avatar: "https://i.pravatar.cc/150?img=60", score: 8529, kills: 235, accuracy: "85%", region: "na", details: { kdRatio: "2.6", winRate: "54%", headshots: "33%", playtime: "168h", longestStreak: "8", favoriteWeapon: "Data Disruptor" } } ]; document.addEventListener('DOMContentLoaded', () => { // Simulate loading setTimeout(() => { document.querySelector('.loader').classList.add('hidden'); renderLeaderboard(players); }, 1500); // Filter change event document.getElementById('filter-region').addEventListener('change', (e) => { const region = e.target.value; const filteredPlayers = region === 'all' ? players : players.filter(player => player.region === region); renderLeaderboard(filteredPlayers); }); // Refresh button click event document.getElementById('refresh-btn').addEventListener('click', () => { const leaderboard = document.getElementById('leaderboard-content'); leaderboard.innerHTML = ''; document.querySelector('.loader').classList.remove('hidden'); setTimeout(() => { document.querySelector('.loader').classList.add('hidden'); // Shuffle players array to simulate refresh const shuffledPlayers = [...players].sort(() => Math.random() - 0.5); renderLeaderboard(shuffledPlayers); }, 1000); }); }); function renderLeaderboard(players) { const leaderboard = document.getElementById('leaderboard-content'); leaderboard.innerHTML = ''; players.forEach((player, index) => { const playerCard = document.createElement('div'); playerCard.className = 'player-card'; playerCard.dataset.id = player.id; // Animation delay based on position playerCard.style.animation = `fadeIn 0.4s ease forwards ${0.9 + (index * 0.1)}s`; const rankClass = index < 3 ? `rank-${index+1}` : ''; playerCard.innerHTML = ` <div class="rank ${rankClass}">${index + 1}</div> <div class="player"> <div class="player-avatar" style="background-image: url(${player.avatar})"></div> <div> <div class="player-name">${player.name}</div> <div class="player-tag">${player.tag}</div> </div> </div> <div class="score">${player.score.toLocaleString()}</div> <div class="kills">${player.kills}</div> <div class="accuracy">${player.accuracy}</div> `; leaderboard.appendChild(playerCard); // Create player detail section but don't append yet const playerDetail = document.createElement('div'); playerDetail.className = 'player-detail'; playerDetail.id = `detail-${player.id}`; const details = player.details; playerDetail.innerHTML = ` <div class="detail-item"> <div class="detail-label">K/D Ratio</div> <div class="detail-value">${details.kdRatio}</div> </div> <div class="detail-item"> <div class="detail-label">Win Rate</div> <div class="detail-value">${details.winRate}</div> </div> <div class="detail-item"> <div class="detail-label">Headshot %</div> <div class="detail-value">${details.headshots}</div> </div> <div class="detail-item"> <div class="detail-label">Playtime</div> <div class="detail-value">${details.playtime}</div> </div> <div class="detail-item"> <div class="detail-label">Longest Streak</div> <div class="detail-value">${details.longestStreak}</div> </div> <div class="detail-item"> <div class="detail-label">Favorite Weapon</div> <div class="detail-value">${details.favoriteWeapon}</div> </div> `; // Click event to toggle details playerCard.addEventListener('click', () => { const existingDetail = document.getElementById(`detail-${player.id}`); // Close any open details document.querySelectorAll('.player-detail').forEach(el => { if (el.id !== `detail-${player.id}`) { el.style.display = 'none'; } }); if (existingDetail) { if (existingDetail.style.display === 'grid') { existingDetail.style.display = 'none'; } else { existingDetail.style.display = 'grid'; } } else { leaderboard.insertBefore(playerDetail, playerCard.nextSibling); playerDetail.style.display = 'grid'; } }); }); } </script> </body> </html>
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Threadscape - Progressive Social Thread Reveal</title> <style> :root { --primary: #5271ff; --primary-light: #8ca0ff; --secondary: #ff5287; --text-dark: #2a2a3a; --text-light: #6e7191; --bg-main: #f9fafc; --bg-card: #ffffff; --shadow-soft: 0 4px 20px rgba(82, 113, 255, 0.05); --shadow-medium: 0 8px 30px rgba(82, 113, 255, 0.1); --transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1); --border-radius: 12px; --font-main: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif; } * { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: var(--font-main); background: var(--bg-main); color: var(--text-dark); line-height: 1.5; font-size: 15px; height: 100vh; overflow-x: hidden; padding: 20px; display: flex; justify-content: center; align-items: center; } .container { width: 100%; max-width: 650px; height: 650px; overflow-y: auto; overflow-x: hidden; padding: 0 10px; border-radius: var(--border-radius); background: var(--bg-card); box-shadow: var(--shadow-medium); scrollbar-width: thin; scrollbar-color: var(--primary-light) var(--bg-main); } .container::-webkit-scrollbar { width: 5px; } .container::-webkit-scrollbar-thumb { background-color: var(--primary-light); border-radius: 20px; } .header { position: sticky; top: 0; padding: 20px 15px; background: var(--bg-card); border-bottom: 1px solid rgba(0, 0, 0, 0.05); display: flex; justify-content: space-between; align-items: center; margin-bottom: 15px; z-index: 10; backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px); } .header h1 { font-size: 20px; background: linear-gradient(135deg, var(--primary), var(--secondary)); background-clip: text; -webkit-background-clip: text; color: transparent; } .profile-button { width: 36px; height: 36px; border-radius: 50%; background: linear-gradient(135deg, var(--primary), var(--secondary)); color: white; display: flex; justify-content: center; align-items: center; font-weight: bold; cursor: pointer; transition: transform 0.2s ease; } .profile-button:hover { transform: scale(1.05); } .compose-area { padding: 15px; border-radius: var(--border-radius); background-color: rgba(230, 232, 248, 0.5); margin-bottom: 20px; transition: var(--transition); } .compose-input { width: 100%; padding: 15px; border: none; background: var(--bg-card); border-radius: 8px; margin-bottom: 10px; resize: none; font-family: var(--font-main); transition: var(--transition); box-shadow: var(--shadow-soft); } .compose-input:focus { outline: none; box-shadow: 0 0 0 2px var(--primary-light); } .compose-actions { display: flex; justify-content: space-between; align-items: center; } .compose-actions button { padding: 8px 15px; border: none; border-radius: 6px; font-weight: 600; cursor: pointer; transition: var(--transition); } .post-button { background: linear-gradient(135deg, var(--primary), var(--primary-light)); color: white; } .post-button:hover { box-shadow: 0 3px 10px rgba(82, 113, 255, 0.2); transform: translateY(-1px); } .thread { margin-bottom: 30px; opacity: 0; transform: translateY(20px); transition: var(--transition); } .thread.visible { opacity: 1; transform: translateY(0); } .thread-main { background: var(--bg-card); border-radius: var(--border-radius); padding: 20px; box-shadow: var(--shadow-soft); margin-bottom: 5px; position: relative; transition: var(--transition); } .thread-main:hover { box-shadow: var(--shadow-medium); } .thread-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px; } .user-info { display: flex; align-items: center; gap: 10px; } .user-avatar { width: 40px; height: 40px; border-radius: 50%; background: linear-gradient(135deg, var(--primary-light), var(--secondary)); display: flex; justify-content: center; align-items: center; color: white; font-weight: bold; } .user-name { font-weight: 600; } .user-handle { color: var(--text-light); font-size: 0.85em; } .thread-time { color: var(--text-light); font-size: 0.85em; } .thread-content { margin-bottom: 15px; } .thread-actions { display: flex; gap: 15px; color: var(--text-light); } .thread-action { display: flex; align-items: center; gap: 5px; cursor: pointer; transition: var(--transition); } .thread-action:hover { color: var(--primary); } .thread-action.liked { color: var(--secondary); } .thread-action i { font-size: 1.2em; } .thread-replies-toggle { text-align: center; color: var(--primary); font-weight: 600; padding: 8px; cursor: pointer; margin-bottom: 10px; position: relative; transition: var(--transition); } .thread-replies-toggle::after { content: ''; position: absolute; left: 50%; bottom: 0; transform: translateX(-50%); width: 0; height: 2px; background: var(--primary); transition: var(--transition); } .thread-replies-toggle:hover::after { width: 50px; } .thread-replies { max-height: 0; overflow: hidden; transition: max-height 0.5s cubic-bezier(0, 1, 0, 1); } .thread-replies.expanded { max-height: 1000px; transition: max-height 1s ease-in-out; } .reply { padding: 15px; margin-left: 20px; margin-bottom: 5px; border-radius: var(--border-radius); background: rgba(239, 241, 254, 0.5); border-left: 2px solid var(--primary-light); opacity: 0; transform: translateY(10px); transition: all 0.3s ease; } .reply.visible { opacity: 1; transform: translateY(0); } .reply-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px; } .reply-content { margin-bottom: 10px; } .reply-actions { display: flex; gap: 15px; color: var(--text-light); font-size: 0.9em; } .gradient-tag { display: inline-block; padding: 3px 10px; border-radius: 20px; background: linear-gradient(135deg, #5271ff11, #ff528711); color: var(--primary); font-size: 0.85em; margin-right: 5px; margin-bottom: 5px; } .thread-image { width: 100%; border-radius: 8px; margin-bottom: 15px; max-height: 200px; object-fit: cover; } /* Pulse animation for new content indicator */ @keyframes pulse { 0% { transform: scale(1); opacity: 1; } 50% { transform: scale(1.05); opacity: 0.8; } 100% { transform: scale(1); opacity: 1; } } .new-content-indicator { position: fixed; bottom: 20px; right: 20px; width: 40px; height: 40px; border-radius: 50%; background: linear-gradient(135deg, var(--primary), var(--secondary)); color: white; display: flex; justify-content: center; align-items: center; box-shadow: var(--shadow-medium); cursor: pointer; animation: pulse 2s infinite; opacity: 0; visibility: hidden; transition: var(--transition); } .new-content-indicator.visible { opacity: 1; visibility: visible; } /* Loading indicator for replies */ .loading-indicator { display: flex; justify-content: center; align-items: center; padding: 10px 0; opacity: 0; transition: opacity 0.3s ease; } .loading-indicator.visible { opacity: 1; } .loading-dot { width: 8px; height: 8px; margin: 0 3px; border-radius: 50%; background-color: var(--primary); animation: dot-pulse 1.5s infinite ease-in-out; } .loading-dot:nth-child(2) { animation-delay: 0.2s; } .loading-dot:nth-child(3) { animation-delay: 0.4s; } @keyframes dot-pulse { 0%, 100% { transform: scale(0.8); opacity: 0.6; } 50% { transform: scale(1.2); opacity: 1; } } /* Typing indicator */ .typing-indicator { display: inline-flex; align-items: center; padding: 5px 10px; background: rgba(243, 244, 254, 0.8); border-radius: 15px; margin-left: 20px; margin-bottom: 10px; font-size: 0.85em; color: var(--text-light); opacity: 0; transition: opacity 0.3s ease; } .typing-indicator.visible { opacity: 1; } .typing-indicator span { width: 5px; height: 5px; margin: 0 2px; background-color: var(--text-light); border-radius: 50%; display: inline-block; animation: typing 1.5s infinite ease-in-out; } .typing-indicator span:nth-child(2) { animation-delay: 0.2s; } .typing-indicator span:nth-child(3) { animation-delay: 0.4s; } @keyframes typing { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-4px); } } /* Shimmer effect for loading content */ @keyframes shimmer { 0% { background-position: -1000px 0; } 100% { background-position: 1000px 0; } } .shimmer { background: linear-gradient(90deg, rgba(255, 255, 255, 0), rgba(255, 255, 255, 0.6), rgba(255, 255, 255, 0)); background-size: 1000px 100%; animation: shimmer 2s infinite linear; } /* Responsive styles */ @media (max-width: 550px) { .container { padding: 0 5px; } .thread-main, .reply { padding: 15px; } .user-avatar { width: 32px; height: 32px; } } </style> </head> <body> <div class="container"> <div class="header"> <h1>Threadscape</h1> <div class="profile-button">TW</div> </div> <div class="compose-area"> <textarea class="compose-input" placeholder="Start a new thread..."></textarea> <div class="compose-actions"> <div> <span class="gradient-tag">#design</span> <span class="gradient-tag">#ux</span> </div> <button class="post-button">Post Thread</button> </div> </div> <div class="thread" id="thread1"> <div class="thread-main"> <div class="thread-header"> <div class="user-info"> <div class="user-avatar">JD</div> <div> <div class="user-name">Jamie Designs</div> <div class="user-handle">@jamiedesigns</div> </div> </div> <div class="thread-time">2 hours ago</div> </div> <div class="thread-content"> <p>Our user testing showed that gradual reveal of comment sections significantly improves engagement metrics. Users spend 27% more time interacting with threads when visual feedback confirms their actions.</p> <img src="https://source.unsplash.com/random/600x300/?interface,ux" alt="UX design mockup" class="thread-image"> </div> <div class="thread-actions"> <div class="thread-action like-action" data-thread="1"> <i>♥</i> <span class="like-count">42</span> </div> <div class="thread-action"> <i>↩</i> <span>12</span> </div> <div class="thread-action"> <i>↪</i> <span>Share</span> </div> </div> </div> <div class="thread-replies-toggle" data-thread="1">Show replies (12)</div> <div class="loading-indicator" id="loading1"> <div class="loading-dot"></div> <div class="loading-dot"></div> <div class="loading-dot"></div> </div> <div class="thread-replies" id="replies1"> <div class="reply"> <div class="reply-header"> <div class="user-info"> <div class="user-avatar">AK</div> <div> <div class="user-name">Alex Kim</div> <div class="user-handle">@alexux</div> </div> </div> <div class="thread-time">1h ago</div> </div> <div class="reply-content"> <p>Did you test different animation durations? I've found that anything over 350ms feels sluggish to power users while anything under 200ms gets missed by casual browsers.</p> </div> <div class="reply-actions"> <div class="thread-action like-action" data-thread="1-1"> <i>♥</i> <span class="like-count">18</span> </div> <div class="thread-action"> <i>↩</i> <span>Reply</span> </div> </div> </div> <div class="reply"> <div class="reply-header"> <div class="user-info"> <div class="user-avatar">JD</div> <div> <div class="user-name">Jamie Designs</div> <div class="user-handle">@jamiedesigns</div> </div> </div> <div class="thread-time">45m ago</div> </div> <div class="reply-content"> <p>Great catch! We settled on 280ms with a slight easing function. A/B testing showed the sweet spot is different for mobile (faster) vs desktop (slightly slower) interactions.</p> </div> <div class="reply-actions"> <div class="thread-action like-action" data-thread="1-2"> <i>♥</i> <span class="like-count">9</span> </div> <div class="thread-action"> <i>↩</i> <span>Reply</span> </div> </div> </div> <div class="reply"> <div class="reply-header"> <div class="user-info"> <div class="user-avatar">TN</div> <div> <div class="user-name">Taylor Nolan</div> <div class="user-handle">@taylorinterface</div> </div> </div> <div class="thread-time">30m ago</div> </div> <div class="reply-content"> <p>I'd love to see how this performs for users with reduced motion preferences enabled. Have you implemented conditional animations based on prefers-reduced-motion media query?</p> </div> <div class="reply-actions"> <div class="thread-action like-action" data-thread="1-3"> <i>♥</i> <span class="like-count">15</span> </div> <div class="thread-action"> <i>↩</i> <span>Reply</span> </div> </div> </div> <div class="typing-indicator" id="typing1"> Someone is typing<span></span><span></span><span></span> </div> </div> </div> <div class="thread" id="thread2"> <div class="thread-main"> <div class="thread-header"> <div class="user-info"> <div class="user-avatar">SP</div> <div> <div class="user-name">Sophia Parks</div> <div class="user-handle">@sophiadesigner</div> </div> </div> <div class="thread-time">4 hours ago</div> </div> <div class="thread-content"> <p>Gradients are making a comeback in 2023 thread UI design, but with subtle sophistication. Using them in moderation for interactive elements creates visual hierarchy without overwhelming the interface.</p> <p>What's your preferred gradient palette for modern social media applications?</p> </div> <div class="thread-actions"> <div class="thread-action like-action" data-thread="2"> <i>♥</i> <span class="like-count">36</span> </div> <div class="thread-action"> <i>↩</i> <span>8</span> </div> <div class="thread-action"> <i>↪</i> <span>Share</span> </div> </div> </div> <div class="thread-replies-toggle" data-thread="2">Show replies (8)</div> <div class="loading-indicator" id="loading2"> <div class="loading-dot"></div> <div class="loading-dot"></div> <div class="loading-dot"></div> </div> <div class="thread-replies" id="replies2"> <div class="reply"> <div class="reply-header"> <div class="user-info"> <div class="user-avatar">MW</div> <div> <div class="user-name">Miguel Wong</div> <div class="user-handle">@miguelw</div> </div> </div> <div class="thread-time">3h ago</div> </div> <div class="reply-content"> <p>I'm leaning toward desaturated purples to teals for financial apps, while social platforms can handle more vibrant blue-pink transitions. The key is keeping the contrast ratio high enough for text legibility.</p> </div> <div class="reply-actions"> <div class="thread-action like-action" data-thread="2-1"> <i>♥</i> <span class="like-count">12</span> </div> <div class="thread-action"> <i>↩</i> <span>Reply</span> </div> </div> </div> <div class="reply"> <div class="reply-header"> <div class="user-info"> <div class="user-avatar">RJ</div> <div> <div class="user-name">Rachel Jones</div> <div class="user-handle">@rachelj</div> </div> </div> <div class="thread-time">2h ago</div> </div> <div class="reply-content"> <p>Agreed on the moderation aspect. I've been using micro-gradients - tiny 2-3px accents rather than full background fills. They signal interactivity without becoming the focal point of the design.</p> </div> <div class="reply-actions"> <div class="thread-action like-action" data-thread="2-2"> <i>♥</i> <span class="like-count">8</span> </div> <div class="thread-action"> <i>↩</i> <span>Reply</span> </div> </div> </div> </div> </div> <div class="thread" id="thread3"> <div class="thread-main"> <div class="thread-header"> <div class="user-info"> <div class="user-avatar">EL</div> <div> <div class="user-name">Eli Lawrence</div> <div class="user-handle">@eliuxdev</div> </div> </div> <div class="thread-time">6 hours ago</div> </div> <div class="thread-content"> <p>Font choice is critical for message thread hierarchies. We're using system fonts with variable weights to indicate thread depth instead of indentation.</p> <p>Main thread: 600 weight<br>First reply: 500 weight<br>Deeper replies: 400 weight</p> <p>This maintains legibility while creating visual distinction. Thoughts?</p> </div> <div class="thread-actions"> <div class="thread-action like-action" data-thread="3"> <i>♥</i> <span class="like-count">24</span> </div> <div class="thread-action"> <i>↩</i> <span>5</span> </div> <div class="thread-action"> <i>↪</i> <span>Share</span> </div> </div> </div> <div class="thread-replies-toggle" data-thread="3">Show replies (5)</div> <div class="loading-indicator" id="loading3"> <div class="loading-dot"></div> <div class="loading-dot"></div> <div class="loading-dot"></div> </div> <div class="thread-replies" id="replies3"> <div class="reply"> <div class="reply-header"> <div class="user-info"> <div class="user-avatar">VM</div> <div> <div class="user-name">Vikram Mehta</div> <div class="user-handle">@vikramux</div> </div> </div> <div class="thread-time">5h ago</div> </div> <div class="reply-content"> <p>Have you considered color as an additional hierarchical indicator? Subtle desaturation for deeper threads can work well with the weight changes you're proposing.</p> </div> <div class="reply-actions"> <div class="thread-action like-action" data-thread="3-1"> <i>♥</i> <span class="like-count">11</span> </div> <div class="thread-action"> <i>↩</i> <span>Reply</span> </div> </div> </div> <div class="reply"> <div class="reply-header"> <div class="user-info"> <div class="user-avatar">KT</div> <div> <div class="user-name">Kai Thompson</div> <div class="user-handle">@kaidevelops</div> </div> </div> <div class="thread-time">4h ago</div> </div> <div class="reply-content"> <p>I'd suggest some minimal indentation (4-8px per level) in addition to the weight changes. Our accessibility tests showed that weight alone wasn't sufficient for users with certain visual impairments to track conversation flow.</p> </div> <div class="reply-actions"> <div class="thread-action like-action" data-thread="3-2"> <i>♥</i> <span class="like-count">15</span> </div> <div class="thread-action"> <i>↩</i> <span>Reply</span> </div> </div> </div> </div> </div> <div class="new-content-indicator"> <i>↓</i> </div> </div> <script> document.addEventListener('DOMContentLoaded', function() { // Progressive reveal of threads on page load const threads = document.querySelectorAll('.thread'); threads.forEach((thread, index) => { setTimeout(() => { thread.classList.add('visible'); }, 150 * index); }); // Toggle thread replies const toggleButtons = document.querySelectorAll('.thread-replies-toggle'); toggleButtons.forEach(button => { button.addEventListener('click', function() { const threadId = this.getAttribute('data-thread'); const repliesContainer = document.getElementById('replies' + threadId); const loadingIndicator = document.getElementById('loading' + threadId); if (repliesContainer.classList.contains('expanded')) { repliesContainer.classList.remove('expanded'); this.textContent = `Show replies (${countReplies(threadId)})`; } else { // Show loading indicator loadingIndicator.classList.add('visible'); // Simulate loading delay setTimeout(() => { loadingIndicator.classList.remove('visible'); repliesContainer.classList.add('expanded'); this.textContent = 'Hide replies'; // Animate in replies const replies = repliesContainer.querySelectorAll('.reply'); replies.forEach((reply, index) => { setTimeout(() => { reply.classList.add('visible'); }, 120 * index); }); // Show typing indicator after replies load setTimeout(() => { const typingIndicator = document.getElementById('typing' + threadId); if (typingIndicator) { typingIndicator.classList.add('visible'); // Hide typing indicator after a while setTimeout(() => { typingIndicator.classList.remove('visible'); }, 4000); } }, replies.length * 120 + 500); }, 800); } }); }); // Count replies in a thread function countReplies(threadId) { const repliesContainer = document.getElementById('replies' + threadId); return repliesContainer.querySelectorAll('.reply').length; } // Like action functionality const likeButtons = document.querySelectorAll('.like-action'); likeButtons.forEach(button => { button.addEventListener('click', function() { const likeCount = this.querySelector('.like-count'); const currentLikes = parseInt(likeCount.textContent); if (this.classList.contains('liked')) { likeCount.textContent = currentLikes - 1; this.classList.remove('liked'); } else { likeCount.textContent = currentLikes + 1; this.classList.add('liked'); // Add a quick pulse animation const icon = this.querySelector('i'); icon.style.animation = 'pulse 0.5s ease'; setTimeout(() => { icon.style.animation = ''; }, 500); } }); }); // New content indicator const newContentIndicator = document.querySelector('.new-content-indicator'); let scrollTimeout; document.querySelector('.container').addEventListener('scroll', function() { clearTimeout(scrollTimeout); // Check if user has scrolled up if (this.scrollTop < this.scrollHeight - this.clientHeight - 200) { newContentIndicator.classList.add('visible'); } else { newContentIndicator.classList.remove('visible'); } scrollTimeout = setTimeout(() => { // Auto-hide indicator after a while newContentIndicator.classList.remove('visible'); }, 5000); }); // Scroll to bottom when indicator is clicked newContentIndicator.addEventListener('click', function() { const container = document.querySelector('.container'); container.scrollTo({ top: container.scrollHeight, behavior: 'smooth' }); this.classList.remove('visible'); }); // Post button functionality const postButton = document.querySelector('.post-button'); const composeInput = document.querySelector('.compose-input'); postButton.addEventListener('click', function() { if (composeInput.value.trim() !== '') { const newThreadHTML = createNewThread(composeInput.value); const threadsContainer = document.querySelector('.container'); const firstThread = document.querySelector('.thread'); // Create and insert the new thread const newThreadElement = document.createElement('div'); newThreadElement.classList.add('thread'); newThreadElement.innerHTML = newThreadHTML; threadsContainer.insertBefore(newThreadElement, firstThread); // Clear the input composeInput.value = ''; // Animate the new thread setTimeout(() => { newThreadElement.classList.add('visible'); }, 100); // Scroll to show the new thread threadsContainer.scrollTo({ top: 0, behavior: 'smooth' }); } }); // Create a new thread HTML function createNewThread(content) { const timestamp = 'Just now'; const randomId = Date.now(); return ` <div class="thread-main"> <div class="thread-header"> <div class="user-info"> <div class="user-avatar">TW</div> <div> <div class="user-name">Thread Writer</div> <div class="user-handle">@threadwriter</div> </div> </div> <div class="thread-time">${timestamp}</div> </div> <div class="thread-content"> <p>${content}</p> </div> <div class="thread-actions"> <div class="thread-action like-action" data-thread="${randomId}"> <i>♥</i> <span class="like-count">0</span> </div> <div class="thread-action"> <i>↩</i> <span>0</span> </div> <div class="thread-action"> <i>↪</i> <span>Share</span> </div> </div> </div> <div class="thread-replies-toggle" data-thread="${randomId}">Show replies (0)</div> <div class="thread-replies" id="replies${randomId}"></div> `; } // Enable Enter key to post composeInput.addEventListener('keydown', function(e) { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); postButton.click(); } }); }); </script> </body> </html>
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <style> @import url('https://fonts.googleapis.com/css2?family=DM+Serif+Display&family=Nunito:wght@300;400;600&display=swap'); * { box-sizing: border-box; margin: 0; padding: 0; } :root { --primary: #f3ebe2; --secondary: #e8d5c4; --accent: #9a8c7e; --dark: #362f2d; --light: #fff8f3; --shadow: rgba(54, 47, 45, 0.1); } body { font-family: 'Nunito', sans-serif; background-color: var(--primary); color: var(--dark); overflow-x: hidden; padding: 20px; line-height: 1.6; } .container { max-width: 650px; margin: 0 auto; position: relative; } header { margin-bottom: 40px; text-align: center; position: relative; } .logo { font-family: 'DM Serif Display', serif; font-size: 2.5rem; letter-spacing: 1px; color: var(--dark); margin-bottom: 10px; } .subtitle { color: var(--accent); font-weight: 300; font-size: 1rem; letter-spacing: 0.5px; } .search-container { position: relative; margin: 25px auto; max-width: 400px; } .search-input { width: 100%; padding: 12px 20px; font-size: 1rem; background: var(--light); border: none; border-radius: 50px; box-shadow: 0 3px 10px var(--shadow); transition: all 0.3s ease; font-family: 'Nunito', sans-serif; } .search-input:focus { outline: none; box-shadow: 0 3px 15px rgba(154, 140, 126, 0.3); transform: translateY(-2px); } .search-icon { position: absolute; right: 15px; top: 50%; transform: translateY(-50%); color: var(--accent); } .blog-feed { margin-top: 30px; } .post { background: var(--light); border-radius: 20px; margin-bottom: 30px; overflow: hidden; box-shadow: 0 5px 15px var(--shadow); opacity: 0; transform: translateY(30px) scale(0.95); transition: opacity 0.8s ease, transform 0.8s ease; } .post.visible { opacity: 1; transform: translateY(0) scale(1); } .post-image { width: 100%; height: 200px; background-size: cover; background-position: center; position: relative; overflow: hidden; transform: scale(1); transition: transform 0.5s ease; } .post:hover .post-image { transform: scale(1.05); } .post-content { padding: 25px; position: relative; } .post-category { display: inline-block; padding: 5px 12px; font-size: 0.7rem; text-transform: uppercase; letter-spacing: 1px; font-weight: 600; color: var(--light); background-color: var(--accent); border-radius: 50px; margin-bottom: 15px; } .post-title { font-family: 'DM Serif Display', serif; font-size: 1.6rem; margin-bottom: 10px; color: var(--dark); line-height: 1.2; } .post-excerpt { color: #6c6560; font-size: 0.95rem; margin-bottom: 15px; line-height: 1.6; } .post-meta { display: flex; align-items: center; color: var(--accent); font-size: 0.8rem; margin-top: 20px; } .author-avatar { width: 28px; height: 28px; border-radius: 50%; margin-right: 10px; background-size: cover; background-position: center; } .reading-time { margin-left: auto; display: flex; align-items: center; } .clock-icon { margin-right: 5px; } .post-tag { display: inline-block; padding: 4px 10px; background-color: var(--secondary); color: var(--dark); border-radius: 4px; font-size: 0.7rem; margin-right: 6px; margin-top: 6px; transition: all 0.3s ease; } .post-tag:hover { background-color: var(--accent); color: var(--light); transform: translateY(-2px); } .tags-container { margin-top: 10px; } .read-more { display: inline-block; margin-top: 15px; font-weight: 600; color: var(--accent); text-decoration: none; position: relative; padding-right: 20px; transition: all 0.3s ease; } .read-more:after { content: '→'; position: absolute; right: 0; top: 0; transition: transform 0.3s ease; } .read-more:hover { color: var(--dark); } .read-more:hover:after { transform: translateX(5px); } .bookmark-btn { position: absolute; top: 20px; right: 20px; background: rgba(255, 255, 255, 0.9); border: none; width: 32px; height: 32px; border-radius: 50%; display: flex; align-items: center; justify-content: center; cursor: pointer; transform: scale(1); transition: all 0.3s ease; z-index: 2; } .bookmark-btn:hover { transform: scale(1.1); } .bookmark-btn svg { width: 16px; height: 16px; fill: none; stroke: var(--accent); transition: all 0.3s ease; } .bookmark-btn.active svg { fill: var(--accent); } .load-more { display: block; width: 180px; margin: 30px auto; padding: 12px 20px; background-color: var(--accent); color: var(--light); border: none; border-radius: 50px; font-family: 'Nunito', sans-serif; font-weight: 600; font-size: 0.9rem; text-align: center; cursor: pointer; transition: all 0.3s ease; box-shadow: 0 4px 10px rgba(154, 140, 126, 0.2); } .load-more:hover { background-color: var(--dark); transform: translateY(-2px); box-shadow: 0 6px 15px rgba(154, 140, 126, 0.3); } .shimmer { position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: linear-gradient( 90deg, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.8) 50%, rgba(255, 255, 255, 0) 100% ); z-index: 1; animation: shimmer 2s infinite; transform: skewX(-20deg); pointer-events: none; } @keyframes shimmer { 0% { transform: translateX(-150%) skewX(-20deg); } 100% { transform: translateX(150%) skewX(-20deg); } } .progress-bar { position: fixed; top: 0; left: 0; height: 3px; background-color: var(--accent); width: 0%; z-index: 1000; transition: width 0.1s ease; } @media (max-width: 600px) { .logo { font-size: 2rem; } .post-title { font-size: 1.3rem; } .post-content { padding: 20px; } .post-image { height: 150px; } } </style> </head> <body> <div class="progress-bar"></div> <div class="container"> <header> <div class="logo">Prose & Palette</div> <div class="subtitle">Thoughts that transcend the ordinary</div> <div class="search-container"> <input type="text" class="search-input" placeholder="Search for topics..."> <span class="search-icon"> <svg width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <circle cx="11" cy="11" r="8" stroke="currentColor" stroke-width="2"/> <path d="M16.5 16.5L21 21" stroke="currentColor" stroke-width="2" stroke-linecap="round"/> </svg> </span> </div> </header> <div class="blog-feed"> <article class="post"> <div class="post-image" style="background-image: url('https://images.unsplash.com/photo-1680987082559-6b0f47a5408e?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=2071&q=80')"> <div class="shimmer"></div> <button class="bookmark-btn"> <svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M5 5C5 3.89543 5.89543 3 7 3H17C18.1046 3 19 3.89543 19 5V21L12 17.5L5 21V5Z" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> </svg> </button> </div> <div class="post-content"> <span class="post-category">Interior Design</span> <h2 class="post-title">Biophilic Design: Bringing Nature Indoors to Enhance Wellbeing</h2> <p class="post-excerpt">In a world increasingly dominated by technology, biophilic design reintroduces elements of the natural world into our living spaces, creating environments that reduce stress and improve cognitive function.</p> <div class="tags-container"> <span class="post-tag">Home Design</span> <span class="post-tag">Wellness</span> <span class="post-tag">Nature</span> </div> <a href="#" class="read-more">Continue reading</a> <div class="post-meta"> <div class="author-avatar" style="background-image: url('https://randomuser.me/api/portraits/women/44.jpg')"></div> <span class="author-name">Emma Woodhouse</span> <span class="reading-time"> <span class="clock-icon"> <svg width="12" height="12" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <circle cx="12" cy="12" r="9" stroke="currentColor" stroke-width="2"/> <path d="M12 7V12L15 15" stroke="currentColor" stroke-width="2" stroke-linecap="round"/> </svg> </span> 6 min read </span> </div> </div> </article> <article class="post"> <div class="post-image" style="background-image: url('https://images.unsplash.com/photo-1607436513449-928fd483847f?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=1974&q=80')"> <div class="shimmer"></div> <button class="bookmark-btn"> <svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M5 5C5 3.89543 5.89543 3 7 3H17C18.1046 3 19 3.89543 19 5V21L12 17.5L5 21V5Z" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> </svg> </button> </div> <div class="post-content"> <span class="post-category">Gastronomy</span> <h2 class="post-title">The Renaissance of Fermentation: Ancient Techniques in Modern Kitchens</h2> <p class="post-excerpt">From kombucha to kimchi, traditional fermentation methods are experiencing a revival as home cooks rediscover the complex flavors and health benefits these techniques offer.</p> <div class="tags-container"> <span class="post-tag">Cooking</span> <span class="post-tag">Health</span> <span class="post-tag">Traditions</span> </div> <a href="#" class="read-more">Continue reading</a> <div class="post-meta"> <div class="author-avatar" style="background-image: url('https://randomuser.me/api/portraits/men/32.jpg')"></div> <span class="author-name">Julian Patel</span> <span class="reading-time"> <span class="clock-icon"> <svg width="12" height="12" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <circle cx="12" cy="12" r="9" stroke="currentColor" stroke-width="2"/> <path d="M12 7V12L15 15" stroke="currentColor" stroke-width="2" stroke-linecap="round"/> </svg> </span> 8 min read </span> </div> </div> </article> <article class="post"> <div class="post-image" style="background-image: url('https://images.unsplash.com/photo-1523206489230-c012c64b2b48?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=1974&q=80')"> <div class="shimmer"></div> <button class="bookmark-btn"> <svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M5 5C5 3.89543 5.89543 3 7 3H17C18.1046 3 19 3.89543 19 5V21L12 17.5L5 21V5Z" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> </svg> </button> </div> <div class="post-content"> <span class="post-category">Technology</span> <h2 class="post-title">Digital Minimalism: Finding Balance in a Connected World</h2> <p class="post-excerpt">As our digital footprints expand, the philosophy of digital minimalism offers a thoughtful approach to technology use—emphasizing intentionality over mindless consumption.</p> <div class="tags-container"> <span class="post-tag">Mindfulness</span> <span class="post-tag">Productivity</span> <span class="post-tag">Lifestyle</span> </div> <a href="#" class="read-more">Continue reading</a> <div class="post-meta"> <div class="author-avatar" style="background-image: url('https://randomuser.me/api/portraits/women/65.jpg')"></div> <span class="author-name">Sophia Chen</span> <span class="reading-time"> <span class="clock-icon"> <svg width="12" height="12" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <circle cx="12" cy="12" r="9" stroke="currentColor" stroke-width="2"/> <path d="M12 7V12L15 15" stroke="currentColor" stroke-width="2" stroke-linecap="round"/> </svg> </span> 5 min read </span> </div> </div> </article> <article class="post"> <div class="post-image" style="background-image: url('https://images.unsplash.com/photo-1501555088652-021faa106b9b?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=2011&q=80')"> <div class="shimmer"></div> <button class="bookmark-btn"> <svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M5 5C5 3.89543 5.89543 3 7 3H17C18.1046 3 19 3.89543 19 5V21L12 17.5L5 21V5Z" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> </svg> </button> </div> <div class="post-content"> <span class="post-category">Travel</span> <h2 class="post-title">Slow Travel: Embracing the Journey Beyond the Destination</h2> <p class="post-excerpt">Rejecting whirlwind itineraries, slow travel encourages deeper connections with places through extended stays, local experiences, and mindful exploration of fewer destinations.</p> <div class="tags-container"> <span class="post-tag">Adventure</span> <span class="post-tag">Sustainable</span> <span class="post-tag">Cultural</span> </div> <a href="#" class="read-more">Continue reading</a> <div class="post-meta"> <div class="author-avatar" style="background-image: url('https://randomuser.me/api/portraits/men/72.jpg')"></div> <span class="author-name">Marco Alvarez</span> <span class="reading-time"> <span class="clock-icon"> <svg width="12" height="12" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <circle cx="12" cy="12" r="9" stroke="currentColor" stroke-width="2"/> <path d="M12 7V12L15 15" stroke="currentColor" stroke-width="2" stroke-linecap="round"/> </svg> </span> 7 min read </span> </div> </div> </article> <button class="load-more">Load more articles</button> </div> </div> <script> document.addEventListener('DOMContentLoaded', function() { // Progress bar window.addEventListener('scroll', function() { const winScroll = document.body.scrollTop || document.documentElement.scrollTop; const height = document.documentElement.scrollHeight - document.documentElement.clientHeight; const scrolled = (winScroll / height) * 100; document.querySelector('.progress-bar').style.width = scrolled + '%'; }); // Reveal posts on scroll const posts = document.querySelectorAll('.post'); const observer = new IntersectionObserver((entries, observer) => { entries.forEach(entry => { if (entry.isIntersecting) { setTimeout(() => { entry.target.classList.add('visible'); }, 150 * Array.from(posts).indexOf(entry.target)); observer.unobserve(entry.target); } }); }, { root: null, rootMargin: '0px', threshold: 0.15 }); posts.forEach(post => { observer.observe(post); }); // Bookmark functionality const bookmarkBtns = document.querySelectorAll('.bookmark-btn'); bookmarkBtns.forEach(btn => { btn.addEventListener('click', function(e) { e.preventDefault(); this.classList.toggle('active'); // Create notification animation if (this.classList.contains('active')) { const notification = document.createElement('div'); notification.style.cssText = ` position: fixed; bottom: 20px; left: 50%; transform: translateX(-50%); background-color: var(--accent); color: white; padding: 10px 20px; border-radius: 50px; font-size: 0.9rem; box-shadow: 0 4px 10px rgba(0,0,0,0.1); z-index: 1000; opacity: 0; transition: opacity 0.3s ease, transform 0.3s ease; `; notification.textContent = 'Post saved to your bookmarks'; document.body.appendChild(notification); setTimeout(() => { notification.style.opacity = '1'; notification.style.transform = 'translateX(-50%) translateY(-10px)'; }, 10); setTimeout(() => { notification.style.opacity = '0'; notification.style.transform = 'translateX(-50%) translateY(0)'; setTimeout(() => { document.body.removeChild(notification); }, 300); }, 2000); } }); }); // Load more button functionality const loadMoreBtn = document.querySelector('.load-more'); loadMoreBtn.addEventListener('click', function() { this.innerHTML = '<span style="display: inline-block; width: 20px; height: 20px; border: 2px solid #fff; border-radius: 50%; border-top-color: transparent; animation: spin 0.8s linear infinite;"></span>'; setTimeout(() => { // Clone the first post and modify it to create a new one const newPost = posts[0].cloneNode(true); newPost.classList.remove('visible'); // Modify the content to make it unique newPost.querySelector('.post-image').style.backgroundImage = "url('https://images.unsplash.com/photo-1536746803623-cef87080bfc8?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=1935&q=80')"; newPost.querySelector('.post-category').textContent = 'Creativity'; newPost.querySelector('.post-title').textContent = 'The Creative Constraint: Why Limitations Spark Innovation'; newPost.querySelector('.post-excerpt').textContent = 'Contrary to popular belief, limitations are not roadblocks to creativity but catalysts—forcing us to think more deeply and explore solutions we might otherwise overlook.'; // Reset bookmark button state const bookmarkBtn = newPost.querySelector('.bookmark-btn'); bookmarkBtn.classList.remove('active'); bookmarkBtn.addEventListener('click', function(e) { e.preventDefault(); this.classList.toggle('active'); }); // Add to the DOM loadMoreBtn.parentNode.insertBefore(newPost, loadMoreBtn); // Animate the new post setTimeout(() => { newPost.classList.add('visible'); }, 100); loadMoreBtn.textContent = 'Load more articles'; }, 1500); }); // Initialize search input const searchInput = document.querySelector('.search-input'); searchInput.addEventListener('focus', function() { this.setAttribute('placeholder', 'Type to search for topics...'); }); searchInput.addEventListener('blur', function() { this.setAttribute('placeholder', 'Search for topics...'); }); // Add a custom animation for the style document.querySelectorAll('.post-image').forEach(img => { img.addEventListener('mouseenter', function() { const shimmer = this.querySelector('.shimmer'); shimmer.style.animation = 'none'; setTimeout(() => { shimmer.style.animation = 'shimmer 2s infinite'; }, 10); }); }); // Animation for "load more" button loadMoreBtn.addEventListener('mouseenter', function() { this.style.transform = 'translateY(-2px)'; }); loadMoreBtn.addEventListener('mouseleave', function() { this.style.transform = 'translateY(0)'; }); // Style animation for keyframes document.createElement('style').innerHTML = ` @keyframes spin { to { transform: rotate(360deg); } } `; document.head.appendChild(document.createElement('style')); }); </script> </body> </html>
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Financial Dashboard Reveal</title> <style> @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap'); * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Inter', sans-serif; } :root { --primary: #1a2b47; --secondary: #2a3f62; --tertiary: #3a5380; --accent: #4d8eff; --success: #37cfab; --warning: #ffbb3a; --danger: #ff6b6b; --text: #e0e6f2; --text-muted: #90a4c7; --gray-dark: #2c3e50; --gray: #465671; --gray-light: #6c7a94; --border: rgba(255, 255, 255, 0.12); --shadow: 0 8px 30px rgba(0, 0, 0, 0.12); } body { background-color: var(--primary); color: var(--text); height: 700px; width: 700px; overflow: hidden; position: relative; padding: 1.5rem; } .dashboard { display: grid; grid-template-columns: 1fr; grid-template-rows: auto 1fr; height: 100%; gap: 1.5rem; opacity: 0; transform: translateY(20px); transition: opacity 0.6s ease-out, transform 0.6s ease-out; } .dashboard.loaded { opacity: 1; transform: translateY(0); } .header { display: flex; justify-content: space-between; align-items: center; padding-bottom: 1rem; border-bottom: 1px solid var(--border); } .header h1 { font-size: 1.5rem; font-weight: 600; } .date-selector { display: flex; align-items: center; background-color: var(--secondary); border-radius: 8px; padding: 0.5rem 1rem; cursor: pointer; transition: all 0.2s ease; } .date-selector:hover { background-color: var(--tertiary); } .date-selector span { margin-right: 0.5rem; font-size: 0.875rem; font-weight: 500; } .main-content { display: grid; grid-template-columns: 1fr; grid-template-rows: auto 1fr; gap: 1.5rem; overflow: auto; scrollbar-width: none; } .main-content::-webkit-scrollbar { display: none; } .kpi-cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 1rem; } .kpi-card { background-color: var(--secondary); border-radius: 12px; padding: 1.25rem; display: flex; flex-direction: column; box-shadow: var(--shadow); transform: translateY(30px); opacity: 0; transition: transform 0.5s ease, opacity 0.5s ease, box-shadow 0.3s ease; } .kpi-card:hover { box-shadow: 0 12px 40px rgba(0, 0, 0, 0.2); } .kpi-card.visible { transform: translateY(0); opacity: 1; } .kpi-title { font-size: 0.75rem; font-weight: 500; color: var(--text-muted); margin-bottom: 0.5rem; text-transform: uppercase; letter-spacing: 0.5px; } .kpi-value { font-size: 1.5rem; font-weight: 600; margin-bottom: 0.25rem; } .kpi-change { display: flex; align-items: center; font-size: 0.75rem; font-weight: 500; } .kpi-change.positive { color: var(--success); } .kpi-change.negative { color: var(--danger); } .charts-container { display: grid; grid-template-columns: 1fr; grid-template-rows: repeat(3, 1fr); gap: 1.5rem; } .chart-card { background-color: var(--secondary); border-radius: 12px; padding: 1.25rem; display: flex; flex-direction: column; height: 100%; box-shadow: var(--shadow); transform: translateY(30px); opacity: 0; transition: transform 0.5s ease, opacity 0.5s ease, box-shadow 0.3s ease; } .chart-card:hover { box-shadow: 0 12px 40px rgba(0, 0, 0, 0.2); } .chart-card.visible { transform: translateY(0); opacity: 1; } .chart-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 1rem; } .chart-title { font-size: 1rem; font-weight: 600; } .legend { display: flex; gap: 1rem; } .legend-item { display: flex; align-items: center; font-size: 0.75rem; color: var(--text-muted); } .legend-color { width: 8px; height: 8px; border-radius: 2px; margin-right: 6px; } .chart-body { flex-grow: 1; position: relative; overflow: hidden; } .bar-chart { height: 100%; display: flex; align-items: flex-end; justify-content: space-between; padding-top: 20px; } .bar-group { display: flex; height: 100%; align-items: flex-end; width: 100%; } .bar { width: 12px; background-color: var(--accent); border-radius: 4px 4px 0 0; margin: 0 4px; transform: scaleY(0); transform-origin: bottom; transition: transform 0.6s cubic-bezier(0.34, 1.56, 0.64, 1); } .bar-secondary { background-color: var(--tertiary); } .chart-card.visible .bar { transform: scaleY(1); } .line-chart { position: relative; height: 100%; width: 100%; padding-top: 20px; } .lines { position: absolute; top: 20px; left: 0; width: 100%; height: calc(100% - 20px); z-index: 1; } .line-path { stroke-dasharray: 1000; stroke-dashoffset: 1000; transition: stroke-dashoffset 1.5s ease-in-out; } .chart-card.visible .line-path { stroke-dashoffset: 0; } .dots { position: absolute; top: 20px; left: 0; width: 100%; height: calc(100% - 20px); z-index: 2; } .dot { width: 8px; height: 8px; background-color: var(--accent); border-radius: 50%; position: absolute; transform: scale(0); transition: transform 0.3s ease; } .dot-secondary { background-color: var(--tertiary); } .chart-card.visible .dot { transform: scale(1); } .grid-lines { position: absolute; width: 100%; height: 100%; top: 0; left: 0; z-index: 0; opacity: 0.1; } .grid-line { position: absolute; width: 100%; height: 1px; background-color: var(--text); } .pie-chart { position: relative; width: 100%; height: 100%; display: flex; align-items: center; justify-content: center; } .pie-segment { position: absolute; width: 120px; height: 120px; clip-path: polygon(50% 50%, 100% 0, 100% 100%); transform: rotate(0deg); transform-origin: center; transition: transform 0.8s ease-out; } .pie-center { position: absolute; width: 80px; height: 80px; background-color: var(--secondary); border-radius: 50%; z-index: 2; display: flex; flex-direction: column; align-items: center; justify-content: center; transform: scale(0); transition: transform 0.5s ease 0.8s; } .chart-card.visible .pie-center { transform: scale(1); } .center-value { font-size: 1.2rem; font-weight: 600; } .center-label { font-size: 0.7rem; color: var(--text-muted); } /* Animation delays */ .kpi-card:nth-child(1) { transition-delay: 0.1s; } .kpi-card:nth-child(2) { transition-delay: 0.2s; } .kpi-card:nth-child(3) { transition-delay: 0.3s; } .kpi-card:nth-child(4) { transition-delay: 0.4s; } .chart-card:nth-child(1) { transition-delay: 0.5s; } .chart-card:nth-child(2) { transition-delay: 0.7s; } .chart-card:nth-child(3) { transition-delay: 0.9s; } .bar:nth-child(1) { transition-delay: 0.6s; } .bar:nth-child(2) { transition-delay: 0.7s; } .bar:nth-child(3) { transition-delay: 0.8s; } .bar:nth-child(4) { transition-delay: 0.9s; } .bar:nth-child(5) { transition-delay: 1s; } .bar:nth-child(6) { transition-delay: 1.1s; } .dot:nth-child(1) { transition-delay: 1.5s; } .dot:nth-child(2) { transition-delay: 1.6s; } .dot:nth-child(3) { transition-delay: 1.7s; } .dot:nth-child(4) { transition-delay: 1.8s; } .dot:nth-child(5) { transition-delay: 1.9s; } .dot:nth-child(6) { transition-delay: 2s; } /* Initial loading effect */ .init-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; background-color: var(--primary); display: flex; justify-content: center; align-items: center; z-index: 1000; transition: opacity 0.5s ease, visibility 0.5s ease; } .init-overlay.hidden { opacity: 0; visibility: hidden; } .loader { width: 48px; height: 48px; border: 3px solid var(--accent); border-bottom-color: transparent; border-radius: 50%; animation: loader 1s linear infinite; } @keyframes loader { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } /* Pulse effect for interaction cue */ .interaction-cue { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 200px; height: 200px; background-color: rgba(77, 142, 255, 0.1); border-radius: 50%; pointer-events: none; opacity: 0; z-index: 0; transition: opacity 0.5s ease; } .interaction-cue.visible { animation: pulse 2s infinite; opacity: 1; } @keyframes pulse { 0% { transform: translate(-50%, -50%) scale(0.8); opacity: 0.7; } 70% { transform: translate(-50%, -50%) scale(1.3); opacity: 0; } 100% { transform: translate(-50%, -50%) scale(0.8); opacity: 0; } } /* Responsive adjustments */ @media (max-width: 600px) { body { padding: 1rem; } .header h1 { font-size: 1.2rem; } .kpi-cards { grid-template-columns: repeat(2, 1fr); } .charts-container { grid-template-rows: repeat(3, 200px); } .kpi-value { font-size: 1.2rem; } } /* Hover interactions */ .chart-body { position: relative; } .tooltip { position: absolute; background-color: var(--gray-dark); border-radius: 6px; padding: 8px 12px; font-size: 0.75rem; font-weight: 500; pointer-events: none; opacity: 0; transition: opacity 0.2s ease; z-index: 10; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); max-width: 150px; } .tooltip.visible { opacity: 1; } .tooltip-title { color: var(--text-muted); font-size: 0.7rem; margin-bottom: 4px; } .tooltip-value { color: var(--text); font-weight: 600; } .interaction-area { position: absolute; width: 100%; height: 100%; top: 0; left: 0; z-index: 5; cursor: pointer; } </style> </head> <body> <div class="init-overlay"> <div class="loader"></div> </div> <div class="interaction-cue"></div> <div class="dashboard"> <div class="header"> <h1>Portfolio Performance</h1> <div class="date-selector"> <span>Q2 2023</span> <svg width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M7 10L12 15L17 10" stroke="#e0e6f2" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> </svg> </div> </div> <div class="main-content"> <div class="kpi-cards"> <div class="kpi-card"> <div class="kpi-title">Portfolio Value</div> <div class="kpi-value">$1.28M</div> <div class="kpi-change positive"> <svg width="12" height="12" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M12 20V4M5 11L12 4L19 11" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> </svg> 8.4% </div> </div> <div class="kpi-card"> <div class="kpi-title">ROI</div> <div class="kpi-value">11.6%</div> <div class="kpi-change positive"> <svg width="12" height="12" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M12 20V4M5 11L12 4L19 11" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> </svg> 2.3% </div> </div> <div class="kpi-card"> <div class="kpi-title">Risk Score</div> <div class="kpi-value">0.78</div> <div class="kpi-change negative"> <svg width="12" height="12" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M12 4V20M5 13L12 20L19 13" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> </svg> 0.05 </div> </div> <div class="kpi-card"> <div class="kpi-title">Cash Position</div> <div class="kpi-value">14.2%</div> <div class="kpi-change positive"> <svg width="12" height="12" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M12 20V4M5 11L12 4L19 11" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> </svg> 1.6% </div> </div> </div> <div class="charts-container"> <div class="chart-card"> <div class="chart-header"> <div class="chart-title">Portfolio Performance</div> <div class="legend"> <div class="legend-item"> <div class="legend-color" style="background-color: var(--accent);"></div> <span>Current</span> </div> <div class="legend-item"> <div class="legend-color" style="background-color: var(--tertiary);"></div> <span>Benchmark</span> </div> </div> </div> <div class="chart-body"> <div class="grid-lines"> <div class="grid-line" style="top: 20%;"></div> <div class="grid-line" style="top: 40%;"></div> <div class="grid-line" style="top: 60%;"></div> <div class="grid-line" style="top: 80%;"></div> </div> <div class="line-chart"> <svg class="lines" viewBox="0 0 100 60" preserveAspectRatio="none"> <path class="line-path" d="M0,45 L20,38 L40,30 L60,25 L80,15 L100,5" fill="none" stroke="var(--accent)" stroke-width="2" /> <path class="line-path" d="M0,45 L20,42 L40,35 L60,33 L80,30 L100,25" fill="none" stroke="var(--tertiary)" stroke-width="2" /> </svg> <div class="dots"> <div class="dot" style="top: 45%; left: 0%; transform: translate(-50%, -50%);"></div> <div class="dot" style="top: 38%; left: 20%; transform: translate(-50%, -50%);"></div> <div class="dot" style="top: 30%; left: 40%; transform: translate(-50%, -50%);"></div> <div class="dot" style="top: 25%; left: 60%; transform: translate(-50%, -50%);"></div> <div class="dot" style="top: 15%; left: 80%; transform: translate(-50%, -50%);"></div> <div class="dot" style="top: 5%; left: 100%; transform: translate(-50%, -50%);"></div> <div class="dot dot-secondary" style="top: 45%; left: 0%; transform: translate(-50%, -50%);"></div> <div class="dot dot-secondary" style="top: 42%; left: 20%; transform: translate(-50%, -50%);"></div> <div class="dot dot-secondary" style="top: 35%; left: 40%; transform: translate(-50%, -50%);"></div> <div class="dot dot-secondary" style="top: 33%; left: 60%; transform: translate(-50%, -50%);"></div> <div class="dot dot-secondary" style="top: 30%; left: 80%; transform: translate(-50%, -50%);"></div> <div class="dot dot-secondary" style="top: 25%; left: 100%; transform: translate(-50%, -50%);"></div> </div> </div> <div class="interaction-area" data-chart="line"></div> <div class="tooltip"> <div class="tooltip-title">Q2 2023</div> <div class="tooltip-value">Portfolio: +11.6%</div> <div class="tooltip-value">Benchmark: +8.2%</div> </div> </div> </div> <div class="chart-card"> <div class="chart-header"> <div class="chart-title">Sector Allocation</div> </div> <div class="chart-body"> <div class="pie-chart"> <div class="pie-segment" style="background-color: var(--accent); transform: rotate(0deg);"></div> <div class="pie-segment" style="background-color: var(--tertiary); transform: rotate(90deg);"></div> <div class="pie-segment" style="background-color: var(--success); transform: rotate(180deg);"></div> <div class="pie-segment" style="background-color: var(--warning); transform: rotate(270deg);"></div> <div class="pie-center"> <div class="center-value">32%</div> <div class="center-label">Tech</div> </div> </div> <div class="legend" style="position: absolute; bottom: 0; left: 0; width: 100%; display: flex; justify-content: center; gap: 1.5rem; padding-bottom: 0.5rem;"> <div class="legend-item"> <div class="legend-color" style="background-color: var(--accent);"></div> <span>Tech</span> </div> <div class="legend-item"> <div class="legend-color" style="background-color: var(--tertiary);"></div> <span>Finance</span> </div> <div class="legend-item"> <div class="legend-color" style="background-color: var(--success);"></div> <span>Healthcare</span> </div> <div class="legend-item"> <div class="legend-color" style="background-color: var(--warning);"></div> <span>Other</span> </div> </div> <div class="interaction-area" data-chart="pie"></div> <div class="tooltip"> <div class="tooltip-title">Tech Sector</div> <div class="tooltip-value">32% of portfolio</div> <div class="tooltip-value">+18.4% YTD</div> </div> </div> </div> <div class="chart-card"> <div class="chart-header"> <div class="chart-title">Monthly Returns</div> </div> <div class="chart-body"> <div class="grid-lines"> <div class="grid-line" style="top: 50%;"></div> </div> <div class="bar-chart"> <div class="bar-group"> <div class="bar" style="height: 60%; background-color: var(--success);"></div> <div class="bar" style="height: 45%; background-color: var(--success);"></div> <div class="bar" style="height: 75%; background-color: var(--success);"></div> <div class="bar" style="height: 20%; background-color: var(--danger);"></div> <div class="bar" style="height: 50%; background-color: var(--success);"></div> <div class="bar" style="height: 65%; background-color: var(--success);"></div> </div> </div> <div class="legend" style="position: absolute; bottom: 0; left: 0; width: 100%; display: flex; justify-content: space-between; padding: 0.5rem;"> <span style="font-size: 0.7rem; color: var(--text-muted);">Jan</span> <span style="font-size: 0.7rem; color: var(--text-muted);">Feb</span> <span style="font-size: 0.7rem; color: var(--text-muted);">Mar</span> <span style="font-size: 0.7rem; color: var(--text-muted);">Apr</span> <span style="font-size: 0.7rem; color: var(--text-muted);">May</span> <span style="font-size: 0.7rem; color: var(--text-muted);">Jun</span> </div> <div class="interaction-area" data-chart="bar"></div> <div class="tooltip"> <div class="tooltip-title">March 2023</div> <div class="tooltip-value">+3.75% Return</div> </div> </div> </div> </div> </div> </div> <script> document.addEventListener('DOMContentLoaded', function() { // Initial loading animation setTimeout(() => { document.querySelector('.init-overlay').classList.add('hidden'); setTimeout(() => { document.querySelector('.dashboard').classList.add('loaded'); setTimeout(() => { const kpiCards = document.querySelectorAll('.kpi-card'); kpiCards.forEach(card => { card.classList.add('visible'); }); setTimeout(() => { const chartCards = document.querySelectorAll('.chart-card'); chartCards.forEach(card => { card.classList.add('visible'); }); // Show interaction cue after all animations setTimeout(() => { document.querySelector('.interaction-cue').classList.add('visible'); // Hide interaction cue after a few seconds setTimeout(() => { document.querySelector('.interaction-cue').classList.remove('visible'); }, 3000); }, 2000); }, 500); }, 300); }, 100); }, 1000); // Pie chart rotation animation const pieSegments = document.querySelectorAll('.pie-segment'); pieSegments.forEach((segment, index) => { setTimeout(() => { segment.style.transform = `rotate(${index * 90 + 45}deg)`; }, 1200 + index * 200); }); // Interactive tooltips const interactionAreas = document.querySelectorAll('.interaction-area'); const tooltip = document.querySelector('.tooltip'); interactionAreas.forEach(area => { area.addEventListener('mousemove', function(e) { const rect = this.getBoundingClientRect(); const x = e.clientX - rect.left; const y = e.clientY - rect.top; const chartType = this.getAttribute('data-chart'); tooltip.style.left = `${x + 10}px`; tooltip.style.top = `${y - 10}px`; tooltip.classList.add('visible'); // Update tooltip content based on chart type and position if (chartType === 'line') { const percent = Math.round(x / rect.width * 100); let month, portfolioVal, benchmarkVal; if (percent < 20) { month = 'January'; portfolioVal = '+1.8%'; benchmarkVal = '+0.6%'; } else if (percent < 40) { month = 'February'; portfolioVal = '+3.2%'; benchmarkVal = '+1.4%'; } else if (percent < 60) { month = 'March'; portfolioVal = '+5.7%'; benchmarkVal = '+3.2%'; } else if (percent < 80) { month = 'April'; portfolioVal = '+8.3%'; benchmarkVal = '+5.1%'; } else { month = 'May'; portfolioVal = '+11.6%'; benchmarkVal = '+8.2%'; } tooltip.innerHTML = ` <div class="tooltip-title">${month} 2023</div> <div class="tooltip-value">Portfolio: ${portfolioVal}</div> <div class="tooltip-value">Benchmark: ${benchmarkVal}</div> `; } else if (chartType === 'pie') { const centerX = rect.width / 2; const centerY = rect.height / 2; const angle = Math.atan2(y - centerY, x - centerX) * 180 / Math.PI + 180; let sector, allocation, growth; if (angle >= 0 && angle < 90) { sector = 'Technology'; allocation = '32%'; growth = '+18.4%'; } else if (angle >= 90 && angle < 180) { sector = 'Finance'; allocation = '24%'; growth = '+9.2%'; } else if (angle >= 180 && angle < 270) { sector = 'Healthcare'; allocation = '21%'; growth = '+12.7%'; } else { sector = 'Other Sectors'; allocation = '23%'; growth = '+6.3%'; } tooltip.innerHTML = ` <div class="tooltip-title">${sector}</div> <div class="tooltip-value">${allocation} of portfolio</div> <div class="tooltip-value">${growth} YTD</div> `; } else if (chartType === 'bar') { const barIndex = Math.floor(x / (rect.width / 6)); let month, value, status; switch(barIndex) { case 0: month = 'January'; value = '+3.0%'; status = 'Growth'; break; case 1: month = 'February'; value = '+2.2%'; status = 'Growth'; break; case 2: month = 'March'; value = '+3.7%'; status = 'Growth'; break; case 3: month = 'April'; value = '-1.3%'; status = 'Decline'; break; case 4: month = 'May'; value = '+2.5%'; status = 'Recovery'; break; case 5: month = 'June'; value = '+3.2%'; status = 'Growth'; break; } tooltip.innerHTML = ` <div class="tooltip-title">${month} 2023</div> <div class="tooltip-value">${value} Return</div> <div class="tooltip-value">${status}</div> `; } }); area.addEventListener('mouseleave', function() { tooltip.classList.remove('visible'); }); area.addEventListener('click', function() { // Simulate data refresh on click const card = this.closest('.chart-card'); card.classList.remove('visible'); setTimeout(() => { card.classList.add('visible'); }, 100); }); }); // Date selector interaction const dateSelector = document.querySelector('.date-selector'); const dates = ['Q2 2023', 'Q1 2023', 'Q4 2022', 'Q3 2022', 'YTD']; let currentDateIndex = 0; dateSelector.addEventListener('click', function() { currentDateIndex = (currentDateIndex + 1) % dates.length; dateSelector.querySelector('span').textContent = dates[currentDateIndex]; // Simulate data refresh when changing date const chartCards = document.querySelectorAll('.chart-card'); chartCards.forEach(card => { card.classList.remove('visible'); }); setTimeout(() => { chartCards.forEach(card => { card.classList.add('visible'); }); }, 300); }); }); </script> </body> </html>
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Chiaroscuro Gallery</title> <style> :root { --primary-bg: #111111; --secondary-bg: #171717; --text-primary: #ffffff; --text-secondary: #cccccc; --accent-1: #ff6b6b; --accent-2: #4ecdc4; --accent-3: #ffe66d; --transition-time: 0.7s; } * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Helvetica Neue', Arial, sans-serif; -webkit-font-smoothing: antialiased; } body { background-color: var(--primary-bg); color: var(--text-primary); overflow-x: hidden; width: 100%; height: 100vh; display: flex; flex-direction: column; } .gallery-container { width: 100%; height: 100%; position: relative; overflow: hidden; } header { padding: 24px; display: flex; justify-content: space-between; align-items: center; background-color: rgba(17, 17, 17, 0.9); position: relative; z-index: 5; border-bottom: 1px solid rgba(255, 255, 255, 0.1); } .gallery-title { font-size: 1.5rem; font-weight: 300; letter-spacing: 2px; text-transform: uppercase; } .gallery-title span { color: var(--accent-1); font-weight: 600; } .nav-links { display: flex; gap: 24px; } .nav-link { color: var(--text-secondary); text-decoration: none; font-size: 0.9rem; letter-spacing: 1px; position: relative; padding-bottom: 4px; transition: color 0.3s ease; } .nav-link:hover { color: var(--text-primary); } .nav-link::after { content: ''; position: absolute; width: 0; height: 1px; bottom: 0; left: 0; background-color: var(--accent-1); transition: width 0.3s ease; } .nav-link:hover::after { width: 100%; } .artwork-container { position: relative; width: 100%; height: calc(100vh - 75px); display: flex; align-items: center; justify-content: center; } .artwork { position: absolute; top: 0; left: 0; width: 100%; height: 100%; display: flex; align-items: center; justify-content: space-between; padding: 40px; opacity: 0; transform: scale(0.95); transition: opacity var(--transition-time) ease, transform var(--transition-time) ease; pointer-events: none; } .artwork.active { opacity: 1; transform: scale(1); pointer-events: all; } .artwork-image { width: 55%; height: 75%; background-size: cover; background-position: center; position: relative; box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5); transform: translateX(-50px); opacity: 0; transition: transform 1s ease 0.3s, opacity 1s ease 0.3s; } .artwork.active .artwork-image { transform: translateX(0); opacity: 1; } .artwork-info { width: 40%; padding: 0 20px; transform: translateX(50px); opacity: 0; transition: transform 1s ease 0.6s, opacity 1s ease 0.6s; } .artwork.active .artwork-info { transform: translateX(0); opacity: 1; } .artwork-title { font-size: 2rem; font-weight: 300; margin-bottom: 16px; letter-spacing: 1px; color: var(--text-primary); } .artwork-artist { font-size: 1.1rem; color: var(--accent-1); margin-bottom: 24px; font-style: italic; } .artwork-description { font-size: 1rem; line-height: 1.6; color: var(--text-secondary); margin-bottom: 32px; } .artwork-details { display: flex; flex-direction: column; gap: 8px; font-size: 0.9rem; margin-bottom: 40px; color: var(--text-secondary); } .artwork-details span { color: var(--text-primary); } .navigation-dots { position: absolute; bottom: 32px; left: 50%; transform: translateX(-50%); display: flex; gap: 12px; z-index: 5; } .dot { width: 10px; height: 10px; border-radius: 50%; background-color: rgba(255, 255, 255, 0.3); cursor: pointer; transition: all 0.3s ease; } .dot.active { background-color: var(--accent-1); transform: scale(1.3); } .dot:hover { background-color: rgba(255, 255, 255, 0.5); } .arrow { position: absolute; top: 50%; transform: translateY(-50%); width: 50px; height: 50px; display: flex; align-items: center; justify-content: center; cursor: pointer; z-index: 5; opacity: 0.6; transition: opacity 0.3s ease, transform 0.3s ease; } .arrow:hover { opacity: 1; } .arrow-left { left: 20px; } .arrow-right { right: 20px; } .arrow svg { width: 24px; height: 24px; fill: var(--text-primary); } .arrow-left:hover { transform: translateY(-50%) translateX(-3px); } .arrow-right:hover { transform: translateY(-50%) translateX(3px); } .artwork-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; background-color: var(--primary-bg); opacity: 0.95; z-index: -1; } .background-pattern { position: absolute; top: 0; left: 0; width: 100%; height: 100%; background-image: linear-gradient(to right, rgba(255, 255, 255, 0.05) 1px, transparent 1px), linear-gradient(to bottom, rgba(255, 255, 255, 0.05) 1px, transparent 1px); background-size: 20px 20px; opacity: 0.15; z-index: -2; } .view-button { display: inline-block; padding: 12px 24px; background-color: transparent; color: var(--text-primary); border: 1px solid var(--accent-1); text-decoration: none; font-size: 0.9rem; letter-spacing: 1px; transition: all 0.3s ease; position: relative; overflow: hidden; cursor: pointer; } .view-button:before { content: ''; position: absolute; top: 0; left: -100%; width: 100%; height: 100%; background-color: var(--accent-1); transition: all 0.4s ease; z-index: -1; } .view-button:hover { color: var(--primary-bg); } .view-button:hover:before { left: 0; } @media (max-width: 768px) { .artwork { flex-direction: column; padding: 20px; justify-content: flex-start; overflow-y: auto; } .artwork-image, .artwork-info { width: 100%; } .artwork-image { height: 40%; margin-bottom: 24px; } .gallery-title { font-size: 1.2rem; } .nav-links { gap: 12px; } .artwork-title { font-size: 1.5rem; } .artwork-description { font-size: 0.9rem; } } /* Animation for the art reveal */ @keyframes revealArt { 0% { clip-path: inset(0 100% 0 0); } 100% { clip-path: inset(0 0 0 0); } } .artwork-image { animation: revealArt 1.2s ease-out 0.3s forwards; clip-path: inset(0 100% 0 0); } /* Cursor effect */ .custom-cursor { width: 40px; height: 40px; border: 1px solid var(--accent-1); border-radius: 50%; position: fixed; transform: translate(-50%, -50%); pointer-events: none; z-index: 9999; mix-blend-mode: difference; transition: all 0.1s ease; display: none; } .custom-cursor.active { transform: translate(-50%, -50%) scale(1.5); background-color: rgba(255, 107, 107, 0.2); } @media (min-width: 769px) { .custom-cursor { display: block; } } </style> </head> <body> <div class="custom-cursor"></div> <div class="gallery-container"> <header> <div class="gallery-title">Chiaro<span>scuro</span></div> <div class="nav-links"> <a href="#" class="nav-link">Current</a> <a href="#" class="nav-link">Artists</a> <a href="#" class="nav-link">About</a> </div> </header> <div class="artwork-container"> <div class="background-pattern"></div> <div class="artwork active" data-index="0"> <div class="artwork-image" style="background-image: url('https://images.unsplash.com/photo-1604537466608-109fa2f16c3b?q=80&w=1000&auto=format&fit=crop')"></div> <div class="artwork-info"> <h2 class="artwork-title">Luminous Descent</h2> <p class="artwork-artist">Elara Voss</p> <p class="artwork-description">An exploration of light's journey through fractured spaces. Voss captures the ephemeral quality of illumination as it cascades through architectural voids, creating a meditation on presence and absence that challenges our perception of spatial boundaries.</p> <div class="artwork-details"> <p>Medium: <span>Oil on canvas</span></p> <p>Year: <span>2023</span></p> <p>Dimensions: <span>120 × 150 cm</span></p> </div> <button class="view-button">View In Detail</button> </div> <div class="artwork-overlay"></div> </div> <div class="artwork" data-index="1"> <div class="artwork-image" style="background-image: url('https://images.unsplash.com/photo-1597873618537-64a04f9a1947?q=80&w=1000&auto=format&fit=crop')"></div> <div class="artwork-info"> <h2 class="artwork-title">Fragmented Memory</h2> <p class="artwork-artist">Theo Kincaid</p> <p class="artwork-description">Kincaid's abstracted composition deconstructs moments of recalled experience into rhythmic forms. Each brushstroke represents a fragment of memory, stripped of context yet emotionally resonant, creating a visual language that speaks to the imperfection of remembrance.</p> <div class="artwork-details"> <p>Medium: <span>Acrylic and mixed media</span></p> <p>Year: <span>2022</span></p> <p>Dimensions: <span>90 × 120 cm</span></p> </div> <button class="view-button">View In Detail</button> </div> <div class="artwork-overlay"></div> </div> <div class="artwork" data-index="2"> <div class="artwork-image" style="background-image: url('https://images.unsplash.com/photo-1574182245530-967d9b3831af?q=80&w=1000&auto=format&fit=crop')"></div> <div class="artwork-info"> <h2 class="artwork-title">Threshold of Perception</h2> <p class="artwork-artist">Mira Kazan</p> <p class="artwork-description">At the convergence of digital and analog realities, Kazan's work examines the liminal space where human consciousness meets algorithmic interpretation. The meticulously layered composition invites viewers to question the authenticity of their visual experience in an increasingly mediated world.</p> <div class="artwork-details"> <p>Medium: <span>Digital print on aluminum</span></p> <p>Year: <span>2023</span></p> <p>Dimensions: <span>100 × 100 cm</span></p> </div> <button class="view-button">View In Detail</button> </div> <div class="artwork-overlay"></div> </div> <div class="artwork" data-index="3"> <div class="artwork-image" style="background-image: url('https://images.unsplash.com/photo-1603486037214-4fec4016a9bf?q=80&w=1000&auto=format&fit=crop')"></div> <div class="artwork-info"> <h2 class="artwork-title">Chromatic Dissolution</h2> <p class="artwork-artist">Julian Mercer</p> <p class="artwork-description">Mercer's experimental approach dissolves the boundaries between color fields, creating tensions between structure and fluidity. Inspired by chemical reactions and natural processes of transformation, this piece invites contemplation on impermanence and the beauty of controlled chaos.</p> <div class="artwork-details"> <p>Medium: <span>Resin and pigment</span></p> <p>Year: <span>2021</span></p> <p>Dimensions: <span>80 × 110 cm</span></p> </div> <button class="view-button">View In Detail</button> </div> <div class="artwork-overlay"></div> </div> <div class="arrow arrow-left"> <svg viewBox="0 0 24 24"> <path d="M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z"/> </svg> </div> <div class="arrow arrow-right"> <svg viewBox="0 0 24 24"> <path d="M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z"/> </svg> </div> <div class="navigation-dots"> <div class="dot active" data-index="0"></div> <div class="dot" data-index="1"></div> <div class="dot" data-index="2"></div> <div class="dot" data-index="3"></div> </div> </div> </div> <script> document.addEventListener('DOMContentLoaded', function() { const artworks = document.querySelectorAll('.artwork'); const dots = document.querySelectorAll('.dot'); const arrowLeft = document.querySelector('.arrow-left'); const arrowRight = document.querySelector('.arrow-right'); const customCursor = document.querySelector('.custom-cursor'); let currentIndex = 0; let isAnimating = false; // Custom cursor document.addEventListener('mousemove', function(e) { if (window.innerWidth > 768) { customCursor.style.left = e.clientX + 'px'; customCursor.style.top = e.clientY + 'px'; } }); document.addEventListener('mousedown', function() { customCursor.classList.add('active'); }); document.addEventListener('mouseup', function() { customCursor.classList.remove('active'); }); // Hover effect for buttons and links const interactiveElements = document.querySelectorAll('.nav-link, .view-button, .dot, .arrow'); interactiveElements.forEach(element => { element.addEventListener('mouseenter', function() { customCursor.classList.add('active'); }); element.addEventListener('mouseleave', function() { customCursor.classList.remove('active'); }); }); // Navigation functionality function showArtwork(index) { if (isAnimating) return; isAnimating = true; artworks.forEach(artwork => { artwork.classList.remove('active'); }); dots.forEach(dot => { dot.classList.remove('active'); }); artworks[index].classList.add('active'); dots[index].classList.add('active'); currentIndex = index; setTimeout(() => { isAnimating = false; }, 1000); // Match this with your longest transition time } function nextArtwork() { let next = currentIndex + 1; if (next >= artworks.length) next = 0; showArtwork(next); } function previousArtwork() { let prev = currentIndex - 1; if (prev < 0) prev = artworks.length - 1; showArtwork(prev); } arrowRight.addEventListener('click', nextArtwork); arrowLeft.addEventListener('click', previousArtwork); dots.forEach(dot => { dot.addEventListener('click', function() { const index = parseInt(this.getAttribute('data-index')); showArtwork(index); }); }); // Auto slide every 8 seconds let slideInterval = setInterval(nextArtwork, 8000); // Pause auto slide when user interacts const pauseElements = document.querySelectorAll('.arrow, .dot, .artwork'); function resetInterval() { clearInterval(slideInterval); slideInterval = setInterval(nextArtwork, 8000); } pauseElements.forEach(element => { element.addEventListener('click', resetInterval); }); // Handle View button click const viewButtons = document.querySelectorAll('.view-button'); viewButtons.forEach(button => { button.addEventListener('click', function(e) { e.preventDefault(); // Find parent artwork to get details for a modal or expanded view const artwork = this.closest('.artwork'); const title = artwork.querySelector('.artwork-title').textContent; // You could show a modal here or trigger expanded view // For now, we'll just add a subtle scale animation const image = artwork.querySelector('.artwork-image'); image.style.transition = 'transform 0.5s ease'; image.style.transform = 'scale(1.05)'; setTimeout(() => { image.style.transform = ''; }, 500); }); }); // Keyboard navigation document.addEventListener('keydown', function(e) { if (e.key === 'ArrowRight') { nextArtwork(); resetInterval(); } else if (e.key === 'ArrowLeft') { previousArtwork(); resetInterval(); } }); // Prevent default on button clicks document.querySelectorAll('button').forEach(button => { button.addEventListener('click', function(e) { e.preventDefault(); }); }); }); </script> </body> </html>