Looking to elevate your web design with visually captivating layouts? Masonry layouts offer a dynamic and engaging way to present content.
Here are 10 stunning masonry layout examples that can inspire your next project.
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
Designers and developers, elevate your projects with Subframe's drag-and-drop interface. Its intuitive, responsive canvas ensures pixel-perfect UI every time.
Loved by professionals, Subframe makes creating stunning masonry layouts a breeze. Start for free 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 transform your web design process? With Subframe, you can create pixel-perfect UIs, including stunning Masonry Layouts, in no time.
Experience unparalleled efficiency and start designing immediately. Start for free today!
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>The Daily Chronicle</title> <style> @import url('https://fonts.googleapis.com/css2?family=Playfair+Display:wght@400;700;900&family=Source+Sans+Pro:wght@300;400;600&display=swap'); * { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: 'Source Sans Pro', sans-serif; background-color: #f9f7f2; color: #222; line-height: 1.6; max-width: 700px; margin: 0 auto; overflow-x: hidden; height: 100vh; padding: 0 10px; } header { padding: 20px 0; border-bottom: 2px solid #222; margin-bottom: 20px; position: sticky; top: 0; background-color: #f9f7f2; z-index: 100; } .header-container { display: flex; justify-content: space-between; align-items: center; } .site-title { font-family: 'Playfair Display', serif; font-weight: 900; font-size: 32px; text-transform: uppercase; letter-spacing: -1px; color: #111; } .date { font-size: 14px; font-weight: 600; color: #555; } .categories { display: flex; gap: 15px; font-size: 14px; margin-top: 10px; overflow-x: auto; padding-bottom: 5px; -ms-overflow-style: none; /* Hide scrollbar for IE and Edge */ scrollbar-width: none; /* Hide scrollbar for Firefox */ } .categories::-webkit-scrollbar { display: none; /* Hide scrollbar for Chrome, Safari and Opera */ } .category { cursor: pointer; padding: 3px 10px; border-radius: 20px; background-color: transparent; transition: all 0.3s ease; white-space: nowrap; } .category:hover, .category.active { background-color: #222; color: #fff; } .masonry-grid { columns: 2; column-gap: 20px; margin-bottom: 40px; } @media (max-width: 600px) { .masonry-grid { columns: 1; } .site-title { font-size: 24px; } } .article { break-inside: avoid; margin-bottom: 20px; background-color: #fff; border-radius: 8px; overflow: hidden; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08); transition: all 0.3s ease; transform: translateY(20px); opacity: 0; position: relative; } .article.show { transform: translateY(0); opacity: 1; } .article:hover { box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12); transform: translateY(-5px); } .article-image { width: 100%; height: 0; padding-bottom: 56.25%; /* 16:9 aspect ratio */ position: relative; overflow: hidden; } .article-image img { position: absolute; top: 0; left: 0; width: 100%; height: 100%; object-fit: cover; transition: transform 0.5s ease; } .article:hover .article-image img { transform: scale(1.05); } .breaking-news { position: absolute; top: 10px; left: 10px; background-color: #e63946; color: white; padding: 5px 10px; font-size: 12px; font-weight: bold; border-radius: 4px; z-index: 10; animation: pulse 2s infinite; } @keyframes pulse { 0% { opacity: 1; } 50% { opacity: 0.7; } 100% { opacity: 1; } } .article-content { padding: 15px; } .article-meta { display: flex; justify-content: space-between; margin-bottom: 10px; font-size: 12px; color: #666; } .article-category { font-weight: 600; text-transform: uppercase; letter-spacing: 1px; } .article-time { display: flex; align-items: center; } .article-time svg { margin-right: 5px; width: 12px; height: 12px; } .article-title { font-family: 'Playfair Display', serif; font-weight: 700; font-size: 20px; line-height: 1.3; margin-bottom: 10px; color: #111; } .article-excerpt { font-size: 14px; margin-bottom: 15px; } .read-more { display: inline-block; font-weight: 600; color: #222; text-decoration: none; position: relative; font-size: 14px; } .read-more::after { content: ''; position: absolute; width: 100%; height: 2px; bottom: -2px; left: 0; background-color: #222; transform-origin: bottom right; transform: scaleX(0); transition: transform 0.3s ease-out; } .read-more:hover::after { transform-origin: bottom left; transform: scaleX(1); } .article.featured { grid-column: span 2; } .article.featured .article-title { font-size: 24px; } .trending { margin-top: 30px; margin-bottom: 20px; } .section-title { font-family: 'Playfair Display', serif; font-weight: 700; font-size: 24px; margin-bottom: 15px; position: relative; display: inline-block; } .section-title::after { content: ''; position: absolute; bottom: -5px; left: 0; width: 100%; height: 3px; background-color: #222; } .trending-articles { display: flex; gap: 15px; overflow-x: auto; padding-bottom: 15px; -ms-overflow-style: none; scrollbar-width: none; } .trending-articles::-webkit-scrollbar { display: none; } .trending-article { flex: 0 0 250px; background-color: #fff; border-radius: 8px; overflow: hidden; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08); transition: all 0.3s ease; } .trending-article:hover { box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12); transform: translateY(-5px); } .trending-image { width: 100%; height: 140px; overflow: hidden; } .trending-image img { width: 100%; height: 100%; object-fit: cover; transition: transform 0.5s ease; } .trending-article:hover .trending-image img { transform: scale(1.05); } .trending-content { padding: 12px; } .trending-title { font-family: 'Playfair Display', serif; font-weight: 700; font-size: 16px; line-height: 1.3; margin-bottom: 5px; color: #111; } .trending-meta { font-size: 12px; color: #666; } .loading { display: flex; justify-content: center; margin: 30px 0; } .loading-spinner { width: 40px; height: 40px; border: 3px solid rgba(0, 0, 0, 0.1); border-radius: 50%; border-top-color: #222; animation: spin 1s ease-in-out infinite; } @keyframes spin { to { transform: rotate(360deg); } } /* Dark mode toggle */ .mode-toggle { position: fixed; bottom: 20px; right: 20px; background-color: #222; color: #fff; width: 50px; height: 50px; border-radius: 50%; display: flex; align-items: center; justify-content: center; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2); cursor: pointer; z-index: 100; transition: all 0.3s ease; } .mode-toggle:hover { transform: scale(1.1); } .dark-mode { background-color: #121212; color: #f1f1f1; } .dark-mode header { background-color: #121212; border-bottom-color: #444; } .dark-mode .site-title, .dark-mode .article-title, .dark-mode .trending-title, .dark-mode .section-title { color: #f1f1f1; } .dark-mode .article, .dark-mode .trending-article { background-color: #1e1e1e; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.25); } .dark-mode .article-meta, .dark-mode .trending-meta, .dark-mode .date { color: #aaa; } .dark-mode .read-more { color: #f1f1f1; } .dark-mode .read-more::after { background-color: #f1f1f1; } .dark-mode .category:hover, .dark-mode .category.active { background-color: #f1f1f1; color: #121212; } .dark-mode .section-title::after { background-color: #f1f1f1; } .dark-mode .mode-toggle { background-color: #f1f1f1; color: #121212; } /* Custom scrollbar for the whole page */ ::-webkit-scrollbar { width: 8px; height: 8px; } ::-webkit-scrollbar-track { background: #f1f1f1; } ::-webkit-scrollbar-thumb { background: #888; border-radius: 4px; } ::-webkit-scrollbar-thumb:hover { background: #555; } .dark-mode ::-webkit-scrollbar-track { background: #1e1e1e; } .dark-mode ::-webkit-scrollbar-thumb { background: #666; } .dark-mode ::-webkit-scrollbar-thumb:hover { background: #888; } .no-result { text-align: center; padding: 30px; font-size: 18px; color: #666; } .no-result svg { width: 60px; height: 60px; margin-bottom: 15px; color: #888; } </style> </head> <body> <header> <div class="header-container"> <h1 class="site-title">The Daily Chronicle</h1> <div class="date" id="current-date"></div> </div> <div class="categories"> <div class="category active" data-category="all">All</div> <div class="category" data-category="politics">Politics</div> <div class="category" data-category="technology">Technology</div> <div class="category" data-category="health">Health</div> <div class="category" data-category="business">Business</div> <div class="category" data-category="science">Science</div> <div class="category" data-category="culture">Culture</div> </div> </header> <main> <div class="masonry-grid" id="articles-container"></div> <div class="loading" id="loading"> <div class="loading-spinner"></div> </div> <div class="trending"> <h2 class="section-title">Trending Now</h2> <div class="trending-articles"> <div class="trending-article"> <div class="trending-image"> <img src="https://source.unsplash.com/random/300x200/?city,night" alt="Urban planning"> </div> <div class="trending-content"> <h3 class="trending-title">Urban Centers Face Housing Crisis Amid Development Boom</h3> <div class="trending-meta">9.5K reads · 2 hours ago</div> </div> </div> <div class="trending-article"> <div class="trending-image"> <img src="https://source.unsplash.com/random/300x200/?tech,device" alt="New smartphone"> </div> <div class="trending-content"> <h3 class="trending-title">Revolutionary E-Ink Smartphone Promises Two-Week Battery Life</h3> <div class="trending-meta">7.3K reads · 5 hours ago</div> </div> </div> <div class="trending-article"> <div class="trending-image"> <img src="https://source.unsplash.com/random/300x200/?climate,forest" alt="Climate report"> </div> <div class="trending-content"> <h3 class="trending-title">New Climate Report Shows Unexpected Reforestation Success</h3> <div class="trending-meta">6.2K reads · 7 hours ago</div> </div> </div> <div class="trending-article"> <div class="trending-image"> <img src="https://source.unsplash.com/random/300x200/?food,restaurant" alt="Restaurant"> </div> <div class="trending-content"> <h3 class="trending-title">Underground Supper Clubs Reshape Fine Dining Experience</h3> <div class="trending-meta">5.1K reads · 1 day ago</div> </div> </div> </div> </div> </main> <div class="mode-toggle" id="mode-toggle"> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"></path></svg> </div> <script> // Sample article data const articles = [ { id: 1, title: "Global Semiconductor Shortage Threatens Auto Industry Recovery", excerpt: "Major automakers announce further production cuts as the global chip crisis deepens, with industry experts forecasting supply issues to persist through 2023.", category: "business", image: "https://source.unsplash.com/random/600x400/?semiconductor,chip", time: "10 minutes ago", breaking: true, featured: true }, { id: 2, title: "Breakthrough mRNA Technology Shows Promise for Malaria Vaccine", excerpt: "Scientists report 87% efficacy in early trials of novel mRNA-based vaccine targeting the deadliest form of malaria, potentially saving millions of lives annually.", category: "health", image: "https://source.unsplash.com/random/600x400/?medical,vaccine", time: "43 minutes ago", breaking: false, featured: false }, { id: 3, title: "Unprecedented Heatwave Shatters Records Across Mediterranean", excerpt: "Temperature records tumble as southern Europe grapples with its most intense heatwave in recorded history, prompting widespread evacuation orders.", category: "science", image: "https://source.unsplash.com/random/600x400/?heatwave,summer", time: "2 hours ago", breaking: true, featured: false }, { id: 4, title: "Supreme Court Rules on Landmark Digital Privacy Case", excerpt: "In a 6-3 decision, the court establishes new precedent on government access to cloud-stored data, requiring warrants for all remotely stored personal information.", category: "politics", image: "https://source.unsplash.com/random/600x400/?court,judge", time: "3 hours ago", breaking: false, featured: false }, { id: 5, title: "Artificial Intelligence Systems Now Capable of Generating Novel Proteins", excerpt: "Researchers demonstrate AI system that designs functional proteins not found in nature, opening new frontiers in drug development and synthetic biology.", category: "technology", image: "https://source.unsplash.com/random/600x400/?ai,technology", time: "5 hours ago", breaking: false, featured: true }, { id: 6, title: "Independent Bookstores Stage Remarkable Comeback Post-Pandemic", excerpt: "Against all odds, independent bookshops report a 32% rise in sales compared to pre-pandemic levels, driven by community support and unique experiences.", category: "culture", image: "https://source.unsplash.com/random/600x400/?bookstore,books", time: "7 hours ago", breaking: false, featured: false }, { id: 7, title: "Quantum Computing Milestone: Error Correction Achieved at Scale", excerpt: "Researchers achieve practical quantum error correction in a 100-qubit system, potentially unlocking the next phase of quantum computing applications.", category: "technology", image: "https://source.unsplash.com/random/600x400/?quantum,computer", time: "Yesterday", breaking: false, featured: false }, { id: 8, title: "Fusion Energy Startup Achieves Net Positive Energy Production", excerpt: "Silicon Valley-backed fusion reactor sustains reaction producing 1.5 times more energy than consumed, marking potential turning point for clean energy.", category: "science", image: "https://source.unsplash.com/random/600x400/?energy,fusion", time: "Yesterday", breaking: false, featured: false }, { id: 9, title: "Central Banks Unveil Digital Currency Framework", excerpt: "Coalition of major central banks announces coordinated approach to central bank digital currencies, outlining cross-border transaction standards.", category: "business", image: "https://source.unsplash.com/random/600x400/?bank,currency", time: "2 days ago", breaking: false, featured: false } ]; // Format current date const formatDate = () => { const options = { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' }; const today = new Date(); return today.toLocaleDateString('en-US', options); }; document.getElementById('current-date').textContent = formatDate(); // Render articles with staggered animation const renderArticles = (filteredArticles) => { const container = document.getElementById('articles-container'); container.innerHTML = ''; if (filteredArticles.length === 0) { container.innerHTML = ` <div class="no-result"> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <circle cx="11" cy="11" r="8"></circle> <line x1="21" y1="21" x2="16.65" y2="16.65"></line> <line x1="8" y1="11" x2="14" y2="11"></line> </svg> <p>No articles found in this category</p> </div> `; return; } filteredArticles.forEach((article) => { const articleEl = document.createElement('div'); articleEl.className = `article ${article.featured ? 'featured' : ''}`; articleEl.innerHTML = ` <div class="article-image"> <img src="${article.image}" alt="${article.title}"> ${article.breaking ? '<div class="breaking-news">Breaking</div>' : ''} </div> <div class="article-content"> <div class="article-meta"> <div class="article-category">${article.category}</div> <div class="article-time"> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <circle cx="12" cy="12" r="10"></circle> <polyline points="12 6 12 12 16 14"></polyline> </svg> ${article.time} </div> </div> <h2 class="article-title">${article.title}</h2> <p class="article-excerpt">${article.excerpt}</p> <a href="#" class="read-more">Continue Reading</a> </div> `; container.appendChild(articleEl); // Trigger staggered animation setTimeout(() => { articleEl.classList.add('show'); }, 100 * container.children.length); }); }; // Initial render const loading = document.getElementById('loading'); // Simulate loading delay setTimeout(() => { loading.style.display = 'none'; renderArticles(articles); }, 1500); // Category filtering const categories = document.querySelectorAll('.category'); categories.forEach(category => { category.addEventListener('click', () => { // Update active class document.querySelector('.category.active').classList.remove('active'); category.classList.add('active'); const selectedCategory = category.dataset.category; // Show loading loading.style.display = 'flex'; // Simulate filtering delay setTimeout(() => { loading.style.display = 'none'; // Filter articles let filteredArticles; if (selectedCategory === 'all') { filteredArticles = articles; } else { filteredArticles = articles.filter(article => article.category === selectedCategory); } renderArticles(filteredArticles); }, 800); }); }); // Dark mode toggle const modeToggle = document.getElementById('mode-toggle'); modeToggle.addEventListener('click', () => { document.body.classList.toggle('dark-mode'); // Change icon based on mode if (document.body.classList.contains('dark-mode')) { modeToggle.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="5"></circle><line x1="12" y1="1" x2="12" y2="3"></line><line x1="12" y1="21" x2="12" y2="23"></line><line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line><line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line><line x1="1" y1="12" x2="3" y2="12"></line><line x1="21" y1="12" x2="23" y2="12"></line><line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line><line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line></svg>'; } else { modeToggle.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"></path></svg>'; } }); </script> </body> </html>
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Ephemera: Photography Showcase</title> <style> :root { --background: #fafafa; --text: #222; --border: rgba(0, 0, 0, 0.08); --hover-bg: rgba(255, 255, 255, 0.92); --transition: all 0.3s cubic-bezier(0.25, 1, 0.5, 1); } * { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif; background-color: var(--background); color: var(--text); line-height: 1.6; padding: 1.5rem; overflow-x: hidden; max-width: 700px; max-height: 700px; margin: 0 auto; } header { margin-bottom: 1.5rem; opacity: 0; transform: translateY(-10px); animation: fadeIn 0.7s forwards 0.2s; } h1 { font-size: 1.75rem; font-weight: 500; letter-spacing: -0.02em; margin-bottom: 0.5rem; } .subtitle { font-size: 0.9rem; color: rgba(0, 0, 0, 0.6); margin-bottom: 0.5rem; } .filters { display: flex; gap: 0.8rem; flex-wrap: wrap; margin: 1rem 0; } .filter-btn { background: transparent; border: 1px solid var(--border); padding: 0.3rem 0.7rem; border-radius: 3rem; font-size: 0.8rem; color: rgba(0, 0, 0, 0.7); cursor: pointer; transition: var(--transition); } .filter-btn:hover { background: rgba(0, 0, 0, 0.05); } .filter-btn.active { background: var(--text); color: white; border-color: var(--text); } .gallery-container { height: calc(700px - 150px); overflow-y: auto; padding-right: 0.5rem; scrollbar-width: thin; scrollbar-color: rgba(0, 0, 0, 0.2) transparent; } .gallery-container::-webkit-scrollbar { width: 5px; } .gallery-container::-webkit-scrollbar-track { background: transparent; } .gallery-container::-webkit-scrollbar-thumb { background-color: rgba(0, 0, 0, 0.2); border-radius: 6px; } .gallery { display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); grid-auto-rows: 5px; grid-gap: 15px; } .gallery-item { grid-row-end: span 1; position: relative; overflow: hidden; border-radius: 4px; box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05); opacity: 0; transform: translateY(10px); animation: fadeIn 0.5s forwards; } @keyframes fadeIn { to { opacity: 1; transform: translateY(0); } } .gallery-item img { width: 100%; height: 100%; object-fit: cover; display: block; transition: var(--transition); } .gallery-item:hover img { transform: scale(1.03); } .image-info { position: absolute; bottom: 0; left: 0; right: 0; background: var(--hover-bg); padding: 0.8rem; transform: translateY(100%); transition: var(--transition); border-top: 1px solid var(--border); } .gallery-item:hover .image-info { transform: translateY(0); } .image-title { font-size: 0.9rem; font-weight: 500; margin-bottom: 0.2rem; } .photographer { font-size: 0.75rem; color: rgba(0, 0, 0, 0.6); } .loader { width: 100%; display: flex; align-items: center; justify-content: center; padding: 2rem 0; } .dot-pulse { position: relative; left: -9999px; width: 6px; height: 6px; border-radius: 5px; background-color: var(--text); color: var(--text); box-shadow: 9999px 0 0 -5px; animation: dot-pulse 1.5s infinite linear; animation-delay: 0.25s; } .dot-pulse::before, .dot-pulse::after { content: ""; display: inline-block; position: absolute; top: 0; width: 6px; height: 6px; border-radius: 5px; background-color: var(--text); color: var(--text); } .dot-pulse::before { box-shadow: 9984px 0 0 -5px; animation: dot-pulse-before 1.5s infinite linear; animation-delay: 0s; } .dot-pulse::after { box-shadow: 10014px 0 0 -5px; animation: dot-pulse-after 1.5s infinite linear; animation-delay: 0.5s; } @keyframes dot-pulse-before { 0% { box-shadow: 9984px 0 0 -5px; } 30% { box-shadow: 9984px 0 0 2px; } 60%, 100% { box-shadow: 9984px 0 0 -5px; } } @keyframes dot-pulse { 0% { box-shadow: 9999px 0 0 -5px; } 30% { box-shadow: 9999px 0 0 2px; } 60%, 100% { box-shadow: 9999px 0 0 -5px; } } @keyframes dot-pulse-after { 0% { box-shadow: 10014px 0 0 -5px; } 30% { box-shadow: 10014px 0 0 2px; } 60%, 100% { box-shadow: 10014px 0 0 -5px; } } @media (max-width: 600px) { .gallery { grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); grid-gap: 10px; } h1 { font-size: 1.5rem; } .filter-btn { font-size: 0.7rem; padding: 0.25rem 0.6rem; } } @media (max-width: 400px) { .gallery { grid-template-columns: repeat(auto-fill, minmax(120px, 1fr)); } body { padding: 1rem; } } </style> </head> <body> <header> <h1>Ephemera</h1> <div class="subtitle">Moments in light and shadow, curated from around the world</div> <div class="filters"> <button class="filter-btn active" data-filter="all">All</button> <button class="filter-btn" data-filter="portrait">Portrait</button> <button class="filter-btn" data-filter="landscape">Landscape</button> <button class="filter-btn" data-filter="street">Street</button> <button class="filter-btn" data-filter="nature">Nature</button> </div> </header> <div class="gallery-container"> <div class="gallery" id="gallery"> <!-- Gallery items will be populated by JS --> </div> <div class="loader"> <div class="dot-pulse"></div> </div> </div> <script> // Photography collection const photos = [ { id: 1, title: "Autumn in Kyoto", photographer: "Haruki Tanaka", src: "https://images.unsplash.com/photo-1601823984263-b87b59798b70?q=80&w=1000&auto=format&fit=crop", category: "nature", aspectRatio: 0.75, // height/width ratio }, { id: 2, title: "Morning Light in Marrakech", photographer: "Sofia Laurent", src: "https://images.unsplash.com/photo-1545597440-c89f4fd29a6a?q=80&w=1000&auto=format&fit=crop", category: "street", aspectRatio: 1.5, }, { id: 3, title: "The Fisherman", photographer: "Niran Patel", src: "https://images.unsplash.com/photo-1542850348-1588e66de70c?q=80&w=1000&auto=format&fit=crop", category: "portrait", aspectRatio: 0.8, }, { id: 4, title: "Misty Mountains", photographer: "Elena Nordström", src: "https://images.unsplash.com/photo-1502472584811-0a2f2feb8968?q=80&w=1000&auto=format&fit=crop", category: "landscape", aspectRatio: 1.8, }, { id: 5, title: "City Reflections", photographer: "Marcus Chen", src: "https://images.unsplash.com/photo-1481365553482-39732cda4dfa?q=80&w=1000&auto=format&fit=crop", category: "street", aspectRatio: 1.2, }, { id: 6, title: "Daydream", photographer: "Olivia Rey", src: "https://images.unsplash.com/photo-1529626455594-4ff0802cfb7e?q=80&w=1000&auto=format&fit=crop", category: "portrait", aspectRatio: 0.7, }, { id: 7, title: "Desert Horizon", photographer: "Ahmed Al-Maskari", src: "https://images.unsplash.com/photo-1509316785289-025f5b846b35?q=80&w=1000&auto=format&fit=crop", category: "landscape", aspectRatio: 1.6, }, { id: 8, title: "Winter Solitude", photographer: "Johanna Berg", src: "https://images.unsplash.com/photo-1457269449834-928af64c684d?q=80&w=1000&auto=format&fit=crop", category: "nature", aspectRatio: 0.9, }, { id: 9, title: "Taipei at Dusk", photographer: "Wei Lin", src: "https://images.unsplash.com/photo-1470770841072-f978cf4d019e?q=80&w=1000&auto=format&fit=crop", category: "landscape", aspectRatio: 1.3, }, { id: 10, title: "Market Portraits", photographer: "Gabriel Santos", src: "https://images.unsplash.com/photo-1504257365157-1496a50d108f?q=80&w=1000&auto=format&fit=crop", category: "street", aspectRatio: 0.8, }, { id: 11, title: "Silent Gaze", photographer: "Ana Moreno", src: "https://images.unsplash.com/photo-1469334031218-e382a71b716b?q=80&w=1000&auto=format&fit=crop", category: "portrait", aspectRatio: 0.75, }, { id: 12, title: "Coastal Fog", photographer: "Isaac Waters", src: "https://images.unsplash.com/photo-1504567961542-e24d9439a724?q=80&w=1000&auto=format&fit=crop", category: "nature", aspectRatio: 1.7, } ]; document.addEventListener('DOMContentLoaded', () => { const gallery = document.getElementById('gallery'); const loader = document.querySelector('.loader'); const filterButtons = document.querySelectorAll('.filter-btn'); let currentFilter = 'all'; // Calculate heights for masonry layout function resizeGridItems() { const gridItems = document.querySelectorAll('.gallery-item'); const grid = document.getElementById('gallery'); const rowHeight = parseInt(window.getComputedStyle(grid).getPropertyValue('grid-auto-rows')); const rowGap = parseInt(window.getComputedStyle(grid).getPropertyValue('grid-gap')); gridItems.forEach(item => { const rowSpan = Math.ceil((item.querySelector('img').getBoundingClientRect().height + rowGap) / (rowHeight + rowGap)); item.style.gridRowEnd = 'span ' + rowSpan; }); } // Render photos with delay for animation function renderPhotos(filter = 'all') { gallery.innerHTML = ''; loader.style.display = 'flex'; setTimeout(() => { const filteredPhotos = filter === 'all' ? photos : photos.filter(photo => photo.category === filter); filteredPhotos.forEach((photo, index) => { const photoElement = document.createElement('div'); photoElement.className = 'gallery-item'; photoElement.style.animation = `fadeIn 0.5s forwards ${index * 0.05}s`; photoElement.innerHTML = ` <img src="${photo.src}" alt="${photo.title}" loading="lazy"> <div class="image-info"> <div class="image-title">${photo.title}</div> <div class="photographer">© ${photo.photographer}</div> </div> `; gallery.appendChild(photoElement); }); loader.style.display = 'none'; // Add delay to allow images to load before calculating height setTimeout(resizeGridItems, 100); }, 300); } // Initialize gallery renderPhotos(); // Filter functionality filterButtons.forEach(button => { button.addEventListener('click', () => { const filter = button.getAttribute('data-filter'); if (filter === currentFilter) return; // Update active state filterButtons.forEach(btn => btn.classList.remove('active')); button.classList.add('active'); currentFilter = filter; renderPhotos(filter); }); }); // Resize event listener window.addEventListener('resize', resizeGridItems); // Recalculate layout when images are loaded window.addEventListener('load', resizeGridItems); // Handle image load events document.addEventListener('load', e => { if (e.target.tagName === 'IMG') { resizeGridItems(); } }, true); }); </script> </body> </html>
<html> <head> <style> * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Inter', sans-serif; } :root { --primary: #FF3366; --secondary: #5D3FD3; --light: #F9F9F9; --dark: #1A1A1A; --success: #2ECC71; } body { background-color: var(--light); color: var(--dark); overflow-x: hidden; width: 100%; height: 100%; padding: 20px; } .container { max-width: 700px; margin: 0 auto; overflow-y: auto; max-height: 690px; scrollbar-width: thin; scrollbar-color: var(--primary) var(--light); } .container::-webkit-scrollbar { width: 6px; } .container::-webkit-scrollbar-track { background: var(--light); } .container::-webkit-scrollbar-thumb { background-color: var(--primary); border-radius: 10px; } header { margin-bottom: 20px; } h1 { font-size: 24px; margin-bottom: 5px; background: linear-gradient(45deg, var(--primary), var(--secondary)); -webkit-background-clip: text; background-clip: text; color: transparent; display: inline-block; } .filters { display: flex; gap: 10px; margin-bottom: 20px; flex-wrap: wrap; } .filter-btn { background: white; border: 1px solid #ddd; border-radius: 20px; padding: 6px 16px; font-size: 13px; cursor: pointer; transition: all 0.3s ease; } .filter-btn:hover, .filter-btn.active { background: var(--primary); color: white; border-color: var(--primary); transform: translateY(-2px); box-shadow: 0 4px 8px rgba(255, 51, 102, 0.2); } .masonry-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); grid-auto-rows: 10px; grid-gap: 15px; } .product-card { grid-row-end: span var(--span); background: white; border-radius: 12px; overflow: hidden; box-shadow: 0 5px 15px rgba(0, 0, 0, 0.05); transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1); position: relative; transform-origin: center; } .product-card:hover { transform: translateY(-5px); box-shadow: 0 10px 20px rgba(0, 0, 0, 0.1); } .product-img { position: relative; width: 100%; height: 65%; overflow: hidden; } .product-img img { width: 100%; height: 100%; object-fit: cover; transition: transform 0.5s ease; } .product-card:hover .product-img img { transform: scale(1.05); } .product-tag { position: absolute; top: 10px; left: 10px; background: var(--secondary); color: white; font-size: 11px; padding: 4px 8px; border-radius: 4px; z-index: 2; font-weight: 500; } .product-tag.sale { background: var(--primary); } .product-info { padding: 15px; } .product-name { font-size: 14px; font-weight: 600; margin-bottom: 5px; height: 2.8em; overflow: hidden; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; } .product-price { display: flex; align-items: center; gap: 8px; margin-bottom: 10px; } .current-price { font-size: 16px; font-weight: 700; color: var(--dark); } .old-price { font-size: 13px; text-decoration: line-through; color: #999; } .product-rating { display: flex; align-items: center; gap: 5px; font-size: 12px; color: #666; margin-bottom: 10px; } .stars { color: #FFD700; } .product-actions { opacity: 0; position: absolute; bottom: 0; left: 0; right: 0; display: flex; transition: all 0.3s ease; transform: translateY(100%); } .product-card:hover .product-actions { opacity: 1; transform: translateY(0); } .action-btn { flex: 1; border: none; padding: 10px; color: white; font-weight: 500; cursor: pointer; font-size: 12px; display: flex; justify-content: center; align-items: center; gap: 5px; transition: all 0.2s ease; } .add-cart { background: var(--primary); } .add-cart:hover { background: #e62e5c; } .quick-view { background: var(--dark); } .quick-view:hover { background: #2c2c2c; } .cart-notification { position: fixed; bottom: 20px; right: 20px; background: var(--success); color: white; padding: 12px 20px; border-radius: 8px; display: flex; align-items: center; gap: 10px; box-shadow: 0 5px 15px rgba(46, 204, 113, 0.3); transform: translateX(150%); transition: transform 0.5s cubic-bezier(0.68, -0.55, 0.27, 1.55); z-index: 1000; } .cart-notification.show { transform: translateX(0); } .cart-icon { position: fixed; top: 20px; right: 20px; background: white; width: 40px; height: 40px; border-radius: 50%; display: flex; justify-content: center; align-items: center; box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); cursor: pointer; z-index: 100; } .cart-count { position: absolute; top: -5px; right: -5px; background: var(--primary); color: white; font-size: 11px; width: 20px; height: 20px; border-radius: 50%; display: flex; justify-content: center; align-items: center; font-weight: bold; transition: all 0.3s ease; } .cart-btn-pulse { animation: pulse 0.5s cubic-bezier(0.68, -0.55, 0.27, 1.55); } @keyframes pulse { 0% { transform: scale(1); } 50% { transform: scale(1.2); } 100% { transform: scale(1); } } @media (max-width: 600px) { .masonry-grid { grid-template-columns: repeat(auto-fill, minmax(130px, 1fr)); grid-gap: 10px; } .product-name { font-size: 13px; } .product-info { padding: 10px; } .container { padding: 10px; } } @media (max-width: 400px) { .masonry-grid { grid-template-columns: repeat(auto-fill, minmax(100px, 1fr)); } } </style> </head> <body> <div class="container"> <header> <h1>Artisan Market</h1> <p>Curated goods that elevate everyday living</p> </header> <div class="filters"> <button class="filter-btn active" data-filter="all">All Products</button> <button class="filter-btn" data-filter="home">Home Decor</button> <button class="filter-btn" data-filter="kitchen">Kitchen</button> <button class="filter-btn" data-filter="tech">Tech</button> <button class="filter-btn" data-filter="apparel">Apparel</button> </div> <div class="masonry-grid" id="product-grid"> <!-- Products will be added dynamically --> </div> </div> <div class="cart-icon"> <svg width="20" height="20" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M6 2L3 6V20C3 20.5304 3.21071 21.0391 3.58579 21.4142C3.96086 21.7893 4.46957 22 5 22H19C19.5304 22 20.0391 21.7893 20.4142 21.4142C20.7893 21.0391 21 20.5304 21 20V6L18 2H6Z" stroke="#333" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> <path d="M3 6H21" stroke="#333" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> <path d="M16 10C16 11.0609 15.5786 12.0783 14.8284 12.8284C14.0783 13.5786 13.0609 14 12 14C10.9391 14 9.92172 13.5786 9.17157 12.8284C8.42143 12.0783 8 11.0609 8 10" stroke="#333" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> </svg> <div class="cart-count">0</div> </div> <div class="cart-notification"> <svg width="18" height="18" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M22 11.08V12C21.9988 14.1564 21.3005 16.2547 20.0093 17.9818C18.7182 19.709 16.9033 20.9725 14.8354 21.5839C12.7674 22.1953 10.5573 22.1219 8.53447 21.3746C6.51168 20.6273 4.78465 19.2461 3.61096 17.4371C2.43727 15.628 1.87979 13.4881 2.02168 11.3363C2.16356 9.18457 2.99721 7.13633 4.39828 5.49707C5.79935 3.85782 7.69279 2.71538 9.79619 2.24015C11.8996 1.76491 14.1003 1.98234 16.07 2.86" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> <path d="M22 4L12 14.01L9 11.01" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> </svg> <span id="notification-message">Added to cart</span> </div> <script> // Products data const products = [ { id: 1, name: "Sculptural Ceramic Vase", price: 49.99, oldPrice: 65.00, image: "https://images.unsplash.com/photo-1602025029573-53a5f5cf2b91?ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=80", height: 26, category: "home", rating: 4.7, reviews: 124, tag: "handcrafted" }, { id: 2, name: "Japanese Cast Iron Teapot", price: 89.00, oldPrice: null, image: "https://images.unsplash.com/photo-1576089073624-b5f8eef70f7b?ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=80", height: 22, category: "kitchen", rating: 4.9, reviews: 87, tag: null }, { id: 3, name: "Minimalist Desk Lamp", price: 69.50, oldPrice: 85.99, image: "https://images.unsplash.com/photo-1507473885765-e6ed057f782c?ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=80", height: 24, category: "home", rating: 4.5, reviews: 56, tag: "sale" }, { id: 4, name: "Natural Linen Table Runner", price: 29.00, oldPrice: null, image: "https://images.unsplash.com/photo-1589141987619-a2a792c6ef84?ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=80", height: 20, category: "home", rating: 4.3, reviews: 41, tag: null }, { id: 5, name: "Handwoven Wool Throw Blanket", price: 119.00, oldPrice: 140.00, image: "https://images.unsplash.com/photo-1519831802596-6aadd85ff671?ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=80", height: 28, category: "home", rating: 4.8, reviews: 93, tag: "sale" }, { id: 6, name: "Wireless Noise-Cancelling Headphones", price: 199.99, oldPrice: 249.99, image: "https://images.unsplash.com/photo-1546435770-a3e426bf472b?ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=80", height: 23, category: "tech", rating: 4.9, reviews: 312, tag: "sale" }, { id: 7, name: "Wood & Brass Coffee Grinder", price: 79.00, oldPrice: null, image: "https://images.unsplash.com/photo-1514432324607-a09d9b4aefdd?ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=80", height: 25, category: "kitchen", rating: 4.6, reviews: 68, tag: "handcrafted" }, { id: 8, name: "Organic Cotton Apron", price: 35.00, oldPrice: null, image: "https://images.unsplash.com/photo-1584284278729-9e87a0f8d3d7?ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=80", height: 21, category: "kitchen", rating: 4.2, reviews: 29, tag: null }, { id: 9, name: "Merino Wool Beanie", price: 45.00, oldPrice: 60.00, image: "https://images.unsplash.com/photo-1576871337622-98d48d1cf531?ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=80", height: 19, category: "apparel", rating: 4.7, reviews: 156, tag: "sale" }, { id: 10, name: "Leather Tech Organizer", price: 59.00, oldPrice: null, image: "https://images.unsplash.com/photo-1559831731-caa534e3586d?ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=80", height: 22, category: "tech", rating: 4.4, reviews: 73, tag: "handcrafted" }, { id: 11, name: "Japanese Ceramic Tea Set", price: 110.00, oldPrice: 130.00, image: "https://images.unsplash.com/photo-1595100364214-2467f308a256?ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=80", height: 27, category: "kitchen", rating: 4.8, reviews: 47, tag: "sale" }, { id: 12, name: "Canvas & Leather Weekender Bag", price: 129.00, oldPrice: null, image: "https://images.unsplash.com/photo-1547949003-9792a18a2601?ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=80", height: 25, category: "apparel", rating: 4.6, reviews: 89, tag: null } ]; // DOM Elements const productGrid = document.getElementById('product-grid'); const filterButtons = document.querySelectorAll('.filter-btn'); const cartCount = document.querySelector('.cart-count'); const cartNotification = document.querySelector('.cart-notification'); const cartIcon = document.querySelector('.cart-icon'); const notificationMessage = document.getElementById('notification-message'); // Track cart count let cartItemCount = 0; // Render products function renderProducts(filteredProducts = products) { productGrid.innerHTML = ''; filteredProducts.forEach(product => { const card = document.createElement('div'); card.className = 'product-card'; card.setAttribute('data-category', product.category); card.style.setProperty('--span', product.height); const tagHTML = product.tag ? `<div class="product-tag ${product.tag === 'sale' ? 'sale' : ''}">${product.tag === 'sale' ? 'Sale' : 'Handcrafted'}</div>` : ''; const oldPriceHTML = product.oldPrice ? `<span class="old-price">$${product.oldPrice.toFixed(2)}</span>` : ''; card.innerHTML = ` <div class="product-img"> ${tagHTML} <img src="${product.image}" alt="${product.name}"> </div> <div class="product-info"> <h3 class="product-name">${product.name}</h3> <div class="product-price"> <span class="current-price">$${product.price.toFixed(2)}</span> ${oldPriceHTML} </div> <div class="product-rating"> <span class="stars">★★★★★</span> <span>${product.rating} (${product.reviews})</span> </div> </div> <div class="product-actions"> <button class="action-btn add-cart" data-id="${product.id}"> <svg width="14" height="14" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M9 22C9.55228 22 10 21.5523 10 21C10 20.4477 9.55228 20 9 20C8.44772 20 8 20.4477 8 21C8 21.5523 8.44772 22 9 22Z" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> <path d="M20 22C20.5523 22 21 21.5523 21 21C21 20.4477 20.5523 20 20 20C19.4477 20 19 20.4477 19 21C19 21.5523 19.4477 22 20 22Z" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> <path d="M1 1H5L7.68 14.39C7.77144 14.8504 8.02191 15.264 8.38755 15.5583C8.75318 15.8526 9.2107 16.009 9.68 16H19.4C19.8693 16.009 20.3268 15.8526 20.6925 15.5583C21.0581 15.264 21.3086 14.8504 21.4 14.39L23 6H6" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> </svg> Add to Cart </button> <button class="action-btn quick-view" data-id="${product.id}"> <svg width="14" height="14" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M1 12C1 12 5 4 12 4C19 4 23 12 23 12C23 12 19 20 12 20C5 20 1 12 1 12Z" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> <path d="M12 15C13.6569 15 15 13.6569 15 12C15 10.3431 13.6569 9 12 9C10.3431 9 9 10.3431 9 12C9 13.6569 10.3431 15 12 15Z" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> </svg> Quick View </button> </div> `; productGrid.appendChild(card); }); // Resizing grid items for masonry layout resizeGridItems(); } // Resize grid items for masonry layout function resizeGridItems() { const grid = document.querySelector(".masonry-grid"); const rowHeight = parseInt(window.getComputedStyle(grid).getPropertyValue('grid-auto-rows')); const rowGap = parseInt(window.getComputedStyle(grid).getPropertyValue('grid-row-gap')); const items = document.querySelectorAll(".product-card"); items.forEach(item => { const content = item.querySelector('.product-img').offsetHeight + item.querySelector('.product-info').offsetHeight; const rowSpan = Math.ceil((content + rowGap) / (rowHeight + rowGap)); item.style.gridRowEnd = "span " + rowSpan; }); } // Handle filters filterButtons.forEach(button => { button.addEventListener('click', () => { // Update active button filterButtons.forEach(btn => btn.classList.remove('active')); button.classList.add('active'); // Filter products const filter = button.getAttribute('data-filter'); const filteredProducts = filter === 'all' ? products : products.filter(product => product.category === filter); renderProducts(filteredProducts); }); }); // Add to cart functionality document.addEventListener('click', (e) => { if (e.target.closest('.add-cart')) { const button = e.target.closest('.add-cart'); const productId = button.getAttribute('data-id'); const product = products.find(p => p.id === parseInt(productId)); // Update cart count cartItemCount++; cartCount.textContent = cartItemCount; cartCount.classList.add('cart-btn-pulse'); // Show notification notificationMessage.textContent = `Added ${product.name} to cart`; cartNotification.classList.add('show'); setTimeout(() => { cartNotification.classList.remove('show'); cartCount.classList.remove('cart-btn-pulse'); }, 3000); } if (e.target.closest('.quick-view')) { const button = e.target.closest('.quick-view'); const productId = button.getAttribute('data-id'); const product = products.find(p => p.id === parseInt(productId)); // Show notification for quick view notificationMessage.textContent = `Quick view: ${product.name}`; cartNotification.classList.add('show'); setTimeout(() => { cartNotification.classList.remove('show'); }, 3000); } }); // Cart icon click cartIcon.addEventListener('click', () => { notificationMessage.textContent = cartItemCount > 0 ? `You have ${cartItemCount} items in your cart` : "Your cart is empty"; cartNotification.classList.add('show'); setTimeout(() => { cartNotification.classList.remove('show'); }, 3000); }); // Window resize handler window.addEventListener('resize', resizeGridItems); // Initial render renderProducts(); </script> </body> </html>
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Lumière Gallery Exhibition</title> <style> @import url('https://fonts.googleapis.com/css2?family=Cormorant+Garamond:wght@300;400;500;600&family=Inter:wght@300;400;500&display=swap'); :root { --primary: #f5f2ed; --secondary: #2b2922; --accent: #d4b996; --text: #1a1814; --subtle: #e3dfd7; --highlight: #c19e6b; --shadow: rgba(30, 30, 30, 0.1); --gap: 12px; --transition: all 0.5s cubic-bezier(0.25, 1, 0.5, 1); } * { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: 'Inter', sans-serif; background-color: var(--primary); color: var(--text); overflow-x: hidden; line-height: 1.5; height: 100%; width: 100%; max-width: 700px; margin: 0 auto; } h1, h2, h3, h4 { font-family: 'Cormorant Garamond', serif; font-weight: 500; } .container { padding: 20px; position: relative; max-width: 700px; margin: 0 auto; height: 100%; } .gallery-header { margin-bottom: 25px; position: relative; } .gallery-header h1 { font-size: 2.2rem; line-height: 1.1; display: inline-block; margin-right: 15px; position: relative; } .gallery-header h1::after { content: ''; position: absolute; bottom: -4px; left: 0; width: 70%; height: 1px; background-color: var(--accent); } .gallery-header p { font-size: 0.85rem; opacity: 0.8; max-width: 90%; margin-top: 8px; } .filters { display: flex; gap: 10px; margin-bottom: 20px; overflow-x: auto; padding-bottom: 5px; position: relative; } .filters::-webkit-scrollbar { height: 2px; } .filters::-webkit-scrollbar-track { background: var(--subtle); } .filters::-webkit-scrollbar-thumb { background: var(--accent); } .filter-btn { border: none; background: var(--subtle); color: var(--text); padding: 8px 14px; border-radius: 20px; font-size: 0.8rem; cursor: pointer; white-space: nowrap; transition: var(--transition); font-family: 'Inter', sans-serif; letter-spacing: 0.5px; } .filter-btn:hover { background: var(--accent); color: var(--primary); transform: translateY(-2px); } .filter-btn.active { background: var(--secondary); color: var(--primary); } .masonry-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); grid-auto-rows: 10px; grid-gap: var(--gap); height: calc(100vh - 180px); max-height: 480px; overflow-y: auto; padding-right: 5px; } .masonry-grid::-webkit-scrollbar { width: 4px; } .masonry-grid::-webkit-scrollbar-track { background: var(--subtle); } .masonry-grid::-webkit-scrollbar-thumb { background: var(--accent); } .tile { grid-row-end: span 28; background-color: var(--subtle); border-radius: 4px; overflow: hidden; box-shadow: 0 3px 10px var(--shadow); position: relative; transform-origin: center; transition: var(--transition); cursor: pointer; opacity: 0; transform: translateY(20px); animation: fadeIn 0.6s forwards; } @keyframes fadeIn { to { opacity: 1; transform: translateY(0); } } .tile:nth-child(2) { animation-delay: 0.1s; } .tile:nth-child(3) { animation-delay: 0.2s; } .tile:nth-child(4) { animation-delay: 0.3s; } .tile:nth-child(5) { animation-delay: 0.4s; } .tile:nth-child(6) { animation-delay: 0.5s; } .tile:nth-child(7) { animation-delay: 0.6s; } .tile:nth-child(8) { animation-delay: 0.7s; } .tile.medium { grid-row-end: span 36; } .tile.large { grid-row-end: span 48; } .tile:hover { box-shadow: 0 5px 15px rgba(30, 30, 30, 0.2); transform: translateY(-5px); } .tile-img { width: 100%; height: 78%; object-fit: cover; object-position: center; display: block; transition: transform 0.8s ease; } .tile:hover .tile-img { transform: scale(1.05); } .tile-info { padding: 10px; background: linear-gradient(to bottom, transparent, rgba(0, 0, 0, 0.7)); position: absolute; bottom: 0; left: 0; right: 0; color: white; transform: translateY(100%); transition: var(--transition); opacity: 0; } .tile:hover .tile-info { transform: translateY(0); opacity: 1; } .tile-title { font-size: 0.95rem; margin-bottom: 3px; } .tile-artist { font-size: 0.75rem; opacity: 0.9; font-style: italic; } .tile-medium { font-size: 0.7rem; opacity: 0.8; margin-top: 4px; } .expanded-view { position: fixed; top: 0; left: 0; right: 0; bottom: 0; background-color: rgba(30, 30, 30, 0.95); z-index: 100; display: flex; flex-direction: column; align-items: center; justify-content: center; padding: 20px; opacity: 0; pointer-events: none; transition: var(--transition); } .expanded-view.active { opacity: 1; pointer-events: all; } .expanded-img { max-width: 90%; max-height: 75vh; object-fit: contain; border: 2px solid var(--accent); box-shadow: 0 10px 25px rgba(0, 0, 0, 0.3); } .expanded-info { color: white; margin-top: 20px; text-align: center; max-width: 500px; } .expanded-info h2 { font-size: 1.4rem; margin-bottom: 8px; } .expanded-info h3 { font-size: 1.1rem; font-style: italic; opacity: 0.9; margin-bottom: 5px; } .expanded-info p { font-size: 0.9rem; opacity: 0.8; line-height: 1.4; } .close-btn { position: absolute; top: 20px; right: 20px; background: none; border: none; color: white; font-size: 1.5rem; cursor: pointer; width: 40px; height: 40px; display: flex; align-items: center; justify-content: center; border-radius: 50%; transition: var(--transition); } .close-btn:hover { background: rgba(255, 255, 255, 0.2); } .no-results { grid-column: 1 / -1; text-align: center; padding: 40px; font-size: 0.9rem; color: var(--text); opacity: 0.7; display: none; } .no-results.show { display: block; grid-row-end: span 20; } .empty-state { height: 100%; display: flex; align-items: center; justify-content: center; flex-direction: column; padding: 30px; text-align: center; } .empty-icon { font-size: 3rem; margin-bottom: 20px; opacity: 0.3; } .exhibition-badge { position: absolute; top: 20px; right: 20px; background-color: var(--accent); color: var(--primary); font-size: 0.7rem; padding: 3px 8px; border-radius: 10px; letter-spacing: 0.5px; font-weight: 600; } @media (max-width: 500px) { .container { padding: 15px; } .gallery-header h1 { font-size: 1.8rem; } .masonry-grid { grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); height: calc(100vh - 160px); max-height: 450px; } .tile { grid-row-end: span 24; } .tile.medium { grid-row-end: span 32; } .tile.large { grid-row-end: span 40; } } /* Custom animation for filter state transitions */ @keyframes tileReveal { 0% { opacity: 0; transform: scale(0.9) translateY(10px); } 100% { opacity: 1; transform: scale(1) translateY(0); } } .tile.reveal { animation: tileReveal 0.5s forwards; } /* Custom loader */ .loader { width: 40px; height: 40px; border: 3px solid var(--subtle); border-top: 3px solid var(--accent); border-radius: 50%; animation: spin 1s linear infinite; margin: 20px auto; } @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } /* Tile background subtle pattern */ .tile::before { content: ''; position: absolute; top: 0; left: 0; right: 0; bottom: 0; background-image: linear-gradient(to right, rgba(255,255,255,0.03) 1px, transparent 1px), linear-gradient(to bottom, rgba(255,255,255,0.03) 1px, transparent 1px); background-size: 15px 15px; pointer-events: none; z-index: 1; } </style> </head> <body> <div class="container"> <div class="gallery-header"> <h1>Lumière Gallery</h1> <div class="exhibition-badge">Summer Exhibition 2023</div> <p>A curated collection exploring light and form through contemporary expressions across diverse mediums and perspectives.</p> </div> <div class="filters"> <button class="filter-btn active" data-filter="all">All Works</button> <button class="filter-btn" data-filter="painting">Paintings</button> <button class="filter-btn" data-filter="sculpture">Sculpture</button> <button class="filter-btn" data-filter="photography">Photography</button> <button class="filter-btn" data-filter="mixed-media">Mixed Media</button> <button class="filter-btn" data-filter="digital">Digital Art</button> </div> <div class="masonry-grid"> <div class="no-results">No artworks match your current filter. Try another category.</div> </div> </div> <div class="expanded-view"> <button class="close-btn">×</button> <img class="expanded-img" src="" alt=""> <div class="expanded-info"> <h2></h2> <h3></h3> <p class="expanded-medium"></p> <p class="expanded-description"></p> </div> </div> <script> document.addEventListener('DOMContentLoaded', function() { const masonryGrid = document.querySelector('.masonry-grid'); const expandedView = document.querySelector('.expanded-view'); const closeBtn = document.querySelector('.close-btn'); const filterBtns = document.querySelectorAll('.filter-btn'); const noResults = document.querySelector('.no-results'); // Art collection data const artworks = [ { id: 1, title: "Ephemeral Light", artist: "Claire Montgomery", medium: "Oil on Canvas", category: "painting", size: "medium", imageUrl: "https://images.unsplash.com/photo-1549289524-06cf8837ace5?ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=80", description: "An atmospheric exploration of morning light as it diffuses through coastal fog, creating a sense of transition and impermanence." }, { id: 2, title: "Fragmented Structures #7", artist: "Liam Chen", medium: "Bronze and Glass", category: "sculpture", size: "large", imageUrl: "https://images.unsplash.com/photo-1576769267415-26cd1bc31325?ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=80", description: "Part of Chen's acclaimed series examining the relationship between industrial architecture and natural forms, cast in bronze with integrated glass elements." }, { id: 3, title: "Subterranean Echo", artist: "Maya Lindström", medium: "Digital Composition", category: "digital", size: "medium", imageUrl: "https://images.unsplash.com/photo-1618005182384-a83a8bd57fbe?ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=80", description: "A digital exploration inspired by underground acoustic phenomena, rendered through multiple algorithmic processes and hand manipulation." }, { id: 4, title: "Fractured Memory", artist: "Joaquin Reyes", medium: "Archival Pigment Print", category: "photography", size: "large", imageUrl: "https://images.unsplash.com/photo-1542038784456-1ea8e935640e?ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=80", description: "Through multiple exposures and intentional light leaks, Reyes explores the imperfect nature of memory and the passage of time." }, { id: 5, title: "Convergence Point", artist: "Sophia James", medium: "Acrylic and Metal Leaf", category: "painting", size: "medium", imageUrl: "https://images.unsplash.com/photo-1557672172-298e090bd0f1?ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=80", description: "Examining themes of interconnection through geometric abstraction with a complex layering technique that creates depth and luminosity." }, { id: 6, title: "Temporal Boundaries", artist: "Marcus Wei", medium: "Found Objects and Resin", category: "mixed-media", size: "large", imageUrl: "https://images.unsplash.com/photo-1536924940846-227afb31e2a5?ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=80", description: "Wei's assemblage incorporates salvaged objects from historic buildings, encased in resin to create a dialogue between preservation and transformation." }, { id: 7, title: "Velvet Revolution", artist: "Elena Petrovich", medium: "Wool and Copper Wire", category: "sculpture", size: "medium", imageUrl: "https://images.unsplash.com/photo-1552850953-f86f3728750e?ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=80", description: "A tactile exploration of contrast through the juxtaposition of soft wool fibers and rigid metallic elements, inviting touch while resisting manipulation." }, { id: 8, title: "Parallel Dimensions", artist: "Amara Washington", medium: "Mixed Media on Paper", category: "mixed-media", size: "medium", imageUrl: "https://images.unsplash.com/photo-1547891654-e66ed7ebb968?ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=80", description: "Washington combines traditional drawing techniques with digital printing and collage to create layered landscapes that exist between reality and imagination." }, { id: 9, title: "Nocturnal Descent", artist: "Thomas Blackwood", medium: "Night Photography", category: "photography", size: "medium", imageUrl: "https://images.unsplash.com/photo-1528459801416-a9e53bbf4e17?ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=80", description: "Captured during a single night in the mountains, this series documents the subtle shifts in light and shadow as darkness descends on the landscape." }, { id: 10, title: "Neural Pathways", artist: "Zara Kumar", medium: "Generative Art/Code", category: "digital", size: "medium", imageUrl: "https://images.unsplash.com/photo-1604871000636-074fa5117945?ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=80", description: "Created through custom algorithms that mimic neural networks, this piece evolves subtly over time, never displaying exactly the same configuration twice." } ]; // Initialize grid with resized tile heights function resizeTiles() { const tiles = document.querySelectorAll('.tile:not(.hide)'); tiles.forEach(tile => { const height = parseInt(getComputedStyle(tile.querySelector('.tile-img')).height); const rowSpan = Math.ceil(height / 10); // 10px is the grid-auto-rows value tile.style.gridRowEnd = `span ${rowSpan}`; }); } // Populate the grid with artwork tiles function populateGrid(artworks) { masonryGrid.innerHTML = '<div class="no-results">No artworks match your current filter. Try another category.</div>'; if (artworks.length === 0) { document.querySelector('.no-results').classList.add('show'); return; } document.querySelector('.no-results').classList.remove('show'); artworks.forEach((artwork, index) => { const tile = document.createElement('div'); tile.classList.add('tile', artwork.size); tile.dataset.category = artwork.category; tile.dataset.id = artwork.id; tile.style.animationDelay = `${index * 0.1}s`; tile.innerHTML = ` <img src="${artwork.imageUrl}" alt="${artwork.title}" class="tile-img"> <div class="tile-info"> <h3 class="tile-title">${artwork.title}</h3> <p class="tile-artist">${artwork.artist}</p> <p class="tile-medium">${artwork.medium}</p> </div> `; masonryGrid.appendChild(tile); tile.addEventListener('click', () => { openExpandedView(artwork); }); }); setTimeout(resizeTiles, 100); } // Initialize with all artworks populateGrid(artworks); // Filter functionality filterBtns.forEach(btn => { btn.addEventListener('click', () => { // Update active state filterBtns.forEach(b => b.classList.remove('active')); btn.classList.add('active'); const filter = btn.dataset.filter; let filteredArtworks; if (filter === 'all') { filteredArtworks = artworks; } else { filteredArtworks = artworks.filter(art => art.category === filter); } // Apply filter with animation populateGrid(filteredArtworks); // Animate new tiles const tiles = document.querySelectorAll('.tile'); tiles.forEach((tile, index) => { tile.classList.add('reveal'); tile.style.animationDelay = `${index * 0.05}s`; }); }); }); // Expanded view functionality function openExpandedView(artwork) { const expandedImg = document.querySelector('.expanded-img'); expandedImg.src = artwork.imageUrl; expandedImg.alt = artwork.title; document.querySelector('.expanded-info h2').textContent = artwork.title; document.querySelector('.expanded-info h3').textContent = artwork.artist; document.querySelector('.expanded-medium').textContent = artwork.medium; document.querySelector('.expanded-description').textContent = artwork.description; expandedView.classList.add('active'); document.body.style.overflow = 'hidden'; } closeBtn.addEventListener('click', () => { expandedView.classList.remove('active'); document.body.style.overflow = ''; }); // Close expanded view when clicking outside the image expandedView.addEventListener('click', (e) => { if (e.target === expandedView) { expandedView.classList.remove('active'); document.body.style.overflow = ''; } }); // Handle window resize window.addEventListener('resize', resizeTiles); // Escape key to close expanded view document.addEventListener('keydown', (e) => { if (e.key === 'Escape' && expandedView.classList.contains('active')) { expandedView.classList.remove('active'); document.body.style.overflow = ''; } }); }); </script> </body> </html>
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Wayfarer's Chronicle - Travel Blog</title> <style> :root { --primary-color: #e07a5f; --secondary-color: #3d405b; --light-color: #f4f1de; --accent-color: #81b29a; --warm-color: #f2cc8f; } * { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: 'Georgia', serif; background-color: var(--light-color); color: var(--secondary-color); line-height: 1.6; padding: 20px; overflow-x: hidden; max-width: 700px; margin: 0 auto; } header { text-align: center; margin-bottom: 30px; position: relative; } .logo { font-family: 'Playfair Display', 'Georgia', serif; font-size: 2.5rem; color: var(--primary-color); margin-bottom: 0; letter-spacing: 1px; position: relative; display: inline-block; } .logo::after { content: ""; position: absolute; bottom: -5px; left: 0; width: 100%; height: 2px; background: var(--primary-color); transform: scaleX(0); transform-origin: right; transition: transform 0.5s ease; } .logo:hover::after { transform: scaleX(1); transform-origin: left; } .tagline { font-style: italic; font-size: 1rem; color: var(--secondary-color); opacity: 0.8; } .masonry-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); grid-gap: 20px; grid-auto-flow: dense; margin-top: 30px; opacity: 0; transform: translateY(30px); animation: fade-in 1s ease forwards; } @keyframes fade-in { to { opacity: 1; transform: translateY(0); } } .blog-card { background: white; border-radius: 10px; overflow: hidden; box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1); transition: all 0.4s ease; opacity: 0; transform: scale(0.9); cursor: pointer; position: relative; } .blog-card.loaded { opacity: 1; transform: scale(1); } .blog-card:hover { transform: translateY(-10px); box-shadow: 0 15px 30px rgba(0, 0, 0, 0.2); } .blog-card:nth-child(3n+1) { grid-column: span 1; } .blog-card:nth-child(3n+2) { grid-column: span 1; } .blog-card:nth-child(3n) { grid-column: span 1; grid-row: span 2; } .blog-card:nth-child(5n) { grid-column: span 2; } @media (max-width: 600px) { .blog-card:nth-child(n) { grid-column: span 1; grid-row: span 1; } } .card-img-container { position: relative; padding-top: 70%; overflow: hidden; } .blog-card:nth-child(3n) .card-img-container { padding-top: 130%; } .card-img { position: absolute; top: 0; left: 0; width: 100%; height: 100%; object-fit: cover; transition: transform 0.7s ease; } .blog-card:hover .card-img { transform: scale(1.1); } .location-tag { position: absolute; top: 10px; right: 10px; background: var(--primary-color); color: white; padding: 5px 10px; border-radius: 20px; font-size: 0.7rem; font-family: 'Montserrat', sans-serif; text-transform: uppercase; letter-spacing: 1px; opacity: 0.9; transform: translateY(-20px); transition: transform 0.4s ease, opacity 0.4s ease; } .blog-card:hover .location-tag { transform: translateY(0); opacity: 1; } .card-content { padding: 15px; } .card-title { font-family: 'Playfair Display', 'Georgia', serif; font-size: 1.2rem; margin-bottom: 5px; color: var(--secondary-color); transition: color 0.3s ease; } .blog-card:hover .card-title { color: var(--primary-color); } .card-date { font-size: 0.8rem; color: #888; font-style: italic; margin-bottom: 10px; } .card-excerpt { font-size: 0.9rem; color: #555; margin-bottom: 15px; display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; } .read-more { font-family: 'Montserrat', sans-serif; font-size: 0.8rem; color: var(--primary-color); text-decoration: none; text-transform: uppercase; letter-spacing: 1px; position: relative; transition: color 0.3s ease; } .read-more::after { content: ""; position: absolute; bottom: -2px; left: 0; width: 100%; height: 1px; background: var(--primary-color); transform: scaleX(0); transform-origin: right; transition: transform 0.3s ease; } .blog-card:hover .read-more::after { transform: scaleX(1); transform-origin: left; } .modal { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0, 0, 0, 0.8); display: flex; justify-content: center; align-items: center; z-index: 1000; opacity: 0; pointer-events: none; transition: opacity 0.4s ease; } .modal.active { opacity: 1; pointer-events: all; } .modal-content { width: 90%; max-width: 600px; max-height: 90vh; background: white; border-radius: 10px; overflow-y: auto; padding: 20px; position: relative; transform: scale(0.9); transition: transform 0.4s ease; } .modal.active .modal-content { transform: scale(1); } .close-modal { position: absolute; top: 20px; right: 20px; background: var(--primary-color); color: white; width: 30px; height: 30px; border-radius: 50%; display: flex; justify-content: center; align-items: center; cursor: pointer; font-size: 1rem; border: none; } .modal-header { margin-bottom: 20px; } .modal-title { font-family: 'Playfair Display', 'Georgia', serif; font-size: 1.8rem; color: var(--secondary-color); margin-bottom: 10px; } .modal-location { font-style: italic; color: var(--primary-color); margin-bottom: 5px; } .modal-date { font-size: 0.9rem; color: #888; } .modal-img { width: 100%; height: 300px; object-fit: cover; border-radius: 5px; margin-bottom: 20px; } .modal-text { font-size: 1rem; line-height: 1.8; color: #555; } .modal-text p { margin-bottom: 15px; } .search-container { margin-bottom: 20px; display: flex; align-items: center; } .search-input { flex-grow: 1; padding: 10px 15px; border: 2px solid var(--warm-color); border-radius: 30px; font-family: 'Georgia', serif; font-size: 0.9rem; background: transparent; color: var(--secondary-color); transition: all 0.3s ease; } .search-input:focus { outline: none; border-color: var(--primary-color); box-shadow: 0 0 10px rgba(224, 122, 95, 0.3); } .search-input::placeholder { color: #aaa; font-style: italic; } .filter-btn { background: var(--primary-color); color: white; border: none; border-radius: 30px; padding: 10px 20px; margin-left: 10px; cursor: pointer; font-family: 'Montserrat', sans-serif; font-size: 0.8rem; text-transform: uppercase; letter-spacing: 1px; transition: all 0.3s ease; } .filter-btn:hover { background: var(--secondary-color); transform: translateY(-2px); box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1); } .no-results { text-align: center; grid-column: 1 / -1; padding: 40px; font-style: italic; color: var(--secondary-color); display: none; } .compass-loader { position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 60px; height: 60px; z-index: 1000; pointer-events: none; opacity: 0; transition: opacity 0.3s ease; } .compass-loader.active { opacity: 1; } .compass-loader svg { width: 100%; height: 100%; animation: spin 3s linear infinite; } @keyframes spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } } .filter-container { display: flex; flex-wrap: wrap; gap: 10px; margin-bottom: 20px; } .filter-tag { background: var(--warm-color); color: var(--secondary-color); padding: 5px 15px; border-radius: 20px; font-size: 0.8rem; cursor: pointer; transition: all 0.3s ease; } .filter-tag:hover, .filter-tag.active { background: var(--primary-color); color: white; } .scroll-to-top { position: fixed; bottom: 20px; right: 20px; width: 40px; height: 40px; background: var(--primary-color); color: white; border-radius: 50%; display: flex; justify-content: center; align-items: center; cursor: pointer; opacity: 0; transform: translateY(20px); transition: all 0.3s ease; z-index: 100; } .scroll-to-top.visible { opacity: 1; transform: translateY(0); } @media (max-width: 700px) { .logo { font-size: 2rem; } .masonry-grid { grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); grid-gap: 15px; } .card-title { font-size: 1rem; } .card-excerpt { -webkit-line-clamp: 2; } .filter-container { justify-content: center; } .search-container { flex-direction: column; } .filter-btn { margin-left: 0; margin-top: 10px; width: 100%; } } </style> </head> <body> <header> <h1 class="logo">Wayfarer's Chronicle</h1> <p class="tagline">Where every journey tells a story</p> </header> <div class="search-container"> <input type="text" class="search-input" placeholder="Search destinations or stories..."> <button class="filter-btn">Filter</button> </div> <div class="filter-container"> <div class="filter-tag" data-region="europe">Europe</div> <div class="filter-tag" data-region="asia">Asia</div> <div class="filter-tag" data-region="africa">Africa</div> <div class="filter-tag" data-region="americas">Americas</div> <div class="filter-tag" data-region="oceania">Oceania</div> <div class="filter-tag" data-tag="adventure">Adventure</div> <div class="filter-tag" data-tag="culture">Culture</div> <div class="filter-tag" data-tag="food">Food</div> </div> <div class="masonry-grid"> <div class="no-results">No stories match your search criteria.</div> <!-- Cards will be dynamically added here --> </div> <div class="modal"> <div class="modal-content"> <button class="close-modal">×</button> <div class="modal-header"> <h2 class="modal-title"></h2> <p class="modal-location"></p> <p class="modal-date"></p> </div> <img src="" alt="" class="modal-img"> <div class="modal-text"> <!-- Content will be dynamically added here --> </div> </div> </div> <div class="compass-loader"> <svg viewBox="0 0 100 100" fill="none" xmlns="http://www.w3.org/2000/svg"> <circle cx="50" cy="50" r="45" stroke="#e07a5f" stroke-width="2" /> <path d="M50 5 L50 95" stroke="#e07a5f" stroke-width="2" /> <path d="M5 50 L95 50" stroke="#e07a5f" stroke-width="2" /> <circle cx="50" cy="50" r="5" fill="#e07a5f" /> <path d="M50 50 L70 30" stroke="#e07a5f" stroke-width="2" stroke-linecap="round" /> <path d="M50 50 L40 60" stroke="#3d405b" stroke-width="2" stroke-linecap="round" /> </svg> </div> <div class="scroll-to-top">↑</div> <script> document.addEventListener('DOMContentLoaded', function() { // Blog post data const blogPosts = [ { id: 1, title: "Lost Among Lavender Fields of Provence", location: "Provence, France", date: "June 21, 2023", excerpt: "My week wandering through endless purple waves of fragrant lavender, stumbling upon ancient villages that time forgot.", image: "https://images.unsplash.com/photo-1499002238440-d264edd596ec?ixlib=rb-1.2.1&auto=format&fit=crop&w=1500&q=80", content: `<p>There's something magical about getting lost in Provence during lavender season. The morning air carries a sweet perfume that seems to whisper stories of old-world charm. I arrived in late June, when the purple blooms reach their peak—not by accident, but after months of planning this pilgrimage.</p> <p>I rented a small Citroën from a family-run agency in Avignon. The owner, Monsieur Laurent, marked a hand-drawn map with spots "only locals know about." His eyes twinkled as he said, "Follow this, and you'll see the real Provence."</p> <p>The Valensole Plateau stretched before me like an artist's canvas—rows of purple brushstrokes against an azure sky. I pulled over at an unmarked dirt path and walked among the fragrant rows. A local farmer, hands weathered from decades of harvests, showed me how to properly cut a sprig—"Angle the scissors, mademoiselle, like this," he demonstrated with calloused fingers.</p> <p>In the village of Sault, I discovered Chez Mathilde, where the elderly proprietress served lavender honey drizzled over fresh goat cheese. "My grandfather planted these fields in 1892," she told me, pointing to a sepia photograph on the wall. "The bees have been making our honey ever since."</p> <p>Time moves differently here. In village squares, locals play pétanque under plane trees that have witnessed centuries pass. At dusk, the light transforms the landscape into something ethereal—what the French call "l'heure bleue." It's no wonder painters have been drawn to this region for generations.</p>`, tags: ["europe", "culture"], region: "europe" }, { id: 2, title: "Midnight Sun and Ancient Fjords", location: "Lofoten Islands, Norway", date: "July 12, 2023", excerpt: "Kayaking under the midnight sun through crystalline fjords, where mountains rise straight from the sea.", image: "https://images.unsplash.com/photo-1516466723877-e4ec1d736c8a?ixlib=rb-1.2.1&auto=format&fit=crop&w=1500&q=80", content: `<p>The concept of night dissolves when you're paddling through a fjord at 1 AM, the sun still painting the sky in impossible shades of gold and rose. My arms ached from hours of kayaking, but I couldn't bear the thought of returning to shore while this otherworldly light show continued.</p> <p>I'd joined a small expedition led by Sigrid, a third-generation fisherwoman whose family has navigated these waters for over a century. "The sea is our highway, our field, our life," she explained as we pushed our kayaks into the glassy waters of Reinefjord.</p> <p>The vertical granite walls of the fjord create a cathedral-like space—sacred and humbling. Arctic terns dove around us, and once, a curious seal popped its head up mere meters from my paddle. Sigrid pointed to subtle marks high on the rock face: "That's where the sea level reached before the last ice age."</p> <p>We beached our kayaks on a sliver of white sand accessible only by water. Sigrid unwrapped homemade brown cheese and cloudberry jam on traditional lefse bread. "My grandmother's recipe," she said proudly. We ate in reverent silence, watching eagles soar above peaks still crowned with snow despite the summer warmth.</p> <p>In these islands, the boundary between land and sea feels as fluid as the boundary between day and night during the midnight sun. Time stretches and bends, and I found myself losing track of days, surrendering to the rhythm of tides and the endless circling of the sun.</p>`, tags: ["europe", "adventure"], region: "europe" }, { id: 3, title: "The Spice Routes of Zanzibar", location: "Stone Town, Zanzibar", date: "August 5, 2023", excerpt: "Exploring ancient trading pathways through narrow alleyways scented with cardamom, clove, and cinnamon.", image: "https://images.unsplash.com/photo-1548708613-8bb2e529a01c?ixlib=rb-1.2.1&auto=format&fit=crop&w=1500&q=80", content: `<p>Stone Town's labyrinthine streets are a sensory overload—a perfumer's dream and a cartographer's nightmare. I intentionally left my map at the hotel, surrendering to the joy of getting thoroughly lost within these ancient coral stone walls.</p> <p>On my second morning, I met Idris, a spice merchant whose family shop has occupied the same corner for seven generations. The small storefront concealed a cavernous space stacked floor to ceiling with burlap sacks of spices from across the Indian Ocean.</p> <p>"Close your eyes," Idris instructed, placing something in my palm. The warm, woody aroma of freshly grated nutmeg filled my senses. "This came by dhow from Maluku last month—the same journey it has made for a thousand years."</p> <p>We ventured deeper into the warren of alleys, passing elaborately carved wooden doors—each telling the story of its original owner through symbols and patterns. Idris pointed to a small brass stud on one particularly grand door. "Pineapples for hospitality, lotus flowers for prosperity, and chains to show the original owner's unfortunate involvement in the slave trade—history hides nothing here."</p> <p>At sunset, we climbed to a rooftop café where cardamom-infused coffee was served in tiny copper cups. Below us, the muezzin's call to prayer blended with the sound of children playing and the distant pulse of taarab music. Stone Town reveals itself slowly, Idris explained, "like good spices in a stew—layer by layer."</p>`, tags: ["africa", "food", "culture"], region: "africa" }, { id: 4, title: "Dawn Patrol: Surfing Remote Mentawai", location: "Mentawai Islands, Indonesia", date: "September 18, 2023", excerpt: "Two weeks aboard a traditional boat chasing perfect waves through Indonesia's most pristine archipelago.", image: "https://images.unsplash.com/photo-1502680390469-be75c86b636f?ixlib=rb-1.2.1&auto=format&fit=crop&w=1500&q=80", content: `<p>The wooden hull of our boat creaked as pre-dawn light began to filter through the cabin windows. Captain Budi, who had been navigating these waters since boyhood, gently knocked on my door. "Ombak bagus," he whispered—good waves.</p> <p>Within minutes, our small crew was on deck, squinting through the morning mist at perfect A-frame waves peeling over a reef that wasn't on any map. Our boat, a converted traditional phinisi schooner, had been tracing a meandering path through the Mentawai archipelago for nine days, always staying ahead of the crowded charter boats and guided tours.</p> <p>I paddled out alongside Wayan, a Balinese surfer who had been visiting these islands since before they became known to the outside world. "This reef is called 'Monkey's Tail' by the locals," he told me as we sat waiting for sets. "See how it curls around the bay?" In the distance, the dense jungle reached almost to the water's edge, occasionally rustling with the movement of wildlife.</p> <p>After a four-hour session, we returned to the boat where Lucas, our cook, had prepared freshly caught tuna with mango and chili. We ate on deck, studying nautical charts spread across a weathered table, plotting our course toward a swell approaching from the southwest.</p> <p>Night fell quickly, as it does near the equator, and soon the sky was ablaze with stars reflected in the glassy sea. The generator was turned off, and in the profound silence, punctuated only by the gentle lapping of water against the hull, Captain Budi pointed out constellations used by his ancestors for navigation. This simple existence—in rhythm with ocean swells and weather patterns—feels like the purest form of living.</p>`, tags: ["asia", "adventure"], region: "asia" }, { id: 5, title: "The Forgotten Libraries of Chinguetti", location: "Chinguetti, Mauritania", date: "October 10, 2023", excerpt: "Discovering ancient manuscripts preserved in desert libraries that have survived centuries of shifting sands.", image: "https://images.unsplash.com/photo-1633897064834-92fa19ecd711?ixlib=rb-1.2.1&auto=format&fit=crop&w=1500&q=80", content: `<p>The Sahara doesn't surrender its treasures easily. After three days crossing its vastness by 4x4, the ancient mud-brick minarets of Chinguetti emerged from the haze like a mirage. Once a bustling center of Islamic scholarship and a crucial stop on trans-Saharan trading routes, Chinguetti now battles the ever-encroaching desert, which has already swallowed half the old town.</p> <p>I was greeted by Sidi Mohammed, a seventh-generation keeper of one of the town's private libraries. His family has preserved their collection of manuscripts for over 700 years. "Each generation adds one room to the house and moves the books further from the shifting dunes," he explained, leading me through a modest doorway.</p> <p>Inside, the temperature dropped noticeably. Thick walls kept out both heat and sand. With reverent hands, Sidi opened a wooden chest containing texts written on gazelle skin—astronomy treatises, mathematical formulas, poetry, and medical knowledge from the 13th century. "This one," he said, carefully unfolding pages of a manuscript, "contains navigation methods for crossing the desert by starlight."</p> <p>The pages were covered in elegant Arabic script, with intricate geometric diagrams in faded crimson and indigo inks. Sidi explained how his ancestors made these inks from desert plants and minerals—recipes now preserved only in the very books they illuminate.</p> <p>At dusk, I sat on the rooftop of my simple guesthouse watching the sunset transform the dunes. The muezzin's call echoed across the town, virtually unchanged for centuries. In a world obsessed with the digital preservation of knowledge, there's profound wisdom in these caretakers who have protected physical books against all odds—passing not just the objects but the responsibility of guardianship from one generation to the next.</p>`, tags: ["africa", "culture"], region: "africa" }, { id: 6, title: "Tracing Japan's Kumano Kodo Pilgrimage", location: "Kii Peninsula, Japan", date: "November 5, 2023", excerpt: "Walking ancient pathways through misty forests to sacred shrines that have welcomed pilgrims for millennia.", image: "https://images.unsplash.com/photo-1492571350019-22de08371fd3?ixlib=rb-1.2.1&auto=format&fit=crop&w=1500&q=80", content: `<p>The stone path disappeared beneath a carpet of crimson maple leaves as I climbed higher into the mountains of the Kii Peninsula. For over a thousand years, imperial nobles and common farmers alike have walked these trails, collectively known as the Kumano Kodo, seeking spiritual renewal amidst some of Japan's most spectacular landscapes.</p> <p>I began my journey at Takijiri-oji, where a small Shinto shrine marks the entrance to the sacred mountains. An elderly couple performed a brief ritual before setting off up the trail ahead of me. The woman turned and, seeing me observing, invited me to clap twice and bow before proceeding—"To announce yourself to the mountain spirits," she explained with a gentle smile.</p> <p>The path ascended through towering cedars and cypress trees, some over 800 years old. Their massive trunks were occasionally marked with small stone Buddha statues, nearly hidden under moss and fallen leaves—placed by pilgrims centuries ago to protect travelers. At particularly steep sections, ancient builders had created stone stairs, worn into shallow depressions by countless footsteps over the ages.</p> <p>In the late afternoon, I arrived at a small minshuku (family-run inn) in a village of just eight houses. The proprietress, Yamada-san, had prepared a traditional meal of local mountain vegetables, wild boar hotpot, and matsutake mushrooms. "My family has been serving pilgrims for seventeen generations," she told me as she poured tea. "My great-great-grandmother's diary mentions a particularly harsh winter in 1854 when the pilgrims had to be dug out of snow."</p> <p>After dinner, I soaked in the inn's cedar ofuro (bath), easing the day's exertion from my muscles while listening to the sound of a mountain stream outside. There is a profound difference between being a tourist and being a pilgrim, I realized. One seeks to check off sights; the other understands that the journey itself is the destination. On the Kumano Kodo, you cannot help but become the latter.</p>`, tags: ["asia", "culture", "adventure"], region: "asia" }, { id: 7, title: "The Floating Markets of Dal Lake", location: "Srinagar, Kashmir", date: "April 28, 2023", excerpt: "Navigating early morning vegetable markets where Kashmiri farmers trade produce from boat to boat as their ancestors have for centuries.", image: "https://images.unsplash.com/photo-1566837497312-85c2f8b2e3e2?ixlib=rb-1.2.1&auto=format&fit=crop&w=1500&q=80", content: `<p>The alarm sounded at 4:30 AM, but I was already awake, listening to the gentle lapping of Dal Lake against my houseboat. Gulzar, my host and guide, had promised we would reach the floating market before dawn—"when the real magic happens," he assured me.</p> <p>We slipped into a traditional shikara boat, its wooden hull adorned with intricate carvings and cushioned with embroidered fabrics. Gulzar's teenage son, Firdous, paddled with practiced efficiency, navigating through narrow waterways between floating gardens where farmers grow tomatoes, cucumbers, and melons directly on the lake surface.</p> <p>The sky was just beginning to brighten when we reached a wide section of the lake where dozens of boats were converging. Unlike the tourist-oriented flower and handicraft sellers that appear later in the day, this was Kashmir's authentic agricultural market. Farmers brought produce harvested before dawn, arranging their goods in precarious towers within their wooden boats.</p> <p>Gulzar explained the intricate system of trade: "Watch how no money changes hands yet." Indeed, I observed complex bartering—lotus roots for kohlrabi, turnips for spinach. One elderly man's boat contained nothing but herbs and spices, carefully wrapped in lotus leaves. "His family has specialized in spices for generations," Firdous whispered.</p> <p>As the rising sun painted the distant Himalayas pink and gold, a boat approached selling Kashmir's famous pink chai. The vendor performed an elaborate pouring ritual, transferring the tea between vessels from increasing heights to create the perfect froth. Gulzar purchased three cups, and we sipped the salt-tinged beverage while watching the market gradually disperse.</p> <p>"This market has continued uninterrupted through empires, invasions, and conflicts," Gulzar said. "During the worst years of unrest, when the streets were too dangerous, the lake became our lifeline." In a world increasingly homogenized by global trade, this ancient commercial ecosystem, operating on trust and tradition, offers a glimpse into a more sustainable, community-based approach to commerce.</p>`, tags: ["asia", "food", "culture"], region: "asia" }, { id: 8, title: "Desert Stars: Night Photography in the Atacama", location: "San Pedro de Atacama, Chile", date: "May 15, 2023", excerpt: "Capturing the Milky Way in one of Earth's darkest skies, where the boundary between heaven and earth dissolves.", image: "https://images.unsplash.com/photo-1516339901601-2e1b62dc0c45?ixlib=rb-1.2.1&auto=format&fit=crop&w=1500&q=80", content: `<p>The thermometer read -5°C as I stepped out of the jeep, but the cold was immediately forgotten when I looked up. The night sky above the Atacama Desert defies description—a celestial tapestry so dense with stars that you can actually see their light reflected on the white salt flats below.</p> <p>My guide, Eduardo, is an astrophotographer who has been documenting these skies for twenty years. "The Atacama has over 300 clear nights annually and virtually no light pollution," he explained as he helped me set up my tripod. "Even veteran astronomers are humbled their first night here."</p> <p>We had driven far from San Pedro, past the Valley of the Moon, to a location Eduardo called "The Photographer's Secret"—a flat expanse where bizarre salt formations create otherworldly foregrounds beneath the cosmic display. As my eyes adjusted to the darkness, I could make out Eduardo's collection of carefully placed lights—small LEDs that would subtly illuminate the landscape during our long exposures without overwhelming the starlight.</p> <p>The Milky Way arched overhead like a luminous river. Eduardo pointed out features I'd never been able to see before—the dark dust lanes cutting through our galaxy, the reddish nebulae where new stars are being born, and the satellite galaxies visible as faint smudges to the naked eye.</p> <p>"The indigenous Atacameños believed the dark patches in the Milky Way were constellations—the negative space between stars represented animals and deities," Eduardo said as he adjusted my camera settings. "They saw not just the stars but the darkness between them as meaningful."</p> <p>Throughout the night, we moved to different locations, capturing star trails over ancient petroglyphs and the rotation of the southern celestial pole. By dawn, my memory cards were full, my fingers were numb, and my perception had been permanently altered. Back in San Pedro, drinking strong Chilean coffee as the sun rose over the volcanoes, I scrolled through images that seemed to belong to another world entirely—a reminder of how small we are, and how vast the universe.</p>`, tags: ["americas", "adventure"], region: "americas" }, { id: 9, title: "Ancient Rhythms: Tribal Festivals of Nagaland", location: "Kohima, Nagaland, India", date: "December 2, 2023", excerpt: "Joining the Hornbill Festival, where 16 tribes gather to celebrate their distinct cultural identities through dance, music, and traditional games.", image: "https://images.unsplash.com/photo-1513415564515-dee0131de397?ixlib=rb-1.2.1&auto=format&fit=crop&w=1500&q=80", content: `<p>The morning mist hung heavy over the hills surrounding Kisama Heritage Village as I made my way toward the festival grounds. Even from a distance, the deep, resonant beat of log drums announced that the day's celebrations had already begun—a heartbeat emanating from one of India's most remote and culturally rich regions.</p> <p>Nagaland, nestled in India's northeastern corner bordering Myanmar, was largely closed to outsiders until recently. Its sixteen major tribes maintained their unique traditions despite centuries of colonization and Christian missionary influence. The Hornbill Festival, named after the region's revered bird, represents a rare gathering of all these tribes in a celebration of cultural pride and identity.</p> <p>Each tribe has established a morung (traditional housing structure) at the festival site, recreating their distinct architectural styles. I was welcomed into the Angami tribe's morung by Kevisielie, a village elder whose face bore traditional tattoos that marked his status as a respected warrior. "Before the festival was established, many young people were losing interest in our ways," he told me while offering rice beer from a bamboo cup. "Now they come home from the cities to participate. They're proud again."</p> <p>Throughout the day, I witnessed competitions in indigenous games: greased bamboo pole climbing, chili eating contests, and the remarkable "stone pulling ceremony" where teams competed to drag massive monoliths using only ropes and wooden levers—a tradition linked to ancient megalithic cultures.</p> <p>The highlight came at sunset when warriors from the Konyak tribe, once fearsome headhunters, performed a battle dance. Adorned with hornbill feathers, wild boar tusks, and intricate beadwork, their synchronized movements told stories of past victories and tribal valor. The eldest dancers, some in their nineties, wore genuine tiger tooth necklaces and facial tattoos that signified successful headhunting raids—cultural practices now relegated to history but honored through these performances.</p> <p>"This is not folklore," explained Tangit, a young Konyak guide. "The elders you see dancing lived this life. They are our living libraries." In a rapidly homogenizing world, the Hornbill Festival offers a powerful reminder that cultural diversity represents humanity's greatest heritage—and that preservation of traditional knowledge often depends on the delicate balance between honoring the past and embracing the future.
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>TechPulse Dashboard</title> <style> :root { --primary: #2D3E50; --secondary: #3498DB; --accent: #1ABC9C; --danger: #E74C3C; --warning: #F39C12; --light: #ECF0F1; --dark: #2C3E50; --gray: #95A5A6; --transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1); } * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; } body { background-color: #f5f8fa; color: var(--dark); height: 100vh; overflow-x: hidden; padding: 15px; } .dashboard { width: 100%; max-width: 700px; margin: 0 auto; height: 670px; overflow-y: auto; scrollbar-width: thin; scrollbar-color: var(--secondary) var(--light); } .dashboard::-webkit-scrollbar { width: 6px; } .dashboard::-webkit-scrollbar-track { background: var(--light); } .dashboard::-webkit-scrollbar-thumb { background-color: var(--secondary); border-radius: 20px; } .header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; position: sticky; top: 0; background-color: rgba(245, 248, 250, 0.9); backdrop-filter: blur(10px); padding: 10px 0; z-index: 10; } .header h1 { font-size: 1.8rem; font-weight: 600; color: var(--primary); display: flex; align-items: center; } .header h1 span { color: var(--secondary); } .header h1::before { content: ''; display: inline-block; width: 12px; height: 12px; background-color: var(--accent); border-radius: 50%; margin-right: 10px; box-shadow: 0 0 0 rgba(26, 188, 156, 0.4); animation: pulse 2s infinite; } @keyframes pulse { 0% { box-shadow: 0 0 0 0 rgba(26, 188, 156, 0.4); } 70% { box-shadow: 0 0 0 10px rgba(26, 188, 156, 0); } 100% { box-shadow: 0 0 0 0 rgba(26, 188, 156, 0); } } .date-time { font-size: 0.9rem; color: var(--gray); font-weight: 500; } .user-profile { display: flex; align-items: center; cursor: pointer; transition: var(--transition); padding: 5px; border-radius: 20px; } .user-profile:hover { background-color: rgba(52, 152, 219, 0.1); } .user-avatar { width: 35px; height: 35px; border-radius: 50%; background-color: var(--secondary); display: flex; align-items: center; justify-content: center; color: white; font-weight: 600; margin-right: 8px; } .grid-container { display: grid; grid-template-columns: repeat(6, 1fr); grid-auto-rows: minmax(80px, auto); grid-gap: 15px; } .grid-item { background-color: white; border-radius: 12px; box-shadow: 0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24); padding: 15px; transition: var(--transition); position: relative; overflow: hidden; } .grid-item:hover { box-shadow: 0 14px 28px rgba(0,0,0,0.15), 0 10px 10px rgba(0,0,0,0.12); transform: translateY(-3px); } .item-1 { grid-column: span 3; grid-row: span 2; } .item-2 { grid-column: span 3; grid-row: span 1; } .item-3 { grid-column: span 2; grid-row: span 2; } .item-4 { grid-column: span 1; grid-row: span 2; } .item-5 { grid-column: span 3; grid-row: span 2; } .item-6 { grid-column: span 3; grid-row: span 1; } .item-7 { grid-column: span 2; grid-row: span 2; } .item-8 { grid-column: span 4; grid-row: span 2; } .widget-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px; } .widget-title { font-size: 0.9rem; font-weight: 600; color: var(--primary); display: flex; align-items: center; gap: 5px; } .widget-actions { display: flex; gap: 5px; } .widget-btn { width: 24px; height: 24px; border-radius: 50%; border: none; background-color: var(--light); color: var(--gray); display: flex; align-items: center; justify-content: center; cursor: pointer; transition: var(--transition); } .widget-btn:hover { background-color: var(--secondary); color: white; } .metrics-container { display: flex; flex-direction: column; height: calc(100% - 30px); justify-content: space-between; } .metric { display: flex; flex-direction: column; } .metric-value { font-size: 1.8rem; font-weight: 700; margin-bottom: 5px; color: var(--dark); } .metric-label { font-size: 0.8rem; color: var(--gray); } .metric-trend { display: flex; align-items: center; font-size: 0.8rem; margin-top: 5px; } .trend-up { color: var(--accent); } .trend-down { color: var(--danger); } .chart-container { height: 100%; position: relative; } .bar-chart { display: flex; align-items: flex-end; height: calc(100% - 40px); margin-top: 10px; gap: 8px; } .bar { flex: 1; background-color: var(--secondary); border-radius: 4px 4px 0 0; transition: var(--transition); position: relative; cursor: pointer; } .bar:hover { background-color: var(--accent); } .bar::after { content: attr(data-value); position: absolute; top: -25px; left: 50%; transform: translateX(-50%); background-color: var(--dark); color: white; padding: 3px 6px; border-radius: 4px; font-size: 0.7rem; opacity: 0; transition: var(--transition); } .bar:hover::after { opacity: 1; top: -20px; } .news-item { margin-bottom: 15px; cursor: pointer; transition: var(--transition); padding: 5px; border-radius: 5px; } .news-item:hover { background-color: rgba(52, 152, 219, 0.05); } .news-title { font-size: 0.9rem; font-weight: 600; margin-bottom: 5px; color: var(--dark); } .news-source { font-size: 0.7rem; color: var(--secondary); display: flex; align-items: center; gap: 5px; } .news-time { font-size: 0.7rem; color: var(--gray); } .task-list { display: flex; flex-direction: column; gap: 10px; height: calc(100% - 30px); overflow-y: auto; } .task-item { display: flex; align-items: center; padding: 8px; border-radius: 5px; transition: var(--transition); cursor: pointer; gap: 8px; } .task-item:hover { background-color: rgba(52, 152, 219, 0.05); } .task-checkbox { width: 18px; height: 18px; border-radius: 4px; border: 2px solid var(--gray); display: flex; align-items: center; justify-content: center; transition: var(--transition); } .task-item:hover .task-checkbox { border-color: var(--secondary); } .task-item.completed .task-checkbox { background-color: var(--accent); border-color: var(--accent); } .task-item.completed .task-checkbox::after { content: '✓'; color: white; font-size: 0.8rem; } .task-content { flex: 1; } .task-title { font-size: 0.85rem; font-weight: 500; color: var(--dark); } .task-item.completed .task-title { text-decoration: line-through; color: var(--gray); } .task-meta { display: flex; justify-content: space-between; font-size: 0.7rem; color: var(--gray); margin-top: 3px; } .notification-list { height: calc(100% - 30px); display: flex; flex-direction: column; gap: 8px; overflow-y: auto; } .notification-item { display: flex; gap: 10px; padding: 8px; border-radius: 5px; cursor: pointer; transition: var(--transition); } .notification-item:hover { background-color: rgba(52, 152, 219, 0.05); } .notification-icon { width: 30px; height: 30px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 0.8rem; color: white; } .icon-info { background-color: var(--secondary); } .icon-warning { background-color: var(--warning); } .icon-success { background-color: var(--accent); } .notification-content { flex: 1; } .notification-message { font-size: 0.8rem; margin-bottom: 3px; color: var(--dark); } .notification-time { font-size: 0.7rem; color: var(--gray); } .progress-container { height: 100%; display: flex; flex-direction: column; justify-content: space-around; } .progress-item { display: flex; flex-direction: column; gap: 5px; } .progress-label { display: flex; justify-content: space-between; font-size: 0.8rem; color: var(--dark); } .progress-bar { height: 6px; background-color: var(--light); border-radius: 3px; overflow: hidden; } .progress-fill { height: 100%; border-radius: 3px; transition: width 1s ease-in-out; } .fill-primary { background-color: var(--secondary); } .fill-success { background-color: var(--accent); } .fill-warning { background-color: var(--warning); } .calendar-widget { height: calc(100% - 30px); display: flex; flex-direction: column; } .calendar-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px; } .calendar-month { font-size: 0.9rem; font-weight: 600; color: var(--dark); } .calendar-nav { display: flex; gap: 5px; } .calendar-btn { width: 24px; height: 24px; border-radius: 50%; border: none; background-color: var(--light); color: var(--gray); display: flex; align-items: center; justify-content: center; cursor: pointer; transition: var(--transition); } .calendar-btn:hover { background-color: var(--secondary); color: white; } .calendar-days { display: grid; grid-template-columns: repeat(7, 1fr); gap: 5px; text-align: center; margin-bottom: 5px; } .day-name { font-size: 0.7rem; color: var(--gray); font-weight: 500; } .calendar-dates { display: grid; grid-template-columns: repeat(7, 1fr); gap: 5px; flex: 1; } .date-cell { font-size: 0.75rem; border-radius: 50%; display: flex; align-items: center; justify-content: center; height: 24px; cursor: pointer; transition: var(--transition); } .date-cell:hover:not(.empty-cell):not(.current-date) { background-color: rgba(52, 152, 219, 0.1); } .current-date { background-color: var(--secondary); color: white; } .has-event { position: relative; } .has-event::after { content: ''; position: absolute; width: 4px; height: 4px; background-color: var(--accent); border-radius: 50%; bottom: 2px; } .empty-cell { color: rgba(149, 165, 166, 0.3); } /* Activity Timeline */ .timeline { height: calc(100% - 30px); position: relative; overflow-y: auto; padding-left: 20px; } .timeline::before { content: ''; position: absolute; left: 0; top: 0; width: 2px; height: 100%; background-color: var(--light); } .timeline-item { position: relative; padding-bottom: 15px; } .timeline-item::before { content: ''; position: absolute; left: -24px; top: 0; width: 10px; height: 10px; border-radius: 50%; background-color: var(--secondary); } .timeline-content { padding-left: 5px; } .timeline-title { font-size: 0.85rem; font-weight: 500; color: var(--dark); margin-bottom: 3px; } .timeline-time { font-size: 0.7rem; color: var(--gray); } /* Resource boxes */ .resources { display: grid; grid-template-columns: repeat(2, 1fr); grid-gap: 10px; height: calc(100% - 30px); } .resource-box { background-color: rgba(52, 152, 219, 0.05); border-radius: 6px; padding: 10px; display: flex; flex-direction: column; gap: 5px; transition: var(--transition); cursor: pointer; } .resource-box:hover { background-color: rgba(52, 152, 219, 0.1); } .resource-icon { width: 40px; height: 40px; border-radius: 8px; display: flex; align-items: center; justify-content: center; margin-bottom: 5px; color: white; font-size: 1.2rem; } .resource-docs { background-color: var(--secondary); } .resource-tools { background-color: var(--accent); } .resource-api { background-color: var(--warning); } .resource-settings { background-color: var(--gray); } .resource-title { font-size: 0.8rem; font-weight: 600; color: var(--dark); } .resource-desc { font-size: 0.7rem; color: var(--gray); } .quick-stats { display: grid; grid-template-columns: repeat(2, 1fr); grid-gap: 10px; height: calc(100% - 30px); } .stat-box { background-color: #f8f9fa; border-radius: 8px; padding: 10px; display: flex; flex-direction: column; transition: var(--transition); } .stat-box:hover { transform: translateY(-2px); box-shadow: 0 5px 15px rgba(0,0,0,0.1); } .stat-value { font-size: 1.5rem; font-weight: 700; color: var(--primary); margin-bottom: 5px; } .stat-label { font-size: 0.7rem; color: var(--gray); } /* Responsive Adjustments */ @media (max-width: 600px) { .grid-container { grid-template-columns: repeat(2, 1fr); } .item-1, .item-2, .item-3, .item-4, .item-5, .item-6, .item-7, .item-8 { grid-column: span 2; grid-row: span 1; } .header h1 { font-size: 1.4rem; } } /* Animations */ @keyframes fadeIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } } .grid-item { animation: fadeIn 0.3s ease-out forwards; } .grid-item:nth-child(1) { animation-delay: 0.1s; } .grid-item:nth-child(2) { animation-delay: 0.2s; } .grid-item:nth-child(3) { animation-delay: 0.3s; } .grid-item:nth-child(4) { animation-delay: 0.4s; } .grid-item:nth-child(5) { animation-delay: 0.5s; } .grid-item:nth-child(6) { animation-delay: 0.6s; } .grid-item:nth-child(7) { animation-delay: 0.7s; } .grid-item:nth-child(8) { animation-delay: 0.8s; } /* Badge/Notification Styles */ .badge { position: absolute; top: -5px; right: -5px; background-color: var(--danger); color: white; width: 18px; height: 18px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 0.7rem; font-weight: 600; } /* Refresh Animation */ .rotate-animation { animation: rotate 1s linear; } @keyframes rotate { from { transform: rotate(0deg); } to { transform: rotate(360deg); } } /* Ripple Effect */ .ripple { position: relative; overflow: hidden; } .ripple::after { content: ""; display: block; position: absolute; width: 100%; height: 100%; top: 0; left: 0; pointer-events: none; background-image: radial-gradient(circle, #fff 10%, transparent 10.01%); background-repeat: no-repeat; background-position: 50%; transform: scale(10, 10); opacity: 0; transition: transform .5s, opacity 1s; } .ripple:active::after { transform: scale(0, 0); opacity: 0.3; transition: 0s; } </style> </head> <body> <div class="dashboard"> <div class="header"> <h1>Tech<span>Pulse</span></h1> <div class="date-time" id="datetime"></div> <div class="user-profile"> <div class="user-avatar">LP</div> </div> </div> <div class="grid-container"> <!-- Key Metrics --> <div class="grid-item item-1"> <div class="widget-header"> <div class="widget-title"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16"> <path d="M4 11a1 1 0 1 1 2 0v1a1 1 0 1 1-2 0v-1zm6-4a1 1 0 1 1 2 0v5a1 1 0 1 1-2 0V7zM7 9a1 1 0 0 1 2 0v3a1 1 0 1 1-2 0V9z"/> <path d="M4 1.5H3a2 2 0 0 0-2 2V14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V3.5a2 2 0 0 0-2-2h-1v1h1a1 1 0 0 1 1 1V14a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V3.5a1 1 0 0 1 1-1h1v-1z"/> <path d="M9.5 1a.5.5 0 0 1 .5.5v1a.5.5 0 0 1-.5.5h-3a.5.5 0 0 1-.5-.5v-1a.5.5 0 0 1 .5-.5h3zm-3-1A1.5 1.5 0 0 0 5 1.5v1A1.5 1.5 0 0 0 6.5 4h3A1.5 1.5 0 0 0 11 2.5v-1A1.5 1.5 0 0 0 9.5 0h-3z"/> </svg> Key Metrics </div> <div class="widget-actions"> <button class="widget-btn" id="refresh-metrics"> <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" fill="currentColor" viewBox="0 0 16 16"> <path fill-rule="evenodd" d="M8 3a5 5 0 1 0 4.546 2.914.5.5 0 0 1 .908-.417A6 6 0 1 1 8 2v1z"/> <path d="M8 4.466V.534a.25.25 0 0 1 .41-.192l2.36 1.966c.12.1.12.284 0 .384L8.41 4.658A.25.25 0 0 1 8 4.466z"/> </svg> </button> </div> </div> <div class="metrics-container"> <div class="metric"> <div class="metric-value" id="active-users">9,427</div> <div class="metric-label">Active users</div> <div class="metric-trend trend-up"> <svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" viewBox="0 0 16 16"> <path fill-rule="evenodd" d="M8 15a.5.5 0 0 0 .5-.5V2.707l3.146 3.147a.5.5 0 0 0 .708-.708l-4-4a.5.5 0 0 0-.708 0l-4 4a.5.5 0 1 0 .708.708L7.5 2.707V14.5a.5.5 0 0 0 .5.5z"/> </svg> 8.5% from last week </div> </div> <div class="metric"> <div class="metric-value" id="conversion-rate">32.8%</div> <div class="metric-label">Conversion rate</div> <div class="metric-trend trend-up"> <svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" viewBox="0 0 16 16"> <path fill-rule="evenodd" d="M8 15a.5.5 0 0 0 .5-.5V2.707l3.146 3.147a.5.5 0 0 0 .708-.708l-4-4a.5.5 0 0 0-.708 0l-4 4a.5.5 0 1 0 .708.708L7.5 2.707V14.5a.5.5 0 0 0 .5.5z"/> </svg> 2.3% from last week </div> </div> <div class="metric"> <div class="metric-value" id="revenue">$128,745</div> <div class="metric-label">Monthly revenue</div> <div class="metric-trend trend-down"> <svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" viewBox="0 0 16 16"> <path fill-rule="evenodd" d="M8 1a.5.5 0 0 1 .5.5v11.793l3.146-3.147a.5.5 0 0 1 .708.708l-4 4a.5.5 0 0 1-.708 0l-4-4a.5.5 0 0 1 .708-.708L7.5 13.293V1.5A.5.5 0 0 1 8 1z"/> </svg> 3.7% from last month </div> </div> </div> </div> <!-- Performance Chart --> <div class="grid-item item-2"> <div class="widget-header"> <div class="widget-title"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16"> <path d="M0 0h1v15h15v1H0V0Zm10 11.5a.5.5 0 0 0 .5.5h4a.5.5 0 0 0 .5-.5v-4a.5.5 0 0 0-1 0v2.6l-3.613-4.417a.5.5 0 0 0-.74-.037L7.06 8.233 3.404 3.206a.5.5 0 0 0-.808.588l4 5.5a.5.5 0 0 0 .758.06l2.609-2.61L13.445 11H10.5a.5.5 0 0 0-.5.5Z"/> </svg> API Performance </div> <div class="widget-actions"> <button class="widget-btn"> <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" fill="currentColor" viewBox="0 0 16 16"> <path d="M3 9.5a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3zm5 0a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3zm5 0a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3z"/> </svg> </button> </div> </div> <div class="chart-container"> <div class="bar-chart" id="api-chart"> <div class="bar" data-value="95ms" style="height: 60%;"></div> <div class="bar" data-value="87ms" style="height: 75%;"></div> <div class="bar" data-value="112ms" style="height: 40%;"></div> <div class="bar" data-value="92ms" style="height: 65%;"></div> <div class="bar" data-value="78ms" style="height: 85%;"></div> <div class="bar" data-value="82ms" style="height: 80%;"></div> <div class="bar" data-value="76ms" style="height: 90%;"></div> </div> </div> </div> <!-- Tech News --> <div class="grid-item item-3"> <div class="widget-header"> <div class="widget-title"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16"> <path d="M0 2.5A1.5 1.5 0 0 1 1.5 1h11A1.5 1.5 0 0 1 14 2.5v10.528c0 .3-.05.654-.238.972h.738a.5.5 0 0 0 .5-.5v-9a.5.5 0 0 1 1 0v9a1.5 1.5 0 0 1-1.5 1.5H1.497A1.497 1.497 0 0 1 0 13.5v-11zM12 14c.37 0 .654-.211.853-.441.092-.106.147-.279.147-.531V2.5a.5.5 0 0 0-.5-.5h-11a.5.5 0 0 0-.5.5v11c0 .278.223.5.497.5H12z"/> <path d="M2 3h10v2H2V3zm0 3h4v3H2V6zm0 4h4v1H2v-1zm0 2h4v1H2v-1zm5-6h2v1H7V6zm3 0h2v1h-2V6zM7 8h2v1H7V8zm3 0h2v1h-2V8zm-3 2h2v1H7v-1zm3 0h2v1h-2v-1zm-3 2h2v1H7v-1zm3 0h2v1h-2v-1z"/> </svg> Tech News </div> <div class="widget-actions"> <button class="widget-btn" id="refresh-news"> <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" fill="currentColor" viewBox="0 0 16 16"> <path fill-rule="evenodd" d="M8 3a5 5 0 1 0 4.546 2.914.5.5 0 0 1 .908-.417A6 6 0 1 1 8 2v1z"/> <path d="M8 4.466V.534a.25.25 0 0 1 .41-.192l2.36 1.966c.12.1.12.284 0 .384L8.41 4.658A.25.25 0 0 1 8 4.466z"/> </svg> </button> </div> </div> <div class="news-list"> <div class="news-item"> <div class="news-title">Quantum Computing Breakthrough: 128-Qubit Processor Achieves Quantum Supremacy</div> <div class="news-source"> <svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" viewBox="0 0 16 16"> <path d="M11 6.5a.5.5 0 0 1 .5-.5h1a.5.5 0 0 1 .5.5v1a.5.5 0 0 1-.5.5h-1a.5.5 0 0 1-.5-.5v-1zm-3 0a.5.5 0 0 1 .5-.5h1a.5.5 0 0 1 .5.5v1a.5.5 0 0 1-.5.5h-1a.5.5 0 0 1-.5-.5v-1zm-5 3a.5.5 0 0 1 .5-.5h1a.5.5 0 0 1 .5.5v1a.5.5 0 0 1-.5.5h-1a.5.5 0 0 1-.5-.5v-1zm3 0a.5.5 0 0 1 .5-.5h1a.5.5 0 0 1 .5.5v1a.5.5 0 0 1-.5.5h-1a.5.5 0 0 1-.5-.5v-1z"/> <path d="M3.5 0a.5.5 0 0 1 .5.5V1h8V.5a.5.5 0 0 1 1 0V1h1a2 2 0 0 1 2 2v11a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V3a2 2 0 0 1 2-2
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Spectacular Events Portfolio</title> <style> :root { --primary: #FF3E6C; --secondary: #4A00E0; --accent1: #FFC107; --accent2: #00BCD4; --dark: #1A1A2E; --light: #F8F9FA; --transition: all 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275); } * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif; } body { background-color: var(--light); color: var(--dark); overflow-x: hidden; height: 100vh; line-height: 1.6; } .container { max-width: 100%; padding: 0 10px; margin: 0 auto; overflow-y: auto; height: 700px; max-height: 700px; scrollbar-width: thin; scrollbar-color: var(--secondary) var(--light); } .container::-webkit-scrollbar { width: 8px; } .container::-webkit-scrollbar-track { background: var(--light); border-radius: 10px; } .container::-webkit-scrollbar-thumb { background: var(--secondary); border-radius: 10px; } header { text-align: center; padding: 20px 15px; position: sticky; top: 0; z-index: 1000; background: rgba(248, 249, 250, 0.95); backdrop-filter: blur(10px); border-bottom: 1px solid rgba(0, 0, 0, 0.05); } h1 { font-size: 28px; margin-bottom: 5px; background: linear-gradient(45deg, var(--primary), var(--secondary)); -webkit-background-clip: text; background-clip: text; color: transparent; font-weight: 800; letter-spacing: -0.5px; } .subtitle { font-size: 14px; color: rgba(26, 26, 46, 0.7); margin-bottom: 15px; } .filters { display: flex; gap: 10px; justify-content: center; margin-bottom: 15px; flex-wrap: wrap; } .filter-btn { background: transparent; border: 2px solid var(--secondary); color: var(--secondary); padding: 8px 16px; border-radius: 50px; cursor: pointer; font-weight: 600; font-size: 12px; transition: var(--transition); outline: none; } .filter-btn:hover, .filter-btn.active { background: var(--secondary); color: white; transform: translateY(-2px); box-shadow: 0 4px 12px rgba(74, 0, 224, 0.2); } .masonry-grid { column-count: 2; column-gap: 15px; padding: 0 5px 20px; } @media (min-width: 600px) { .masonry-grid { column-count: 3; } } .event-card { break-inside: avoid; margin-bottom: 15px; position: relative; border-radius: 12px; overflow: hidden; background: white; box-shadow: 0 4px 15px rgba(0, 0, 0, 0.05); transform: translateY(0); transition: var(--transition); } .event-card:hover { transform: translateY(-5px); box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1); } .event-image { width: 100%; height: auto; display: block; aspect-ratio: 1 / 1; object-fit: cover; transition: var(--transition); } .event-card:hover .event-image { transform: scale(1.05); } .event-info { padding: 15px; position: relative; } .event-date { display: inline-block; background: var(--accent1); color: var(--dark); padding: 4px 10px; font-size: 11px; font-weight: 700; border-radius: 30px; margin-bottom: 8px; transform: translateY(0); transition: var(--transition); } .event-card:hover .event-date { transform: translateY(-2px); } .event-title { font-size: 16px; font-weight: 700; margin-bottom: 6px; color: var(--dark); line-height: 1.3; } .event-location { font-size: 12px; color: rgba(26, 26, 46, 0.6); display: flex; align-items: center; margin-bottom: 10px; } .event-location::before { content: "📍"; margin-right: 5px; } .event-description { font-size: 13px; color: rgba(26, 26, 46, 0.8); margin-bottom: 12px; display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; transition: var(--transition); } .event-card:hover .event-description { color: var(--dark); } .tag-container { display: flex; flex-wrap: wrap; gap: 6px; } .event-tag { font-size: 10px; background: rgba(74, 0, 224, 0.1); color: var(--secondary); padding: 3px 8px; border-radius: 4px; font-weight: 600; } .event-tag.corporate { background: rgba(0, 188, 212, 0.1); color: var(--accent2); } .event-tag.wedding { background: rgba(255, 62, 108, 0.1); color: var(--primary); } .event-tag.festival { background: rgba(255, 193, 7, 0.1); color: #FF8F00; } .highlight-badge { position: absolute; top: 15px; right: 15px; background: var(--accent2); color: white; padding: 4px 10px; border-radius: 30px; font-size: 10px; font-weight: 700; box-shadow: 0 4px 10px rgba(0, 188, 212, 0.3); opacity: 0; transform: translateY(-10px); transition: var(--transition); } .event-card:hover .highlight-badge { opacity: 1; transform: translateY(0); } .featured .highlight-badge { background: var(--primary); box-shadow: 0 4px 10px rgba(255, 62, 108, 0.3); } .featured .event-image { aspect-ratio: 4 / 3; } .empty-state { text-align: center; padding: 60px 20px; display: none; } .empty-state img { width: 120px; height: auto; margin-bottom: 20px; opacity: 0.7; } .empty-state h3 { font-size: 18px; margin-bottom: 10px; color: var(--dark); } .empty-state p { font-size: 14px; color: rgba(26, 26, 46, 0.6); max-width: 300px; margin: 0 auto; } .shimmer { position: relative; overflow: hidden; } .shimmer::after { content: ''; position: absolute; top: 0; right: 0; width: 100%; height: 100%; background: linear-gradient( 90deg, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.5) 50%, rgba(255, 255, 255, 0) 100% ); animation: shimmer 2s infinite; } @keyframes shimmer { 0% { transform: translateX(-100%); } 100% { transform: translateX(100%); } } @keyframes float { 0% { transform: translateY(0px); } 50% { transform: translateY(-5px); } 100% { transform: translateY(0px); } } .floating { animation: float 3s ease-in-out infinite; } </style> </head> <body> <div class="container"> <header> <h1>Spectacular Events</h1> <p class="subtitle">Creating unforgettable moments since 2015</p> <div class="filters"> <button class="filter-btn active" data-filter="all">All Events</button> <button class="filter-btn" data-filter="corporate">Corporate</button> <button class="filter-btn" data-filter="wedding">Weddings</button> <button class="filter-btn" data-filter="festival">Festivals</button> <button class="filter-btn" data-filter="conference">Conferences</button> </div> </header> <div class="masonry-grid" id="eventsGrid"> <div class="event-card featured" data-category="corporate"> <div class="highlight-badge">Featured</div> <img src="https://images.unsplash.com/photo-1540575467063-178a50c2df87?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=1170&q=80" alt="TechCorp Annual Summit" class="event-image"> <div class="event-info"> <div class="event-date">May 15, 2023</div> <h3 class="event-title">TechCorp Annual Summit</h3> <p class="event-location">Hyatt Downtown, San Francisco</p> <p class="event-description">A three-day innovation conference featuring keynotes from tech leaders, interactive workshops, and product launches that positioned TechCorp as an industry thought leader.</p> <div class="tag-container"> <span class="event-tag corporate">Corporate</span> <span class="event-tag">500+ Attendees</span> <span class="event-tag">Tech</span> </div> </div> </div> <div class="event-card" data-category="wedding"> <img src="https://images.unsplash.com/photo-1519741497674-611481863552?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=1170&q=80" alt="Emma & James Wedding" class="event-image"> <div class="event-info"> <div class="event-date">June 28, 2023</div> <h3 class="event-title">Emma & James Wedding</h3> <p class="event-location">Rosewood Estate, Napa Valley</p> <p class="event-description">An intimate vineyard wedding featuring custom floral installations, farm-to-table dining, and a sunset ceremony overlooking the valley.</p> <div class="tag-container"> <span class="event-tag wedding">Wedding</span> <span class="event-tag">150 Guests</span> <span class="event-tag">Outdoor</span> </div> </div> </div> <div class="event-card" data-category="festival"> <img src="https://images.unsplash.com/photo-1492684223066-81342ee5ff30?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=1170&q=80" alt="Summer Beats Festival" class="event-image"> <div class="event-info"> <div class="event-date">July 8-10, 2023</div> <h3 class="event-title">Summer Beats Festival</h3> <p class="event-location">Grant Park, Chicago</p> <p class="event-description">A multi-stage music festival featuring 42 artists across genres, interactive art installations, and sustainable food vendors that attracted a record crowd.</p> <div class="tag-container"> <span class="event-tag festival">Festival</span> <span class="event-tag">15K+ Attendees</span> <span class="event-tag">Music</span> </div> </div> </div> <div class="event-card" data-category="corporate"> <div class="highlight-badge">Client Favorite</div> <img src="https://images.unsplash.com/photo-1556761175-4b46a572b786?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=1074&q=80" alt="FinTech Innovation Awards" class="event-image"> <div class="event-info"> <div class="event-date">March 22, 2023</div> <h3 class="event-title">FinTech Innovation Awards</h3> <p class="event-location">Plaza Hotel, New York</p> <p class="event-description">An elegant gala recognizing breakthrough financial technologies, featuring interactive demos, celebrity hosts, and a champagne reception.</p> <div class="tag-container"> <span class="event-tag corporate">Corporate</span> <span class="event-tag">300 Attendees</span> <span class="event-tag">Finance</span> </div> </div> </div> <div class="event-card" data-category="conference"> <img src="https://images.unsplash.com/photo-1587825140708-dfaf72ae4b04?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=1170&q=80" alt="Healthcare Innovation Summit" class="event-image"> <div class="event-info"> <div class="event-date">April 15, 2023</div> <h3 class="event-title">Healthcare Innovation Summit</h3> <p class="event-location">Convention Center, Boston</p> <p class="event-description">A conference focused on cutting-edge medical technologies and practices, featuring virtual reality demonstrations and networking sessions with healthcare leaders.</p> <div class="tag-container"> <span class="event-tag">Conference</span> <span class="event-tag">600+ Attendees</span> <span class="event-tag">Healthcare</span> </div> </div> </div> <div class="event-card" data-category="wedding"> <img src="https://images.unsplash.com/photo-1465495976277-4387d4b0b4c6?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=1170&q=80" alt="Alex & Sarah Destination Wedding" class="event-image"> <div class="event-info"> <div class="event-date">February 14, 2023</div> <h3 class="event-title">Alex & Sarah Destination Wedding</h3> <p class="event-location">Tulum Beach Resort, Mexico</p> <p class="event-description">A four-day celebration combining traditional ceremonies with beachfront activities, featuring custom cocktails and local cultural performances.</p> <div class="tag-container"> <span class="event-tag wedding">Wedding</span> <span class="event-tag">80 Guests</span> <span class="event-tag">Destination</span> </div> </div> </div> <div class="event-card featured" data-category="festival"> <div class="highlight-badge">Featured</div> <img src="https://images.unsplash.com/photo-1514525253161-7a46d19cd819?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=1074&q=80" alt="Winter Lights Festival" class="event-image"> <div class="event-info"> <div class="event-date">December 10-20, 2022</div> <h3 class="event-title">Winter Lights Festival</h3> <p class="event-location">Civic Park, Portland</p> <p class="event-description">A community celebration featuring interactive light installations by 24 artists, food trucks, live music, and family-friendly activities that transformed the city park.</p> <div class="tag-container"> <span class="event-tag festival">Festival</span> <span class="event-tag">20K+ Visitors</span> <span class="event-tag">Art</span> </div> </div> </div> <div class="event-card" data-category="conference"> <img src="https://images.unsplash.com/photo-1515187029135-18ee286d815b?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=1170&q=80" alt="Marketing Masters Conference" class="event-image"> <div class="event-info"> <div class="event-date">September 5, 2023</div> <h3 class="event-title">Marketing Masters Conference</h3> <p class="event-location">Marriott Marquis, Atlanta</p> <p class="event-description">A two-day digital marketing conference with hands-on workshops, AI demo stations, and personalized strategy sessions led by industry experts.</p> <div class="tag-container"> <span class="event-tag">Conference</span> <span class="event-tag">450 Attendees</span> <span class="event-tag">Marketing</span> </div> </div> </div> </div> <div class="empty-state" id="emptyState"> <img src="https://assets.codepen.io/t-1/undraw_empty_street_sfxm.svg" alt="No events found" class="floating"> <h3>No events found</h3> <p>Try selecting a different category or check back later for new events.</p> </div> </div> <script> document.addEventListener('DOMContentLoaded', function() { // Filter buttons functionality const filterBtns = document.querySelectorAll('.filter-btn'); const eventCards = document.querySelectorAll('.event-card'); const emptyState = document.getElementById('emptyState'); const eventsGrid = document.getElementById('eventsGrid'); // Add click event to filter buttons filterBtns.forEach(btn => { btn.addEventListener('click', () => { // Remove active class from all buttons filterBtns.forEach(b => b.classList.remove('active')); // Add active class to clicked button btn.classList.add('active'); const filter = btn.getAttribute('data-filter'); let visibleCount = 0; // Show/hide cards based on filter eventCards.forEach(card => { const category = card.getAttribute('data-category'); if (filter === 'all' || category === filter) { card.style.display = 'block'; // Add a staggered animation effect card.style.opacity = '0'; card.style.transform = 'translateY(20px)'; setTimeout(() => { card.style.opacity = '1'; card.style.transform = 'translateY(0)'; }, visibleCount * 50); visibleCount++; } else { card.style.display = 'none'; } }); // Show empty state if no cards visible if (visibleCount === 0) { emptyState.style.display = 'block'; eventsGrid.style.display = 'none'; } else { emptyState.style.display = 'none'; eventsGrid.style.display = 'block'; } }); }); // Simulate loading animations eventCards.forEach((card, index) => { card.style.opacity = '0'; card.style.transform = 'translateY(20px)'; setTimeout(() => { card.style.opacity = '1'; card.style.transform = 'translateY(0)'; }, 100 + index * 100); }); // Optional: Add random shimmer effect to some cards periodically setInterval(() => { const randomCard = eventCards[Math.floor(Math.random() * eventCards.length)]; randomCard.classList.add('shimmer'); setTimeout(() => { randomCard.classList.remove('shimmer'); }, 2000); }, 5000); }); </script> </body> </html>
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Savory Seasons - Food & Recipe Blog</title> <style> :root { --primary: #ff6b6b; --secondary: #4ecdc4; --accent: #ffe66d; --text: #2d3436; --light: #f9f7f7; --dark: #333333; --shadow: rgba(0, 0, 0, 0.1); } * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Poppins', sans-serif; } body { background-color: var(--light); color: var(--text); overflow-x: hidden; max-width: 700px; height: 700px; margin: 0 auto; position: relative; } .container { padding: 20px; height: 100%; overflow-y: auto; scrollbar-width: thin; } .container::-webkit-scrollbar { width: 5px; } .container::-webkit-scrollbar-thumb { background-color: var(--primary); border-radius: 10px; } header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; position: relative; } .logo { display: flex; align-items: center; gap: 10px; } .logo h1 { font-size: 1.8rem; font-weight: 700; color: var(--primary); letter-spacing: 0.5px; } .logo-icon { width: 40px; height: 40px; display: flex; align-items: center; justify-content: center; position: relative; } .logo-icon svg { width: 100%; height: 100%; } .menu-btn { background: none; border: none; cursor: pointer; display: flex; flex-direction: column; gap: 6px; z-index: 101; } .menu-btn span { display: block; width: 25px; height: 3px; background-color: var(--primary); border-radius: 3px; transition: all 0.3s ease; } .menu-btn.active span:nth-child(1) { transform: translateY(9px) rotate(45deg); } .menu-btn.active span:nth-child(2) { opacity: 0; } .menu-btn.active span:nth-child(3) { transform: translateY(-9px) rotate(-45deg); } .menu { position: absolute; top: 0; right: -100%; width: 200px; height: 100%; background-color: var(--light); box-shadow: -5px 0 15px var(--shadow); z-index: 100; padding: 80px 20px 20px; transition: right 0.3s ease; } .menu.active { right: 0; } .menu ul { list-style: none; } .menu li { margin-bottom: 15px; } .menu a { text-decoration: none; color: var(--text); font-weight: 500; font-size: 1.1rem; transition: color 0.3s ease; position: relative; } .menu a::before { content: ''; position: absolute; bottom: -2px; left: 0; width: 0; height: 2px; background-color: var(--primary); transition: width 0.3s ease; } .menu a:hover { color: var(--primary); } .menu a:hover::before { width: 100%; } .search-bar { display: flex; align-items: center; background-color: #fff; border-radius: 30px; padding: 10px 15px; margin-bottom: 25px; box-shadow: 0 3px 10px var(--shadow); transition: all 0.3s ease; position: relative; } .search-bar:focus-within { box-shadow: 0 5px 15px var(--shadow); } .search-bar input { width: 100%; border: none; outline: none; padding: 0 10px; font-size: 0.9rem; color: var(--text); } .search-bar button { background: var(--primary); border: none; border-radius: 50%; width: 30px; height: 30px; display: flex; align-items: center; justify-content: center; cursor: pointer; transition: all 0.3s ease; } .search-bar button:hover { background: #ff5252; transform: scale(1.05); } .search-bar button svg { fill: white; width: 15px; height: 15px; } .filter-tags { display: flex; flex-wrap: wrap; gap: 10px; margin-bottom: 25px; } .filter-tag { background-color: white; border: 2px solid var(--secondary); border-radius: 20px; padding: 5px 15px; font-size: 0.8rem; font-weight: 500; color: var(--text); cursor: pointer; transition: all 0.3s ease; position: relative; overflow: hidden; } .filter-tag.active { background-color: var(--secondary); color: white; } .filter-tag:hover { transform: translateY(-3px); box-shadow: 0 5px 10px var(--shadow); } .filter-tag::after { content: ''; position: absolute; top: 50%; left: 50%; width: 100px; height: 100px; background-color: rgba(255, 255, 255, 0.2); border-radius: 50%; transform: translate(-50%, -50%) scale(0); transition: transform 0.5s ease; } .filter-tag:active::after { transform: translate(-50%, -50%) scale(1); opacity: 0; transition: transform 0.5s ease, opacity 0.3s ease 0.2s; } .masonry-grid { column-count: 2; column-gap: 15px; margin-bottom: 20px; } .recipe-card { break-inside: avoid; margin-bottom: 15px; background-color: white; border-radius: 15px; overflow: hidden; box-shadow: 0 5px 15px var(--shadow); transition: all 0.3s ease; cursor: pointer; transform: scale(1); position: relative; } .recipe-card:hover { transform: translateY(-10px); box-shadow: 0 15px 30px var(--shadow); } .recipe-img { width: 100%; height: 180px; object-fit: cover; border-radius: 15px 15px 0 0; transition: all 0.5s ease; } .recipe-card:hover .recipe-img { transform: scale(1.05); } .recipe-content { padding: 15px; position: relative; } .recipe-tag { position: absolute; top: -12px; right: 15px; background-color: var(--primary); color: white; font-size: 0.7rem; font-weight: 600; padding: 3px 10px; border-radius: 10px; box-shadow: 0 3px 10px rgba(255, 107, 107, 0.3); } .recipe-title { font-size: 1rem; font-weight: 600; margin-bottom: 10px; line-height: 1.4; color: var(--dark); } .recipe-meta { display: flex; justify-content: space-between; font-size: 0.75rem; color: #666; } .recipe-meta span { display: flex; align-items: center; gap: 5px; } .recipe-meta svg { width: 14px; height: 14px; fill: var(--secondary); } .recipe-card.expanded { position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 90%; max-width: 600px; height: auto; max-height: 80vh; z-index: 1000; overflow-y: auto; } .recipe-details { padding: 0 15px 15px; height: 0; overflow: hidden; transition: height 0.3s ease; } .recipe-details.visible { height: auto; margin-top: 10px; } .recipe-details h4 { font-size: 0.9rem; font-weight: 600; margin-bottom: 10px; color: var(--primary); } .ingredients-list { list-style: none; margin-bottom: 15px; } .ingredients-list li { font-size: 0.85rem; margin-bottom: 5px; padding-left: 20px; position: relative; } .ingredients-list li::before { content: ''; position: absolute; left: 0; top: 50%; width: 6px; height: 6px; background-color: var(--secondary); border-radius: 50%; transform: translateY(-50%); } .cooking-steps { list-style: none; counter-reset: step-counter; } .cooking-steps li { font-size: 0.85rem; margin-bottom: 10px; padding-left: 25px; position: relative; } .cooking-steps li::before { counter-increment: step-counter; content: counter(step-counter); position: absolute; left: 0; top: 2px; width: 18px; height: 18px; background-color: var(--accent); border-radius: 50%; font-size: 0.7rem; font-weight: 600; display: flex; align-items: center; justify-content: center; color: var(--dark); } .close-recipe { position: absolute; top: 10px; right: 10px; background-color: rgba(255, 255, 255, 0.8); border-radius: 50%; width: 30px; height: 30px; display: flex; align-items: center; justify-content: center; cursor: pointer; z-index: 10; border: none; transition: all 0.3s ease; } .close-recipe:hover { background-color: var(--primary); } .close-recipe svg { width: 15px; height: 15px; fill: var(--text); transition: fill 0.3s ease; } .close-recipe:hover svg { fill: white; } .overlay { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(0, 0, 0, 0.5); opacity: 0; visibility: hidden; transition: all 0.3s ease; z-index: 999; } .overlay.visible { opacity: 1; visibility: visible; } .hand-drawn { position: absolute; width: 80px; height: 80px; opacity: 0.8; pointer-events: none; z-index: -1; } .hand-drawn.fork { top: 20px; right: 20px; transform: rotate(15deg); } .hand-drawn.spoon { bottom: 50px; left: 20px; transform: rotate(-20deg); } .hand-drawn.leaf { bottom: 30px; right: 40px; transform: rotate(45deg); } @media (max-width: 480px) { .masonry-grid { column-count: 1; } .logo h1 { font-size: 1.4rem; } .filter-tags { gap: 5px; } .filter-tag { padding: 4px 10px; font-size: 0.7rem; } } .float-btn { position: fixed; bottom: 20px; right: 20px; width: 50px; height: 50px; background-color: var(--primary); border-radius: 50%; display: flex; align-items: center; justify-content: center; box-shadow: 0 5px 15px rgba(255, 107, 107, 0.4); cursor: pointer; z-index: 90; transition: all 0.3s ease; animation: pulse 2s infinite; } .float-btn:hover { background-color: #ff5252; transform: scale(1.1) rotate(45deg); animation: none; } .float-btn svg { width: 24px; height: 24px; fill: white; } @keyframes pulse { 0% { transform: scale(1); box-shadow: 0 5px 15px rgba(255, 107, 107, 0.4); } 50% { transform: scale(1.05); box-shadow: 0 5px 25px rgba(255, 107, 107, 0.6); } 100% { transform: scale(1); box-shadow: 0 5px 15px rgba(255, 107, 107, 0.4); } } .bounce-in { animation: bounceIn 0.5s ease; } @keyframes bounceIn { 0% { opacity: 0; transform: scale(0.3); } 50% { opacity: 1; transform: scale(1.05); } 70% { transform: scale(0.9); } 100% { transform: scale(1); } } .fade-in { animation: fadeIn 0.5s ease; } @keyframes fadeIn { 0% { opacity: 0; } 100% { opacity: 1; } } .shake { animation: shake 0.82s cubic-bezier(.36,.07,.19,.97) both; } @keyframes shake { 10%, 90% { transform: translate3d(-1px, 0, 0); } 20%, 80% { transform: translate3d(2px, 0, 0); } 30%, 50%, 70% { transform: translate3d(-4px, 0, 0); } 40%, 60% { transform: translate3d(4px, 0, 0); } } </style> </head> <body> <div class="container"> <header> <div class="logo"> <div class="logo-icon"> <svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M12 2L15.09 8.26L22 9.27L17 14.14L18.18 21.02L12 17.77L5.82 21.02L7 14.14L2 9.27L8.91 8.26L12 2Z" fill="#ff6b6b"/> </svg> </div> <h1>Savory Seasons</h1> </div> <button class="menu-btn"> <span></span> <span></span> <span></span> </button> <nav class="menu"> <ul> <li><a href="#">Home</a></li> <li><a href="#">Recipes</a></li> <li><a href="#">Meal Plans</a></li> <li><a href="#">About</a></li> <li><a href="#">Contact</a></li> </ul> </nav> </header> <div class="search-bar"> <input type="text" placeholder="Search for recipes..."> <button> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> <path d="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"/> </svg> </button> </div> <div class="filter-tags"> <div class="filter-tag" data-filter="all">All</div> <div class="filter-tag" data-filter="vegetarian">Vegetarian</div> <div class="filter-tag" data-filter="vegan">Vegan</div> <div class="filter-tag" data-filter="gluten-free">Gluten-Free</div> <div class="filter-tag" data-filter="quick">Under 30 min</div> <div class="filter-tag" data-filter="dessert">Dessert</div> </div> <div class="masonry-grid"> <div class="recipe-card" data-categories="vegetarian,quick"> <button class="close-recipe" style="display: none;"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> <path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/> </svg> </button> <img src="https://images.unsplash.com/photo-1593560708920-61b98ae52d42?ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=80" alt="Roasted Vegetable Bowl" class="recipe-img"> <div class="recipe-content"> <span class="recipe-tag">Vegetarian</span> <h3 class="recipe-title">Rainbow Roasted Vegetable Bowl</h3> <div class="recipe-meta"> <span> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> <path d="M11.99 2C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zM12 20c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8z"/> <path d="M12.5 7H11v6l5.25 3.15.75-1.23-4.5-2.67z"/> </svg> 25 mins </span> <span> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> <path d="M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z"/> </svg> 286 </span> </div> </div> <div class="recipe-details"> <h4>Ingredients</h4> <ul class="ingredients-list"> <li>1 sweet potato, cubed</li> <li>1 red bell pepper, sliced</li> <li>1 zucchini, sliced</li> <li>1 red onion, chunked</li> <li>2 tbsp olive oil</li> <li>1 tsp smoked paprika</li> <li>1 tsp cumin</li> <li>Salt & pepper to taste</li> <li>1 cup quinoa, cooked</li> <li>1 avocado, sliced</li> <li>Fresh herbs (cilantro, parsley)</li> </ul> <h4>Method</h4> <ol class="cooking-steps"> <li>Preheat oven to 425°F (220°C).</li> <li>Toss vegetables with oil and spices on a baking sheet.</li> <li>Roast for 20-25 minutes until tender and caramelized.</li> <li>Serve over cooked quinoa, top with avocado and fresh herbs.</li> <li>For extra flavor, drizzle with tahini sauce or lemon juice.</li> </ol> </div> </div> <div class="recipe-card" data-categories="quick,gluten-free"> <button class="close-recipe" style="display: none;"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> <path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/> </svg> </button> <img src="https://images.unsplash.com/photo-1559847844-5315695dadae?ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=80" alt="Salmon Bowl" class="recipe-img"> <div class="recipe-content"> <span class="recipe-tag">Gluten-Free</span> <h3 class="recipe-title">Miso Glazed Salmon Rice Bowl</h3> <div class="recipe-meta"> <span> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> <path d="M11.99 2C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zM12 20c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8z"/> <path d="M12.5 7H11v6l5.25 3.15.75-1.23-4.5-2.67z"/> </svg> 20 mins </span> <span> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> <path d="M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z"/> </svg> 342 </span> </div> </div> <div class="recipe-details"> <h4>Ingredients</h4> <ul class="ingredients-list"> <li>2 salmon fillets (6oz each)</li> <li>2 tbsp white miso paste</li> <li>1 tbsp maple syrup</li> <li>1 tbsp rice vinegar</li> <li>1 tsp grated ginger</li> <li>1 cup short-grain rice, cooked</li> <li>1 cucumber, thinly sliced</li> <li>1 avocado, sliced</li> <li>2 radishes, thinly sliced</li> <li>Sesame seeds for garnish</li> <li>Nori strips (optional)</li> </ul> <h4>Method</h4> <ol class="cooking-steps"> <li>Mix miso, maple syrup, vinegar, and ginger in a bowl.</li> <li>Brush mixture on salmon fillets.</li> <li>Broil salmon for 8-10 minutes until caramelized and cooked through.</li> <li>Serve over rice with fresh vegetables.</li> <li>Sprinkle with sesame seeds and nori strips if using.</li> </ol> </div> </div> <div class="recipe-card" data-categories="vegan,dessert"> <button class="close-recipe" style="display: none;"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> <path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/> </svg> </button> <img src="https://images.unsplash.com/photo-1541599188877-c4bc76925791?ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=80" alt="Chia Pudding" class="recipe-img"> <div class="recipe-content"> <span class="recipe-tag">Vegan</span> <h3 class="recipe-title">Coconut Mango Chia Pudding</h3> <div class="recipe-meta"> <span> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> <path d="M11.99 2C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zM12 20c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8z"/> <path d="M12.5 7H11v6l5.25 3.15.75-1.23-4.5-2.67z"/> </svg> 10 mins + chill </span> <span> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> <path d="M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z"/> </svg> 198 </span> </div> </div> <div class="recipe-details"> <h4>Ingredients</h4> <ul class="ingredients-list"> <li>1/4 cup chia seeds</li> <li>1 cup coconut milk</li> <li>1 tbsp maple syrup</li> <li>1/2 tsp vanilla extract</li> <li>1 ripe mango, diced</li> <li>2 tbsp toasted coconut flakes</li> <li>Fresh mint leaves (optional)</li> </ul> <h4>Method</h4> <ol class="cooking-steps"> <li>Mix chia seeds, coconut milk, maple syrup, and vanilla in a bowl.</li> <li>Stir well and let sit for 5 minutes, then stir again to prevent clumping.</li> <li>Refrigerate for at least 4 hours or overnight.</li> <li>Layer pudding with fresh mango in serving glasses.</li> <li>Top with toasted coconut flakes and mint if using.</li> </ol> </div> </div> <div class="recipe-card" data-categories="vegetarian,gluten-free"> <button class="close-recipe" style="display: none;"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> <path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/> </svg> </button> <img src="https://images.unsplash.com/photo-1505253716362-afaea1d3d1af?ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=80" alt="Frittata" class="recipe-img"> <div class="recipe-content"> <span class="recipe-tag">Gluten-Free</span> <h3 class="recipe-title">Mediterranean Vegetable Frittata</h3> <div class="recipe-meta"> <span> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> <path d="M11.99 2C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zM12 20c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8z"/> <path d="M12.5 7H11v6l5.25 3.15.75-1.23-4.5-2.67z"/> </svg> 30 mins </span> <span> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> <path d="M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z"/> </svg> 215 </span> </div> </div> <div class="recipe-details"> <h4>Ingredients</h4> <ul class="ingredients-list"> <li>8 large eggs</li> <li>1/4 cup milk (any kind)</li> <li>1 zucchini, diced</li> <li>1 red bell pepper, diced</li> <li>1/2 cup cherry tomatoes, halved</li> <li>1/3 cup crumbled feta cheese</li> <li>2 tbsp olive oil</li> <li>2 cloves garlic, minced</li> <li>1 tsp dried oregano</li> <li>Fresh basil leaves, torn</li> <li>Salt & pepper to taste</li> </ul> <h4>Method</h4> <ol class="cooking-steps"> <li>Preheat oven to 375°F (190°C).</li> <li>In an oven-safe skillet, heat olive oil and sauté vegetables until tender.</li> <li>Add garlic and oregano, cook for 1 minute.</li> <li>Whisk eggs with milk, salt, and pepper; pour over vegetables.</li> <li>Sprinkle with feta cheese and cook on stovetop for 3-4 minutes.</li> <li>Transfer to oven and bake for 15-18 minutes until set.</li> <li>Garnish with fresh basil before serving.</li> </ol> </div> </div> <div class="recipe-card" data-categories="vegan,quick"> <button class="close-recipe" style="display: none;"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> <path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/> </svg> </button> <img src="https://images.unsplash.com/photo-1607532941433-304659e8198a?ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=80" alt="Curry" class="recipe-img"> <div class="recipe-content"> <span class="recipe-tag">Vegan</span> <h3 class="recipe-title">Quick Coconut Chickpea Curry</h3> <div class="recipe-meta"> <span> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> <path d="M11.99 2C6.
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <style> :root { --primary-color: #f7f5f2; --secondary-color: #e9e4dc; --text-color: #444; --accent-color: #91a59b; --dark-accent: #6c7c70; --font-main: 'Poppins', -apple-system, BlinkMacSystemFont, sans-serif; --font-accent: 'Playfair Display', Georgia, serif; } * { margin: 0; padding: 0; box-sizing: border-box; } body { background-color: var(--primary-color); color: var(--text-color); font-family: var(--font-main); line-height: 1.6; overflow-x: hidden; max-width: 700px; margin: 0 auto; height: 700px; padding: 0 15px; } .container { max-width: 100%; height: 100%; margin: 0 auto; display: flex; flex-direction: column; } header { padding: 20px 0; text-align: center; position: relative; } h1 { font-family: var(--font-accent); font-weight: 300; font-size: 1.8rem; letter-spacing: 1px; margin-bottom: 8px; color: var(--dark-accent); } p.tagline { font-size: 0.9rem; color: var(--text-color); margin-bottom: 15px; font-weight: 300; } .filter-container { display: flex; justify-content: center; flex-wrap: wrap; gap: 8px; margin-bottom: 20px; } .filter-btn { background: transparent; border: 1px solid var(--accent-color); color: var(--accent-color); padding: 5px 12px; border-radius: 20px; font-size: 0.8rem; cursor: pointer; transition: all 0.3s ease; outline: none; } .filter-btn:hover, .filter-btn.active { background-color: var(--accent-color); color: white; transform: translateY(-2px); box-shadow: 0 3px 10px rgba(145, 165, 155, 0.2); } .masonry-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); grid-auto-rows: 10px; gap: 15px; overflow-y: auto; padding: 0 0 20px 0; max-height: calc(100% - 150px); scrollbar-width: thin; scrollbar-color: var(--accent-color) var(--primary-color); position: relative; } .masonry-grid::-webkit-scrollbar { width: 6px; } .masonry-grid::-webkit-scrollbar-track { background: var(--primary-color); } .masonry-grid::-webkit-scrollbar-thumb { background-color: var(--accent-color); border-radius: 20px; } .grid-item { grid-row-end: span var(--span); border-radius: 8px; overflow: hidden; transition: all 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275); background-color: white; box-shadow: 0 4px 20px rgba(0, 0, 0, 0.05); opacity: 0; transform: translateY(20px); position: relative; } .grid-item.show { opacity: 1; transform: translateY(0); } .grid-item:hover { transform: translateY(-5px); box-shadow: 0 8px 25px rgba(0, 0, 0, 0.1); } .grid-item img { width: 100%; height: auto; display: block; object-fit: cover; } .item-content { padding: 15px; } .item-title { font-family: var(--font-accent); font-size: 1rem; color: var(--dark-accent); margin-bottom: 5px; } .item-desc { font-size: 0.85rem; margin-bottom: 10px; color: #666; } .item-tag { display: inline-block; font-size: 0.7rem; background-color: var(--secondary-color); color: var(--text-color); padding: 2px 8px; border-radius: 10px; margin-top: 5px; } .diy-steps { margin-top: 10px; padding-top: 10px; border-top: 1px dashed var(--secondary-color); } .diy-steps ol { font-size: 0.8rem; padding-left: 18px; } .diy-steps li { margin-bottom: 4px; } .image-item { position: relative; overflow: hidden; } .image-item::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.3) 100%); opacity: 0; transition: opacity 0.3s ease; } .image-item:hover::after { opacity: 1; } .image-caption { position: absolute; bottom: 15px; left: 15px; color: white; font-size: 0.9rem; z-index: 2; opacity: 0; transform: translateY(10px); transition: all 0.3s ease; text-shadow: 0 1px 3px rgba(0, 0, 0, 0.3); } .image-item:hover .image-caption { opacity: 1; transform: translateY(0); } .load-more { background-color: var(--accent-color); color: white; border: none; padding: 8px 20px; border-radius: 25px; font-size: 0.9rem; margin: 10px auto 0; cursor: pointer; display: block; transition: all 0.3s ease; } .load-more:hover { background-color: var(--dark-accent); transform: translateY(-2px); box-shadow: 0 4px 12px rgba(108, 124, 112, 0.3); } @media (max-width: 500px) { h1 { font-size: 1.5rem; } .masonry-grid { grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); } .filter-container { gap: 5px; } .filter-btn { padding: 4px 10px; font-size: 0.75rem; } } /* Pulse animation for new items */ @keyframes pulse { 0% { box-shadow: 0 0 0 0 rgba(145, 165, 155, 0.7); } 70% { box-shadow: 0 0 0 10px rgba(145, 165, 155, 0); } 100% { box-shadow: 0 0 0 0 rgba(145, 165, 155, 0); } } .grid-item.new { animation: pulse 2s 1; } /* Cursor style */ .custom-cursor { position: fixed; width: 20px; height: 20px; border: 1px solid var(--accent-color); border-radius: 50%; transform: translate(-50%, -50%); pointer-events: none; z-index: 9999; transition: width 0.2s, height 0.2s, background-color 0.2s; } .custom-cursor.hover { width: 40px; height: 40px; background-color: rgba(145, 165, 155, 0.1); } /* Loading animation */ .loader { width: 30px; height: 30px; border: 3px solid var(--secondary-color); border-top-color: var(--accent-color); border-radius: 50%; margin: 20px auto; animation: spin 1s linear infinite; display: none; } @keyframes spin { to { transform: rotate(360deg); } } </style> </head> <body> <div class="custom-cursor"></div> <div class="container"> <header> <h1>NORDISK HJEM</h1> <p class="tagline">Scandinavian simplicity meets functional beauty</p> </header> <div class="filter-container"> <button class="filter-btn active" data-filter="all">All</button> <button class="filter-btn" data-filter="living">Living Room</button> <button class="filter-btn" data-filter="kitchen">Kitchen</button> <button class="filter-btn" data-filter="bedroom">Bedroom</button> <button class="filter-btn" data-filter="diy">DIY Projects</button> </div> <div class="masonry-grid"> <!-- Grid items will be inserted here by JavaScript --> </div> <div class="loader"></div> <button class="load-more">Load More</button> </div> <script> // Grid items data const items = [ { type: 'image', category: 'living', imageUrl: 'https://images.unsplash.com/photo-1616486338812-3dadae4b4ace?ixlib=rb-1.2.1&auto=format&fit=crop&w=400&q=80', caption: 'Minimalist living space with natural light', span: 25 }, { type: 'diy', category: 'diy', title: 'Woven Jute Wall Hanging', description: 'A natural fiber wall art that adds warmth and texture.', imageUrl: 'https://images.unsplash.com/photo-1614252235316-8c857d38b5f4?ixlib=rb-1.2.1&auto=format&fit=crop&w=400&q=80', steps: [ 'Cut jute rope into desired lengths', 'Create a wooden dowel frame', 'Knot jute strands using simple macramé techniques', 'Trim ends for a clean finish' ], span: 42 }, { type: 'image', category: 'kitchen', imageUrl: 'https://images.unsplash.com/photo-1556911220-e15b29be8c8f?ixlib=rb-1.2.1&auto=format&fit=crop&w=400&q=80', caption: 'Open shelving with ceramics and wood elements', span: 28 }, { type: 'diy', category: 'diy', title: 'Concrete Geometric Planters', description: 'Modern vessels for your favorite indoor plants.', imageUrl: 'https://images.unsplash.com/photo-1485955900006-10f4d324d411?ixlib=rb-1.2.1&auto=format&fit=crop&w=400&q=80', steps: [ 'Create geometric molds with cardboard', 'Mix concrete according to package instructions', 'Pour into molds and allow to set for 24 hours', 'Sand edges and seal if desired' ], span: 38 }, { type: 'image', category: 'bedroom', imageUrl: 'https://images.unsplash.com/photo-1588046130717-0eb0c9a3ba15?ixlib=rb-1.2.1&auto=format&fit=crop&w=400&q=80', caption: 'Serene bedroom with linen bedding and natural wood', span: 30 }, { type: 'diy', category: 'diy', title: 'Wooden Lamp Base', description: 'Create a sculptural lamp from a driftwood piece.', imageUrl: 'https://images.unsplash.com/photo-1507473885765-e6ed057f782c?ixlib=rb-1.2.1&auto=format&fit=crop&w=400&q=80', steps: [ 'Select a sturdy piece of dried driftwood', 'Drill a hole through the center', 'Feed lamp wiring kit through the hole', 'Attach socket and a simple linen shade' ], span: 45 }, { type: 'image', category: 'living', imageUrl: 'https://images.unsplash.com/photo-1598928636135-d146006ff4be?ixlib=rb-1.2.1&auto=format&fit=crop&w=400&q=80', caption: 'Reading nook with bouclé chair and pendant light', span: 26 }, { type: 'image', category: 'kitchen', imageUrl: 'https://images.unsplash.com/photo-1484154218962-a197022b5858?ixlib=rb-1.2.1&auto=format&fit=crop&w=400&q=80', caption: 'Marble countertop with brass fixtures', span: 22 }, { type: 'diy', category: 'diy', title: 'Linen Wall Organizer', description: 'A practical and beautiful fabric storage solution.', imageUrl: 'https://images.unsplash.com/photo-1519643381401-22c77e60520e?ixlib=rb-1.2.1&auto=format&fit=crop&w=400&q=80', steps: [ 'Cut heavyweight linen to desired size', 'Fold and stitch pockets of varying sizes', 'Add wooden dowel at top for hanging', 'Secure with leather straps for a finished look' ], span: 40 }, { type: 'image', category: 'bedroom', imageUrl: 'https://images.unsplash.com/photo-1616594039964-ae9021a400a0?ixlib=rb-1.2.1&auto=format&fit=crop&w=400&q=80', caption: 'Minimal bedside with layered textiles', span: 32 }, { type: 'image', category: 'living', imageUrl: 'https://images.unsplash.com/photo-1583847268964-b28dc8f51f92?ixlib=rb-1.2.1&auto=format&fit=crop&w=400&q=80', caption: 'Gallery wall with black frames and botanical prints', span: 28 }, { type: 'diy', category: 'diy', title: 'Wood Bead Garland', description: 'A versatile decorative piece for any surface.', imageUrl: 'https://images.unsplash.com/photo-1515516969-9a6a6f4a7e75?ixlib=rb-1.2.1&auto=format&fit=crop&w=400&q=80', steps: [ 'String wooden beads of various sizes', 'Intersperse with tassels made from natural twine', 'Knot ends securely', 'Drape across shelves or use as a table accent' ], span: 36 } ]; // More items for "load more" functionality const moreItems = [ { type: 'image', category: 'kitchen', imageUrl: 'https://images.unsplash.com/photo-1600585154340-be6161a56a0c?ixlib=rb-1.2.1&auto=format&fit=crop&w=400&q=80', caption: 'Scandinavian kitchen with oak cabinetry', span: 27 }, { type: 'diy', category: 'diy', title: 'Pressed Flower Art', description: 'Botanical specimens as minimalist wall decor.', imageUrl: 'https://images.unsplash.com/photo-1611145439436-397190271413?ixlib=rb-1.2.1&auto=format&fit=crop&w=400&q=80', steps: [ 'Press flowers between heavy books for 2-3 weeks', 'Arrange on acid-free paper', 'Secure in floating glass frames', 'Create a gallery arrangement on a neutral wall' ], span: 43 }, { type: 'image', category: 'bedroom', imageUrl: 'https://images.unsplash.com/photo-1551298457-c72eced6d0ad?ixlib=rb-1.2.1&auto=format&fit=crop&w=400&q=80', caption: 'Simple bedroom storage with woven baskets', span: 29 }, { type: 'image', category: 'living', imageUrl: 'https://images.unsplash.com/photo-1581467695675-07203e88b5cd?ixlib=rb-1.2.1&auto=format&fit=crop&w=400&q=80', caption: 'Cozy corner with handcrafted ceramic planters', span: 26 } ]; // DOM elements const masonryGrid = document.querySelector('.masonry-grid'); const filterBtns = document.querySelectorAll('.filter-btn'); const loadMoreBtn = document.querySelector('.load-more'); const loader = document.querySelector('.loader'); const customCursor = document.querySelector('.custom-cursor'); // Initialize grid let currentFilter = 'all'; let loadedCount = 0; // Custom cursor effect document.addEventListener('mousemove', (e) => { customCursor.style.left = `${e.clientX}px`; customCursor.style.top = `${e.clientY}px`; }); document.addEventListener('mousedown', () => { customCursor.style.transform = 'translate(-50%, -50%) scale(0.9)'; }); document.addEventListener('mouseup', () => { customCursor.style.transform = 'translate(-50%, -50%) scale(1)'; }); document.querySelectorAll('button, a, .grid-item').forEach(el => { el.addEventListener('mouseenter', () => { customCursor.classList.add('hover'); }); el.addEventListener('mouseleave', () => { customCursor.classList.remove('hover'); }); }); // Create grid item function createGridItem(item) { const gridItem = document.createElement('div'); gridItem.className = `grid-item ${item.category}`; gridItem.style.setProperty('--span', item.span); if (item.type === 'image') { gridItem.innerHTML = ` <div class="image-item"> <img src="${item.imageUrl}" alt="${item.caption}"> <div class="image-caption">${item.caption}</div> </div> `; } else if (item.type === 'diy') { gridItem.innerHTML = ` <img src="${item.imageUrl}" alt="${item.title}"> <div class="item-content"> <h3 class="item-title">${item.title}</h3> <p class="item-desc">${item.description}</p> <span class="item-tag">DIY</span> <div class="diy-steps"> <ol> ${item.steps.map(step => `<li>${step}</li>`).join('')} </ol> </div> </div> `; } return gridItem; } // Load grid items function loadItems(filterValue = 'all', newItems = []) { const itemsToAdd = newItems.length > 0 ? newItems : items.slice(loadedCount, loadedCount + 6); loadedCount += itemsToAdd.length; if (loadedCount >= items.length && newItems.length === 0) { loadMoreBtn.style.display = 'none'; } const fragment = document.createDocumentFragment(); itemsToAdd.forEach((item) => { if (filterValue === 'all' || item.category === filterValue) { const gridItem = createGridItem(item); if (newItems.length > 0) { gridItem.classList.add('new'); } fragment.appendChild(gridItem); } }); masonryGrid.appendChild(fragment); // Trigger layout and add show class setTimeout(() => { document.querySelectorAll('.grid-item:not(.show)').forEach((item, index) => { setTimeout(() => { item.classList.add('show'); }, index * 50); }); }, 10); // Recalculate grid layout resizeGridItems(); } // Filter grid items function filterGrid(filterValue) { currentFilter = filterValue; masonryGrid.innerHTML = ''; loadedCount = 0; loadMoreBtn.style.display = 'block'; loadItems(filterValue); } // Calculate grid item heights function resizeGridItems() { const grid = document.querySelector('.masonry-grid'); const rowHeight = parseInt(window.getComputedStyle(grid).getPropertyValue('grid-auto-rows')); const rowGap = parseInt(window.getComputedStyle(grid).getPropertyValue('grid-row-gap')); document.querySelectorAll('.grid-item').forEach(item => { const contentHeight = item.querySelector('img').offsetHeight + (item.querySelector('.item-content') ? item.querySelector('.item-content').offsetHeight : 0); const rowSpan = Math.ceil((contentHeight + rowGap) / (rowHeight + rowGap)); item.style.setProperty('--span', rowSpan); }); } // Event listeners window.addEventListener('load', () => { loadItems(); window.addEventListener('resize', resizeGridItems); }); filterBtns.forEach(btn => { btn.addEventListener('click', () => { filterBtns.forEach(b => b.classList.remove('active')); btn.classList.add('active'); filterGrid(btn.getAttribute('data-filter')); }); }); loadMoreBtn.addEventListener('click', () => { loader.style.display = 'block'; loadMoreBtn.style.display = 'none'; // Simulate loading delay setTimeout(() => { loader.style.display = 'none'; loadMoreBtn.style.display = 'block'; if (loadedCount >= items.length) { loadItems(currentFilter, moreItems); loadMoreBtn.style.display = 'none'; } else { loadItems(currentFilter); } }, 800); }); </script> </body> </html>
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Innovative Startup Portfolio</title> <style> :root { --primary: #FF6B6B; --secondary: #4ECDC4; --accent: #FFE66D; --dark: #292F36; --light: #F7FFF7; --transition: 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275); } * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; } body { background-color: var(--light); color: var(--dark); overflow-x: hidden; padding: 1rem; max-width: 700px; margin: 0 auto; height: 700px; overflow-y: auto; scrollbar-width: thin; } body::-webkit-scrollbar { width: 6px; } body::-webkit-scrollbar-thumb { background-color: var(--primary); border-radius: 6px; } header { margin-bottom: 2rem; position: relative; z-index: 2; } h1 { font-size: 2.5rem; margin-bottom: 0.5rem; background: linear-gradient(135deg, var(--primary), var(--secondary)); -webkit-background-clip: text; background-clip: text; color: transparent; position: relative; display: inline-block; } h1::after { content: ""; position: absolute; bottom: 0; left: 0; height: 4px; width: 0; background: linear-gradient(90deg, var(--primary), var(--secondary)); transition: width 1s ease; } h1:hover::after { width: 100%; } .subtitle { font-size: 1rem; color: var(--dark); opacity: 0.8; max-width: 500px; margin-bottom: 1rem; } .filter-container { display: flex; gap: 0.75rem; flex-wrap: wrap; margin-bottom: 1.5rem; } .filter-btn { padding: 0.4rem 1rem; background: transparent; border: 2px solid var(--dark); border-radius: 25px; font-weight: 600; cursor: pointer; transition: all 0.3s ease; font-size: 0.85rem; position: relative; overflow: hidden; } .filter-btn::before { content: ''; position: absolute; top: 0; left: 0; width: 0%; height: 100%; background: var(--primary); transition: all 0.3s ease; z-index: -1; } .filter-btn:hover { color: white; border-color: var(--primary); } .filter-btn:hover::before { width: 100%; } .filter-btn.active { background: var(--dark); color: white; border-color: var(--dark); } .portfolio-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); grid-auto-rows: minmax(180px, auto); grid-auto-flow: dense; gap: 1.25rem; position: relative; } .portfolio-item { background: white; border-radius: 12px; overflow: hidden; box-shadow: 0 10px 30px rgba(0, 0, 0, 0.05); position: relative; cursor: pointer; transform: translateY(20px); opacity: 0; animation: fadeUp 0.6s forwards; transition: all var(--transition); } .portfolio-item:hover { transform: translateY(-10px); box-shadow: 0 15px 35px rgba(0, 0, 0, 0.1); } .portfolio-item::before { content: ''; position: absolute; top: 0; left: 0; width: 100%; height: 4px; background: linear-gradient(90deg, var(--primary), var(--secondary)); transform: scaleX(0); transform-origin: left; transition: transform 0.3s ease; } .portfolio-item:hover::before { transform: scaleX(1); } .item-1 { grid-column: span 1; grid-row: span 1; animation-delay: 0.1s; } .item-2 { grid-column: span 1; grid-row: span 2; animation-delay: 0.2s; } .item-3 { grid-column: span 2; grid-row: span 1; animation-delay: 0.3s; } .item-4 { grid-column: span 1; grid-row: span 1; animation-delay: 0.4s; } .item-5 { grid-column: span 2; grid-row: span 2; animation-delay: 0.5s; } .item-6 { grid-column: span 1; grid-row: span 1; animation-delay: 0.6s; } .item-img { height: 160px; position: relative; overflow: hidden; } .item-2 .item-img, .item-5 .item-img { height: 200px; } .item-img img { width: 100%; height: 100%; object-fit: cover; transition: transform 0.6s ease; } .portfolio-item:hover .item-img img { transform: scale(1.1); } .item-category { position: absolute; top: 1rem; left: 1rem; background: var(--accent); color: var(--dark); padding: 0.3rem 0.8rem; border-radius: 25px; font-size: 0.7rem; font-weight: 600; box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1); opacity: 0; transform: translateY(10px); transition: all 0.3s ease; } .portfolio-item:hover .item-category { opacity: 1; transform: translateY(0); } .item-content { padding: 1rem; position: relative; } .item-title { font-size: 1rem; font-weight: 700; margin-bottom: 0.5rem; color: var(--dark); } .item-desc { font-size: 0.8rem; color: #666; margin-bottom: 0.5rem; line-height: 1.4; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; } .item-footer { display: flex; align-items: center; justify-content: space-between; margin-top: 0.75rem; } .item-tech { display: flex; gap: 0.5rem; } .tech-badge { width: 24px; height: 24px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 0.6rem; font-weight: 700; color: white; background: var(--secondary); } .tech-badge:nth-child(2) { background: var(--primary); } .tech-badge:nth-child(3) { background: var(--dark); } .item-year { font-size: 0.75rem; color: #888; font-weight: 500; } /* Shapes */ .shape { position: fixed; z-index: -1; opacity: 0.5; } .shape-1 { width: 100px; height: 100px; background: var(--primary); border-radius: 50%; top: 10%; right: -30px; filter: blur(30px); } .shape-2 { width: 150px; height: 150px; background: var(--secondary); border-radius: 30% 70% 70% 30% / 30% 30% 70% 70%; bottom: 10%; left: -50px; filter: blur(40px); } .shape-3 { width: 80px; height: 80px; background: var(--accent); border-radius: 63% 37% 30% 70% / 50% 45% 55% 50%; top: 40%; left: 20%; filter: blur(20px); } /* Modal */ .modal { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0, 0, 0, 0.8); display: flex; align-items: center; justify-content: center; z-index: 1000; opacity: 0; visibility: hidden; transition: all 0.3s ease; } .modal.active { opacity: 1; visibility: visible; } .modal-content { background: white; width: 90%; max-width: 600px; max-height: 90vh; overflow-y: auto; border-radius: 12px; position: relative; transform: scale(0.8); opacity: 0; transition: all 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275); } .modal.active .modal-content { transform: scale(1); opacity: 1; } .modal-close { position: absolute; top: 1rem; right: 1rem; background: var(--dark); color: white; width: 32px; height: 32px; border-radius: 50%; display: flex; align-items: center; justify-content: center; cursor: pointer; transition: all 0.3s ease; z-index: 10; } .modal-close:hover { background: var(--primary); transform: rotate(90deg); } .modal-header { padding: 1.5rem; border-bottom: 1px solid rgba(0, 0, 0, 0.1); } .modal-body { padding: 1.5rem; } .modal-title { font-size: 1.5rem; margin-bottom: 0.5rem; } .modal-category { display: inline-block; background: var(--accent); color: var(--dark); padding: 0.3rem 0.8rem; border-radius: 25px; font-size: 0.75rem; font-weight: 600; margin-bottom: 1rem; } .modal-img { width: 100%; height: 250px; object-fit: cover; border-radius: 8px; margin-bottom: 1.5rem; } .modal-desc { font-size: 0.9rem; line-height: 1.6; color: #444; margin-bottom: 1.5rem; } .tech-stack { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-bottom: 1.5rem; } .tech-item { background: #f0f0f0; padding: 0.4rem 0.8rem; border-radius: 4px; font-size: 0.8rem; font-weight: 500; } .project-stats { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1rem; margin-bottom: 1.5rem; } .stat-item { background: #f9f9f9; padding: 1rem; border-radius: 8px; text-align: center; } .stat-value { font-size: 1.5rem; font-weight: 700; margin-bottom: 0.25rem; color: var(--primary); } .stat-label { font-size: 0.75rem; color: #666; } /* Animations */ @keyframes fadeUp { to { opacity: 1; transform: translateY(0); } } @media (max-width: 600px) { .portfolio-grid { grid-template-columns: 1fr; } .item-1, .item-2, .item-3, .item-4, .item-5, .item-6 { grid-column: span 1; grid-row: span 1; } .item-img { height: 180px; } .project-stats { grid-template-columns: 1fr; } } /* Loading animation */ .loading { position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: var(--light); display: flex; align-items: center; justify-content: center; z-index: 9999; transition: opacity 0.6s ease, visibility 0.6s ease; } .loading.hidden { opacity: 0; visibility: hidden; } .loading-spinner { width: 60px; height: 60px; position: relative; } .loading-spinner div { position: absolute; width: 16px; height: 16px; border-radius: 50%; animation: loading-spinner 1.2s linear infinite; } .loading-spinner div:nth-child(1) { background: var(--primary); top: 0; left: 22px; animation-delay: 0s; } .loading-spinner div:nth-child(2) { background: var(--secondary); top: 16px; left: 40px; animation-delay: -0.4s; } .loading-spinner div:nth-child(3) { background: var(--accent); top: 38px; left: 22px; animation-delay: -0.8s; } .loading-spinner div:nth-child(4) { background: var(--dark); top: 16px; left: 5px; animation-delay: -1.2s; } @keyframes loading-spinner { 0%, 100% { opacity: 1; transform: scale(1); } 50% { opacity: 0.5; transform: scale(0.7); } } </style> </head> <body> <div class="loading"> <div class="loading-spinner"> <div></div> <div></div> <div></div> <div></div> </div> </div> <div class="shape shape-1"></div> <div class="shape shape-2"></div> <div class="shape shape-3"></div> <header> <h1>Startup Showcase</h1> <p class="subtitle">A curated collection of innovative startups and digital products that are redefining industries and pushing boundaries.</p> <div class="filter-container"> <button class="filter-btn active" data-filter="all">All Projects</button> <button class="filter-btn" data-filter="fintech">Fintech</button> <button class="filter-btn" data-filter="health">Health Tech</button> <button class="filter-btn" data-filter="ai">AI Solutions</button> <button class="filter-btn" data-filter="saas">SaaS</button> </div> </header> <div class="portfolio-grid"> <div class="portfolio-item item-1" data-category="fintech"> <div class="item-img"> <img src="https://images.unsplash.com/photo-1551288049-bebda4e38f71?ixlib=rb-1.2.1&auto=format&fit=crop&w=600&q=80" alt="CashFlow"> <div class="item-category">Fintech</div> </div> <div class="item-content"> <h3 class="item-title">CashFlow</h3> <p class="item-desc">AI-powered expense tracking and budgeting solution for small businesses.</p> <div class="item-footer"> <div class="item-tech"> <div class="tech-badge">Py</div> <div class="tech-badge">Tf</div> </div> <div class="item-year">2023</div> </div> </div> </div> <div class="portfolio-item item-2" data-category="health"> <div class="item-img"> <img src="https://images.unsplash.com/photo-1576091160550-2173dba999ef?ixlib=rb-1.2.1&auto=format&fit=crop&w=600&q=80" alt="MediSync"> <div class="item-category">Health Tech</div> </div> <div class="item-content"> <h3 class="item-title">MediSync</h3> <p class="item-desc">Remote patient monitoring and telemedicine platform with real-time health analytics.</p> <div class="item-footer"> <div class="item-tech"> <div class="tech-badge">Re</div> <div class="tech-badge">No</div> <div class="tech-badge">ML</div> </div> <div class="item-year">2022</div> </div> </div> </div> <div class="portfolio-item item-3" data-category="ai"> <div class="item-img"> <img src="https://images.unsplash.com/photo-1535378620166-273708d44e4c?ixlib=rb-1.2.1&auto=format&fit=crop&w=600&q=80" alt="NeuralWriter"> <div class="item-category">AI Solutions</div> </div> <div class="item-content"> <h3 class="item-title">NeuralWriter</h3> <p class="item-desc">AI-powered content generation platform for marketing teams with tone adaptation.</p> <div class="item-footer"> <div class="item-tech"> <div class="tech-badge">Py</div> <div class="tech-badge">Tr</div> </div> <div class="item-year">2023</div> </div> </div> </div> <div class="portfolio-item item-4" data-category="saas"> <div class="item-img"> <img src="https://images.unsplash.com/photo-1483478550801-ceba5fe50e8e?ixlib=rb-1.2.1&auto=format&fit=crop&w=600&q=80" alt="TaskFlow"> <div class="item-category">SaaS</div> </div> <div class="item-content"> <h3 class="item-title">TaskFlow</h3> <p class="item-desc">Project management tool with integrated workflow automation for remote teams.</p> <div class="item-footer"> <div class="item-tech"> <div class="tech-badge">Js</div> <div class="tech-badge">Vu</div> </div> <div class="item-year">2022</div> </div> </div> </div> <div class="portfolio-item item-5" data-category="ai"> <div class="item-img"> <img src="https://images.unsplash.com/photo-1551434678-e076c223a692?ixlib=rb-1.2.1&auto=format&fit=crop&w=600&q=80" alt="CodePilot"> <div class="item-category">AI Solutions</div> </div> <div class="item-content"> <h3 class="item-title">CodePilot</h3> <p class="item-desc">AI-assisted code generation platform for developers with smart refactoring and documentation.</p> <div class="item-footer"> <div class="item-tech"> <div class="tech-badge">Py</div> <div class="tech-badge">Js</div> <div class="tech-badge">Go</div> </div> <div class="item-year">2023</div> </div> </div> </div> <div class="portfolio-item item-6" data-category="fintech"> <div class="item-img"> <img src="https://images.unsplash.com/photo-1563986768494-4dee2763ff3f?ixlib=rb-1.2.1&auto=format&fit=crop&w=600&q=80" alt="Crypta"> <div class="item-category">Fintech</div> </div> <div class="item-content"> <h3 class="item-title">Crypta</h3> <p class="item-desc">Secure cryptocurrency wallet with advanced fraud detection and market analytics.</p> <div class="item-footer"> <div class="item-tech"> <div class="tech-badge">Ru</div> <div class="tech-badge">Bc</div> </div> <div class="item-year">2022</div> </div> </div> </div> </div> <div class="modal"> <div class="modal-content"> <div class="modal-close">×</div> <div class="modal-header"> <h2 class="modal-title">Project Title</h2> <div class="modal-category">Category</div> </div> <div class="modal-body"> <img class="modal-img" src="" alt="Project Image"> <div class="modal-desc"> <p>Project description will appear here with detailed information about the startup, their unique value proposition, and the challenges they overcame.</p> </div> <div class="tech-stack"> <div class="tech-item">React</div> <div class="tech-item">Node.js</div> <div class="tech-item">PostgreSQL</div> <div class="tech-item">AWS</div> </div> <div class="project-stats"> <div class="stat-item"> <div class="stat-value">87%</div> <div class="stat-label">Conversion Rate</div> </div> <div class="stat-item"> <div class="stat-value">$2.5M</div> <div class="stat-label">Funding Raised</div> </div> <div class="stat-item"> <div class="stat-value">125K</div> <div class="stat-label">Active Users</div> </div> </div> </div> </div> </div> <script> document.addEventListener('DOMContentLoaded', function() { // Simulate loading setTimeout(() => { document.querySelector('.loading').classList.add('hidden'); }, 1000); const filterBtns = document.querySelectorAll('.filter-btn'); const portfolioItems = document.querySelectorAll('.portfolio-item'); const modal = document.querySelector('.modal'); const modalContent = document.querySelector('.modal-content'); const modalClose = document.querySelector('.modal-close'); // Filter functionality filterBtns.forEach(btn => { btn.addEventListener('click', () => { // Remove active class from all buttons filterBtns.forEach(b => b.classList.remove('active')); // Add active class to clicked button btn.classList.add('active'); const filterValue = btn.getAttribute('data-filter'); // Filter portfolio items portfolioItems.forEach(item => { if (filterValue === 'all' || item.getAttribute('data-category') === filterValue) { item.style.display = 'block'; setTimeout(() => { item.style.opacity = '1'; item.style.transform = 'translateY(0)'; }, 100); } else { item.style.opacity = '0'; item.style.transform = 'translateY(20px)'; setTimeout(() => { item.style.display = 'none'; }, 300); } }); }); }); // Project data const projectsData = { 'CashFlow': { title: 'CashFlow', category: 'Fintech', image: 'https://images.unsplash.com/photo-1551288049-bebda4e38f71?ixlib=rb-1.2.1&auto=format&fit=crop&w=600&q=80', description: 'CashFlow is revolutionizing how small businesses manage their finances with an AI-powered expense tracking system. The platform automatically categorizes transactions, predicts cash flow, and provides actionable insights to improve financial health. Using computer vision, it can extract data from receipts and invoices without manual input, saving businesses an average of 5 hours per week on financial management tasks.', tech: ['Python', 'TensorFlow', 'React Native', 'PostgreSQL', 'AWS'], stats: { metric1: { value: '45%', label: 'Cost Reduction' }, metric2: { value: '$1.8M', label: 'Seed Funding' }, metric3: { value: '3,200+', label: 'Business Users' } } }, 'MediSync': { title: 'MediSync', category: 'Health Tech', image: 'https://images.unsplash.com/photo-1576091160550-2173dba999ef?ixlib=rb-1.2.1&auto=format&fit=crop&w=600&q=80', description: 'MediSync bridges the gap between patients and healthcare providers through its comprehensive remote monitoring platform. The system connects with FDA-approved medical devices to track vital signs in real-time, while its AI algorithms detect anomalies before they become emergencies. Its secure video consultation feature supports end-to-end encrypted sessions with automatic transcription and medical record integration, reducing hospital readmissions by 32% in pilot programs.', tech: ['React', 'Node.js', 'MongoDB', 'TensorFlow', 'WebRTC'], stats: { metric1: { value: '93%', label: 'Patient Satisfaction' }, metric2: { value: '$4.2M', label: 'Series A Funding' }, metric3: { value: '32%', label: 'Reduced Readmissions' } } }, 'NeuralWriter': { title: 'NeuralWriter', category: 'AI Solutions', image: 'https://images.unsplash.com/photo-1535378620166-273708d44e4c?ixlib=rb-1.2.1&auto=format&fit=crop&w=600&q=80', description: 'NeuralWriter is transforming content creation with its advanced AI models that can adapt to specific brand voices and tones. The platform allows marketing teams to generate SEO-optimized blog posts, social media content, and ad copy that maintains consistent messaging across channels. Its proprietary "brand voice fingerprinting" technology analyzes existing content to replicate specific writing styles, while its competitor analysis tool identifies content gaps and opportunities in any industry.', tech: ['Python', 'Transformer Models', 'Vue.js', 'FastAPI', 'GCP'], stats: { metric1: { value: '67%', label: 'Content Production Increase' }, metric2: { value: '$3.5M', label: 'Seed Funding' }, metric3: { value: '12,400', label: 'Monthly Active Users' } } }, 'TaskFlow': { title: 'TaskFlow', category: 'SaaS', image: 'https://images.unsplash.com/photo-1483478550801-ceba5fe50e8e?ixlib=rb-1.2.1&auto=format&fit=crop&w=600&q=80', description: 'TaskFlow is designed specifically for remote-first teams with its integrated project management and workflow automation platform. The system features intelligent task prioritization, workload balancing, and cross-timezone scheduling to improve team productivity. Its unique "flow state" feature detects when team members are in deep work based on activity patterns and automatically mutes notifications, while its "async standups" replace traditional meetings with status updates that respect different time zones.', tech: ['JavaScript', 'Vue.js', 'Firebase', 'Node.js', 'Electron'], stats: { metric1: { value: '26%', label: 'Productivity Increase' }, metric2: { value: '$1.2M', label: 'Angel Investment' }, metric3: { value: '8,750', label: 'Teams Onboarded' } } }, 'CodePilot': { title: 'CodePilot', category: 'AI Solutions', image: 'https://images.unsplash.com/photo-1551434678-e076c223a692?ixlib=rb-1.2.1&auto=format&fit=crop&w=600&q=80', description: 'CodePilot is enhancing developer productivity through AI-assisted programming tools that understand context and intent. The platform can generate code snippets, complete functions, and refactor existing code while adhering to project-specific patterns and best practices. Its semantic code search allows developers to find relevant code examples using natural language queries, while its automated documentation generator creates comprehensive docs from code with minimal human input, reducing technical debt across projects.', tech: ['Python', 'JavaScript', 'Go', 'LSTM Models', 'Docker'], stats: { metric1: { value: '35%', label: 'Dev Time Saved' }, metric2: { value: '$5.8M', label: 'Series A Funding' }, metric3: { value: '42,000', label: 'Developer Community' } } }, 'Crypta': { title: 'Crypta', category: 'Fintech', image: 'https://images.unsplash.com/photo-1563986768494-4dee2763ff3f?ixlib=rb-1.2.1&auto=format&fit=crop&w=600&q=80', description: 'Crypta provides institutional-grade security for cryptocurrency holdings with multi-signature technology and advanced behavioral fraud detection. The platform features a proprietary market analysis tool that tracks on-chain data and social sentiment to provide actionable trading insights. Its "custody-as-a-service" offering allows businesses to integrate secure cryptocurrency storage into their products with just a few lines of code, while maintaining full regulatory compliance across multiple jurisdictions.', tech: ['Ruby', 'Blockchain', 'React', 'PostgreSQL', 'Redis'], stats: { metric1: { value: '99.99%', label: 'Uptime' }, metric2: { value: '$2.1B', label: 'Assets Secured' }, metric3: { value: '0', label: 'Security Breaches' } } } }; // Modal functionality portfolioItems.forEach(item => { item.addEventListener('click', () => { const projectTitle = item.querySelector('.item-title').textContent; const project = projectsData[projectTitle]; // Fill modal with project data document.querySelector('.modal-title').textContent = project.title; document.querySelector('.modal-category').textContent = project.category; document.querySelector('.modal-img').src = project.image; document.querySelector('.modal-desc').innerHTML = `<p>${project.description}</p>`; // Create tech stack items const techStack = document.querySelector('.tech-stack'); techStack.innerHTML = ''; project.tech.forEach(tech => { const techItem = document.createElement('div'); techItem.classList.add('tech-item'); techItem.textContent = tech; techStack.appendChild(techItem); }); // Create stats const statsContainer = document.querySelector('.project-stats'); statsContainer.innerHTML = ''; Object.values(project.stats).forEach(stat => { const statItem = document.createElement('div'); statItem.classList.add('stat-item'); statItem.innerHTML = ` <div class="stat-value">${stat.value}</div> <div class="stat-label">${stat.label}</div> `; statsContainer.appendChild(statItem); }); // Show modal modal.classList.add('active'); }); }); // Close modal modalClose.addEventListener('click', () => { modal.classList.remove('active'); }); // Close modal when clicking outside modal.addEventListener('click', (e) => { if (e.target === modal) { modal.classList.remove('active'); } }); // Prevent modal content clicks from closing modal modalContent.addEventListener('click', (e) => { e.stopPropagation(); }); // Add scroll animation for portfolio items const observerOptions = { threshold: 0.1 }; const observer = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { entry.target.style.opacity = '1'; entry.target.style.transform = 'translateY(0)'; } }); }, observerOptions); portfolioItems.forEach(item => { observer.observe(item); }); }); </script> </body> </html>