Tags are the building blocks of HTML, providing structure and meaning to web content. Understanding how to use them effectively is crucial for creating well-organized and accessible web pages.
In this article, we will explore 10 tag examples that demonstrate the versatility and power of HTML. These examples will help you enhance your web development skills and create more engaging user experiences.
CODE1
Here's the code:
CODETEXT1
CODE2
Here's the code:
CODETEXT2
CODE3
Here's the code:
CODETEXT3
CODE4
Here's the code:
CODETEXT4
CODE5
Here's the code:
CODETEXT5
Subframe's drag-and-drop interface and intuitive, responsive canvas empower designers and developers to create pixel-perfect UI effortlessly. Loved by professionals, it ensures every design is both stunning and functional.
Start for free and experience the ease of designing with Subframe today!
CODE6
Here's the code:
CODETEXT6
CODE7
Here's the code:
CODETEXT7
CODE8
Here's the code:
CODETEXT8
CODE9
Here's the code:
CODETEXT9
CODE10
Here's the code:
CODETEXT10
Ready to elevate your UI design game? With Subframe, you can create pixel-perfect interfaces, including tags, in minutes. Experience unparalleled efficiency and stunning results.
Don't wait—start for free and begin designing immediately. Transform your ideas into reality with Subframe today!
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>E-commerce Product Management Tags</title> <style> :root { --electronics-start: #3a7bd5; --electronics-end: #00d2ff; --fashion-start: #ff9966; --fashion-end: #ff5e62; --home-start: #56ab2f; --home-end: #a8e063; --beauty-start: #cb356b; --beauty-end: #bd3f32; --sports-start: #8e2de2; --sports-end: #4a00e0; --food-start: #f0c27b; --food-end: #e94057; } * { box-sizing: border-box; margin: 0; padding: 0; font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; } body { background-color: #f8f9fa; color: #333; display: flex; flex-direction: column; align-items: center; justify-content: flex-start; min-height: 100vh; padding: 2rem 1rem; overflow-x: hidden; } .container { max-width: 680px; width: 100%; } h1 { font-size: 1.5rem; font-weight: 700; margin-bottom: 0.75rem; color: #1a1a1a; } p { font-size: 0.9rem; line-height: 1.5; color: #666; margin-bottom: 1.5rem; } .tag-manager { background-color: white; border-radius: 12px; box-shadow: 0 4px 20px rgba(0, 0, 0, 0.06); padding: 1.5rem; margin-bottom: 1.5rem; } .search-section { margin-bottom: 1.5rem; } .search-container { position: relative; margin-bottom: 0.75rem; } .search-input { width: 100%; padding: 0.75rem 1rem 0.75rem 2.5rem; font-size: 0.9rem; border: 1px solid #e0e0e0; border-radius: 8px; background-color: #f9f9f9; transition: all 0.3s ease; } .search-input:focus { outline: none; border-color: #3a7bd5; background-color: #fff; box-shadow: 0 0 0 3px rgba(58, 123, 213, 0.1); } .search-icon { position: absolute; left: 0.75rem; top: 50%; transform: translateY(-50%); color: #aaa; } .tags-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(120px, 1fr)); gap: 12px; margin-bottom: 1.5rem; } .tag { cursor: pointer; padding: 0.5rem 0.75rem; border-radius: 8px; font-size: 0.85rem; font-weight: 500; color: white; text-align: center; position: relative; overflow: hidden; transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1); box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08); transform: translateY(0); display: flex; align-items: center; justify-content: center; height: 38px; } .tag::before { content: ''; position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: linear-gradient(135deg, rgba(255, 255, 255, 0.2) 0%, rgba(255, 255, 255, 0) 50%); z-index: 1; } .tag:hover { transform: translateY(-2px); box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); } .tag:active { transform: translateY(1px); box-shadow: 0 1px 4px rgba(0, 0, 0, 0.1); } .tag.electronics { background: linear-gradient(135deg, var(--electronics-start), var(--electronics-end)); } .tag.fashion { background: linear-gradient(135deg, var(--fashion-start), var(--fashion-end)); } .tag.home { background: linear-gradient(135deg, var(--home-start), var(--home-end)); } .tag.beauty { background: linear-gradient(135deg, var(--beauty-start), var(--beauty-end)); } .tag.sports { background: linear-gradient(135deg, var(--sports-start), var(--sports-end)); } .tag.food { background: linear-gradient(135deg, var(--food-start), var(--food-end)); } .selected-tags { margin-top: 1.5rem; } .selected-tags-title { font-size: 0.9rem; font-weight: 600; color: #666; margin-bottom: 0.75rem; } .selected-tags-container { display: flex; flex-wrap: wrap; gap: 10px; min-height: 38px; padding: 4px; } .selected-tag { display: flex; align-items: center; padding: 0.5rem 0.75rem; border-radius: 6px; font-size: 0.85rem; font-weight: 500; color: white; position: relative; box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1); animation: tagAddAnimation 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275) forwards; } .selected-tag::before { content: ''; position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: linear-gradient(135deg, rgba(255, 255, 255, 0.15) 0%, rgba(255, 255, 255, 0) 50%); border-radius: 6px; z-index: 1; } .remove-tag { margin-left: 0.5rem; width: 16px; height: 16px; border-radius: 50%; background-color: rgba(255, 255, 255, 0.3); display: flex; align-items: center; justify-content: center; cursor: pointer; transition: background-color 0.2s ease; z-index: 2; } .remove-tag:hover { background-color: rgba(255, 255, 255, 0.5); } .product-list { background-color: white; border-radius: 12px; box-shadow: 0 4px 20px rgba(0, 0, 0, 0.06); padding: 1.5rem; } .product-list-title { font-size: 1.1rem; font-weight: 600; margin-bottom: 1rem; display: flex; align-items: center; justify-content: space-between; } .filter-count { font-size: 0.8rem; font-weight: 500; background: #f0f0f0; color: #666; padding: 0.25rem 0.5rem; border-radius: 12px; } .product-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); gap: 16px; } .product-card { border-radius: 8px; overflow: hidden; transition: all 0.3s ease; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05); } .product-card:hover { transform: translateY(-3px); box-shadow: 0 6px 16px rgba(0, 0, 0, 0.1); } .product-image { height: 100px; background-color: #f5f5f5; display: flex; align-items: center; justify-content: center; overflow: hidden; } .product-image img { width: 100%; height: 100%; object-fit: cover; } .product-info { padding: 0.75rem; } .product-name { font-size: 0.85rem; font-weight: 500; margin-bottom: 0.25rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .product-category { font-size: 0.75rem; color: #888; display: flex; align-items: center; } .category-dot { width: 8px; height: 8px; border-radius: 50%; margin-right: 4px; } .legend { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 1.5rem; } .legend-item { display: flex; align-items: center; font-size: 0.75rem; color: #777; } .legend-color { width: 12px; height: 12px; border-radius: 50%; margin-right: 4px; } .empty-state { display: none; text-align: center; padding: 2rem; color: #888; font-size: 0.9rem; } @keyframes tagAddAnimation { 0% { opacity: 0; transform: scale(0.8); } 70% { transform: scale(1.05); } 100% { opacity: 1; transform: scale(1); } } @keyframes tagRemoveAnimation { 0% { opacity: 1; transform: scale(1); } 100% { opacity: 0; transform: scale(0.8); } } @media (max-width: 480px) { .tags-grid { grid-template-columns: repeat(auto-fill, minmax(100px, 1fr)); } .product-grid { grid-template-columns: repeat(auto-fill, minmax(120px, 1fr)); } } </style> </head> <body> <div class="container"> <h1>Product Category Manager</h1> <p>Organize your e-commerce product listings by selecting category tags. Apply multiple filters to refine inventory views and manage your product catalog efficiently.</p> <div class="tag-manager"> <div class="search-section"> <div class="search-container"> <svg class="search-icon" width="20" height="20" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M11 19C15.4183 19 19 15.4183 19 11C19 6.58172 15.4183 3 11 3C6.58172 3 3 6.58172 3 11C3 15.4183 6.58172 19 11 19Z" stroke="#AAAAAA" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> <path d="M21 21L16.65 16.65" stroke="#AAAAAA" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> </svg> <input type="text" class="search-input" placeholder="Search categories..."> </div> <div class="tags-grid"> <div class="tag electronics" data-category="electronics">Electronics</div> <div class="tag fashion" data-category="fashion">Fashion</div> <div class="tag home" data-category="home">Home & Garden</div> <div class="tag beauty" data-category="beauty">Beauty</div> <div class="tag sports" data-category="sports">Sports</div> <div class="tag food" data-category="food">Food & Drinks</div> </div> </div> <div class="selected-tags"> <div class="selected-tags-title">Active Filters</div> <div class="selected-tags-container" id="selectedTags"></div> </div> </div> <div class="product-list"> <div class="product-list-title"> <span>Product Inventory</span> <span class="filter-count">0 filters applied</span> </div> <div class="product-grid" id="productGrid"> <!-- Products will be dynamically added here --> </div> <div class="empty-state" id="emptyState"> No products match the selected categories </div> <div class="legend"> <div class="legend-item"> <div class="legend-color" style="background: linear-gradient(135deg, var(--electronics-start), var(--electronics-end));"></div> <span>Electronics</span> </div> <div class="legend-item"> <div class="legend-color" style="background: linear-gradient(135deg, var(--fashion-start), var(--fashion-end));"></div> <span>Fashion</span> </div> <div class="legend-item"> <div class="legend-color" style="background: linear-gradient(135deg, var(--home-start), var(--home-end));"></div> <span>Home & Garden</span> </div> <div class="legend-item"> <div class="legend-color" style="background: linear-gradient(135deg, var(--beauty-start), var(--beauty-end));"></div> <span>Beauty</span> </div> <div class="legend-item"> <div class="legend-color" style="background: linear-gradient(135deg, var(--sports-start), var(--sports-end));"></div> <span>Sports</span> </div> <div class="legend-item"> <div class="legend-color" style="background: linear-gradient(135deg, var(--food-start), var(--food-end));"></div> <span>Food & Drinks</span> </div> </div> </div> </div> <script> document.addEventListener('DOMContentLoaded', function() { // Products data const products = [ { id: 1, name: "Wireless Earbuds", category: "electronics", image: "https://source.unsplash.com/random/200x200/?earbuds" }, { id: 2, name: "Denim Jacket", category: "fashion", image: "https://source.unsplash.com/random/200x200/?jacket" }, { id: 3, name: "Smart Thermostat", category: "home", image: "https://source.unsplash.com/random/200x200/?thermostat" }, { id: 4, name: "Facial Serum", category: "beauty", image: "https://source.unsplash.com/random/200x200/?serum" }, { id: 5, name: "Yoga Mat", category: "sports", image: "https://source.unsplash.com/random/200x200/?yoga" }, { id: 6, name: "Organic Coffee", category: "food", image: "https://source.unsplash.com/random/200x200/?coffee" }, { id: 7, name: "Smartphone", category: "electronics", image: "https://source.unsplash.com/random/200x200/?smartphone" }, { id: 8, name: "Running Shoes", category: "fashion", image: "https://source.unsplash.com/random/200x200/?shoes" }, { id: 9, name: "LED Plant Light", category: "home", image: "https://source.unsplash.com/random/200x200/?plant-light" }, { id: 10, name: "Lipstick Set", category: "beauty", image: "https://source.unsplash.com/random/200x200/?lipstick" }, { id: 11, name: "Dumbbells", category: "sports", image: "https://source.unsplash.com/random/200x200/?dumbbells" }, { id: 12, name: "Artisanal Tea", category: "food", image: "https://source.unsplash.com/random/200x200/?tea" } ]; // DOM elements const tagsGrid = document.querySelector('.tags-grid'); const selectedTagsContainer = document.getElementById('selectedTags'); const productGrid = document.getElementById('productGrid'); const emptyState = document.getElementById('emptyState'); const filterCount = document.querySelector('.filter-count'); const searchInput = document.querySelector('.search-input'); // Array to store selected categories let selectedCategories = []; // Initial render of products renderProducts(products); // Event listener for tag selection tagsGrid.addEventListener('click', function(e) { if (e.target.classList.contains('tag')) { const category = e.target.dataset.category; // If already selected, do nothing if (selectedCategories.includes(category)) { return; } // Add to selected categories selectedCategories.push(category); // Create and add selected tag element const selectedTag = document.createElement('div'); selectedTag.className = `selected-tag ${category}`; selectedTag.dataset.category = category; const tagText = document.createTextNode(e.target.textContent); selectedTag.appendChild(tagText); const removeBtn = document.createElement('div'); removeBtn.className = 'remove-tag'; removeBtn.innerHTML = '×'; selectedTag.appendChild(removeBtn); selectedTagsContainer.appendChild(selectedTag); // Filter products filterProducts(); } }); // Event listener for removing selected tags selectedTagsContainer.addEventListener('click', function(e) { if (e.target.classList.contains('remove-tag')) { const selectedTag = e.target.parentElement; const category = selectedTag.dataset.category; // Remove animation selectedTag.style.animation = 'tagRemoveAnimation 0.2s forwards'; // After animation, remove from DOM and array setTimeout(() => { selectedTag.remove(); selectedCategories = selectedCategories.filter(cat => cat !== category); filterProducts(); }, 200); } }); // Event listener for search input searchInput.addEventListener('input', function(e) { const searchTerm = e.target.value.toLowerCase(); // Filter tags based on search term const tags = document.querySelectorAll('.tag'); tags.forEach(tag => { const tagText = tag.textContent.toLowerCase(); if (tagText.includes(searchTerm) || searchTerm === '') { tag.style.display = 'flex'; } else { tag.style.display = 'none'; } }); }); // Function to filter products based on selected categories function filterProducts() { let filteredProducts = products; if (selectedCategories.length > 0) { filteredProducts = products.filter(product => selectedCategories.includes(product.category) ); } // Update filter count filterCount.textContent = `${selectedCategories.length} filter${selectedCategories.length !== 1 ? 's' : ''} applied`; // Render filtered products renderProducts(filteredProducts); } // Function to render products function renderProducts(productsToRender) { productGrid.innerHTML = ''; if (productsToRender.length === 0) { emptyState.style.display = 'block'; productGrid.style.display = 'none'; } else { emptyState.style.display = 'none'; productGrid.style.display = 'grid'; productsToRender.forEach(product => { const productCard = document.createElement('div'); productCard.className = 'product-card'; productCard.innerHTML = ` <div class="product-image"> <img src="${product.image}" alt="${product.name}"> </div> <div class="product-info"> <div class="product-name">${product.name}</div> <div class="product-category"> <div class="category-dot" style="background: linear-gradient(135deg, var(--${product.category}-start), var(--${product.category}-end));"></div> <span>${getCategoryName(product.category)}</span> </div> </div> `; productGrid.appendChild(productCard); }); } } // Helper function to get full category name function getCategoryName(category) { const names = { electronics: 'Electronics', fashion: 'Fashion', home: 'Home & Garden', beauty: 'Beauty', sports: 'Sports', food: 'Food & Drinks' }; return names[category] || category; } }); </script> </body> </html>
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Project Management Dashboard</title> <style> :root { --critical: #ff4757; --high: #ff6b81; --medium: #ffa502; --low: #2ed573; --completed: #7bed9f; --dark: #2f3542; --light: #f1f2f6; --accent: #5352ed; --grey: #a4b0be; --white: #ffffff; } * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; } body { background-color: var(--light); color: var(--dark); font-size: 16px; line-height: 1.5; max-width: 700px; max-height: 700px; overflow: hidden; margin: 0 auto; } .dashboard { display: grid; grid-template-rows: auto 1fr auto; height: 100vh; max-height: 700px; background-color: var(--white); border-radius: 16px; overflow: hidden; box-shadow: 0 10px 30px rgba(0, 0, 0, 0.05); } header { padding: 20px; background-color: var(--white); border-bottom: 1px solid rgba(0, 0, 0, 0.05); display: flex; justify-content: space-between; align-items: center; position: relative; z-index: 10; } .logo { font-weight: 700; font-size: 1.25rem; color: var(--accent); display: flex; align-items: center; gap: 8px; } .logo svg { height: 24px; width: 24px; fill: var(--accent); } .actions { display: flex; gap: 10px; } .btn { padding: 8px 16px; background-color: var(--accent); color: white; border: none; border-radius: 8px; cursor: pointer; font-weight: 600; transition: all 0.2s ease; display: flex; align-items: center; gap: 6px; } .btn:hover { background-color: #4240db; transform: translateY(-2px); box-shadow: 0 5px 15px rgba(83, 82, 237, 0.2); } .btn svg { width: 16px; height: 16px; fill: white; } .main { overflow-y: auto; padding: 0; position: relative; } .container { padding: 20px; } .task-list { display: flex; flex-direction: column; gap: 12px; min-height: 400px; } .task-column { margin-bottom: 20px; } .column-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px; } .column-title { font-weight: 600; font-size: 1rem; color: var(--dark); display: flex; align-items: center; gap: 8px; } .task-count { background-color: var(--light); border-radius: 12px; padding: 2px 8px; font-size: 0.75rem; font-weight: 700; color: var(--dark); } .task-card { background-color: var(--white); border-radius: 8px; padding: 16px; margin-bottom: 12px; cursor: move; position: relative; box-shadow: 0 2px 10px rgba(0, 0, 0, 0.04); border-left: 4px solid var(--medium); transition: all 0.2s ease; transform-origin: center; } .task-card:hover { transform: translateY(-2px); box-shadow: 0 5px 15px rgba(0, 0, 0, 0.08); } .task-card.critical { border-left-color: var(--critical); } .task-card.high { border-left-color: var(--high); } .task-card.medium { border-left-color: var(--medium); } .task-card.low { border-left-color: var(--low); } .task-card.completed { border-left-color: var(--completed); background-color: rgba(126, 214, 159, 0.05); } .task-header { display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 8px; } .task-title { font-weight: 600; font-size: 1rem; color: var(--dark); margin-bottom: 5px; } .task-card.completed .task-title { text-decoration: line-through; color: var(--grey); } .priority-tag { font-size: 0.7rem; font-weight: 700; text-transform: uppercase; padding: 4px 8px; border-radius: 4px; color: white; } .priority-tag.critical { background-color: var(--critical); } .priority-tag.high { background-color: var(--high); } .priority-tag.medium { background-color: var(--medium); } .priority-tag.low { background-color: var(--low); } .priority-tag.completed { background-color: var(--completed); color: var(--dark); } .task-meta { display: flex; justify-content: space-between; font-size: 0.8rem; color: var(--grey); margin-top: 10px; } .task-actions { display: flex; gap: 5px; } .task-btn { background: none; border: none; cursor: pointer; color: var(--grey); transition: all 0.2s ease; } .task-btn:hover { color: var(--accent); } .task-btn svg { width: 16px; height: 16px; fill: currentColor; } .tooltip { position: absolute; background-color: var(--dark); color: white; padding: 8px 12px; border-radius: 6px; font-size: 0.75rem; z-index: 100; opacity: 0; pointer-events: none; transition: opacity 0.2s ease, transform 0.2s ease; transform: translateY(10px); max-width: 250px; box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2); } .tooltip::before { content: ''; position: absolute; bottom: -5px; left: 50%; transform: translateX(-50%); width: 0; height: 0; border-left: 6px solid transparent; border-right: 6px solid transparent; border-top: 6px solid var(--dark); } .progress-section { margin-bottom: 20px; } .progress-title { font-weight: 600; font-size: 0.9rem; color: var(--dark); margin-bottom: 8px; display: flex; justify-content: space-between; } .progress-bar { height: 8px; background-color: var(--light); border-radius: 4px; overflow: hidden; margin-bottom: 5px; } .progress-fill { height: 100%; background-color: var(--accent); width: 45%; border-radius: 4px; transition: width 0.5s ease; } .task-assignee { display: flex; align-items: center; gap: 5px; } .assignee-avatar { width: 24px; height: 24px; border-radius: 50%; background-color: var(--accent); display: flex; align-items: center; justify-content: center; color: white; font-weight: 600; font-size: 0.75rem; } .dragging { opacity: 0.7; transform: scale(1.02); z-index: 100; } .placeholder { border: 2px dashed var(--grey); background-color: rgba(164, 176, 190, 0.1); } .filter-tabs { display: flex; gap: 10px; padding: 15px 20px; overflow-x: auto; border-bottom: 1px solid rgba(0, 0, 0, 0.05); background-color: var(--white); position: sticky; top: 0; z-index: 5; } .filter-tab { padding: 6px 14px; border-radius: 20px; font-weight: 600; font-size: 0.9rem; cursor: pointer; transition: all 0.2s ease; white-space: nowrap; border: 1px solid transparent; } .filter-tab:hover { background-color: var(--light); } .filter-tab.active { background-color: var(--accent); color: white; box-shadow: 0 2px 8px rgba(83, 82, 237, 0.2); } .no-tasks { text-align: center; padding: 40px 20px; color: var(--grey); font-size: 0.9rem; } .no-tasks svg { width: 60px; height: 60px; fill: var(--grey); margin-bottom: 15px; opacity: 0.5; } footer { padding: 15px 20px; display: flex; justify-content: space-between; align-items: center; border-top: 1px solid rgba(0, 0, 0, 0.05); font-size: 0.8rem; color: var(--grey); background-color: var(--white); } .task-description { font-size: 0.9rem; color: var(--dark); margin-bottom: 10px; line-height: 1.5; } /* Animations */ @keyframes slideIn { from { transform: translateY(20px); opacity: 0; } to { transform: translateY(0); opacity: 1; } } .task-card { animation: slideIn 0.3s ease forwards; } /* Responsive */ @media (max-width: 600px) { .dashboard { border-radius: 0; height: 100vh; } header { padding: 15px; } .logo span { display: none; } .btn span { display: none; } .filter-tabs { padding: 10px 15px; } .container { padding: 15px; } .task-card { padding: 12px; } } /* Custom Scrollbar */ .main::-webkit-scrollbar { width: 8px; } .main::-webkit-scrollbar-track { background: transparent; } .main::-webkit-scrollbar-thumb { background-color: var(--grey); border-radius: 4px; } .main::-webkit-scrollbar-thumb:hover { background-color: #8c98a8; } </style> </head> <body> <div class="dashboard"> <header> <div class="logo"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> <path d="M3 13h8V3H3v10zm0 8h8v-6H3v6zm10 0h8V11h-8v10zm0-18v6h8V3h-8z"/> </svg> <span>TaskMaster</span> </div> <div class="actions"> <button class="btn add-task-btn"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> <path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/> </svg> <span>Add Task</span> </button> </div> </header> <div class="main"> <div class="filter-tabs"> <div class="filter-tab active" data-filter="all">All Tasks</div> <div class="filter-tab" data-filter="critical">Critical</div> <div class="filter-tab" data-filter="high">High Priority</div> <div class="filter-tab" data-filter="medium">Medium Priority</div> <div class="filter-tab" data-filter="low">Low Priority</div> <div class="filter-tab" data-filter="completed">Completed</div> </div> <div class="container"> <div class="progress-section"> <div class="progress-title"> <span>Project Progress</span> <span>45%</span> </div> <div class="progress-bar"> <div class="progress-fill"></div> </div> </div> <div class="task-column"> <div class="column-header"> <div class="column-title"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="currentColor"> <path d="M3 13h2v-2H3v2zm0 4h2v-2H3v2zm0-8h2V7H3v2zm4 4h14v-2H7v2zm0 4h14v-2H7v2zM7 7v2h14V7H7z"/> </svg> Tasks <div class="task-count">5</div> </div> </div> <div class="task-list" id="taskList"> <div class="task-card critical" draggable="true" data-priority="critical"> <div class="task-header"> <div class="task-title">Backend API Security Vulnerability Fix</div> <div class="priority-tag critical">Critical</div> </div> <div class="task-description">Fix OAuth token validation issue discovered in user authentication flow that could allow unauthorized access.</div> <div class="task-meta"> <div class="task-date">Due: Today</div> <div class="task-assignee"> <div class="assignee-avatar">JD</div> </div> </div> <div class="tooltip">Urgent: Security vulnerability needs immediate attention. Client data at risk.</div> </div> <div class="task-card high" draggable="true" data-priority="high"> <div class="task-header"> <div class="task-title">Finalize Q3 Roadmap Features</div> <div class="priority-tag high">High</div> </div> <div class="task-description">Consolidate feature requests, align with stakeholders, and lock final Q3 product development roadmap.</div> <div class="task-meta"> <div class="task-date">Due: Jun 28</div> <div class="task-assignee"> <div class="assignee-avatar">KP</div> </div> </div> <div class="tooltip">Board presentation next week - need finalized roadmap with development estimates.</div> </div> <div class="task-card medium" draggable="true" data-priority="medium"> <div class="task-header"> <div class="task-title">Implement Data Visualization Components</div> <div class="priority-tag medium">Medium</div> </div> <div class="task-description">Create reusable chart components for dashboard analytics using D3.js with responsive design.</div> <div class="task-meta"> <div class="task-date">Due: Jul 3</div> <div class="task-assignee"> <div class="assignee-avatar">MS</div> </div> </div> <div class="tooltip">Support for line charts, bar graphs, and heat maps needed with export functionality.</div> </div> <div class="task-card low" draggable="true" data-priority="low"> <div class="task-header"> <div class="task-title">Update Documentation for v2.4</div> <div class="priority-tag low">Low</div> </div> <div class="task-description">Review and update developer documentation to reflect recent API changes and new features.</div> <div class="task-meta"> <div class="task-date">Due: Jul 10</div> <div class="task-assignee"> <div class="assignee-avatar">TW</div> </div> </div> <div class="tooltip">Focus on new authentication flow and webhook integration examples.</div> </div> <div class="task-card completed" draggable="true" data-priority="completed"> <div class="task-header"> <div class="task-title">UI Component Library Migration</div> <div class="priority-tag completed">Completed</div> </div> <div class="task-description">Migrate from Bootstrap to custom component system with improved accessibility and performance.</div> <div class="task-meta"> <div class="task-date">Completed: Jun 22</div> <div class="task-assignee"> <div class="assignee-avatar">RL</div> </div> </div> <div class="tooltip">Successfully reduced bundle size by 40% and improved loading performance.</div> </div> </div> </div> </div> </div> <footer> <div>Last updated: June 25, 2023 at 10:45 AM</div> <div>TaskMaster Pro v2.4</div> </footer> </div> <script> document.addEventListener('DOMContentLoaded', function() { // Drag and drop functionality const taskCards = document.querySelectorAll('.task-card'); const taskList = document.getElementById('taskList'); let draggedItem = null; taskCards.forEach(card => { // Drag start event card.addEventListener('dragstart', function(e) { draggedItem = this; setTimeout(() => { this.classList.add('dragging'); }, 0); }); // Drag end event card.addEventListener('dragend', function() { this.classList.remove('dragging'); draggedItem = null; }); // Tooltip functionality card.addEventListener('mouseover', function(e) { const tooltip = this.querySelector('.tooltip'); if (tooltip) { tooltip.style.opacity = '1'; tooltip.style.transform = 'translateY(0)'; // Position the tooltip const rect = this.getBoundingClientRect(); tooltip.style.bottom = '100%'; tooltip.style.left = '50%'; tooltip.style.transform = 'translateX(-50%)'; tooltip.style.marginBottom = '10px'; } }); card.addEventListener('mouseout', function() { const tooltip = this.querySelector('.tooltip'); if (tooltip) { tooltip.style.opacity = '0'; tooltip.style.transform = 'translateY(10px)'; } }); }); // Handle the drag over event on the container taskList.addEventListener('dragover', function(e) { e.preventDefault(); const afterElement = getDragAfterElement(taskList, e.clientY); const placeholder = document.querySelector('.placeholder'); if (placeholder) { placeholder.remove(); } if (afterElement == null) { taskList.appendChild(draggedItem); } else { taskList.insertBefore(draggedItem, afterElement); } }); // Get the element after the current drag position function getDragAfterElement(container, y) { const draggableElements = [...container.querySelectorAll('.task-card:not(.dragging)')]; return draggableElements.reduce((closest, child) => { const box = child.getBoundingClientRect(); const offset = y - box.top - box.height / 2; if (offset < 0 && offset > closest.offset) { return { offset: offset, element: child }; } else { return closest; } }, { offset: Number.NEGATIVE_INFINITY }).element; } // Filter tabs functionality const filterTabs = document.querySelectorAll('.filter-tab'); filterTabs.forEach(tab => { tab.addEventListener('click', function() { // Remove active class from all tabs filterTabs.forEach(t => t.classList.remove('active')); // Add active class to clicked tab this.classList.add('active'); // Get filter value const filter = this.getAttribute('data-filter'); // Filter tasks filterTasks(filter); }); }); function filterTasks(filter) { taskCards.forEach(card => { if (filter === 'all' || card.getAttribute('data-priority') === filter) { card.style.display = 'block'; // Add animation card.style.animation = 'none'; setTimeout(() => { card.style.animation = 'slideIn 0.3s ease forwards'; }, 10); } else { card.style.display = 'none'; } }); // Check if no tasks are visible after filtering const visibleTasks = document.querySelectorAll('.task-card[style="display: block"]'); const noTasksElement = document.querySelector('.no-tasks'); if (visibleTasks.length === 0 && !noTasksElement) { const noTasksDiv = document.createElement('div'); noTasksDiv.className = 'no-tasks'; noTasksDiv.innerHTML = ` <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> <path d="M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 16H5V5h14v14zM7 10h2v7H7zm4-3h2v10h-2zm4 6h2v4h-2z"/> </svg> <p>No tasks found with ${filter} priority</p> `; taskList.appendChild(noTasksDiv); } else if (visibleTasks.length > 0 && noTasksElement) { noTasksElement.remove(); } // Update task count document.querySelector('.task-count').textContent = visibleTasks.length; } // Add task button functionality const addTaskBtn = document.querySelector('.add-task-btn'); addTaskBtn.addEventListener('click', function() { // Create new task card const newTask = document.createElement('div'); newTask.className = 'task-card medium'; newTask.setAttribute('draggable', 'true'); newTask.setAttribute('data-priority', 'medium'); newTask.innerHTML = ` <div class="task-header"> <div class="task-title">New Feature Implementation</div> <div class="priority-tag medium">Medium</div> </div> <div class="task-description">Implement new feature as per the latest sprint planning discussion.</div> <div class="task-meta"> <div class="task-date">Due: Jul 15</div> <div class="task-assignee"> <div class="assignee-avatar">YO</div> </div> </div> <div class="tooltip">Newly added task - assign team member and update details.</div> `; // Add to the beginning of the list taskList.insertBefore(newTask, taskList.firstChild); // Update task count const taskCount = document.querySelector('.task-count'); taskCount.textContent = parseInt(taskCount.textContent) + 1; // Add the same event listeners as other cards newTask.addEventListener('dragstart', function(e) { draggedItem = this; setTimeout(() => { this.classList.add('dragging'); }, 0); }); newTask.addEventListener('dragend', function() { this.classList.remove('dragging'); draggedItem = null; }); newTask.addEventListener('mouseover', function() { const tooltip = this.querySelector('.tooltip'); if (tooltip) { tooltip.style.opacity = '1'; tooltip.style.transform = 'translateY(0)'; // Position the tooltip tooltip.style.bottom = '100%'; tooltip.style.left = '50%'; tooltip.style.transform = 'translateX(-50%)'; tooltip.style.marginBottom = '10px'; } }); newTask.addEventListener('mouseout', function() { const tooltip = this.querySelector('.tooltip'); if (tooltip) { tooltip.style.opacity = '0'; tooltip.style.transform = 'translateY(10px)'; } }); // Apply animation newTask.style.animation = 'none'; setTimeout(() => { newTask.style.animation = 'slideIn 0.3s ease forwards'; }, 10); }); }); </script> </body> </html>
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Social Media Hashtag Interface</title> <style> :root { --neon-pink: #ff36ab; --neon-blue: #3646ff; --neon-green: #36ff46; --neon-purple: #b736ff; --neon-yellow: #f2ff36; --bg-dark: #0a0a0a; --text-light: #f5f5f5; --tag-bg: rgba(30, 30, 30, 0.7); --tag-active-bg: rgba(50, 50, 50, 0.85); } * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; } body { background-color: var(--bg-dark); color: var(--text-light); display: flex; justify-content: center; align-items: center; min-height: 100vh; overflow-x: hidden; padding: 15px; } .container { width: 100%; max-width: 700px; height: 700px; display: flex; flex-direction: column; gap: 30px; padding: 30px; position: relative; overflow: hidden; } .background-grid { position: absolute; top: 0; left: 0; width: 100%; height: 100%; background-image: radial-gradient(var(--neon-blue) 1px, transparent 1px), radial-gradient(var(--neon-pink) 1px, transparent 1px); background-size: 30px 30px; background-position: 0 0, 15px 15px; opacity: 0.05; z-index: -1; } .title { font-size: 2.5rem; font-weight: 800; letter-spacing: -0.5px; text-shadow: 0 0 10px var(--neon-blue), 0 0 20px var(--neon-pink); text-align: center; margin-bottom: 10px; } .subtitle { font-size: 1rem; color: rgba(255, 255, 255, 0.7); text-align: center; max-width: 500px; margin: 0 auto 30px; } .search-container { position: relative; margin-bottom: 20px; } .search-input { width: 100%; padding: 15px 60px 15px 20px; background-color: rgba(30, 30, 30, 0.7); border: 2px solid rgba(255, 255, 255, 0.1); border-radius: 12px; color: var(--text-light); font-size: 1rem; transition: all 0.3s ease; letter-spacing: 0.5px; } .search-input:focus { outline: none; border-color: var(--neon-blue); box-shadow: 0 0 15px rgba(54, 70, 255, 0.3); } .search-icon { position: absolute; right: 20px; top: 50%; transform: translateY(-50%); color: rgba(255, 255, 255, 0.5); font-size: 1.2rem; } .hashtag-container { width: 100%; display: flex; flex-wrap: wrap; gap: 12px; margin-bottom: 30px; } .section-title { width: 100%; font-size: 1.2rem; margin-bottom: 15px; font-weight: 600; color: rgba(255, 255, 255, 0.8); } .hashtag { display: inline-flex; align-items: center; padding: 8px 14px; background-color: var(--tag-bg); border-radius: 30px; font-size: 0.9rem; cursor: pointer; transition: all 0.25s cubic-bezier(0.2, 0.8, 0.2, 1); backdrop-filter: blur(5px); position: relative; overflow: hidden; border: 1px solid rgba(255, 255, 255, 0.1); color: rgba(255,255,255,0.9); } .hashtag:hover { transform: translateY(-2px) scale(1.05); background-color: var(--tag-active-bg); } .hashtag::before { content: ""; position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.1), transparent); transform: translateX(-100%); } .hashtag:hover::before { animation: shimmer 1.5s infinite; } .hashtag.active { background-color: rgba(54, 70, 255, 0.2); border-color: var(--neon-blue); box-shadow: 0 0 10px rgba(54, 70, 255, 0.4); transform: translateY(-2px); } .hashtag.active.pink { background-color: rgba(255, 54, 171, 0.2); border-color: var(--neon-pink); box-shadow: 0 0 10px rgba(255, 54, 171, 0.4); } .hashtag.active.green { background-color: rgba(54, 255, 70, 0.2); border-color: var(--neon-green); box-shadow: 0 0 10px rgba(54, 255, 70, 0.4); } .hashtag.active.purple { background-color: rgba(183, 54, 255, 0.2); border-color: var(--neon-purple); box-shadow: 0 0 10px rgba(183, 54, 255, 0.4); } .hashtag.active.yellow { background-color: rgba(242, 255, 54, 0.2); border-color: var(--neon-yellow); box-shadow: 0 0 10px rgba(242, 255, 54, 0.4); color: rgba(10, 10, 10, 0.9); } .hashtag-symbol { color: var(--neon-blue); margin-right: 2px; font-weight: bold; } .active.pink .hashtag-symbol { color: var(--neon-pink); } .active.green .hashtag-symbol { color: var(--neon-green); } .active.purple .hashtag-symbol { color: var(--neon-purple); } .active.yellow .hashtag-symbol { color: var(--neon-yellow); } .hashtag-count { font-size: 0.75rem; margin-left: 5px; opacity: 0.7; } .trending-feed { background-color: rgba(30, 30, 30, 0.7); border-radius: 12px; padding: 20px; border: 1px solid rgba(255, 255, 255, 0.1); flex-grow: 1; overflow-y: auto; } .trending-feed::-webkit-scrollbar { width: 5px; } .trending-feed::-webkit-scrollbar-track { background: rgba(30, 30, 30, 0.3); } .trending-feed::-webkit-scrollbar-thumb { background-color: rgba(255, 255, 255, 0.2); border-radius: 10px; } .feed-title { font-size: 1.1rem; margin-bottom: 15px; display: flex; align-items: center; gap: 8px; } .feed-title svg { color: var(--neon-pink); } .post { padding: 15px 0; border-bottom: 1px solid rgba(255, 255, 255, 0.1); } .post:last-child { border-bottom: none; } .post-header { display: flex; align-items: center; margin-bottom: 10px; } .post-avatar { width: 35px; height: 35px; border-radius: 50%; background-color: var(--neon-blue); margin-right: 10px; display: flex; align-items: center; justify-content: center; font-weight: bold; font-size: 0.8rem; } .post-user { font-weight: 600; font-size: 0.9rem; } .post-time { font-size: 0.75rem; opacity: 0.6; margin-left: 10px; } .post-content { font-size: 0.9rem; line-height: 1.5; margin-bottom: 10px; } .post-tags { display: flex; flex-wrap: wrap; gap: 5px; } .post-tag { font-size: 0.8rem; color: var(--neon-blue); font-weight: 600; } .pulse { animation: pulse 2s infinite; } @keyframes pulse { 0% { box-shadow: 0 0 0 0 rgba(54, 70, 255, 0.4); } 70% { box-shadow: 0 0 0 10px rgba(54, 70, 255, 0); } 100% { box-shadow: 0 0 0 0 rgba(54, 70, 255, 0); } } @keyframes shimmer { 100% { transform: translateX(100%); } } @media (max-width: 600px) { .container { padding: 20px; } .title { font-size: 2rem; } .hashtag { font-size: 0.8rem; padding: 6px 12px; } } </style> </head> <body> <div class="container"> <div class="background-grid"></div> <h1 class="title">TrendTags</h1> <p class="subtitle">Discover viral hashtags and amplify your social reach with our trending tag interface</p> <div class="search-container"> <input type="text" class="search-input" placeholder="Search hashtags..."> <div class="search-icon"> <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" 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> </svg> </div> </div> <div class="hashtag-container"> <h2 class="section-title">Your Active Tags</h2> <div class="hashtag active"> <span class="hashtag-symbol">#</span>TechInnovation <span class="hashtag-count">2.3M</span> </div> <div class="hashtag active pink"> <span class="hashtag-symbol">#</span>DigitalNomad <span class="hashtag-count">1.8M</span> </div> <div class="hashtag active green"> <span class="hashtag-symbol">#</span>SustainableLiving <span class="hashtag-count">4.2M</span> </div> </div> <div class="hashtag-container"> <h2 class="section-title">Suggested For You</h2> <div class="hashtag"> <span class="hashtag-symbol">#</span>AIEthics <span class="hashtag-count">893K</span> </div> <div class="hashtag"> <span class="hashtag-symbol">#</span>FutureTech <span class="hashtag-count">1.5M</span> </div> <div class="hashtag"> <span class="hashtag-symbol">#</span>RemoteWork <span class="hashtag-count">5.7M</span> </div> <div class="hashtag"> <span class="hashtag-symbol">#</span>CodingLife <span class="hashtag-count">732K</span> </div> <div class="hashtag"> <span class="hashtag-symbol">#</span>UXDesign <span class="hashtag-count">2.1M</span> </div> <div class="hashtag pulse"> <span class="hashtag-symbol">#</span>TrendingNow <span class="hashtag-count">8.3M</span> </div> </div> <div class="trending-feed"> <h3 class="feed-title"> <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"></polygon> </svg> Trending with your tags </h3> <div class="post"> <div class="post-header"> <div class="post-avatar">KL</div> <span class="post-user">Karen Liu</span> <span class="post-time">2h ago</span> </div> <p class="post-content">Just wrapped up a month of working from Bali. The digital nomad community here is incredible! Next stop: Singapore 🌏✈️</p> <div class="post-tags"> <span class="post-tag">#DigitalNomad</span> <span class="post-tag">#RemoteWork</span> <span class="post-tag">#WorkFromAnywhere</span> </div> </div> <div class="post"> <div class="post-header"> <div class="post-avatar">MS</div> <span class="post-user">Mark Summers</span> <span class="post-time">5h ago</span> </div> <p class="post-content">Our startup just launched a zero-waste packaging solution that's completely biodegradable. Excited to see the impact this makes! 🌱 #SustainableLiving</p> <div class="post-tags"> <span class="post-tag">#SustainableLiving</span> <span class="post-tag">#ZeroWaste</span> <span class="post-tag">#GreenTech</span> </div> </div> <div class="post"> <div class="post-header"> <div class="post-avatar">AT</div> <span class="post-user">Ava Thompson</span> <span class="post-time">8h ago</span> </div> <p class="post-content">Just presented our research on ethical AI frameworks at the Tech Summit. The conversation around responsible innovation is finally gaining momentum!</p> <div class="post-tags"> <span class="post-tag">#TechInnovation</span> <span class="post-tag">#AIEthics</span> <span class="post-tag">#ResponsibleTech</span> </div> </div> </div> </div> <script> document.addEventListener('DOMContentLoaded', function() { // Handle hashtag clicking const hashtags = document.querySelectorAll('.hashtag:not(.active)'); const colors = ['pink', 'blue', 'green', 'purple', 'yellow']; hashtags.forEach(hashtag => { hashtag.addEventListener('click', function() { // Toggle active class this.classList.toggle('active'); // Add random color class if becoming active if (this.classList.contains('active')) { const randomColor = colors[Math.floor(Math.random() * colors.length)]; this.classList.add(randomColor); // Create the pulsating effect this.style.animation = 'pulse 1.5s'; setTimeout(() => { this.style.animation = ''; }, 1500); } else { // Remove all color classes if no longer active colors.forEach(color => { this.classList.remove(color); }); } }); }); // Handle search input const searchInput = document.querySelector('.search-input'); searchInput.addEventListener('focus', function() { this.placeholder = ''; }); searchInput.addEventListener('blur', function() { this.placeholder = 'Search hashtags...'; }); searchInput.addEventListener('keyup', function(e) { if (e.key === 'Enter') { const searchTerm = this.value.trim(); if (searchTerm.length > 0) { // Create new hashtag element const newHashtag = document.createElement('div'); newHashtag.className = 'hashtag active pulse'; // Add random color const randomColor = colors[Math.floor(Math.random() * colors.length)]; newHashtag.classList.add(randomColor); // Create inner content const tagText = searchTerm.startsWith('#') ? searchTerm.slice(1) : searchTerm; newHashtag.innerHTML = `<span class="hashtag-symbol">#</span>${tagText}<span class="hashtag-count">New</span>`; // Add to active tags const activeContainer = document.querySelectorAll('.hashtag-container')[0]; activeContainer.appendChild(newHashtag); // Clear search this.value = ''; // Add event listener to the new hashtag newHashtag.addEventListener('click', function() { this.classList.toggle('active'); if (!this.classList.contains('active')) { colors.forEach(color => { this.classList.remove(color); }); } }); } } }); // Simulate loading new trending posts const trendingFeed = document.querySelector('.trending-feed'); const simulateNewPost = () => { const randomTime = Math.floor(Math.random() * (180000 - 60000)) + 60000; // Between 1-3 minutes setTimeout(() => { const users = [ { name: 'Jamie Chen', initials: 'JC', content: 'Just launched our new AR app that helps visualize sustainable home improvements. Check it out! #TechInnovation #SustainableLiving' }, { name: 'Rachel Kim', initials: 'RK', content: 'Working remotely while traveling through Europe has completely changed my perspective on work-life balance. #DigitalNomad life forever! 🌍' }, { name: 'Dev Patel', initials: 'DP', content: 'Our team is revolutionizing the way we approach renewable energy storage. Exciting times ahead for #TechInnovation in the green space!' } ]; const randomUser = users[Math.floor(Math.random() * users.length)]; const newPost = document.createElement('div'); newPost.className = 'post'; newPost.innerHTML = ` <div class="post-header"> <div class="post-avatar">${randomUser.initials}</div> <span class="post-user">${randomUser.name}</span> <span class="post-time">Just now</span> </div> <p class="post-content">${randomUser.content}</p> <div class="post-tags"> ${randomUser.content.match(/#\w+/g).map(tag => `<span class="post-tag">${tag}</span>`).join('')} </div> `; // Add new post with animation newPost.style.opacity = '0'; newPost.style.transform = 'translateY(20px)'; trendingFeed.insertBefore(newPost, trendingFeed.firstChild.nextSibling); setTimeout(() => { newPost.style.transition = 'all 0.5s ease'; newPost.style.opacity = '1'; newPost.style.transform = 'translateY(0)'; }, 100); // Call recursively for continuous simulation simulateNewPost(); }, randomTime); }; // Start the simulation simulateNewPost(); }); </script> </body> </html>
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>News Topic Filters</title> <style> :root { --color-primary: #dd3333; --color-secondary: #ffd800; --color-tertiary: #44aadd; --color-background: #f2f2f2; --color-text: #333333; --color-text-light: #666666; --shadow-active: 0 4px 8px rgba(0, 0, 0, 0.1); --transition-speed: 0.3s; } * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', sans-serif; } body { background-color: var(--color-background); color: var(--color-text); display: flex; flex-direction: column; align-items: center; justify-content: flex-start; min-height: 100vh; padding: 20px; max-width: 700px; margin: 0 auto; } header { width: 100%; text-align: center; margin-bottom: 20px; } h1 { font-size: 1.8rem; margin-bottom: 6px; font-weight: 700; position: relative; display: inline-block; } h1::after { content: ''; position: absolute; bottom: -4px; left: 10%; width: 80%; height: 3px; background: linear-gradient(90deg, var(--color-primary), var(--color-tertiary)); border-radius: 2px; } .subtitle { font-size: 0.9rem; color: var(--color-text-light); margin-bottom: 16px; } .filter-container { width: 100%; margin-bottom: 16px; } .filter-groups { display: flex; flex-wrap: wrap; gap: 12px; margin-bottom: 24px; justify-content: center; } .filter-group { background-color: white; padding: 12px 16px; border-radius: 12px; box-shadow: 0 2px 6px rgba(0, 0, 0, 0.05); flex: 1; min-width: 140px; max-width: 280px; } .group-title { font-size: 0.85rem; text-transform: uppercase; letter-spacing: 0.5px; margin-bottom: 12px; color: var(--color-text-light); font-weight: 600; } .filter-tags { display: flex; flex-wrap: wrap; gap: 8px; } .filter-tag { padding: 6px 12px; border-radius: 50px; border: 1px solid #e0e0e0; background-color: white; font-size: 0.85rem; cursor: pointer; transition: all var(--transition-speed) ease; user-select: none; position: relative; overflow: hidden; } .filter-tag::before { content: ''; position: absolute; left: 0; top: 0; width: 100%; height: 100%; background: linear-gradient(45deg, rgba(255,255,255,0.1), rgba(255,255,255,0.5)); transform: translateY(100%); transition: transform var(--transition-speed) ease; } .filter-tag:hover::before { transform: translateY(0); } .filter-tag.active { box-shadow: var(--shadow-active); font-weight: 500; transform: translateY(-2px); } .news-container { width: 100%; background-color: white; border-radius: 12px; box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05); padding: 16px; overflow-y: auto; max-height: 400px; transition: all var(--transition-speed) ease; } .news-item { padding: 16px; margin-bottom: 16px; border-radius: 8px; border-left: 4px solid transparent; background-color: var(--color-background); transition: all var(--transition-speed) ease; opacity: 0; transform: translateY(20px); animation: fadeIn 0.5s forwards; } @keyframes fadeIn { to { opacity: 1; transform: translateY(0); } } .news-item:last-child { margin-bottom: 0; } .news-item .title { font-size: 1.1rem; font-weight: 600; margin-bottom: 8px; } .news-item .source { font-size: 0.8rem; color: var(--color-text-light); margin-bottom: 6px; display: flex; align-items: center; } .news-item .source::before { content: ''; display: inline-block; width: 8px; height: 8px; border-radius: 50%; margin-right: 8px; } .news-item .description { font-size: 0.9rem; line-height: 1.5; color: var(--color-text); margin-bottom: 12px; } .news-item .meta { display: flex; align-items: center; justify-content: space-between; font-size: 0.8rem; color: var(--color-text-light); } .news-item .tags { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 8px; } .news-item .tag { font-size: 0.75rem; padding: 2px 8px; border-radius: 50px; background-color: rgba(220, 220, 220, 0.5); } .news-item[data-category="health"] { border-left-color: var(--color-primary); } .news-item[data-category="health"] .source::before { background-color: var(--color-primary); } .news-item[data-category="technology"] { border-left-color: var(--color-tertiary); } .news-item[data-category="technology"] .source::before { background-color: var(--color-tertiary); } .news-item[data-category="economy"] { border-left-color: var(--color-secondary); } .news-item[data-category="economy"] .source::before { background-color: var(--color-secondary); } .filter-tag[data-category="health"].active { background-color: var(--color-primary); color: white; border-color: var(--color-primary); } .filter-tag[data-category="technology"].active { background-color: var(--color-tertiary); color: white; border-color: var(--color-tertiary); } .filter-tag[data-category="economy"].active { background-color: var(--color-secondary); color: #333; border-color: var(--color-secondary); } .status-message { padding: 20px; text-align: center; color: var(--color-text-light); display: none; } .clear-filters { margin-top: 16px; padding: 8px 16px; background-color: white; border: 1px solid #e0e0e0; border-radius: 50px; font-size: 0.85rem; cursor: pointer; transition: all var(--transition-speed) ease; color: var(--color-text-light); display: none; } .clear-filters:hover { background-color: #f5f5f5; transform: translateY(-1px); } .clear-filters.visible { display: block; animation: fadeIn 0.3s forwards; } .filter-tag .count { font-size: 0.7rem; background-color: rgba(0, 0, 0, 0.1); padding: 2px 6px; border-radius: 10px; margin-left: 6px; display: inline-block; } .active .count { background-color: rgba(255, 255, 255, 0.3); } @media (max-width: 600px) { h1 { font-size: 1.5rem; } .filter-groups { flex-direction: column; align-items: stretch; } .filter-group { max-width: 100%; } } /* Animation for new content */ @keyframes pulseHighlight { 0% { background-color: var(--color-background); } 50% { background-color: rgba(68, 170, 221, 0.1); } 100% { background-color: var(--color-background); } } .news-item.new-content { animation: fadeIn 0.5s forwards, pulseHighlight 2s 0.5s; } .no-results { padding: 32px; text-align: center; color: var(--color-text-light); font-style: italic; } /* Progress indicator for search */ .search-indicator { width: 100%; height: 3px; background-color: #f0f0f0; position: relative; overflow: hidden; margin-bottom: 16px; border-radius: 3px; display: none; } .search-indicator.active { display: block; } .search-indicator::before { content: ''; position: absolute; height: 100%; width: 30%; background-color: var(--color-tertiary); animation: searchProgress 1.5s infinite ease-in-out; } @keyframes searchProgress { 0% { left: -30%; } 100% { left: 100%; } } </style> </head> <body> <header> <h1>Outbreak Newsroom</h1> <p class="subtitle">Filtered perspectives on what matters today</p> </header> <div class="filter-container"> <div class="filter-groups"> <div class="filter-group"> <h3 class="group-title">Categories</h3> <div class="filter-tags"> <div class="filter-tag" data-type="category" data-category="health">Health <span class="count">5</span></div> <div class="filter-tag" data-type="category" data-category="technology">Technology <span class="count">4</span></div> <div class="filter-tag" data-type="category" data-category="economy">Economy <span class="count">3</span></div> </div> </div> <div class="filter-group"> <h3 class="group-title">Regions</h3> <div class="filter-tags"> <div class="filter-tag" data-type="region" data-region="global">Global <span class="count">8</span></div> <div class="filter-tag" data-type="region" data-region="americas">Americas <span class="count">6</span></div> <div class="filter-tag" data-type="region" data-region="europe">Europe <span class="count">3</span></div> <div class="filter-tag" data-type="region" data-region="asia">Asia <span class="count">4</span></div> </div> </div> <div class="filter-group"> <h3 class="group-title">Time Frame</h3> <div class="filter-tags"> <div class="filter-tag" data-type="time" data-time="today">Today <span class="count">4</span></div> <div class="filter-tag" data-type="time" data-time="week">This Week <span class="count">7</span></div> <div class="filter-tag" data-type="time" data-time="month">This Month <span class="count">12</span></div> </div> </div> </div> <div class="search-indicator"></div> <button class="clear-filters">Clear All Filters</button> </div> <div class="news-container"> <div class="news-item" data-category="health" data-region="global" data-time="today"> <div class="title">WHO Declares New Protocol for Infectious Disease Monitoring</div> <div class="source">World Health Organization</div> <div class="description">New standards require countries to report potential outbreaks within 24 hours of detection, enhancing global surveillance capabilities for emerging health threats.</div> <div class="meta"> <div class="date">Today, 09:45 AM</div> <div class="tags"> <span class="tag">Policy</span> <span class="tag">Global Health</span> </div> </div> </div> <div class="news-item" data-category="technology" data-region="americas" data-time="today"> <div class="title">AI System Predicts COVID Variant Evolution with 89% Accuracy</div> <div class="source">MIT Technology Review</div> <div class="description">Researchers have developed a machine learning model that can forecast viral mutations months before they occur, potentially revolutionizing vaccine development timelines.</div> <div class="meta"> <div class="date">Today, 11:30 AM</div> <div class="tags"> <span class="tag">AI</span> <span class="tag">Virology</span> <span class="tag">Research</span> </div> </div> </div> <div class="news-item" data-category="economy" data-region="global" data-time="week"> <div class="title">Pharmaceutical Supply Chains Facing Critical Disruptions</div> <div class="source">Financial Times</div> <div class="description">Global shortages of key pharmaceutical ingredients are threatening production capacity as manufacturing hubs struggle with increased demand and regulatory challenges.</div> <div class="meta"> <div class="date">Yesterday, 03:15 PM</div> <div class="tags"> <span class="tag">Supply Chain</span> <span class="tag">Pharmaceuticals</span> </div> </div> </div> <div class="news-item" data-category="health" data-region="asia" data-time="week"> <div class="title">Novel Mosquito-Borne Virus Identified in Southeast Asia</div> <div class="source">The Lancet</div> <div class="description">Scientists have discovered a previously unknown arbovirus in Malaysia with potential for human transmission. Early symptoms resemble dengue but with neurological complications.</div> <div class="meta"> <div class="date">2 days ago</div> <div class="tags"> <span class="tag">Vector-borne</span> <span class="tag">Emerging Diseases</span> </div> </div> </div> <div class="news-item" data-category="technology" data-region="americas" data-time="week"> <div class="title">Wearable Tech to Monitor Infectious Disease Exposure Launches Beta</div> <div class="source">WIRED</div> <div class="description">A Stanford-developed wristband can detect airborne pathogens and alert wearers to potential exposure risks in real-time through environmental sampling and PCR technology.</div> <div class="meta"> <div class="date">3 days ago</div> <div class="tags"> <span class="tag">Wearables</span> <span class="tag">Prevention</span> </div> </div> </div> <div class="news-item" data-category="health" data-region="europe" data-time="month"> <div class="title">EU Launches Unified Disease Surveillance Network</div> <div class="source">European Commission</div> <div class="description">The European Health Emergency Preparedness Authority has connected all 27 member states into a real-time outbreak monitoring system with standardized reporting protocols.</div> <div class="meta"> <div class="date">1 week ago</div> <div class="tags"> <span class="tag">Infrastructure</span> <span class="tag">Public Health</span> </div> </div> </div> <div class="news-item" data-category="economy" data-region="global" data-time="month"> <div class="title">Pandemic Insurance Products See Surge in Corporate Adoption</div> <div class="source">Bloomberg</div> <div class="description">Following recent outbreak disruptions, multinational corporations are increasingly investing in specialized insurance coverage for business continuity during health emergencies.</div> <div class="meta"> <div class="date">2 weeks ago</div> <div class="tags"> <span class="tag">Insurance</span> <span class="tag">Business</span> </div> </div> </div> <div class="news-item" data-category="technology" data-region="europe" data-time="month"> <div class="title">Digital Contact Tracing 2.0 Addresses Privacy Concerns</div> <div class="source">TechCrunch</div> <div class="description">Next-generation contact tracing platforms use zero-knowledge proofs and decentralized data storage to enable effective outbreak control while preserving user anonymity.</div> <div class="meta"> <div class="date">2 weeks ago</div> <div class="tags"> <span class="tag">Privacy</span> <span class="tag">Public Health</span> </div> </div> </div> <div class="news-item" data-category="health" data-region="americas" data-time="today"> <div class="title">CDC Revises Guidelines for Hospital Outbreak Protocols</div> <div class="source">Centers for Disease Control</div> <div class="description">Updated guidelines recommend significant changes to healthcare facility ventilation systems and staff rotation policies based on lessons from recent respiratory disease clusters.</div> <div class="meta"> <div class="date">Today, 08:15 AM</div> <div class="tags"> <span class="tag">Healthcare</span> <span class="tag">Guidelines</span> </div> </div> </div> <div class="news-item" data-category="technology" data-region="global" data-time="today"> <div class="title">Satellite Imagery Algorithm Detects Animal Die-offs Before Reports</div> <div class="source">Nature Technology</div> <div class="description">Researchers demonstrate how machine learning applied to satellite imagery can identify animal mortality events weeks before traditional reporting systems, providing early warning for zoonotic threats.</div> <div class="meta"> <div class="date">Today, 10:45 AM</div> <div class="tags"> <span class="tag">Early Warning</span> <span class="tag">Zoonotic</span> </div> </div> </div> <div class="news-item" data-category="economy" data-region="asia" data-time="month"> <div class="title">Asian Nations Form Regional Vaccine Production Alliance</div> <div class="source">Nikkei Asia</div> <div class="description">Six Asian countries have signed an agreement to pool resources for vaccine manufacturing capacity, aiming to reduce dependency on western pharmaceutical imports during health emergencies.</div> <div class="meta"> <div class="date">3 weeks ago</div> <div class="tags"> <span class="tag">Manufacturing</span> <span class="tag">Vaccines</span> </div> </div> </div> <div class="news-item" data-category="health" data-region="asia" data-time="week"> <div class="title">Rapid Diagnostics Breakthrough Enables 30-Second Testing</div> <div class="source">Science Advances</div> <div class="description">A Japanese research team has developed a paper-based diagnostic tool that can detect multiple pathogens simultaneously through a color-changing reaction visible to the naked eye.</div> <div class="meta"> <div class="date">5 days ago</div> <div class="tags"> <span class="tag">Diagnostics</span> <span class="tag">Innovation</span> </div> </div> </div> </div> <script> document.addEventListener('DOMContentLoaded', function() { const filterTags = document.querySelectorAll('.filter-tag'); const newsItems = document.querySelectorAll('.news-item'); const clearFiltersBtn = document.querySelector('.clear-filters'); const searchIndicator = document.querySelector('.search-indicator'); const newsContainer = document.querySelector('.news-container'); let activeFilters = { category: [], region: [], time: [] }; // Initialize all items as visible updateNewsDisplay(); filterTags.forEach(tag => { tag.addEventListener('click', function() { const type = this.dataset.type; const value = this.dataset[type]; // Toggle active state visually this.classList.toggle('active'); // Update filter arrays if (this.classList.contains('active')) { activeFilters[type].push(value); } else { const index = activeFilters[type].indexOf(value); if (index > -1) { activeFilters[type].splice(index, 1); } } // Show loading indicator searchIndicator.classList.add('active'); // Simulate processing delay setTimeout(() => { updateNewsDisplay(); searchIndicator.classList.remove('active'); }, 400); // Show/hide clear filters button updateClearFiltersButton(); }); }); clearFiltersBtn.addEventListener('click', function() { // Reset all active filters activeFilters = { category: [], region: [], time: [] }; // Remove active class from all tags filterTags.forEach(tag => { tag.classList.remove('active'); }); // Show loading indicator searchIndicator.classList.add('active'); // Update display after a small delay setTimeout(() => { updateNewsDisplay(); searchIndicator.classList.remove('active'); this.classList.remove('visible'); }, 400); }); function updateNewsDisplay() { let visibleCount = 0; const hasActiveFilters = Object.values(activeFilters).some(arr => arr.length > 0); // Remove any existing "no results" message const existingNoResults = document.querySelector('.no-results'); if (existingNoResults) { existingNoResults.remove(); } newsItems.forEach(item => { if (!hasActiveFilters) { // If no filters are active, show all items item.style.display = 'block'; visibleCount++; return; } // Check if the item matches all active filter categories let matchesCategory = activeFilters.category.length === 0 || activeFilters.category.includes(item.dataset.category); let matchesRegion = activeFilters.region.length === 0 || activeFilters.region.includes(item.dataset.region); let matchesTime = activeFilters.time.length === 0 || activeFilters.time.includes(item.dataset.time); if (matchesCategory && matchesRegion && matchesTime) { item.style.display = 'block'; visibleCount++; } else { item.style.display = 'none'; } }); // Show "no results" message if needed if (visibleCount === 0 && hasActiveFilters) { const noResults = document.createElement('div'); noResults.className = 'no-results'; noResults.textContent = 'No news matches your current filters. Try adjusting your selection.'; newsContainer.appendChild(noResults); } // Add animation class to visible items const visibleItems = Array.from(newsItems).filter(item => item.style.display !== 'none'); visibleItems.forEach((item, index) => { // Remove any existing animation classes item.classList.remove('new-content'); // Stagger the animations setTimeout(() => { item.classList.add('new-content'); }, index * 50); }); } function updateClearFiltersButton() { const hasActiveFilters = Object.values(activeFilters).some(arr => arr.length > 0); if (hasActiveFilters) { clearFiltersBtn.classList.add('visible'); } else { clearFiltersBtn.classList.remove('visible'); } } // Simulate new content arrival setTimeout(() => { const newItem = document.createElement('div'); newItem.className = 'news-item new-content'; newItem.dataset.category = 'health'; newItem.dataset.region = 'global'; newItem.dataset.time = 'today'; newItem.innerHTML = ` <div class="title">Breaking: Global Health Summit Announces Pandemic Prevention Fund</div> <div class="source">Reuters</div> <div class="description">World leaders have committed $10 billion to a new fund aimed at strengthening healthcare systems and pandemic response capabilities in vulnerable regions.</div> <div class="meta"> <div class="date">Just now</div> <div class="tags"> <span class="tag">Funding</span> <span class="tag">Global Health</span> </div> </div> `; newsContainer.insertBefore(newItem, newsContainer.firstChild); updateNewsDisplay(); // Update the counter on the health tag const healthTag = document.querySelector('.filter-tag[data-category="health"] .count'); const newCount = parseInt(healthTag.textContent) + 1; healthTag.textContent = newCount; // Update the counter on the global tag const globalTag = document.querySelector('.filter-tag[data-region="global"] .count'); const newGlobalCount = parseInt(globalTag.textContent) + 1; globalTag.textContent = newGlobalCount; // Update the counter on the today tag const todayTag = document.querySelector('.filter-tag[data-time="today"] .count'); const newTodayCount = parseInt(todayTag.textContent) + 1; todayTag.textContent = newTodayCount; }, 8000); }); </script> </body> </html>
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <style> * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; } body { background: #f9f9fb; display: flex; flex-direction: column; justify-content: center; align-items: center; min-height: 100vh; padding: 20px; color: #333; overflow-x: hidden; } .container { width: 100%; max-width: 650px; background: #fff; border-radius: 16px; box-shadow: 0 10px 30px rgba(0, 0, 0, 0.08); padding: 30px; position: relative; overflow: hidden; } .container::before { content: ""; position: absolute; top: 0; left: 0; width: 100%; height: 8px; background: linear-gradient(90deg, #4d6ce1, #5e81ff); } h1 { font-size: 24px; margin-bottom: 6px; background: linear-gradient(90deg, #4d6ce1, #5e81ff); -webkit-background-clip: text; background-clip: text; color: transparent; font-weight: 700; } p { color: #666; margin-bottom: 24px; font-size: 15px; line-height: 1.5; } .tag-input-container { display: flex; align-items: center; border: 2px solid #eaeaea; border-radius: 12px; padding: 10px 15px; margin-bottom: 20px; transition: all 0.3s ease; } .tag-input-container:focus-within { border-color: #5e81ff; box-shadow: 0 0 0 3px rgba(94, 129, 255, 0.1); } #tag-input { flex: 1; border: none; padding: 8px 0; font-size: 15px; outline: none; } .add-button { background: #5e81ff; color: white; border: none; border-radius: 8px; padding: 8px 16px; cursor: pointer; font-weight: 600; font-size: 14px; margin-left: 10px; transition: all 0.2s ease; position: relative; overflow: hidden; } .add-button:hover { background: #4d6ce1; } .add-button:active { transform: scale(0.97); } .ripple { position: absolute; border-radius: 50%; transform: scale(0); animation: ripple 0.6s linear; background-color: rgba(255, 255, 255, 0.4); } @keyframes ripple { to { transform: scale(4); opacity: 0; } } .tags-wrapper { margin-top: 10px; border-radius: 12px; border: 2px solid #eaeaea; padding: 20px; min-height: 200px; position: relative; } .tags-container { display: flex; flex-wrap: wrap; gap: 10px; } .tag { display: inline-flex; align-items: center; border-radius: 30px; padding: 6px 12px; font-size: 14px; font-weight: 500; cursor: pointer; transition: transform 0.2s ease, box-shadow 0.2s ease; color: #fff; position: relative; overflow: hidden; user-select: none; } .tag:hover { transform: translateY(-2px); box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); } .tag:active { transform: translateY(0); } .tag .close { margin-left: 8px; width: 18px; height: 18px; border-radius: 50%; background: rgba(255, 255, 255, 0.3); display: flex; align-items: center; justify-content: center; font-size: 12px; transition: background 0.2s ease; } .tag .close:hover { background: rgba(255, 255, 255, 0.5); } .tag-color-1 { background: #FF5757; } .tag-color-2 { background: #4ECDC4; } .tag-color-3 { background: #FF9F1C; } .tag-color-4 { background: #7678ED; } .tag-color-5 { background: #F67280; } .tag-color-6 { background: #45B69C; } .tag-color-7 { background: #6A67CE; } .tag-color-8 { background: #FFB6B9; } .empty-state { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); text-align: center; color: #b3b3b3; font-size: 15px; width: 100%; padding: 0 20px; } .empty-state .icon { font-size: 32px; margin-bottom: 10px; opacity: 0.5; } .help-section { margin-top: 30px; background: #f9f9fb; border-radius: 12px; padding: 15px; } .help-section h3 { font-size: 16px; margin-bottom: 10px; color: #555; } .tips { list-style: none; } .tips li { margin-bottom: 8px; font-size: 14px; color: #666; display: flex; align-items: center; } .tips li::before { content: "•"; color: #5e81ff; font-weight: bold; margin-right: 10px; } @keyframes floatIn { 0% { opacity: 0; transform: translateY(20px); } 100% { opacity: 1; transform: translateY(0); } } .tag { animation: floatIn 0.3s ease forwards; } @keyframes shake { 0%, 100% { transform: translateX(0); } 25% { transform: translateX(-5px); } 50% { transform: translateX(5px); } 75% { transform: translateX(-5px); } } .shake { animation: shake 0.5s ease; } @media (max-width: 500px) { .container { padding: 20px; border-radius: 12px; } h1 { font-size: 20px; } .tag-input-container { flex-direction: column; align-items: stretch; padding: 10px; } #tag-input { margin-bottom: 10px; } .add-button { margin-left: 0; width: 100%; } } </style> </head> <body> <div class="container"> <h1>Mobile-Friendly Tag System</h1> <p>Create beautiful, responsive tags with touch animations perfect for mobile interfaces.</p> <div class="tag-input-container"> <input type="text" id="tag-input" placeholder="Enter a tag (e.g., #feature, #category, #status)" /> <button class="add-button">Add Tag</button> </div> <div class="tags-wrapper"> <div class="tags-container"></div> <div class="empty-state"> <div class="icon">🏷️</div> <p>Add tags to organize your content</p> </div> </div> <div class="help-section"> <h3>Smart Tagging Tips</h3> <ul class="tips"> <li>Use descriptive, concise tags like "urgent" or "high-priority"</li> <li>Tap on a tag to highlight related content</li> <li>Swipe or click the × to remove tags</li> <li>Tags auto-adapt to different screen sizes</li> </ul> </div> </div> <script> document.addEventListener('DOMContentLoaded', function() { const tagInput = document.getElementById('tag-input'); const addButton = document.querySelector('.add-button'); const tagsContainer = document.querySelector('.tags-container'); const emptyState = document.querySelector('.empty-state'); const tagsWrapper = document.querySelector('.tags-wrapper'); // Sample tag suggestions (used when no input is provided) const sampleTags = [ 'Priority', 'Feature', 'Bug', 'Enhancement', 'Urgent', 'Mobile', 'Desktop', 'Backend', 'Frontend', 'Design', 'API', 'Database' ]; // Add ripple effect to button addButton.addEventListener('click', function(e) { createRipple(e, this); addTag(); }); // Listen for Enter key tagInput.addEventListener('keydown', function(e) { if (e.key === 'Enter') { addTag(); } }); // Focus on input when page loads tagInput.focus(); function createRipple(event, button) { const circle = document.createElement('span'); const diameter = Math.max(button.clientWidth, button.clientHeight); const radius = diameter / 2; circle.style.width = circle.style.height = `${diameter}px`; circle.style.left = `${event.clientX - button.getBoundingClientRect().left - radius}px`; circle.style.top = `${event.clientY - button.getBoundingClientRect().top - radius}px`; circle.classList.add('ripple'); const ripple = button.getElementsByClassName('ripple')[0]; if (ripple) { ripple.remove(); } button.appendChild(circle); } function addTag() { let tagText = tagInput.value.trim(); if (tagText === '') { // If no input, suggest a random sample tag tagText = sampleTags[Math.floor(Math.random() * sampleTags.length)]; } // Check if tag already exists const existingTags = Array.from(tagsContainer.children).map(tag => tag.textContent.replace('×', '').trim()); if (existingTags.includes(tagText)) { // Shake the input to indicate duplicate tag tagInput.classList.add('shake'); setTimeout(() => tagInput.classList.remove('shake'), 500); return; } // Create new tag element const tag = document.createElement('div'); tag.classList.add('tag'); // Assign random color class const colorIndex = Math.floor(Math.random() * 8) + 1; tag.classList.add(`tag-color-${colorIndex}`); tag.innerHTML = ` ${tagText} <span class="close">×</span> `; // Add click event for removal tag.querySelector('.close').addEventListener('click', function(e) { e.stopPropagation(); removeTag(tag); }); // Add click event for the tag to simulate selection tag.addEventListener('click', function() { selectTag(this); }); // Add touch feedback for mobile tag.addEventListener('touchstart', function() { this.style.opacity = '0.8'; }); tag.addEventListener('touchend', function() { this.style.opacity = '1'; }); // Add the tag to container tagsContainer.appendChild(tag); // Clear input tagInput.value = ''; tagInput.focus(); // Update empty state visibility updateEmptyState(); } function removeTag(tag) { // Create a fade out animation tag.style.transition = 'all 0.3s ease'; tag.style.transform = 'scale(0.8)'; tag.style.opacity = '0'; // Remove after animation completes setTimeout(() => { tag.remove(); updateEmptyState(); }, 300); } function selectTag(tag) { // Create a pulse effect on selection tag.style.transform = 'scale(1.05)'; setTimeout(() => { tag.style.transform = ''; }, 200); // Toggle a selected class for styling tag.classList.toggle('selected'); } function updateEmptyState() { if (tagsContainer.children.length > 0) { emptyState.style.display = 'none'; } else { emptyState.style.display = 'block'; } } // Add touch ripple effect for mobile devices tagsWrapper.addEventListener('touchstart', function(e) { if (e.target === tagsWrapper) { const touch = e.touches[0]; const rect = tagsWrapper.getBoundingClientRect(); const x = touch.clientX - rect.left; const y = touch.clientY - rect.top; const ripple = document.createElement('div'); ripple.style.position = 'absolute'; ripple.style.width = '20px'; ripple.style.height = '20px'; ripple.style.borderRadius = '50%'; ripple.style.backgroundColor = 'rgba(94, 129, 255, 0.1)'; ripple.style.left = `${x - 10}px`; ripple.style.top = `${y - 10}px`; ripple.style.transform = 'scale(0)'; ripple.style.animation = 'ripple 0.6s linear'; tagsWrapper.appendChild(ripple); setTimeout(() => { ripple.remove(); }, 600); } }); }); </script> </body> </html>
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>CMS Tagging Interface</title> <style> :root { --primary: #3a3a3a; --secondary: #f7f7f7; --accent: #5d5d5d; --highlight: #e0e0e0; --error: #ff5252; --success: #4caf50; --border-radius: 50px; --transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1); --shadow: 0 1px 3px rgba(0, 0, 0, 0.1); --font-main: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; } * { box-sizing: border-box; margin: 0; padding: 0; } body { font-family: var(--font-main); background-color: #f9f9f9; color: var(--primary); max-width: 700px; height: 700px; margin: 0 auto; padding: 20px; overflow-x: hidden; } .container { background-color: white; border-radius: 12px; box-shadow: 0 4px 20px rgba(0, 0, 0, 0.05); padding: 30px; height: 100%; display: flex; flex-direction: column; } h1 { font-size: 24px; font-weight: 600; margin-bottom: 8px; color: var(--primary); } p.subtitle { font-size: 14px; color: var(--accent); margin-bottom: 24px; line-height: 1.5; } .tag-management { margin-bottom: 30px; } .input-container { position: relative; margin-bottom: 20px; } .tag-input { width: 100%; padding: 12px 16px; font-size: 15px; border: 2px solid var(--highlight); border-radius: 8px; background-color: var(--secondary); color: var(--primary); transition: var(--transition); } .tag-input:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px rgba(93, 93, 93, 0.1); } .tag-input::placeholder { color: #9e9e9e; } .dropdown { position: absolute; top: 100%; left: 0; width: 100%; max-height: 200px; overflow-y: auto; background-color: white; border-radius: 8px; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); z-index: 100; display: none; border: 1px solid var(--highlight); } .dropdown.active { display: block; animation: slideDown 0.2s ease-out; } .dropdown-item { padding: 12px 16px; cursor: pointer; transition: var(--transition); border-bottom: 1px solid #f0f0f0; } .dropdown-item:last-child { border-bottom: none; } .dropdown-item:hover, .dropdown-item.selected { background-color: var(--secondary); } .tags-container { display: flex; flex-wrap: wrap; gap: 10px; margin-bottom: 24px; } .tag { display: inline-flex; align-items: center; background-color: var(--secondary); border-radius: var(--border-radius); padding: 6px 12px; font-size: 14px; font-weight: 500; color: var(--primary); transition: var(--transition); cursor: default; border: 1px solid transparent; animation: tagAppear 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275); } .tag:hover { background-color: #eeeeee; transform: translateY(-1px); } .tag.focused { border-color: var(--accent); box-shadow: 0 0 0 2px rgba(93, 93, 93, 0.2); } .tag .remove { margin-left: 8px; width: 16px; height: 16px; display: inline-flex; align-items: center; justify-content: center; border-radius: 50%; color: var(--accent); font-size: 12px; transition: var(--transition); cursor: pointer; } .tag .remove:hover { background-color: rgba(0, 0, 0, 0.1); color: var(--error); } .category-container { flex: 1; overflow-y: auto; padding-right: 5px; } .category { margin-bottom: 24px; } .category h3 { font-size: 16px; font-weight: 600; margin-bottom: 12px; color: var(--primary); display: flex; align-items: center; } .category h3 .count { margin-left: 8px; font-size: 13px; color: var(--accent); font-weight: normal; } .category-tags { display: flex; flex-wrap: wrap; gap: 8px; } .keyboard-shortcuts { margin-top: auto; padding-top: 16px; border-top: 1px solid var(--highlight); } .shortcuts-title { font-size: 14px; font-weight: 600; margin-bottom: 10px; color: var(--primary); } .shortcuts-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: 10px; } .shortcut { display: flex; align-items: center; font-size: 13px; color: var(--accent); } .key { display: inline-block; background-color: var(--secondary); border: 1px solid var(--highlight); border-radius: 4px; padding: 2px 6px; font-size: 12px; font-weight: 500; margin-right: 8px; color: var(--primary); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); } .message { position: fixed; bottom: 20px; left: 50%; transform: translateX(-50%) translateY(100px); background-color: var(--primary); color: white; padding: 10px 16px; border-radius: 8px; font-size: 14px; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); opacity: 0; transition: transform 0.3s ease, opacity 0.3s ease; z-index: 1000; } .message.show { transform: translateX(-50%) translateY(0); opacity: 1; } .message.success { background-color: var(--success); } .message.error { background-color: var(--error); } /* Scrollbar styling */ ::-webkit-scrollbar { width: 8px; } ::-webkit-scrollbar-track { background: #f1f1f1; border-radius: 10px; } ::-webkit-scrollbar-thumb { background: #c1c1c1; border-radius: 10px; } ::-webkit-scrollbar-thumb:hover { background: #a8a8a8; } /* Animations */ @keyframes tagAppear { from { opacity: 0; transform: scale(0.8); } to { opacity: 1; transform: scale(1); } } @keyframes pulse { 0% { box-shadow: 0 0 0 0 rgba(93, 93, 93, 0.4); } 70% { box-shadow: 0 0 0 6px rgba(93, 93, 93, 0); } 100% { box-shadow: 0 0 0 0 rgba(93, 93, 93, 0); } } @keyframes slideDown { from { opacity: 0; transform: translateY(-10px); } to { opacity: 1; transform: translateY(0); } } /* Responsive adjustments */ @media (max-width: 550px) { .container { padding: 20px; } h1 { font-size: 20px; } .shortcuts-grid { grid-template-columns: 1fr 1fr; } } @media (max-width: 400px) { .shortcuts-grid { grid-template-columns: 1fr; } } </style> </head> <body> <div class="container"> <h1>Content Tagging System</h1> <p class="subtitle">Organize your content with capsule-style tags. Use categories to easily find and manage your taxonomy.</p> <div class="tag-management"> <div class="input-container"> <input type="text" class="tag-input" placeholder="Add a tag (press Enter to confirm)" autocomplete="off" aria-label="Tag input"> <div class="dropdown" id="tag-suggestions"></div> </div> <div class="tags-container" id="active-tags"></div> </div> <div class="category-container"> <div class="category"> <h3>Content Types <span class="count">(8 tags)</span></h3> <div class="category-tags"> <div class="tag" tabindex="0" data-category="content-types">Article</div> <div class="tag" tabindex="0" data-category="content-types">Blog Post</div> <div class="tag" tabindex="0" data-category="content-types">Landing Page</div> <div class="tag" tabindex="0" data-category="content-types">Product Page</div> <div class="tag" tabindex="0" data-category="content-types">Case Study</div> <div class="tag" tabindex="0" data-category="content-types">Whitepaper</div> <div class="tag" tabindex="0" data-category="content-types">Guide</div> <div class="tag" tabindex="0" data-category="content-types">Tutorial</div> </div> </div> <div class="category"> <h3>Topics <span class="count">(6 tags)</span></h3> <div class="category-tags"> <div class="tag" tabindex="0" data-category="topics">Design Systems</div> <div class="tag" tabindex="0" data-category="topics">UX Research</div> <div class="tag" tabindex="0" data-category="topics">Frontend Development</div> <div class="tag" tabindex="0" data-category="topics">Accessibility</div> <div class="tag" tabindex="0" data-category="topics">Content Strategy</div> <div class="tag" tabindex="0" data-category="topics">Design Thinking</div> </div> </div> <div class="category"> <h3>Audience <span class="count">(5 tags)</span></h3> <div class="category-tags"> <div class="tag" tabindex="0" data-category="audience">Designers</div> <div class="tag" tabindex="0" data-category="audience">Developers</div> <div class="tag" tabindex="0" data-category="audience">Product Managers</div> <div class="tag" tabindex="0" data-category="audience">Marketing Teams</div> <div class="tag" tabindex="0" data-category="audience">Executives</div> </div> </div> </div> <div class="keyboard-shortcuts"> <div class="shortcuts-title">Keyboard Shortcuts</div> <div class="shortcuts-grid"> <div class="shortcut"> <span class="key">Tab</span> <span>Navigate tags</span> </div> <div class="shortcut"> <span class="key">Enter</span> <span>Add tag</span> </div> <div class="shortcut"> <span class="key">↑</span>/<span class="key">↓</span> <span>Browse suggestions</span> </div> <div class="shortcut"> <span class="key">Backspace</span> <span>Remove last tag</span> </div> </div> </div> </div> <div class="message" id="message"></div> <script> document.addEventListener('DOMContentLoaded', function() { const tagInput = document.querySelector('.tag-input'); const tagsContainer = document.getElementById('active-tags'); const dropdown = document.getElementById('tag-suggestions'); const message = document.getElementById('message'); // Sample suggestions for dropdown const allSuggestions = [ 'Article', 'Blog Post', 'Landing Page', 'Product Page', 'Case Study', 'Whitepaper', 'Guide', 'Tutorial', 'Design Systems', 'UX Research', 'Frontend Development', 'Accessibility', 'Content Strategy', 'Design Thinking', 'Designers', 'Developers', 'Product Managers', 'Marketing Teams', 'Executives', 'Analytics', 'Performance', 'Mobile Design', 'Responsive', 'Information Architecture', 'User Testing', 'Wireframing', 'Prototyping', 'Visual Design', 'Typography', 'Color Theory' ]; let activeTags = []; let selectedSuggestionIndex = -1; // Show a notification message function showMessage(text, type = '') { message.textContent = text; message.className = 'message show ' + type; setTimeout(() => { message.className = 'message'; }, 3000); } // Add a tag to the active tags container function addTag(tagText) { if (!tagText || tagText.trim() === '') return; // Check for duplicates if (activeTags.includes(tagText)) { showMessage(`"${tagText}" tag already exists`, 'error'); return; } const tag = document.createElement('div'); tag.className = 'tag'; tag.setAttribute('tabindex', '0'); tag.textContent = tagText; const removeBtn = document.createElement('span'); removeBtn.className = 'remove'; removeBtn.innerHTML = '×'; removeBtn.setAttribute('aria-label', `Remove ${tagText} tag`); removeBtn.addEventListener('click', (e) => { e.stopPropagation(); removeTag(tag, tagText); }); tag.appendChild(removeBtn); tagsContainer.appendChild(tag); activeTags.push(tagText); showMessage(`"${tagText}" tag added`, 'success'); // Add keyboard interactions for the tag tag.addEventListener('keydown', (e) => { if (e.key === 'Delete' || e.key === 'Backspace') { removeTag(tag, tagText); } }); } // Remove a tag function removeTag(tagElement, tagText) { tagElement.style.transform = 'scale(0.8)'; tagElement.style.opacity = '0'; setTimeout(() => { tagElement.remove(); activeTags = activeTags.filter(t => t !== tagText); showMessage(`"${tagText}" tag removed`); }, 200); } // Filter suggestions based on input function filterSuggestions(inputValue) { if (!inputValue) return []; inputValue = inputValue.toLowerCase(); return allSuggestions.filter(tag => tag.toLowerCase().includes(inputValue) && !activeTags.includes(tag) ); } // Render dropdown suggestions function renderSuggestions(suggestions) { dropdown.innerHTML = ''; if (suggestions.length === 0) { dropdown.classList.remove('active'); return; } suggestions.forEach((suggestion, index) => { const item = document.createElement('div'); item.className = 'dropdown-item'; if (index === selectedSuggestionIndex) { item.classList.add('selected'); } item.textContent = suggestion; item.addEventListener('click', () => { addTag(suggestion); tagInput.value = ''; dropdown.classList.remove('active'); tagInput.focus(); }); dropdown.appendChild(item); }); dropdown.classList.add('active'); } // Input event handler tagInput.addEventListener('input', () => { const inputValue = tagInput.value.trim(); const suggestions = filterSuggestions(inputValue); selectedSuggestionIndex = -1; renderSuggestions(suggestions); }); // Focus events tagInput.addEventListener('focus', () => { if (tagInput.value.trim()) { const suggestions = filterSuggestions(tagInput.value.trim()); renderSuggestions(suggestions); } }); // Blur event to hide dropdown document.addEventListener('click', (e) => { if (!dropdown.contains(e.target) && e.target !== tagInput) { dropdown.classList.remove('active'); } }); // Keyboard navigation tagInput.addEventListener('keydown', (e) => { const suggestions = Array.from(dropdown.querySelectorAll('.dropdown-item')); if (e.key === 'ArrowDown') { e.preventDefault(); selectedSuggestionIndex = Math.min(selectedSuggestionIndex + 1, suggestions.length - 1); renderSuggestions(filterSuggestions(tagInput.value.trim())); if (suggestions[selectedSuggestionIndex]) { suggestions[selectedSuggestionIndex].scrollIntoView({ block: 'nearest' }); } } else if (e.key === 'ArrowUp') { e.preventDefault(); selectedSuggestionIndex = Math.max(selectedSuggestionIndex - 1, -1); renderSuggestions(filterSuggestions(tagInput.value.trim())); if (suggestions[selectedSuggestionIndex]) { suggestions[selectedSuggestionIndex].scrollIntoView({ block: 'nearest' }); } } else if (e.key === 'Enter') { e.preventDefault(); if (selectedSuggestionIndex >= 0 && suggestions[selectedSuggestionIndex]) { addTag(suggestions[selectedSuggestionIndex].textContent); } else if (tagInput.value.trim()) { addTag(tagInput.value.trim()); } tagInput.value = ''; dropdown.classList.remove('active'); } else if (e.key === 'Escape') { dropdown.classList.remove('active'); } else if (e.key === 'Backspace' && tagInput.value === '') { const lastTag = tagsContainer.lastElementChild; if (lastTag) { const tagText = lastTag.textContent.replace('×', '').trim(); removeTag(lastTag, tagText); } } }); // Handle clicks on predefined category tags document.querySelectorAll('.category-tags .tag').forEach(tag => { tag.addEventListener('click', () => { const tagText = tag.textContent; if (!activeTags.includes(tagText)) { addTag(tagText); } else { showMessage(`"${tagText}" tag already exists`, 'error'); // Pulse animation to show it already exists tag.style.animation = 'pulse 0.5s'; setTimeout(() => { tag.style.animation = ''; }, 500); } }); // Keyboard handling for accessibility tag.addEventListener('keydown', (e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); tag.click(); } }); // Focus/blur styling for keyboard navigation tag.addEventListener('focus', () => { tag.classList.add('focused'); }); tag.addEventListener('blur', () => { tag.classList.remove('focused'); }); }); // Make tags accessible with keyboard document.addEventListener('keydown', (e) => { if (e.target.classList.contains('tag') && (e.key === 'Enter' || e.key === ' ')) { e.preventDefault(); // We don't want to add the tag again if it's already in the active tags // but we should allow removal with delete/backspace key } }); }); </script> </body> </html>
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Recipe Ingredient Tagger</title> <style> @import url('https://fonts.googleapis.com/css2?family=Caveat:wght@400;600&family=Quicksand:wght@400;600&display=swap'); :root { --tomato: #ff6347; --basil: #579E39; --saffron: #F4C430; --blueberry: #4F86F7; --eggplant: #614051; --salt: #F5F5F5; --pepper: #333333; --butter: #F3E5AB; } * { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: 'Quicksand', sans-serif; background-color: #fff8f2; color: var(--pepper); display: flex; flex-direction: column; align-items: center; padding: 20px; min-height: 700px; max-width: 700px; margin: 0 auto; } header { text-align: center; margin-bottom: 20px; } h1 { font-family: 'Caveat', cursive; font-size: 2.5rem; color: var(--tomato); margin-bottom: 5px; text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.1); } .app-container { width: 100%; display: flex; flex-direction: column; gap: 20px; background-color: white; padding: 25px; border-radius: 15px; box-shadow: 0 8px 25px rgba(0, 0, 0, 0.05); position: relative; overflow: hidden; } .app-container::before { content: ""; position: absolute; top: 0; right: 0; width: 100px; height: 100px; background: radial-gradient(var(--butter) 20%, transparent 70%); opacity: 0.5; border-radius: 0 0 0 100%; z-index: 0; } .input-section { display: flex; flex-direction: column; gap: 10px; } .input-container { position: relative; display: flex; align-items: center; } .ingredient-input { width: 100%; padding: 15px; border: 2px solid #e0e0e0; border-radius: 50px; font-family: 'Quicksand', sans-serif; font-size: 1rem; transition: all 0.3s ease; } .ingredient-input:focus { outline: none; border-color: var(--basil); box-shadow: 0 0 0 3px rgba(87, 158, 57, 0.2); } .add-btn { position: absolute; right: 5px; background-color: var(--basil); color: white; border: none; border-radius: 50px; width: 40px; height: 40px; display: flex; align-items: center; justify-content: center; cursor: pointer; transition: all 0.3s ease; } .add-btn:hover { background-color: #467e2d; transform: scale(1.05); } .add-btn i { font-size: 1.2rem; } .filter-section { display: flex; flex-wrap: wrap; gap: 10px; margin-bottom: 10px; } .filter-btn { background-color: var(--salt); border: none; border-radius: 30px; padding: 8px 15px; font-family: 'Quicksand', sans-serif; font-weight: 600; cursor: pointer; transition: all 0.3s ease; } .filter-btn.active { background-color: var(--tomato); color: white; } .tags-container { display: flex; flex-wrap: wrap; gap: 10px; min-height: 50px; } .tag { display: inline-flex; align-items: center; gap: 5px; padding: 8px 15px; border-radius: 30px; font-family: 'Caveat', cursive; font-size: 1.1rem; font-weight: 600; color: white; transition: all 0.3s ease; animation: tagAppear 0.3s forwards; cursor: default; } .tag.protein { background-color: var(--tomato); } .tag.vegetable { background-color: var(--basil); } .tag.fruit { background-color: var(--saffron); color: var(--pepper); } .tag.dairy { background-color: var(--butter); color: var(--pepper); } .tag.grain { background-color: var(--eggplant); } .tag.herb { background-color: #8FBC8F; } .tag.spice { background-color: #CD853F; } .tag.other { background-color: var(--blueberry); } .remove-tag { background: rgba(255, 255, 255, 0.3); border: none; border-radius: 50%; width: 20px; height: 20px; display: flex; align-items: center; justify-content: center; cursor: pointer; transition: all 0.2s ease; font-size: 0.8rem; line-height: 1; } .remove-tag:hover { background: rgba(255, 255, 255, 0.5); transform: scale(1.1); } .recipe-preview { margin-top: 20px; padding: 15px; border-radius: 10px; background-color: var(--salt); display: none; } .recipe-preview h3 { font-family: 'Caveat', cursive; font-size: 1.5rem; margin-bottom: 10px; color: var(--basil); } .recipe-list { list-style-type: none; padding: 0; } .recipe-item { padding: 12px; border-radius: 8px; margin-bottom: 10px; background-color: white; box-shadow: 0 2px 5px rgba(0, 0, 0, 0.05); cursor: pointer; transition: all 0.2s ease; } .recipe-item:hover { transform: translateY(-2px); box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); } .recipe-name { font-weight: 600; margin-bottom: 5px; } .recipe-ingredients { font-size: 0.9rem; color: #666; } .empty-state { text-align: center; padding: 20px; color: #888; font-style: italic; } @keyframes tagAppear { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } } @keyframes tagRemove { to { opacity: 0; transform: translateY(-10px) scale(0.8); } } .suggestions { position: absolute; top: 100%; left: 0; right: 0; background: white; border-radius: 0 0 10px 10px; box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1); z-index: 10; max-height: 200px; overflow-y: auto; display: none; } .suggestion-item { padding: 10px 15px; cursor: pointer; transition: background-color 0.2s; display: flex; align-items: center; } .suggestion-item:hover { background-color: #f5f5f5; } .suggestion-item .category-dot { width: 10px; height: 10px; border-radius: 50%; margin-right: 10px; } .category-dot.protein { background-color: var(--tomato); } .category-dot.vegetable { background-color: var(--basil); } .category-dot.fruit { background-color: var(--saffron); } .category-dot.dairy { background-color: var(--butter); } .category-dot.grain { background-color: var(--eggplant); } .category-dot.herb { background-color: #8FBC8F; } .category-dot.spice { background-color: #CD853F; } .category-dot.other { background-color: var(--blueberry); } .whisk-animation { position: absolute; bottom: 20px; right: 20px; width: 80px; height: 80px; opacity: 0.1; pointer-events: none; } @media (max-width: 600px) { h1 { font-size: 2rem; } .app-container { padding: 15px; } .ingredient-input { padding: 12px; } .tag { padding: 6px 12px; font-size: 1rem; } } </style> </head> <body> <header> <h1>Flavor Tags</h1> <p>Tag ingredients and discover recipe matches</p> </header> <main class="app-container"> <section class="input-section"> <div class="input-container"> <input type="text" class="ingredient-input" placeholder="Add an ingredient (e.g. chicken, basil, rice)"> <button class="add-btn">+</button> <div class="suggestions"></div> </div> </section> <section class="filter-section"> <button class="filter-btn active" data-filter="all">All</button> <button class="filter-btn" data-filter="protein">Proteins</button> <button class="filter-btn" data-filter="vegetable">Vegetables</button> <button class="filter-btn" data-filter="fruit">Fruits</button> <button class="filter-btn" data-filter="dairy">Dairy</button> <button class="filter-btn" data-filter="grain">Grains</button> <button class="filter-btn" data-filter="herb">Herbs</button> <button class="filter-btn" data-filter="spice">Spices</button> </section> <div class="tags-container"></div> <section class="recipe-preview"> <h3>Recipe Suggestions</h3> <ul class="recipe-list"></ul> </section> <svg class="whisk-animation" viewBox="0 0 100 100"> <path d="M30,85 Q35,75 40,80 Q45,85 50,80 Q55,75 60,80 Q65,85 70,80" stroke="#999" stroke-width="2" fill="none"> <animateTransform attributeName="transform" attributeType="XML" type="rotate" from="0 50 80" to="360 50 80" dur="8s" repeatCount="indefinite"/> </path> <path d="M40,80 L40,40 Q50,30 60,40 L60,80" stroke="#999" stroke-width="2" fill="none"> <animateTransform attributeName="transform" attributeType="XML" type="rotate" from="0 50 80" to="360 50 80" dur="8s" repeatCount="indefinite"/> </path> </svg> </main> <script> document.addEventListener('DOMContentLoaded', function() { const ingredientInput = document.querySelector('.ingredient-input'); const addBtn = document.querySelector('.add-btn'); const tagsContainer = document.querySelector('.tags-container'); const filterBtns = document.querySelectorAll('.filter-btn'); const suggestionsContainer = document.querySelector('.suggestions'); const recipePreview = document.querySelector('.recipe-preview'); const recipeList = document.querySelector('.recipe-list'); // Ingredient database with categories const ingredients = { // Proteins "chicken": "protein", "beef": "protein", "pork": "protein", "salmon": "protein", "tuna": "protein", "shrimp": "protein", "tofu": "protein", "eggs": "protein", "turkey": "protein", "lamb": "protein", "chickpeas": "protein", "lentils": "protein", // Vegetables "spinach": "vegetable", "kale": "vegetable", "broccoli": "vegetable", "carrot": "vegetable", "bell pepper": "vegetable", "onion": "vegetable", "garlic": "vegetable", "tomato": "vegetable", "potato": "vegetable", "sweet potato": "vegetable", "zucchini": "vegetable", "eggplant": "vegetable", "mushroom": "vegetable", "cauliflower": "vegetable", // Fruits "apple": "fruit", "banana": "fruit", "orange": "fruit", "lemon": "fruit", "lime": "fruit", "strawberry": "fruit", "blueberry": "fruit", "mango": "fruit", "pineapple": "fruit", "avocado": "fruit", // Dairy "milk": "dairy", "cheese": "dairy", "yogurt": "dairy", "butter": "dairy", "cream": "dairy", "sour cream": "dairy", "cream cheese": "dairy", // Grains "rice": "grain", "pasta": "grain", "bread": "grain", "quinoa": "grain", "oats": "grain", "flour": "grain", "couscous": "grain", "barley": "grain", // Herbs "basil": "herb", "parsley": "herb", "cilantro": "herb", "mint": "herb", "rosemary": "herb", "thyme": "herb", "oregano": "herb", "sage": "herb", "dill": "herb", // Spices "salt": "spice", "pepper": "spice", "cumin": "spice", "paprika": "spice", "cinnamon": "spice", "nutmeg": "spice", "chili powder": "spice", "turmeric": "spice", "cardamom": "spice", "ginger": "spice", // Others "olive oil": "other", "honey": "other", "soy sauce": "other", "vinegar": "other", "wine": "other", "mustard": "other", "maple syrup": "other", "coconut milk": "other" }; // Sample recipes database const recipes = [ { name: "Classic Tomato Pasta", ingredients: ["pasta", "tomato", "garlic", "onion", "basil", "olive oil", "salt", "pepper", "parmesan cheese"] }, { name: "Chicken Stir Fry", ingredients: ["chicken", "bell pepper", "broccoli", "carrot", "onion", "garlic", "soy sauce", "rice"] }, { name: "Avocado Toast", ingredients: ["bread", "avocado", "lemon", "salt", "pepper", "olive oil", "eggs"] }, { name: "Berry Smoothie Bowl", ingredients: ["strawberry", "blueberry", "banana", "yogurt", "honey", "oats"] }, { name: "Roasted Vegetable Quinoa", ingredients: ["quinoa", "bell pepper", "zucchini", "eggplant", "onion", "olive oil", "salt", "pepper", "lemon"] }, { name: "Creamy Mushroom Risotto", ingredients: ["rice", "mushroom", "onion", "garlic", "butter", "parmesan cheese", "white wine", "vegetable stock"] }, { name: "Spicy Lentil Soup", ingredients: ["lentils", "carrot", "onion", "tomato", "garlic", "cumin", "chili powder", "olive oil", "salt"] } ]; // Keep track of added tags let addedTags = []; let currentFilter = 'all'; // Add tag function function addTag(ingredient) { if (ingredient && !addedTags.includes(ingredient)) { const category = ingredients[ingredient.toLowerCase()] || "other"; const tag = document.createElement('div'); tag.classList.add('tag', category); tag.dataset.category = category; const tagText = document.createElement('span'); tagText.textContent = ingredient; const removeBtn = document.createElement('button'); removeBtn.classList.add('remove-tag'); removeBtn.textContent = '×'; removeBtn.addEventListener('click', function() { removeTag(tag, ingredient); }); tag.appendChild(tagText); tag.appendChild(removeBtn); tagsContainer.appendChild(tag); addedTags.push(ingredient); ingredientInput.value = ''; updateRecipes(); filterTags(); } } // Remove tag function function removeTag(tagElement, ingredient) { tagElement.style.animation = 'tagRemove 0.3s forwards'; setTimeout(() => { tagsContainer.removeChild(tagElement); addedTags = addedTags.filter(tag => tag !== ingredient); updateRecipes(); }, 300); } // Update recipe suggestions based on ingredients function updateRecipes() { if (addedTags.length === 0) { recipePreview.style.display = 'none'; return; } recipePreview.style.display = 'block'; recipeList.innerHTML = ''; // Sort recipes by the number of matching ingredients const matchingRecipes = recipes .map(recipe => { const matchingIngredients = recipe.ingredients.filter(ingredient => addedTags.some(tag => ingredient.includes(tag.toLowerCase())) ); return { ...recipe, matchCount: matchingIngredients.length, matches: matchingIngredients }; }) .filter(recipe => recipe.matchCount > 0) .sort((a, b) => b.matchCount - a.matchCount); if (matchingRecipes.length === 0) { const emptyState = document.createElement('div'); emptyState.classList.add('empty-state'); emptyState.textContent = 'No recipes match your ingredients yet. Try adding more!'; recipeList.appendChild(emptyState); return; } matchingRecipes.forEach(recipe => { const recipeItem = document.createElement('li'); recipeItem.classList.add('recipe-item'); const recipeName = document.createElement('div'); recipeName.classList.add('recipe-name'); recipeName.textContent = recipe.name; const recipeIngredients = document.createElement('div'); recipeIngredients.classList.add('recipe-ingredients'); recipeIngredients.textContent = `Matches ${recipe.matchCount} of your ingredients`; recipeItem.appendChild(recipeName); recipeItem.appendChild(recipeIngredients); recipeList.appendChild(recipeItem); // Add a nice hover animation recipeItem.addEventListener('mouseenter', function() { this.style.backgroundColor = '#f9f9f9'; }); recipeItem.addEventListener('mouseleave', function() { this.style.backgroundColor = 'white'; }); }); } // Filter tags based on category function filterTags() { const tags = document.querySelectorAll('.tag'); tags.forEach(tag => { if (currentFilter === 'all' || tag.dataset.category === currentFilter) { tag.style.display = 'inline-flex'; } else { tag.style.display = 'none'; } }); } // Display ingredient suggestions function showSuggestions(input) { suggestionsContainer.innerHTML = ''; if (!input) { suggestionsContainer.style.display = 'none'; return; } const matchingIngredients = Object.keys(ingredients).filter(ingredient => ingredient.toLowerCase().includes(input.toLowerCase()) && !addedTags.includes(ingredient) ); if (matchingIngredients.length === 0) { suggestionsContainer.style.display = 'none'; return; } matchingIngredients.slice(0, 5).forEach(ingredient => { const suggestionItem = document.createElement('div'); suggestionItem.classList.add('suggestion-item'); const categoryDot = document.createElement('span'); categoryDot.classList.add('category-dot', ingredients[ingredient]); const suggestionText = document.createElement('span'); suggestionText.textContent = ingredient; suggestionItem.appendChild(categoryDot); suggestionItem.appendChild(suggestionText); suggestionsContainer.appendChild(suggestionItem); suggestionItem.addEventListener('click', function() { addTag(ingredient); suggestionsContainer.style.display = 'none'; }); }); suggestionsContainer.style.display = 'block'; } // Event listeners addBtn.addEventListener('click', function() { const ingredient = ingredientInput.value.trim(); addTag(ingredient); }); ingredientInput.addEventListener('keyup', function(e) { if (e.key === 'Enter') { const ingredient = this.value.trim(); addTag(ingredient); } else { showSuggestions(this.value.trim()); } }); // Hide suggestions when clicking elsewhere document.addEventListener('click', function(e) { if (!suggestionsContainer.contains(e.target) && e.target !== ingredientInput) { suggestionsContainer.style.display = 'none'; } }); // Filter button functionality filterBtns.forEach(btn => { btn.addEventListener('click', function() { filterBtns.forEach(b => b.classList.remove('active')); this.classList.add('active'); currentFilter = this.dataset.filter; filterTags(); }); }); // Add some initial example tags setTimeout(() => { addTag('tomato'); addTag('basil'); addTag('mozzarella cheese'); }, 500); }); </script> </body> </html>
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Boutique Event Filtering</title> <style> @import url('https://fonts.googleapis.com/css2?family=Cormorant+Garamond:wght@300;400;500;600&family=Montserrat:wght@300;400;500;600&display=swap'); :root { --primary-color: #394867; --secondary-color: #9BA4B5; --accent-color: #F1F6F9; --dark-color: #212A3E; --highlight-color: #F0DBAF; --tag-transition: 0.35s cubic-bezier(0.25, 1, 0.5, 1); } * { box-sizing: border-box; margin: 0; padding: 0; } body { font-family: 'Montserrat', sans-serif; background-color: var(--accent-color); color: var(--dark-color); display: flex; flex-direction: column; align-items: center; justify-content: flex-start; min-height: 100vh; padding: 2rem 1rem; overflow-x: hidden; } .container { max-width: 650px; width: 100%; } header { margin-bottom: 2.5rem; text-align: center; } h1 { font-family: 'Cormorant Garamond', serif; font-weight: 500; font-size: 2.5rem; letter-spacing: -0.02em; margin-bottom: 0.5rem; color: var(--dark-color); } .subtitle { font-weight: 300; font-size: 1rem; color: var(--primary-color); max-width: 500px; margin: 0 auto; line-height: 1.6; } .filter-section { margin-bottom: 2rem; } h2 { font-family: 'Cormorant Garamond', serif; font-weight: 500; font-size: 1.5rem; margin-bottom: 1rem; position: relative; display: inline-block; } h2::after { content: ''; position: absolute; bottom: -5px; left: 0; width: 100%; height: 2px; background-color: var(--highlight-color); } .tags-container { display: flex; flex-wrap: wrap; gap: 0.875rem; margin-bottom: 1.5rem; } .tag { position: relative; padding: 0.75rem 1.25rem; border: 1px solid var(--primary-color); background-color: transparent; color: var(--primary-color); font-size: 0.875rem; font-weight: 500; cursor: pointer; transition: all var(--tag-transition); overflow: hidden; user-select: none; display: flex; align-items: center; justify-content: center; } .tag::before { content: ''; position: absolute; top: 0; left: 0; width: 100%; height: 100%; background-color: var(--primary-color); transform: translateY(100%); transition: transform var(--tag-transition); z-index: -1; } .tag:hover { color: var(--accent-color); } .tag:hover::before { transform: translateY(0); } .tag:focus-visible { outline: 2px solid var(--highlight-color); outline-offset: 2px; } .tag.selected { background-color: var(--primary-color); color: var(--accent-color); border-color: var(--primary-color); } .tag.selected::before { transform: translateY(0); } .tag .checkmark { opacity: 0; transform: scale(0); transition: all 0.3s ease; margin-left: 0.5rem; font-size: 0.75rem; } .tag.selected .checkmark { opacity: 1; transform: scale(1); } .event-list { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 1.5rem; } .event-card { background-color: white; border: 1px solid var(--secondary-color); padding: 1.5rem; transition: all 0.3s ease-in-out; opacity: 1; transform: scale(1); position: relative; overflow: hidden; } .event-card::before { content: ''; position: absolute; top: 0; left: 0; width: 4px; height: 0; background-color: var(--highlight-color); transition: height 0.4s ease-in-out; } .event-card:hover::before { height: 100%; } .event-card.hidden { display: none; } .event-card h3 { font-family: 'Cormorant Garamond', serif; font-weight: 600; font-size: 1.25rem; margin-bottom: 0.5rem; color: var(--dark-color); } .event-date { color: var(--primary-color); font-size: 0.875rem; font-weight: 500; margin-bottom: 1rem; display: block; } .event-description { font-size: 0.875rem; line-height: 1.6; color: var(--dark-color); margin-bottom: 1rem; } .event-tags { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-top: 1rem; } .event-tag { padding: 0.25rem 0.75rem; background-color: var(--accent-color); font-size: 0.75rem; border: 1px solid var(--secondary-color); } .reset-filters { background: none; border: none; color: var(--primary-color); font-size: 0.875rem; font-weight: 500; cursor: pointer; padding: 0.5rem 1rem; margin-bottom: 2rem; transition: all 0.3s ease; position: relative; overflow: hidden; } .reset-filters::after { content: ''; position: absolute; bottom: 0; left: 0; width: 0; height: 1px; background-color: var(--primary-color); transition: width 0.3s ease; } .reset-filters:hover::after { width: 100%; } .reset-filters:focus-visible { outline: 2px solid var(--highlight-color); outline-offset: 2px; } .no-results { text-align: center; grid-column: 1 / -1; padding: 2rem; background-color: white; border: 1px solid var(--secondary-color); display: none; } .no-results.visible { display: block; animation: fadeIn 0.5s ease-in-out; } @keyframes fadeIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } } .selected-count { font-size: 0.875rem; color: var(--primary-color); margin-bottom: 1rem; transition: all 0.3s ease; opacity: 0; height: 0; overflow: hidden; } .selected-count.visible { opacity: 1; height: auto; margin-bottom: 1.5rem; } @media (max-width: 600px) { h1 { font-size: 2rem; } .tags-container { gap: 0.625rem; } .tag { padding: 0.625rem 1rem; font-size: 0.75rem; } .event-list { grid-template-columns: 1fr; } } </style> </head> <body> <div class="container"> <header> <h1>Curated Experiences</h1> <p class="subtitle">Filter through our collection of bespoke events to find the perfect gathering for your refined taste and schedule.</p> </header> <section class="filter-section"> <h2>Filter Events</h2> <div class="tags-container" id="event-filters"> <button class="tag" data-type="corporate"> Corporate <span class="checkmark">✓</span> </button> <button class="tag" data-type="gala"> Gala <span class="checkmark">✓</span> </button> <button class="tag" data-type="workshop"> Workshop <span class="checkmark">✓</span> </button> <button class="tag" data-type="conference"> Conference <span class="checkmark">✓</span> </button> <button class="tag" data-type="exhibition"> Exhibition <span class="checkmark">✓</span> </button> <button class="tag" data-type="networking"> Networking <span class="checkmark">✓</span> </button> <button class="tag" data-type="retreat"> Retreat <span class="checkmark">✓</span> </button> <button class="tag" data-type="charity"> Charity <span class="checkmark">✓</span> </button> </div> <div class="selected-count" id="selected-count"></div> <button class="reset-filters" id="reset-filters">Reset Filters</button> </section> <section class="events-section"> <div class="event-list" id="event-list"> <div class="event-card" data-types="corporate conference"> <h3>Annual Tech Leaders Summit</h3> <span class="event-date">September 15-16, 2023</span> <p class="event-description">An exclusive gathering of industry pioneers discussing emerging technologies and strategic innovation for the next decade.</p> <div class="event-tags"> <span class="event-tag">Corporate</span> <span class="event-tag">Conference</span> </div> </div> <div class="event-card" data-types="gala charity"> <h3>Metropolitan Arts Foundation Gala</h3> <span class="event-date">October 7, 2023</span> <p class="event-description">A black-tie fundraising affair featuring curated performances, a silent auction of rare collectibles, and a five-course tasting menu.</p> <div class="event-tags"> <span class="event-tag">Gala</span> <span class="event-tag">Charity</span> </div> </div> <div class="event-card" data-types="workshop retreat"> <h3>Creative Direction Masterclass</h3> <span class="event-date">November 3-5, 2023</span> <p class="event-description">An immersive three-day workshop for design leaders to refine their creative direction skills in an inspiring countryside setting.</p> <div class="event-tags"> <span class="event-tag">Workshop</span> <span class="event-tag">Retreat</span> </div> </div> <div class="event-card" data-types="exhibition networking"> <h3>Contemporary Craft Showcase</h3> <span class="event-date">December 1-3, 2023</span> <p class="event-description">A curated exhibition featuring master artisans and their exceptional craftsmanship with exclusive networking sessions for collectors.</p> <div class="event-tags"> <span class="event-tag">Exhibition</span> <span class="event-tag">Networking</span> </div> </div> <div class="event-card" data-types="corporate networking"> <h3>Executive Roundtable: Future of Work</h3> <span class="event-date">January 19, 2024</span> <p class="event-description">A private discussion forum for C-suite executives to exchange insights on workplace transformation and talent cultivation strategies.</p> <div class="event-tags"> <span class="event-tag">Corporate</span> <span class="event-tag">Networking</span> </div> </div> <div class="event-card" data-types="conference workshop"> <h3>Sustainable Design Symposium</h3> <span class="event-date">February 8-9, 2024</span> <p class="event-description">A forward-thinking conference featuring keynotes from ecological innovators and hands-on workshops for sustainable product creation.</p> <div class="event-tags"> <span class="event-tag">Conference</span> <span class="event-tag">Workshop</span> </div> </div> <div class="event-card" data-types="retreat charity"> <h3>Wellness Leadership Retreat</h3> <span class="event-date">March 15-17, 2024</span> <p class="event-description">A restorative weekend retreat combining mindfulness practices, strategic thinking sessions, and fundraising for mental health initiatives.</p> <div class="event-tags"> <span class="event-tag">Retreat</span> <span class="event-tag">Charity</span> </div> </div> <div class="event-card" data-types="gala exhibition"> <h3>Spring Fashion Archive Preview</h3> <span class="event-date">April 28, 2024</span> <p class="event-description">An elegant evening celebrating the unveiling of rare vintage couture pieces, with champagne reception and curator-led tours.</p> <div class="event-tags"> <span class="event-tag">Gala</span> <span class="event-tag">Exhibition</span> </div> </div> <div class="no-results" id="no-results"> <h3>No events match your selected filters</h3> <p>Please adjust your selection or reset filters to view more events.</p> </div> </div> </section> </div> <script> document.addEventListener('DOMContentLoaded', function() { const tags = document.querySelectorAll('.tag'); const eventCards = document.querySelectorAll('.event-card'); const resetButton = document.getElementById('reset-filters'); const noResults = document.getElementById('no-results'); const selectedCountElement = document.getElementById('selected-count'); let selectedFilters = []; // Function to update the event display based on selected filters function updateEvents() { if (selectedFilters.length === 0) { // Show all events if no filters are selected eventCards.forEach(card => { card.classList.remove('hidden'); animateCard(card, true); }); noResults.classList.remove('visible'); selectedCountElement.classList.remove('visible'); return; } // Show the counter of selected filters selectedCountElement.textContent = `${selectedFilters.length} filter${selectedFilters.length > 1 ? 's' : ''} selected`; selectedCountElement.classList.add('visible'); // Count visible cards to check if we have results let visibleCount = 0; // Filter the events eventCards.forEach(card => { const cardTypes = card.dataset.types.split(' '); // Check if ANY of the selected filters match the card's types const shouldShow = selectedFilters.some(filter => cardTypes.includes(filter)); if (shouldShow) { card.classList.remove('hidden'); animateCard(card, true); visibleCount++; } else { animateCard(card, false); setTimeout(() => { card.classList.add('hidden'); }, 300); } }); // Show or hide the "no results" message if (visibleCount === 0) { noResults.classList.add('visible'); } else { noResults.classList.remove('visible'); } } // Animate card showing/hiding with a slight scale effect function animateCard(card, show) { if (show) { card.style.opacity = '1'; card.style.transform = 'scale(1)'; } else { card.style.opacity = '0'; card.style.transform = 'scale(0.95)'; } } // Add click event listeners to the tags tags.forEach(tag => { tag.addEventListener('click', function() { const filterType = this.dataset.type; // Toggle the selected class this.classList.toggle('selected'); // Add or remove from selected filters array if (this.classList.contains('selected')) { selectedFilters.push(filterType); // Add a small animation to show selection this.style.transform = 'scale(1.05)'; setTimeout(() => { this.style.transform = 'scale(1)'; }, 200); } else { const index = selectedFilters.indexOf(filterType); if (index > -1) { selectedFilters.splice(index, 1); } } // Update the events display updateEvents(); }); // Add keyboard support for accessibility tag.addEventListener('keydown', function(e) { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); this.click(); } }); }); // Reset filters resetButton.addEventListener('click', function() { tags.forEach(tag => { tag.classList.remove('selected'); }); selectedFilters = []; updateEvents(); }); // Initialize updateEvents(); }); </script> </body> </html>
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Wanderlust Location Tags</title> <style> /* Reset and base styles */ * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Poppins', 'Segoe UI', sans-serif; } body { background-color: #f9f9f9; color: #333; height: 100%; width: 100%; overflow-x: hidden; display: flex; flex-direction: column; align-items: center; justify-content: center; padding: 20px; } .container { max-width: 100%; width: 680px; margin: 0 auto; padding: 1.5rem; border-radius: 16px; background-color: #ffffff; box-shadow: 0 4px 24px rgba(0, 0, 0, 0.06); height: auto; position: relative; } header { margin-bottom: 2rem; text-align: center; } h1 { font-size: 2rem; font-weight: 700; margin-bottom: 0.5rem; color: #333; letter-spacing: -0.5px; } p.subtitle { font-size: 1rem; color: #666; max-width: 500px; margin: 0 auto 1.5rem; line-height: 1.5; } /* Tag collection section */ .tag-collection { display: flex; flex-wrap: wrap; gap: 12px; justify-content: center; margin-bottom: 2.5rem; } /* Tag styles */ .location-tag { padding: 10px 18px; border-radius: 30px; font-size: 0.9rem; font-weight: 500; cursor: pointer; transition: all 0.3s ease; position: relative; overflow: hidden; display: flex; align-items: center; box-shadow: 0 3px 8px rgba(0, 0, 0, 0.08); transform: translateY(0); } .location-tag:hover { transform: translateY(-4px); box-shadow: 0 6px 12px rgba(0, 0, 0, 0.1); } .location-tag::before { content: ""; position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: rgba(255, 255, 255, 0.1); transform: translateX(-100%); transition: transform 0.4s ease-out; } .location-tag:hover::before { transform: translateX(0); } .location-tag.active { transform: scale(1.05); font-weight: 600; } .tag-icon { margin-right: 8px; height: 16px; width: 16px; opacity: 0.8; } /* Pastel color variations */ .tag-beach { background-color: #FFD4B8; color: #BA5730; } .tag-mountain { background-color: #C1E8E0; color: #2A7D6E; } .tag-city { background-color: #D4BBDD; color: #6E3880; } .tag-historic { background-color: #FEE7AE; color: #B67F1A; } .tag-tropical { background-color: #C9F2C7; color: #358241; } .tag-adventure { background-color: #FFC5C5; color: #A73737; } .tag-cultural { background-color: #B1E1FF; color: #1A5F8C; } .tag-foodie { background-color: #FFE5CC; color: #B5631B; } /* Destination showcase */ .destination-showcase { height: 250px; border-radius: 12px; overflow: hidden; position: relative; box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1); } .destination-card { position: absolute; top: 0; left: 0; width: 100%; height: 100%; background-size: cover; background-position: center; opacity: 0; transition: opacity 0.5s ease; display: flex; flex-direction: column; justify-content: flex-end; padding: 20px; color: white; } .destination-card.active { opacity: 1; z-index: 1; } .card-content { background: linear-gradient(to top, rgba(0, 0, 0, 0.8), transparent); padding: 20px; border-radius: 8px; transform: translateY(20px); opacity: 0; transition: all 0.4s ease; } .destination-card.active .card-content { transform: translateY(0); opacity: 1; } .card-title { font-size: 1.5rem; font-weight: 700; margin-bottom: 6px; } .card-description { font-size: 0.9rem; margin-bottom: 12px; line-height: 1.4; } .explore-btn { display: inline-block; padding: 8px 16px; background-color: #ffffff; color: #333; border-radius: 20px; font-size: 0.85rem; font-weight: 600; cursor: pointer; transition: all 0.2s ease; border: none; box-shadow: 0 2px 6px rgba(0, 0, 0, 0.2); text-decoration: none; } .explore-btn:hover { transform: scale(1.05); box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3); } /* Legend for the tags */ .tag-legend { margin-top: 1.5rem; text-align: center; color: #777; font-size: 0.85rem; opacity: 0.8; } /* Responsive adjustments */ @media (max-width: 640px) { .container { padding: 1rem; } h1 { font-size: 1.75rem; } .destination-showcase { height: 200px; } .location-tag { padding: 8px 14px; font-size: 0.8rem; } .card-title { font-size: 1.25rem; } .card-description { font-size: 0.8rem; } } /* Custom animation for tags */ @keyframes tagPulse { 0% { box-shadow: 0 3px 8px rgba(0, 0, 0, 0.08); } 50% { box-shadow: 0 5px 15px rgba(0, 0, 0, 0.15); } 100% { box-shadow: 0 3px 8px rgba(0, 0, 0, 0.08); } } .location-tag.pulse { animation: tagPulse 1.5s infinite; } /* Loading animation */ .loading { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: #ffffff; display: flex; justify-content: center; align-items: center; z-index: 1000; opacity: 1; transition: opacity 0.5s ease, visibility 0.5s ease; } .loading.hidden { opacity: 0; visibility: hidden; } .loading-spinner { width: 40px; height: 40px; border: 3px solid transparent; border-top-color: #3498db; border-radius: 50%; animation: spin 1s linear infinite; } @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } </style> </head> <body> <div class="loading"> <div class="loading-spinner"></div> </div> <div class="container"> <header> <h1>Discover Your Next Getaway</h1> <p class="subtitle">Explore destinations by mood and preference. Click the colorful tags below to find your perfect travel inspiration.</p> </header> <div class="tag-collection"> <div class="location-tag tag-beach" data-type="beach"> <svg class="tag-icon" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M8 17.0001C4.5 17.0001 3 15.5001 3 15.5001C3 15.5001 4.5 14.0001 8 14.0001C11.5 14.0001 13 15.5001 13 15.5001C13 15.5001 11.5 17.0001 8 17.0001Z" stroke="currentColor" stroke-width="2"/> <path d="M12 12C12 12 16 10.5 16 7C16 3.5 12 2 12 2" stroke="currentColor" stroke-width="2"/> <path d="M12 12C12 12 8 10.5 8 7C8 3.5 12 2 12 2" stroke="currentColor" stroke-width="2"/> <path d="M16 17.0001C19.5 17.0001 21 15.5001 21 15.5001C21 15.5001 19.5 14.0001 16 14.0001C12.5 14.0001 11 15.5001 11 15.5001C11 15.5001 12.5 17.0001 16 17.0001Z" stroke="currentColor" stroke-width="2"/> <path d="M3 22.0001C3 21.0001 4 19.0001 8 19.0001C12 19.0001 13 21.0001 13 22.0001" stroke="currentColor" stroke-width="2"/> <path d="M11 22.0001C11 21.0001 12 19.0001 16 19.0001C20 19.0001 21 21.0001 21 22.0001" stroke="currentColor" stroke-width="2"/> </svg> Beach </div> <div class="location-tag tag-mountain" data-type="mountain"> <svg class="tag-icon" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M8 3L4 15H20L16 3" stroke="currentColor" stroke-width="2"/> <path d="M4 15L2 22H22L20 15" stroke="currentColor" stroke-width="2"/> </svg> Mountain </div> <div class="location-tag tag-city" data-type="city"> <svg class="tag-icon" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M3 21H21" stroke="currentColor" stroke-width="2"/> <path d="M3 7V21" stroke="currentColor" stroke-width="2"/> <path d="M21 7V21" stroke="currentColor" stroke-width="2"/> <path d="M7 7V21" stroke="currentColor" stroke-width="2"/> <path d="M17 7V21" stroke="currentColor" stroke-width="2"/> <path d="M3 7C3 5.89543 3.89543 5 5 5H19C20.1046 5 21 5.89543 21 7V7H3V7Z" stroke="currentColor" stroke-width="2"/> <path d="M7 21V17H17V21" stroke="currentColor" stroke-width="2"/> </svg> City </div> <div class="location-tag tag-historic" data-type="historic"> <svg class="tag-icon" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M19 21V5C19 3.89543 18.1046 3 17 3H7C5.89543 3 5 3.89543 5 5V21" stroke="currentColor" stroke-width="2"/> <path d="M21 21V19C21 18.4477 20.5523 18 20 18H4C3.44772 18 3 18.4477 3 19V21" stroke="currentColor" stroke-width="2"/> </svg> Historic </div> <div class="location-tag tag-tropical" data-type="tropical"> <svg class="tag-icon" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M13 17C14 10 21 5 21 5C21 5 16 8 16 15M13 17H16M13 17C11.8954 17 11 16.1046 11 15C11 13.8954 11.8954 13 13 13C13.4596 13 13.8841 13.1492 14.2222 13.4019M5.36508 13C5.15165 13.6373 5 14.3015 5 15C5 16.1046 5.89543 17 7 17C8.10457 17 9 16.1046 9 15C9 14.3015 8.84835 13.6373 8.63492 13M5.36508 13C5.73797 11.7777 6.31936 10.7014 7 10C7.68064 10.7014 8.26203 11.7777 8.63492 13M5.36508 13H8.63492" stroke="currentColor" stroke-width="2"/> </svg> Tropical </div> <div class="location-tag tag-adventure" data-type="adventure"> <svg class="tag-icon" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M3 8L10 8" stroke="currentColor" stroke-width="2"/> <path d="M14 8L21 8" stroke="currentColor" stroke-width="2"/> <circle cx="12" cy="8" r="2" stroke="currentColor" stroke-width="2"/> <path d="M10 8V19L12 17L14 19V8" stroke="currentColor" stroke-width="2"/> </svg> Adventure </div> <div class="location-tag tag-cultural" data-type="cultural"> <svg class="tag-icon" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <circle cx="12" cy="7" r="5" stroke="currentColor" stroke-width="2"/> <path d="M17 22H7C5.89543 22 5 21.1046 5 20V12.0161C5 12.0054 5.00859 12 5.01913 12H18.9809C18.9914 12 19 12.0054 19 12.0161V20C19 21.1046 18.1046 22 17 22Z" stroke="currentColor" stroke-width="2"/> </svg> Cultural </div> <div class="location-tag tag-foodie" data-type="foodie"> <svg class="tag-icon" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M6 2V22" stroke="currentColor" stroke-width="2"/> <path d="M12 9L6 9" stroke="currentColor" stroke-width="2"/> <path d="M15 22V16C15 13.7909 16.7909 12 19 12V12C19 12 19 2 15 2" stroke="currentColor" stroke-width="2"/> </svg> Foodie </div> </div> <div class="destination-showcase"> <div class="destination-card" data-type="beach" style="background-image: url('https://images.unsplash.com/photo-1507525428034-b723cf961d3e?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=800&q=80')"> <div class="card-content"> <h3 class="card-title">Maldives Crystal Waters</h3> <p class="card-description">Pristine white sands meet turquoise lagoons in these world-renowned overwater bungalows. Perfect for honeymooners seeking privacy.</p> <button class="explore-btn">Explore Destination</button> </div> </div> <div class="destination-card" data-type="mountain" style="background-image: url('https://images.unsplash.com/photo-1464822759023-fed622ff2c3b?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=800&q=80')"> <div class="card-content"> <h3 class="card-title">Swiss Alps Wilderness</h3> <p class="card-description">Majestic peaks and rolling meadows make this destination a year-round haven for hikers in summer and skiers in winter.</p> <button class="explore-btn">Explore Destination</button> </div> </div> <div class="destination-card" data-type="city" style="background-image: url('https://images.unsplash.com/photo-1502602898657-3e91760cbb34?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=800&q=80')"> <div class="card-content"> <h3 class="card-title">Paris City of Light</h3> <p class="card-description">Elegant boulevards and café culture make this iconic metropolis perfect for art lovers and gourmands seeking urban sophistication.</p> <button class="explore-btn">Explore Destination</button> </div> </div> <div class="destination-card" data-type="historic" style="background-image: url('https://images.unsplash.com/photo-1563838619-81121146ff70?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=800&q=80')"> <div class="card-content"> <h3 class="card-title">Ancient Rome's Colosseum</h3> <p class="card-description">Walk through millennia of history where gladiators once battled. Rome's archaeological wonders transport you to the Imperial age.</p> <button class="explore-btn">Explore Destination</button> </div> </div> <div class="destination-card" data-type="tropical" style="background-image: url('https://images.unsplash.com/photo-1518509562904-e7ef99cdcc86?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=800&q=80')"> <div class="card-content"> <h3 class="card-title">Bali's Lush Rainforests</h3> <p class="card-description">Emerald rice terraces and sacred monkey forests create a tropical paradise for yogis and nature lovers seeking spiritual renewal.</p> <button class="explore-btn">Explore Destination</button> </div> </div> <div class="destination-card" data-type="adventure" style="background-image: url('https://images.unsplash.com/photo-1543922596-b3bbaba80649?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=800&q=80')"> <div class="card-content"> <h3 class="card-title">New Zealand's Fiordland</h3> <p class="card-description">Dramatic landscapes for bungee jumping, kayaking, and hiking. The adrenaline capital of the world with breathtaking fjords.</p> <button class="explore-btn">Explore Destination</button> </div> </div> <div class="destination-card" data-type="cultural" style="background-image: url('https://images.unsplash.com/photo-1493976040374-85c8e12f0c0e?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=800&q=80')"> <div class="card-content"> <h3 class="card-title">Kyoto's Temple Gardens</h3> <p class="card-description">Traditional tea ceremonies and geisha districts offer glimpses into Japan's cultural heritage amidst serene bamboo groves.</p> <button class="explore-btn">Explore Destination</button> </div> </div> <div class="destination-card" data-type="foodie" style="background-image: url('https://images.unsplash.com/photo-1580237072353-751a8a5b2561?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=800&q=80')"> <div class="card-content"> <h3 class="card-title">Barcelona's Tapas Culture</h3> <p class="card-description">Market-fresh seafood and Catalonian specialties await in this Mediterranean culinary hotspot famous for innovative gastronomy.</p> <button class="explore-btn">Explore Destination</button> </div> </div> </div> <div class="tag-legend"> Click any tag to filter travel destinations by mood and preferences </div> </div> <script> document.addEventListener('DOMContentLoaded', function() { // Hide loading spinner setTimeout(function() { document.querySelector('.loading').classList.add('hidden'); }, 800); // Get all location tags and destination cards const locationTags = document.querySelectorAll('.location-tag'); const destinationCards = document.querySelectorAll('.destination-card'); // Set first tag and card as active by default locationTags[0].classList.add('active'); showDestination(locationTags[0].getAttribute('data-type')); // Add click event listeners to all tags locationTags.forEach(tag => { tag.addEventListener('click', function() { const type = this.getAttribute('data-type'); // Toggle classes and show destination locationTags.forEach(t => t.classList.remove('active')); this.classList.add('active'); // Add pulse animation and remove after transition this.classList.add('pulse'); setTimeout(() => { this.classList.remove('pulse'); }, 1500); showDestination(type); }); }); // Function to show destination based on tag type function showDestination(type) { destinationCards.forEach(card => { if (card.getAttribute('data-type') === type) { card.classList.add('active'); } else { card.classList.remove('active'); } }); } // Button explore interaction const exploreButtons = document.querySelectorAll('.explore-btn'); exploreButtons.forEach(button => { button.addEventListener('click', function(e) { e.preventDefault(); // Add visual feedback this.style.transform = 'scale(0.95)'; setTimeout(() => { this.style.transform = ''; // Show a simulated loading or action feedback const card = this.closest('.destination-card'); const cardTitle = card.querySelector('.card-title').textContent; // Create a notification that fades in and out const notification = document.createElement('div'); notification.style.position = 'fixed'; notification.style.bottom = '20px'; notification.style.left = '50%'; notification.style.transform = 'translateX(-50%)'; notification.style.backgroundColor = '#333'; notification.style.color = '#fff'; notification.style.padding = '10px 20px'; notification.style.borderRadius = '30px'; notification.style.boxShadow = '0 4px 12px rgba(0,0,0,0.15)'; notification.style.zIndex = '1000'; notification.style.opacity = '0'; notification.style.transition = 'opacity 0.3s ease'; notification.style.fontSize = '14px'; notification.textContent = `Exploring ${cardTitle}...`; document.body.appendChild(notification); // Show notification setTimeout(() => { notification.style.opacity = '1'; }, 10); // Hide notification after 2 seconds setTimeout(() => { notification.style.opacity = '0'; setTimeout(() => { document.body.removeChild(notification); }, 300); }, 2000); }, 200); }); }); // Auto rotation for showcase if no interaction let autoRotationTimer; let currentTagIndex = 0; function startAutoRotation() { autoRotationTimer = setInterval(() => { currentTagIndex = (currentTagIndex + 1) % locationTags.length; locationTags[currentTagIndex].click(); }, 5000); } function stopAutoRotation() { clearInterval(autoRotationTimer); } // Start auto rotation startAutoRotation(); // Stop rotation on user interaction and restart after inactivity document.querySelector('.container').addEventListener('mousemove', function() { stopAutoRotation(); // Restart after 10 seconds of inactivity clearTimeout(window.restartTimer); window.restartTimer = setTimeout(startAutoRotation, 10000); }); // Make sure explore buttons don't trigger redirects document.querySelectorAll('.explore-btn').forEach(btn => { btn.addEventListener('click', function(e) { e.preventDefault(); return false; }); }); }); </script> </body> </html>
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Talent Booking Expertise Tags</title> <style> :root { --primary-color: #5928E5; --secondary-color: #FC4A6A; --tertiary-color: #16C172; --highlight-color: #F9CB40; --dark-color: #2D3047; --light-color: #F5F5F7; --transition-speed: 0.3s; --border-radius: 8px; } * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', sans-serif; } body { background-color: var(--light-color); color: var(--dark-color); display: flex; flex-direction: column; align-items: center; justify-content: flex-start; min-height: 100vh; padding: 1.5rem; overflow-x: hidden; } .container { max-width: 650px; width: 100%; background-color: white; border-radius: 16px; box-shadow: 0 10px 30px rgba(0, 0, 0, 0.08); padding: 2rem; display: flex; flex-direction: column; gap: 1.5rem; } header { text-align: center; margin-bottom: 1rem; } h1 { font-size: 1.8rem; color: var(--dark-color); margin-bottom: 0.5rem; font-weight: 700; } p.subtitle { color: #666; font-size: 1rem; line-height: 1.5; margin-bottom: 1rem; } .input-group { position: relative; margin-bottom: 1rem; } .search-input { width: 100%; padding: 1rem 1rem 1rem 3rem; border: 2px solid #E0E0E0; border-radius: var(--border-radius); font-size: 1rem; transition: all var(--transition-speed); background-color: white; } .search-input:focus { outline: none; border-color: var(--primary-color); box-shadow: 0 0 0 3px rgba(89, 40, 229, 0.15); } .search-icon { position: absolute; left: 1rem; top: 50%; transform: translateY(-50%); color: #888; pointer-events: none; } .suggestions { position: absolute; top: 100%; left: 0; right: 0; background-color: white; border-radius: 0 0 var(--border-radius) var(--border-radius); border: 2px solid var(--primary-color); border-top: none; max-height: 200px; overflow-y: auto; z-index: 10; box-shadow: 0 10px 20px rgba(0, 0, 0, 0.1); display: none; } .suggestion-item { padding: 0.75rem 1rem; cursor: pointer; transition: background-color var(--transition-speed); border-bottom: 1px solid #f0f0f0; } .suggestion-item:hover { background-color: #f5f0ff; } .suggestion-item:last-child { border-bottom: none; } .tag-section { margin-bottom: 1.5rem; } .section-title { font-size: 1rem; font-weight: 600; margin-bottom: 0.75rem; color: var(--dark-color); display: flex; align-items: center; gap: 0.5rem; } .section-title .icon { color: var(--primary-color); } .tags-container { display: flex; flex-wrap: wrap; gap: 0.75rem; min-height: 40px; } .tag { display: inline-flex; align-items: center; padding: 0.5rem 0.75rem; border-radius: 50px; font-size: 0.875rem; font-weight: 500; color: white; cursor: pointer; transition: all var(--transition-speed); animation: tagAppear 0.3s ease forwards; transform-origin: left; gap: 0.5rem; box-shadow: 0 3px 8px rgba(0, 0, 0, 0.12); user-select: none; } .tag-icon { font-size: 1rem; } .tag.music { background: linear-gradient(135deg, var(--primary-color), #8A4FFF); } .tag.performance { background: linear-gradient(135deg, var(--secondary-color), #FF7A9C); } .tag.events { background: linear-gradient(135deg, var(--tertiary-color), #4AE3A9); } .tag.media { background: linear-gradient(135deg, var(--highlight-color), #FFDE82); color: var(--dark-color); } .tag:hover { transform: translateY(-2px) scale(1.02); box-shadow: 0 5px 12px rgba(0, 0, 0, 0.18); } .tag .remove-icon { margin-left: 0.25rem; opacity: 0.7; transition: opacity var(--transition-speed); } .tag .remove-icon:hover { opacity: 1; } .info-text { font-size: 0.875rem; color: #888; margin-top: 0.5rem; font-style: italic; } .secondary-tags { opacity: 0.85; } .divider { height: 1px; background-color: #E0E0E0; margin: 1rem 0; } .drag-indicator { display: inline-flex; justify-content: center; align-items: center; font-size: 0.85rem; opacity: 0.6; margin-right: 0.25rem; } @keyframes tagAppear { 0% { opacity: 0; transform: scale(0.8); } 70% { transform: scale(1.05); } 100% { opacity: 1; transform: scale(1); } } .tag.removing { animation: tagRemove 0.3s ease forwards; } @keyframes tagRemove { 0% { opacity: 1; transform: scale(1); } 100% { opacity: 0; transform: scale(0.8); margin-left: -10px; margin-right: -10px; padding-left: 0; padding-right: 0; width: 0; } } .legend { display: grid; grid-template-columns: repeat(4, 1fr); gap: 0.75rem; margin-top: 1rem; } .legend-item { display: flex; align-items: center; gap: 0.5rem; font-size: 0.75rem; color: #666; } .legend-color { width: 12px; height: 12px; border-radius: 50%; } .legend-color.music { background: var(--primary-color); } .legend-color.performance { background: var(--secondary-color); } .legend-color.events { background: var(--tertiary-color); } .legend-color.media { background: var(--highlight-color); } .empty-state { display: flex; flex-direction: column; align-items: center; justify-content: center; padding: 1.5rem; background-color: #f9f9f9; border-radius: var(--border-radius); color: #888; text-align: center; min-height: 100px; gap: 0.5rem; } .empty-state-icon { font-size: 1.5rem; margin-bottom: 0.5rem; opacity: 0.5; } @media (max-width: 500px) { .container { padding: 1.5rem; } h1 { font-size: 1.5rem; } .legend { grid-template-columns: repeat(2, 1fr); } } .pulse { animation: pulse 2s infinite; } @keyframes pulse { 0% { box-shadow: 0 0 0 0 rgba(89, 40, 229, 0.4); } 70% { box-shadow: 0 0 0 10px rgba(89, 40, 229, 0); } 100% { box-shadow: 0 0 0 0 rgba(89, 40, 229, 0); } } .tooltip { position: relative; display: inline-block; cursor: help; } .tooltip .tooltip-text { visibility: hidden; width: 200px; background-color: var(--dark-color); color: white; text-align: center; border-radius: 6px; padding: 0.5rem; position: absolute; z-index: 1; bottom: 125%; left: 50%; transform: translateX(-50%); opacity: 0; transition: opacity 0.3s; font-size: 0.75rem; pointer-events: none; } .tooltip:hover .tooltip-text { visibility: visible; opacity: 1; } </style> </head> <body> <div class="container"> <header> <h1>Talent Booking Expertise Tagger</h1> <p class="subtitle">Categorize artists and performers by their skills and specialties using intuitive, color-coded tags for easier talent matching and booking.</p> </header> <div class="input-group"> <span class="search-icon"> <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" 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> </svg> </span> <input type="text" class="search-input pulse" placeholder="Type to search skills (e.g. 'DJ', 'Jazz', 'Event Host')" id="skill-input"> <div class="suggestions" id="suggestions"></div> </div> <div class="tag-section"> <div class="section-title"> <span class="icon"> <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <path d="M12 2L2 7l10 5 10-5-10-5z"></path> <path d="M2 17l10 5 10-5"></path> <path d="M2 12l10 5 10-5"></path> </svg> </span> Primary Expertise <span class="tooltip"> <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" 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> <path d="M12 8v4"></path> <path d="M12 16h.01"></path> </svg> <span class="tooltip-text">These are the main skills that define this talent's core offerings</span> </span> </div> <div class="tags-container" id="primary-tags"> <div class="empty-state"> <div class="empty-state-icon">🎯</div> <div>Add primary expertise tags that showcase the talent's main skills</div> </div> </div> </div> <div class="divider"></div> <div class="tag-section"> <div class="section-title"> <span class="icon"> <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <polyline points="22 12 16 12 14 15 10 15 8 12 2 12"></polyline> <path d="M5.45 5.11L2 12v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-6l-3.45-6.89A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11z"></path> </svg> </span> Secondary Expertise <span class="tooltip"> <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" 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> <path d="M12 8v4"></path> <path d="M12 16h.01"></path> </svg> <span class="tooltip-text">Additional skills that complement the talent's primary expertise</span> </span> </div> <div class="tags-container secondary-tags" id="secondary-tags"> <div class="empty-state"> <div class="empty-state-icon">✨</div> <div>Add secondary expertise tags that highlight additional skills</div> </div> </div> </div> <div class="legend"> <div class="legend-item"> <div class="legend-color music"></div> <span>Music</span> </div> <div class="legend-item"> <div class="legend-color performance"></div> <span>Performance</span> </div> <div class="legend-item"> <div class="legend-color events"></div> <span>Events</span> </div> <div class="legend-item"> <div class="legend-color media"></div> <span>Media</span> </div> </div> </div> <script> document.addEventListener('DOMContentLoaded', function() { const skillInput = document.getElementById('skill-input'); const suggestionsContainer = document.getElementById('suggestions'); const primaryTagsContainer = document.getElementById('primary-tags'); const secondaryTagsContainer = document.getElementById('secondary-tags'); // Remove pulse animation after user interaction skillInput.addEventListener('focus', function() { this.classList.remove('pulse'); }); // Sample expertise database with categories const expertiseDatabase = [ { id: 1, name: "DJ", category: "music", icon: "🎧" }, { id: 2, name: "Live Band", category: "music", icon: "🎸" }, { id: 3, name: "Jazz Vocalist", category: "music", icon: "🎤" }, { id: 4, name: "Classical Pianist", category: "music", icon: "🎹" }, { id: 5, name: "Hip Hop Producer", category: "music", icon: "🎛️" }, { id: 6, name: "Opera Singer", category: "music", icon: "🎭" }, { id: 7, name: "Choreographer", category: "performance", icon: "💃" }, { id: 8, name: "Stand-up Comedian", category: "performance", icon: "🎭" }, { id: 9, name: "Magician", category: "performance", icon: "✨" }, { id: 10, name: "Acrobat", category: "performance", icon: "🤸" }, { id: 11, name: "Dancer", category: "performance", icon: "💃" }, { id: 12, name: "Improv Actor", category: "performance", icon: "🎭" }, { id: 13, name: "Event Host", category: "events", icon: "🎤" }, { id: 14, name: "Wedding Specialist", category: "events", icon: "💍" }, { id: 15, name: "Festival Coordinator", category: "events", icon: "🎪" }, { id: 16, name: "Corporate Entertainer", category: "events", icon: "👔" }, { id: 17, name: "Auctioneer", category: "events", icon: "🔨" }, { id: 18, name: "Emcee", category: "events", icon: "📢" }, { id: 19, name: "Voice Actor", category: "media", icon: "🎙️" }, { id: 20, name: "Video Performer", category: "media", icon: "🎬" }, { id: 21, name: "Podcast Host", category: "media", icon: "🎙️" }, { id: 22, name: "Commercial Talent", category: "media", icon: "📺" }, { id: 23, name: "Social Media Performer", category: "media", icon: "📱" }, { id: 24, name: "Music Producer", category: "music", icon: "🎛️" }, { id: 25, name: "Session Musician", category: "music", icon: "🎻" }, { id: 26, name: "Beat Boxer", category: "music", icon: "👄" }, { id: 27, name: "Celebrity Impersonator", category: "performance", icon: "👯" }, { id: 28, name: "Motivational Speaker", category: "events", icon: "🔊" }, { id: 29, name: "Live Streaming Host", category: "media", icon: "📡" }, { id: 30, name: "Violinist", category: "music", icon: "🎻" } ]; // Track selected tags const selectedTags = { primary: [], secondary: [] }; // Handle input changes for suggestions skillInput.addEventListener('input', function() { const query = this.value.toLowerCase(); if (query.length < 2) { suggestionsContainer.style.display = 'none'; return; } const matchedExpertise = expertiseDatabase.filter(item => item.name.toLowerCase().includes(query) ); if (matchedExpertise.length === 0) { suggestionsContainer.style.display = 'none'; return; } suggestionsContainer.innerHTML = ''; matchedExpertise.forEach(item => { const suggestionItem = document.createElement('div'); suggestionItem.className = 'suggestion-item'; suggestionItem.textContent = `${item.icon} ${item.name}`; suggestionItem.dataset.id = item.id; suggestionItem.dataset.category = item.category; suggestionItem.dataset.icon = item.icon; suggestionItem.dataset.name = item.name; suggestionItem.addEventListener('click', function() { addTag(this.dataset.id, this.dataset.name, this.dataset.category, this.dataset.icon, 'primary'); skillInput.value = ''; suggestionsContainer.style.display = 'none'; }); suggestionsContainer.appendChild(suggestionItem); }); suggestionsContainer.style.display = 'block'; }); // Hide suggestions when clicking outside document.addEventListener('click', function(e) { if (e.target !== skillInput && e.target !== suggestionsContainer) { suggestionsContainer.style.display = 'none'; } }); // Function to add a tag function addTag(id, name, category, icon, tagType = 'primary') { // Check if tag already exists in either container if (selectedTags.primary.some(tag => tag.id === id) || selectedTags.secondary.some(tag => tag.id === id)) { return; } const tagsContainer = tagType === 'primary' ? primaryTagsContainer : secondaryTagsContainer; // Remove empty state if it exists const emptyState = tagsContainer.querySelector('.empty-state'); if (emptyState) { tagsContainer.removeChild(emptyState); } const tag = document.createElement('div'); tag.className = `tag ${category}`; tag.dataset.id = id; tag.innerHTML = ` <span class="tag-icon">${icon}</span> ${name} <span class="remove-icon"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <line x1="18" y1="6" x2="6" y2="18"></line> <line x1="6" y1="6" x2="18" y2="18"></line> </svg> </span> `; // Store in selected tags selectedTags[tagType].push({ id, name, category, icon, element: tag }); // Add event listeners tag.addEventListener('click', function(e) { if (e.target.closest('.remove-icon')) { removeTag(id, tagType); } else if (tagType === 'primary') { // Move from primary to secondary moveTag(id, 'primary', 'secondary'); } else { // Move from secondary to primary moveTag(id, 'secondary', 'primary'); } }); tagsContainer.appendChild(tag); } // Function to remove a tag function removeTag(id, tagType) { const tagIndex = selectedTags[tagType].findIndex(tag => tag.id === id); if (tagIndex === -1) return; const tag = selectedTags[tagType][tagIndex].element; tag.classList.add('removing'); setTimeout(() => { tag.remove(); selectedTags[tagType].splice(tagIndex, 1); // Add empty state if no tags remain const tagsContainer = tagType === 'primary' ? primaryTagsContainer : secondaryTagsContainer; if (selectedTags[tagType].length === 0) { addEmptyState(tagsContainer, tagType); } }, 300); } // Function to move a tag between containers function moveTag(id, fromType, toType) { const fromIndex = selectedTags[fromType].findIndex(tag => tag.id === id); if (fromIndex === -1) return; const tagData = selectedTags[fromType][fromIndex]; // Remove from current container with animation tagData.element.classList.add('removing'); setTimeout(() => { tagData.element.remove(); selectedTags[fromType].splice(fromIndex, 1); // Add empty state if needed const fromContainer = fromType === 'primary' ? primaryTagsContainer : secondaryTagsContainer; if (selectedTags[fromType].length === 0) { addEmptyState(fromContainer, fromType); } // Add to new container addTag(tagData.id, tagData.name, tagData.category, tagData.icon, toType); }, 300); } // Function to add empty state function addEmptyState(container, type) { const emptyState = document.createElement('div'); emptyState.className = 'empty-state'; if (type === 'primary') { emptyState.innerHTML = ` <div class="empty-state-icon">🎯</div> <div>Add primary expertise tags that showcase the talent's main skills</div> `; } else { emptyState.innerHTML = ` <div class="empty-state-icon">✨</div> <div>Add secondary expertise tags that highlight additional skills</div> `; } container.appendChild(emptyState); } // Initialize with some sample tags for demonstration addTag(1, 'DJ', 'music', '🎧', 'primary'); addTag(8, 'Stand-up Comedian', 'performance', '🎭', 'primary'); addTag(13, 'Event Host', 'events', '🎤', 'secondary'); addTag(20, 'Video Performer', 'media', '🎬', 'secondary'); }); </script> </body> </html>