Range sliders are versatile UI components that allow users to select a value or range of values within a predefined range. They are commonly used in applications for tasks like filtering search results, adjusting settings, or selecting price ranges.
In this article, we will explore 10 range slider examples that showcase different styles, functionalities, and use cases. These examples will help you understand how to implement and customize range sliders to enhance your application's user experience.
CODE1
Here's the code:
CODETEXT1
CODE2
Here's the code:
CODETEXT2
CODE3
Here's the code:
CODETEXT3
CODE4
Here's the code:
CODETEXT4
CODE5
Here's the code:
CODETEXT5
Designers and developers love Subframe for its drag-and-drop interface and intuitive, responsive canvas. Create pixel-perfect range sliders effortlessly, ensuring a seamless user experience every time.
Join the community of satisfied users and elevate your UI design. Start for free today!
CODE6
Here's the code:
CODETEXT6
CODE7
Here's the code:
CODETEXT7
CODE8
Here's the code:
CODETEXT8
CODE9
Here's the code:
CODETEXT9
CODE10
Here's the code:
CODETEXT10
Ready to elevate your UI design game? With Subframe, you can create pixel-perfect range sliders and other UI components effortlessly. Our drag-and-drop interface ensures efficiency and precision.
Don't wait! Start for free and begin designing stunning UIs immediately.
<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: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; } body { height: 100vh; background-color: #f8f9fa; display: flex; justify-content: center; align-items: center; color: #2d3436; overflow: hidden; } .container { width: 650px; padding: 32px; background-color: #fff; border-radius: 20px; box-shadow: 0 10px 30px rgba(0, 0, 0, 0.05); position: relative; overflow: hidden; } .container::before { content: ''; position: absolute; top: 0; left: 0; width: 100%; height: 8px; background: linear-gradient(90deg, #74b9ff, #0984e3, #e84393, #d63031); border-radius: 8px 8px 0 0; } h1 { font-size: 24px; font-weight: 700; margin-bottom: 6px; color: #2d3436; } .subtitle { font-size: 14px; font-weight: 400; color: #636e72; margin-bottom: 32px; } .price-map { display: flex; justify-content: space-between; margin-bottom: 12px; font-size: 13px; font-weight: 500; } .price-map span { color: #636e72; } .price-icons { display: flex; justify-content: space-between; margin-bottom: 28px; } .price-icon { display: flex; flex-direction: column; align-items: center; position: relative; cursor: pointer; transition: transform 0.3s ease; } .price-icon:hover { transform: translateY(-5px); } .price-icon .icon { font-size: 28px; margin-bottom: 8px; opacity: 0.7; transition: opacity 0.3s ease; } .price-icon:hover .icon { opacity: 1; } .price-icon .label { font-size: 12px; font-weight: 500; color: #636e72; } .slider-container { position: relative; margin-bottom: 40px; } .slider { -webkit-appearance: none; width: 100%; height: 8px; border-radius: 8px; background: linear-gradient(90deg, #74b9ff, #0984e3, #e84393, #d63031); outline: none; cursor: pointer; } .slider::-webkit-slider-thumb { -webkit-appearance: none; appearance: none; width: 24px; height: 24px; border-radius: 50%; background: #fff; cursor: pointer; border: none; box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2); transition: transform 0.2s ease, box-shadow 0.2s ease; } .slider::-moz-range-thumb { width: 24px; height: 24px; border-radius: 50%; background: #fff; cursor: pointer; border: none; box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2); transition: transform 0.2s ease, box-shadow 0.2s ease; } .slider::-webkit-slider-thumb:hover { transform: scale(1.1); box-shadow: 0 4px 15px rgba(0, 0, 0, 0.3); } .slider::-moz-range-thumb:hover { transform: scale(1.1); box-shadow: 0 4px 15px rgba(0, 0, 0, 0.3); } .tooltip { position: absolute; left: 0; top: -45px; padding: 8px 12px; background: #2d3436; color: #fff; font-size: 14px; border-radius: 8px; box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1); transform: translateX(-50%); opacity: 0; transition: opacity 0.3s ease; pointer-events: none; white-space: nowrap; } .tooltip::after { content: ''; position: absolute; left: 50%; bottom: -5px; transform: translateX(-50%) rotate(45deg); width: 10px; height: 10px; background: #2d3436; } .tooltip.active { opacity: 1; } .result-container { background-color: #f7f7f7; border-radius: 16px; padding: 24px; transition: all 0.3s ease; border: 1px solid #eee; } .result-heading { display: flex; justify-content: space-between; align-items: center; margin-bottom: 16px; } .result-heading h2 { font-size: 18px; font-weight: 600; } .result-price { font-size: 18px; font-weight: 700; color: #0984e3; background: linear-gradient(90deg, #74b9ff, #0984e3); -webkit-background-clip: text; -webkit-text-fill-color: transparent; transition: all 0.3s ease; } .result-price.mid { background: linear-gradient(90deg, #0984e3, #e84393); -webkit-background-clip: text; -webkit-text-fill-color: transparent; } .result-price.high { background: linear-gradient(90deg, #e84393, #d63031); -webkit-background-clip: text; -webkit-text-fill-color: transparent; } .result-stats { display: flex; flex-wrap: wrap; gap: 16px; } .stat { flex: 1; min-width: 120px; background: white; border-radius: 12px; padding: 14px; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05); transition: all 0.3s ease; } .stat-label { font-size: 12px; color: #636e72; margin-bottom: 6px; } .stat-value { font-size: 16px; font-weight: 600; } .cta-button { margin-top: 24px; width: 100%; padding: 14px; background: linear-gradient(90deg, #0984e3, #74b9ff); border: none; border-radius: 12px; color: white; font-weight: 600; font-size: 16px; cursor: pointer; transition: all 0.3s ease; box-shadow: 0 4px 12px rgba(9, 132, 227, 0.3); } .cta-button:hover { transform: translateY(-2px); box-shadow: 0 6px 15px rgba(9, 132, 227, 0.4); background: linear-gradient(90deg, #0970c3, #5aadff); } @media (max-width: 700px) { .container { width: 95%; padding: 24px; } .result-stats { gap: 10px; } .stat { min-width: 100px; padding: 10px; } .price-icon .icon { font-size: 24px; } .price-icon .label { font-size: 10px; } } @media (max-width: 500px) { .result-stats { flex-direction: column; } .stat { width: 100%; } } .pulse { animation: pulse 1.5s infinite; } @keyframes pulse { 0% { box-shadow: 0 0 0 0 rgba(9, 132, 227, 0.4); } 70% { box-shadow: 0 0 0 10px rgba(9, 132, 227, 0); } 100% { box-shadow: 0 0 0 0 rgba(9, 132, 227, 0); } } .ripple { position: absolute; border-radius: 50%; background: rgba(9, 132, 227, 0.2); transform: scale(0); animation: ripple 0.6s linear; pointer-events: none; } @keyframes ripple { to { transform: scale(4); opacity: 0; } } </style> </head> <body> <div class="container"> <h1>Find Your Dream Home</h1> <p class="subtitle">Adjust the slider to find properties in your budget range</p> <div class="price-map"> <span>$100k</span> <span>$1.5M+</span> </div> <div class="price-icons"> <div class="price-icon" data-value="100000"> <div class="icon">🏠</div> <div class="label">Starter</div> </div> <div class="price-icon" data-value="350000"> <div class="icon">🏡</div> <div class="label">Family</div> </div> <div class="price-icon" data-value="750000"> <div class="icon">🏘️</div> <div class="label">Luxury</div> </div> <div class="price-icon" data-value="1200000"> <div class="icon">🏰</div> <div class="label">Premium</div> </div> <div class="price-icon" data-value="1500000"> <div class="icon">✨</div> <div class="label">Elite</div> </div> </div> <div class="slider-container"> <input type="range" min="100000" max="1500000" value="350000" class="slider" id="priceRange"> <div class="tooltip" id="tooltip">$350,000</div> </div> <div class="result-container"> <div class="result-heading"> <h2>Your Price Range</h2> <div class="result-price" id="displayPrice">$350,000</div> </div> <div class="result-stats"> <div class="stat"> <div class="stat-label">Est. Monthly</div> <div class="stat-value" id="monthly">$1,542</div> </div> <div class="stat"> <div class="stat-label">Listings</div> <div class="stat-value" id="listings">123</div> </div> <div class="stat"> <div class="stat-label">Sq. Footage</div> <div class="stat-value" id="sqft">1,850</div> </div> </div> <button class="cta-button pulse">View 123 Matching Properties</button> </div> </div> <script> const slider = document.getElementById('priceRange'); const tooltip = document.getElementById('tooltip'); const displayPrice = document.getElementById('displayPrice'); const monthly = document.getElementById('monthly'); const listings = document.getElementById('listings'); const sqft = document.getElementById('sqft'); const ctaButton = document.querySelector('.cta-button'); const priceIcons = document.querySelectorAll('.price-icon'); // Format currency const formatCurrency = (value) => { return new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD', minimumFractionDigits: 0, maximumFractionDigits: 0 }).format(value); }; // Format number with commas const formatNumber = (num) => { return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ','); }; // Calculate related values const calculateValues = (price) => { // Monthly payment (simplified calculation) const interestRate = 0.04; // 4% interest rate const loanTerm = 30; // 30 years const monthlyRate = interestRate / 12; const numPayments = loanTerm * 12; const loanAmount = price * 0.8; // 20% down payment const monthlyPayment = loanAmount * (monthlyRate * Math.pow(1 + monthlyRate, numPayments)) / (Math.pow(1 + monthlyRate, numPayments) - 1); // Available listings (made up formula for demo) const availableListings = Math.round(380 - (price * 0.00022)); // Square footage (made up formula for demo) let squareFeet; if (price < 300000) { squareFeet = 800 + (price * 0.0025); } else if (price < 750000) { squareFeet = 1500 + (price * 0.0007); } else { squareFeet = 2800 + (price * 0.0004); } return { monthly: formatCurrency(monthlyPayment), listings: Math.max(availableListings, 5), sqft: formatNumber(Math.round(squareFeet / 10) * 10) }; }; // Update the display const updateDisplay = (price) => { const formattedPrice = formatCurrency(price); tooltip.textContent = formattedPrice; displayPrice.textContent = formattedPrice; // Update CTA button ctaButton.textContent = `View ${listings.textContent} Matching Properties`; // Update price color class displayPrice.classList.remove('mid', 'high'); if (price >= 750000) { displayPrice.classList.add('high'); } else if (price >= 350000) { displayPrice.classList.add('mid'); } // Position the tooltip const percent = (price - slider.min) / (slider.max - slider.min); const thumbWidth = 24; const sliderWidth = slider.offsetWidth; const offset = percent * (sliderWidth - thumbWidth); tooltip.style.left = `${offset + thumbWidth/2}px`; // Update stats const values = calculateValues(price); monthly.textContent = values.monthly; listings.textContent = values.listings; sqft.textContent = values.sqft; }; // Initialize updateDisplay(slider.value); // Event listeners slider.addEventListener('input', () => { updateDisplay(Number(slider.value)); tooltip.classList.add('active'); }); slider.addEventListener('mousedown', () => { tooltip.classList.add('active'); }); slider.addEventListener('mouseup', () => { setTimeout(() => { tooltip.classList.remove('active'); }, 1000); }); slider.addEventListener('mouseleave', () => { tooltip.classList.remove('active'); }); // Price icon clicks priceIcons.forEach(icon => { icon.addEventListener('click', (e) => { const value = icon.dataset.value; slider.value = value; updateDisplay(Number(value)); // Create ripple effect const rect = icon.getBoundingClientRect(); const ripple = document.createElement('div'); ripple.className = 'ripple'; ripple.style.left = `${e.clientX - rect.left}px`; ripple.style.top = `${e.clientY - rect.top}px`; icon.appendChild(ripple); setTimeout(() => { ripple.remove(); }, 600); }); }); // CTA button click handling ctaButton.addEventListener('click', () => { // Remove pulse animation when clicked ctaButton.classList.remove('pulse'); ctaButton.textContent = "Finding properties..."; // Simulate loading setTimeout(() => { ctaButton.textContent = `View ${listings.textContent} Matching Properties`; // Add pulse back after a delay setTimeout(() => { ctaButton.classList.add('pulse'); }, 500); }, 1500); }); </script> </body> </html>
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Video Editing Timeline Control</title> <style> :root { --primary-color: #2a2a2a; --secondary-color: #3a3a3a; --accent-color: #565656; --highlight-color: #e0e0e0; --slider-color: #4d4d4d; --handle-color: #b3b3b3; --handle-hover-color: #e6e6e6; --track-color: #1e1e1e; --time-marker-color: rgba(255, 255, 255, 0.2); --text-color: #d9d9d9; --shadow-color: rgba(0, 0, 0, 0.4); } * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Segoe UI', 'Roboto', sans-serif; } body { background-color: var(--primary-color); color: var(--text-color); display: flex; flex-direction: column; align-items: center; justify-content: center; height: 100vh; width: 100%; overflow: hidden; padding: 20px; } .editor-container { width: 100%; max-width: 680px; background-color: var(--secondary-color); border-radius: 6px; box-shadow: 0 8px 24px var(--shadow-color); padding: 24px; transition: all 0.3s ease; } .video-preview { width: 100%; height: 240px; background-color: var(--track-color); border-radius: 4px; margin-bottom: 20px; position: relative; overflow: hidden; display: flex; align-items: center; justify-content: center; } .video-content { width: 100%; height: 100%; background: linear-gradient(45deg, #2a2a2a 25%, transparent 25%, transparent 75%, #2a2a2a 75%), linear-gradient(45deg, #2a2a2a 25%, transparent 25%, transparent 75%, #2a2a2a 75%); background-size: 20px 20px; background-position: 0 0, 10px 10px; position: relative; } .playhead { position: absolute; top: 0; height: 100%; width: 2px; background-color: var(--highlight-color); z-index: 10; box-shadow: 0 0 8px rgba(255, 255, 255, 0.5); transition: left 0.2s ease; } .timeline-container { position: relative; width: 100%; margin-top: 30px; } .time-markers { display: flex; justify-content: space-between; width: 100%; margin-bottom: 5px; padding: 0 12px; position: relative; height: 25px; } .time-marker { position: absolute; font-size: 11px; color: var(--text-color); opacity: 0.7; transform: translateX(-50%); } .time-marker:before { content: ''; position: absolute; top: 18px; left: 50%; height: 5px; width: 1px; background-color: var(--time-marker-color); } .timeline-track { height: 60px; background-color: var(--track-color); border-radius: 4px; position: relative; overflow: hidden; margin-bottom: 15px; display: flex; align-items: center; cursor: pointer; } .timeline-segments { position: absolute; height: 100%; width: 100%; display: flex; align-items: center; } .segment { height: 36px; position: absolute; border-radius: 3px; background-color: var(--accent-color); opacity: 0.9; transition: all 0.2s ease; } .segment:hover { opacity: 1; transform: scaleY(1.05); } .segment-label { position: absolute; font-size: 10px; color: var(--highlight-color); opacity: 0.8; top: 50%; left: 50%; transform: translate(-50%, -50%); white-space: nowrap; pointer-events: none; } .range-slider { position: relative; height: 30px; width: 100%; margin: 10px 0; } .range-track { position: absolute; height: 4px; width: 100%; background-color: var(--slider-color); top: 50%; transform: translateY(-50%); border-radius: 2px; } .range-progress { position: absolute; height: 100%; background-color: var(--highlight-color); border-radius: 2px; } .range-handle { position: absolute; width: 18px; height: 18px; background-color: var(--handle-color); border-radius: 50%; top: 50%; transform: translateY(-50%); cursor: grab; box-shadow: 0 2px 6px var(--shadow-color); z-index: 10; transition: background-color 0.2s ease, transform 0.1s ease; } .range-handle:hover, .range-handle.active { background-color: var(--handle-hover-color); transform: translateY(-50%) scale(1.1); } .range-handle.active { cursor: grabbing; } .range-tooltip { position: absolute; background-color: var(--secondary-color); color: var(--text-color); font-size: 12px; padding: 4px 8px; border-radius: 3px; bottom: 30px; transform: translateX(-50%); opacity: 0; pointer-events: none; box-shadow: 0 2px 10px var(--shadow-color); transition: opacity 0.2s ease, transform 0.2s ease; } .range-tooltip.visible { opacity: 1; transform: translateX(-50%) translateY(-5px); } .time-display { display: flex; justify-content: space-between; margin-top: 10px; font-size: 13px; font-weight: 500; color: var(--text-color); } .control-panel { display: flex; justify-content: space-between; align-items: center; margin-top: 20px; padding-top: 15px; border-top: 1px solid rgba(255, 255, 255, 0.1); } .playback-controls { display: flex; gap: 15px; } .control-button { background-color: var(--slider-color); border: none; border-radius: 4px; width: 36px; height: 36px; display: flex; align-items: center; justify-content: center; cursor: pointer; transition: all 0.2s ease; color: var(--text-color); font-size: 16px; } .control-button:hover { background-color: var(--accent-color); transform: translateY(-2px); } .control-button:active { transform: translateY(0); } .zoom-controls { display: flex; gap: 10px; align-items: center; } .zoom-level { font-size: 13px; font-weight: 500; min-width: 60px; text-align: center; } .title-bar { display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; } .editor-title { font-size: 18px; font-weight: 600; } .project-info { font-size: 12px; opacity: 0.7; display: flex; align-items: center; gap: 8px; } .status-indicator { width: 8px; height: 8px; border-radius: 50%; background-color: #4CAF50; display: inline-block; } .waveform { position: absolute; bottom: 0; width: 100%; height: 20px; display: flex; align-items: flex-end; justify-content: space-between; padding: 0 5px; } .waveform-bar { width: 2px; background-color: rgba(255, 255, 255, 0.2); margin: 0 1px; } .markers-container { position: absolute; top: 0; left: 0; width: 100%; height: 100%; pointer-events: none; } .marker { position: absolute; width: 2px; height: 100%; background-color: rgba(255, 255, 255, 0.3); top: 0; } .marker:after { content: ''; position: absolute; top: 0; left: -4px; width: 10px; height: 10px; background-color: var(--highlight-color); border-radius: 50%; transform: translateY(-50%); } @media screen and (max-width: 600px) { .editor-container { padding: 15px; } .video-preview { height: 180px; } .timeline-track { height: 50px; } .control-panel { flex-direction: column; gap: 15px; } .playback-controls { width: 100%; justify-content: center; } .zoom-controls { width: 100%; justify-content: center; } } .ripple { position: absolute; border-radius: 50%; background-color: rgba(255, 255, 255, 0.4); transform: scale(0); animation: ripple-animation 0.6s linear; pointer-events: none; } @keyframes ripple-animation { to { transform: scale(4); opacity: 0; } } .keyboard-shortcuts { position: absolute; bottom: 15px; right: 15px; font-size: 11px; opacity: 0.6; } .keyboard-shortcuts kbd { background-color: var(--slider-color); border-radius: 3px; padding: 1px 3px; font-family: monospace; margin: 0 2px; } </style> </head> <body> <div class="editor-container"> <div class="title-bar"> <div class="editor-title">ProCut Timeline</div> <div class="project-info"> <span class="status-indicator"></span> <span>Project: Interview_Final_v2.mp4</span> </div> </div> <div class="video-preview"> <div class="video-content"> <!-- Simulated video preview --> <div class="playhead" id="playhead"></div> </div> </div> <div class="time-display"> <div id="current-time">00:00:12.500</div> <div id="duration">00:02:30.000</div> </div> <div class="timeline-container"> <div class="time-markers" id="time-markers"> <!-- Time markers will be generated by JS --> </div> <div class="timeline-track" id="timeline-track"> <div class="markers-container" id="markers-container"> <!-- Markers will be generated by JS --> </div> <div class="timeline-segments" id="timeline-segments"> <!-- Segments will be generated by JS --> </div> <div class="waveform" id="waveform"> <!-- Waveform will be generated by JS --> </div> </div> <div class="range-slider" id="range-slider"> <div class="range-track"> <div class="range-progress" id="range-progress"></div> </div> <div class="range-handle" id="range-handle-start"></div> <div class="range-handle" id="range-handle-end"></div> <div class="range-tooltip" id="tooltip-start"></div> <div class="range-tooltip" id="tooltip-end"></div> </div> </div> <div class="control-panel"> <div class="playback-controls"> <button class="control-button" id="prev-frame">⏮</button> <button class="control-button" id="play-pause">▶</button> <button class="control-button" id="next-frame">⏭</button> <button class="control-button" id="add-marker">+</button> <button class="control-button" id="split">✂️</button> </div> <div class="zoom-controls"> <button class="control-button" id="zoom-out">−</button> <span class="zoom-level" id="zoom-level">100%</span> <button class="control-button" id="zoom-in">+</button> </div> </div> <div class="keyboard-shortcuts"> Shortcuts: <kbd>Space</kbd> Play/Pause <kbd>I</kbd> In point <kbd>O</kbd> Out point <kbd>M</kbd> Marker </div> </div> <script> document.addEventListener('DOMContentLoaded', function() { // Constants const DURATION = 150; // in seconds const MIN_START = 0; const MAX_END = DURATION; // State let isPlaying = false; let currentTime = 12.5; // in seconds let startValue = 10; // in seconds let endValue = 35; // in seconds let zoomLevel = 100; // percentage let isDraggingStart = false; let isDraggingEnd = false; let isDraggingPlayhead = false; let frameRequestId = null; let markers = [25, 78, 120]; // marker positions in seconds // DOM elements const rangeSlider = document.getElementById('range-slider'); const progressBar = document.getElementById('range-progress'); const startHandle = document.getElementById('range-handle-start'); const endHandle = document.getElementById('range-handle-end'); const startTooltip = document.getElementById('tooltip-start'); const endTooltip = document.getElementById('tooltip-end'); const currentTimeDisplay = document.getElementById('current-time'); const durationDisplay = document.getElementById('duration'); const playPauseButton = document.getElementById('play-pause'); const prevFrameButton = document.getElementById('prev-frame'); const nextFrameButton = document.getElementById('next-frame'); const addMarkerButton = document.getElementById('add-marker'); const splitButton = document.getElementById('split'); const zoomInButton = document.getElementById('zoom-in'); const zoomOutButton = document.getElementById('zoom-out'); const zoomLevelDisplay = document.getElementById('zoom-level'); const timelineTrack = document.getElementById('timeline-track'); const timeMarkers = document.getElementById('time-markers'); const timelineSegments = document.getElementById('timeline-segments'); const playhead = document.getElementById('playhead'); const waveform = document.getElementById('waveform'); const markersContainer = document.getElementById('markers-container'); // Generate timeline segments const segments = [ { start: 0, end: 15, label: "Intro" }, { start: 15, end: 45, label: "Interview A" }, { start: 50, end: 85, label: "B-Roll" }, { start: 85, end: 120, label: "Interview B" }, { start: 125, end: 150, label: "Outro" } ]; function generateSegments() { timelineSegments.innerHTML = ''; segments.forEach(segment => { const segmentEl = document.createElement('div'); segmentEl.className = 'segment'; const startPercent = (segment.start / DURATION) * 100; const widthPercent = ((segment.end - segment.start) / DURATION) * 100; segmentEl.style.left = `${startPercent}%`; segmentEl.style.width = `${widthPercent}%`; const label = document.createElement('div'); label.className = 'segment-label'; label.textContent = segment.label; segmentEl.appendChild(label); timelineSegments.appendChild(segmentEl); }); } // Generate time markers function generateTimeMarkers() { timeMarkers.innerHTML = ''; const numMarkers = 11; // 0, 10%, 20%, ..., 100% for (let i = 0; i < numMarkers; i++) { const percent = i * (100 / (numMarkers - 1)); const time = (DURATION * percent) / 100; const marker = document.createElement('div'); marker.className = 'time-marker'; marker.style.left = `${percent}%`; marker.textContent = formatTime(time, false); timeMarkers.appendChild(marker); } } // Generate waveform visualization function generateWaveform() { waveform.innerHTML = ''; const numBars = 150; for (let i = 0; i < numBars; i++) { const height = Math.random() * 18 + 2; // Random height between 2-20px const bar = document.createElement('div'); bar.className = 'waveform-bar'; bar.style.height = `${height}px`; waveform.appendChild(bar); } } // Generate timeline markers function generateMarkers() { markersContainer.innerHTML = ''; markers.forEach(time => { const percent = (time / DURATION) * 100; const marker = document.createElement('div'); marker.className = 'marker'; marker.style.left = `${percent}%`; markersContainer.appendChild(marker); }); } // Initialize the slider function initSlider() { updateHandlePositions(); updateProgressBar(); updateTooltips(); updateTimeDisplay(); generateTimeMarkers(); generateSegments(); generateWaveform(); generateMarkers(); updatePlayhead(); } // Format time (seconds to MM:SS.SSS) function formatTime(seconds, includeMilliseconds = true) { const hrs = Math.floor(seconds / 3600); const mins = Math.floor((seconds % 3600) / 60); const secs = Math.floor(seconds % 60); const millisecs = Math.floor((seconds % 1) * 1000); let timeStr = ''; if (hrs > 0) { timeStr += `${String(hrs).padStart(2, '0')}:`; } timeStr += `${String(mins).padStart(2, '0')}:${String(secs).padStart(2, '0')}`; if (includeMilliseconds) { timeStr += `.${String(millisecs).padStart(3, '0')}`; } return timeStr; } // Convert position to time value function positionToValue(position) { const rect = rangeSlider.getBoundingClientRect(); const percent = Math.max(0, Math.min(1, (position - rect.left) / rect.width)); return MIN_START + percent * (MAX_END - MIN_START); } // Update handle positions based on values function updateHandlePositions() { const startPercent = ((startValue - MIN_START) / (MAX_END - MIN_START)) * 100; const endPercent = ((endValue - MIN_START) / (MAX_END - MIN_START)) * 100; startHandle.style.left = `${startPercent}%`; endHandle.style.left = `${endPercent}%`; startTooltip.style.left = `${startPercent}%`; endTooltip.style.left = `${endPercent}%`; } // Update progress bar function updateProgressBar() { const startPercent = ((startValue - MIN_START) / (MAX_END - MIN_START)) * 100; const endPercent = ((endValue - MIN_START) / (MAX_END - MIN_START)) * 100; progressBar.style.left = `${startPercent}%`; progressBar.style.width = `${endPercent - startPercent}%`; } // Update tooltips function updateTooltips() { startTooltip.textContent = formatTime(startValue); endTooltip.textContent = formatTime(endValue); } // Update time display function updateTimeDisplay() { currentTimeDisplay.textContent = formatTime(currentTime); durationDisplay.textContent = formatTime(DURATION); } // Update playhead position function updatePlayhead() { const percent = (currentTime / DURATION) * 100; playhead.style.left = `${percent}%`; } // Play/pause video simulation function togglePlayPause() { isPlaying = !isPlaying; playPauseButton.textContent = isPlaying ? '⏸' : '▶'; if (isPlaying) { playVideo(); } else { cancelAnimationFrame(frameRequestId); } } // Simulate video playback function playVideo() { const startTime = performance.now(); const startCurrentTime = currentTime; function animate(now) { const deltaSeconds = (now - startTime) / 1000; currentTime = startCurrentTime + deltaSeconds; if (currentTime >= endValue) { currentTime = startValue; } updateTimeDisplay(); updatePlayhead(); if (isPlaying) { frameRequestId = requestAnimationFrame(animate); } } frameRequestId = requestAnimationFrame(animate); } // Add ripple effect function addRippleEffect(event, element) { const rect = element.getBoundingClientRect(); const x = event.clientX - rect.left; const y = event.clientY - rect.top; const ripple = document.createElement('span'); ripple.className = 'ripple'; ripple.style.left = `${x}px`; ripple.style.top = `${y}px`; element.appendChild(ripple); setTimeout(() => { ripple.remove(); }, 600); } // Add new marker function addMarker() { if (!markers.includes(currentTime)) { markers.push(currentTime); markers.sort((a, b) => a - b); generateMarkers(); } } // Jump to next frame (simulate frame advance) function nextFrame() { currentTime = Math.min(currentTime + 1/30, DURATION); updateTimeDisplay(); updatePlayhead(); } // Jump to previous frame (simulate frame rewind) function prevFrame() { currentTime = Math.max(currentTime - 1/30, 0); updateTimeDisplay(); updatePlayhead(); } // Simulate splitting clip at current position function splitClip() { for (let i = 0; i < segments.length; i++) { const segment = segments[i]; if (currentTime > segment.start && currentTime < segment.end) { // Create two segments from one const newSegment = { start: currentTime, end: segment.end, label: segment.label + " (split)" }; segments[i].end = currentTime; segments.splice(i + 1, 0, newSegment); generateSegments(); break; } } } // Change zoom level function changeZoom(delta) { zoomLevel = Math.max(50, Math.min(200, zoomLevel + delta)); zoomLevelDisplay.textContent = `${zoomLevel}%`; // In a real implementation, this would adjust the visible timeline range } // Event Listeners for handles startHandle.addEventListener('mousedown', function(e) { isDraggingStart = true; startHandle.classList.add('active'); startTooltip.classList.add('visible'); document.addEventListener('mousemove', handleDrag); document.addEventListener('mouseup', stopDrag); e.preventDefault(); }); endHandle.addEventListener('mousedown', function(e) { isDraggingEnd = true; endHandle.classList.add('active'); endTooltip.classList.add('visible'); document.addEventListener('mousemove', handleDrag); document.addEventListener('mouseup', stopDrag); e.preventDefault(); }); // Timeline track click to set playhead timelineTrack.addEventListener('click', function(e) { const rect = timelineTrack.getBoundingClientRect(); const clickPercent = (e.clientX - rect.left) / rect.width; currentTime = clickPercent * DURATION; updatePlayhead(); updateTimeDisplay(); }); // Handle drag function handleDrag(e) { if (isDraggingStart || isDraggingEnd) { const value = positionToValue(e.clientX); if (isDraggingStart) { startValue = Math.max(MIN_START, Math.min(endValue - 1, value)); } else { endValue = Math.min(MAX_END, Math.max(startValue + 1, value)); } updateHandlePositions(); updateProgressBar(); updateTooltips(); } } // Stop drag function stopDrag() { isDraggingStart = false; isDraggingEnd = false; startHandle.classList.remove('active'); endHandle.classList.remove('active'); startTooltip.classList.remove('visible'); endTooltip.classList.remove('visible'); document.removeEventListener('mousemove', handleDrag); document.removeEventListener('mouseup', stopDrag); } // Playback control listeners playPauseButton.addEventListener('click', function(e) { togglePlayPause(); addRippleEffect(e, this); }); prevFrameButton.addEventListener('click', function(e) { prevFrame(); addRippleEffect(e, this); }); nextFrameButton.addEventListener('click', function(e) { nextFrame(); addRippleEffect(e, this); }); addMarkerButton.addEventListener('click', function(e) { addMarker(); addRippleEffect(e, this); }); splitButton.addEventListener('click', function(e) { splitClip(); addRippleEffect(e, this); }); zoomInButton.addEventListener('click', function(e) { changeZoom(10); addRippleEffect(e, this); }); zoomOutButton.addEventListener('click', function(e) { changeZoom(-10); addRippleEffect(e, this); }); // Keyboard shortcuts document.addEventListener('keydown', function(e) { switch(e.key) { case ' ': togglePlayPause(); e.preventDefault(); break; case 'i': case 'I': startValue = currentTime; updateHandlePositions(); updateProgressBar(); updateTooltips(); break; case 'o': case 'O': endValue = currentTime; updateHandlePositions(); updateProgressBar(); updateTooltips(); break; case 'm': case 'M': addMarker(); break; } }); // Touch support for mobile devices startHandle.addEventListener('touchstart', function(e) { isDraggingStart = true; startHandle.classList.add('active'); startTooltip.classList.add('visible'); document.addEventListener('touchmove', handleTouchDrag); document.addEventListener('touchend', stopTouchDrag); e.preventDefault(); }); endHandle.addEventListener('touchstart', function(e) { isDraggingEnd = true; endHandle.classList.add('active'); endTooltip.classList.add('visible'); document.addEventListener('touchmove', handleTouchDrag); document.addEventListener('touchend', stopTouchDrag); e.preventDefault(); }); function handleTouchDrag(e) { if (isDraggingStart || isDraggingEnd) { const touch = e.touches[0]; const value = positionToValue(touch.clientX); if (isDraggingStart) { startValue = Math.max(MIN_START, Math.min(endValue - 1, value)); } else { endValue = Math.min(MAX_END, Math.max(startValue + 1, value)); } updateHandlePositions(); updateProgressBar(); updateTooltips(); } } function stopTouchDrag() { isDraggingStart = false; isDraggingEnd = false; startHandle.classList.remove('active'); endHandle.classList.remove('active'); startTooltip.classList.remove('visible'); endTooltip.classList.remove('visible'); document.removeEventListener('touchmove', handleTouchDrag); document.removeEventListener('touchend', stopTouchDrag); } // Initialize the slider initSlider(); }); </script> </body> </html>
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Audio Equalizer Control</title> <style> :root { --neon-cyan: #00f0ff; --neon-pink: #ff00e6; --neon-blue: #3633ff; --neon-green: #2fff00; --dark-bg: #0a0a12; --dark-panel: #14141f; --glow-intensity: 10px; } * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Rajdhani', 'Orbitron', sans-serif; } body { background-color: var(--dark-bg); color: white; display: flex; justify-content: center; align-items: center; min-height: 100vh; overflow: hidden; } .container { width: 100%; max-width: 680px; background-color: var(--dark-panel); border-radius: 12px; padding: 25px; box-shadow: 0 0 20px rgba(0, 0, 0, 0.5); position: relative; overflow: hidden; } .grid-background { position: absolute; top: 0; left: 0; width: 100%; height: 100%; background-image: linear-gradient(rgba(27, 27, 36, 0.6) 1px, transparent 1px), linear-gradient(90deg, rgba(27, 27, 36, 0.6) 1px, transparent 1px); background-size: 20px 20px; z-index: 0; opacity: 0.3; } .title { font-size: 2rem; text-align: center; margin-bottom: 20px; color: #fff; text-shadow: 0 0 5px rgba(0, 240, 255, 0.7); position: relative; z-index: 1; } .title span { background: linear-gradient(90deg, var(--neon-blue), var(--neon-cyan)); -webkit-background-clip: text; background-clip: text; color: transparent; font-weight: 700; } .equalizer-container { display: flex; flex-direction: column; gap: 20px; margin-top: 30px; position: relative; z-index: 1; } .slider-container { position: relative; } .frequency-band { display: flex; justify-content: space-between; font-size: 0.75rem; color: rgba(255, 255, 255, 0.7); margin-bottom: 5px; position: relative; } .frequency-band::before { content: ''; position: absolute; top: 20px; left: 0; width: 100%; height: 1px; background: linear-gradient(90deg, rgba(255, 255, 255, 0.1), rgba(255, 255, 255, 0.4), rgba(255, 255, 255, 0.1)); } .frequency-marks { position: absolute; top: -15px; left: 0; width: 100%; display: flex; justify-content: space-between; font-size: 0.7rem; color: rgba(255, 255, 255, 0.6); } .frequency-marks span { position: absolute; transform: translateX(-50%); } .frequency-marks span:nth-child(1) { left: 0%; } .frequency-marks span:nth-child(2) { left: 10%; } .frequency-marks span:nth-child(3) { left: 20%; } .frequency-marks span:nth-child(4) { left: 30%; } .frequency-marks span:nth-child(5) { left: 40%; } .frequency-marks span:nth-child(6) { left: 50%; } .frequency-marks span:nth-child(7) { left: 60%; } .frequency-marks span:nth-child(8) { left: 70%; } .frequency-marks span:nth-child(9) { left: 80%; } .frequency-marks span:nth-child(10) { left: 90%; } .frequency-marks span:nth-child(11) { left: 100%; } .slider { -webkit-appearance: none; width: 100%; height: 4px; background: linear-gradient(90deg, var(--neon-pink), var(--neon-blue), var(--neon-cyan), var(--neon-green)); outline: none; border-radius: 2px; box-shadow: 0 0 var(--glow-intensity) rgba(0, 240, 255, 0.5); margin-top: 20px; margin-bottom: 30px; position: relative; z-index: 1; } .slider::-webkit-slider-thumb { -webkit-appearance: none; appearance: none; width: 22px; height: 22px; border-radius: 50%; background: #fff; cursor: pointer; box-shadow: 0 0 0 3px rgba(0, 0, 0, 0.8), 0 0 15px var(--neon-cyan); transition: all 0.2s ease; } .slider::-moz-range-thumb { width: 22px; height: 22px; border-radius: 50%; background: #fff; cursor: pointer; box-shadow: 0 0 0 3px rgba(0, 0, 0, 0.8), 0 0 15px var(--neon-cyan); transition: all 0.2s ease; } .slider:active::-webkit-slider-thumb { box-shadow: 0 0 0 3px rgba(0, 0, 0, 0.8), 0 0 15px var(--neon-pink), 0 0 30px rgba(255, 0, 230, 0.7); transform: scale(1.1); } .slider:active::-moz-range-thumb { box-shadow: 0 0 0 3px rgba(0, 0, 0, 0.8), 0 0 15px var(--neon-pink), 0 0 30px rgba(255, 0, 230, 0.7); transform: scale(1.1); } .eq-presets { display: flex; justify-content: space-between; gap: 10px; margin-top: 10px; position: relative; z-index: 1; } .preset-btn { flex: 1; padding: 8px 12px; background-color: rgba(20, 20, 31, 0.8); border: 1px solid rgba(0, 240, 255, 0.3); color: rgba(255, 255, 255, 0.8); border-radius: 6px; cursor: pointer; font-size: 0.75rem; font-weight: bold; text-transform: uppercase; transition: all 0.3s ease; box-shadow: 0 0 5px rgba(0, 240, 255, 0.1); } .preset-btn:hover { background-color: rgba(0, 240, 255, 0.1); border-color: var(--neon-cyan); color: white; box-shadow: 0 0 10px rgba(0, 240, 255, 0.3); } .preset-btn.active { background-color: rgba(0, 240, 255, 0.2); border-color: var(--neon-cyan); color: white; box-shadow: 0 0 15px rgba(0, 240, 255, 0.5); } .frequency-visualization { height: 100px; margin-top: 20px; display: flex; justify-content: space-between; align-items: flex-end; position: relative; z-index: 1; } .frequency-bar { flex: 1; background: linear-gradient(180deg, var(--neon-cyan), var(--neon-blue), var(--neon-pink)); margin: 0 2px; border-radius: 3px 3px 0 0; box-shadow: 0 0 5px rgba(0, 240, 255, 0.5); transition: height 0.2s ease; } .controls { display: flex; gap: 15px; margin-top: 25px; position: relative; z-index: 1; } .control-btn { flex: 1; display: flex; align-items: center; justify-content: center; padding: 12px; background-color: rgba(20, 20, 31, 0.8); border: 1px solid rgba(0, 240, 255, 0.3); color: rgba(255, 255, 255, 0.8); border-radius: 8px; cursor: pointer; font-size: 0.9rem; font-weight: bold; transition: all 0.3s ease; position: relative; overflow: hidden; } .control-btn:hover { background-color: rgba(0, 240, 255, 0.1); border-color: var(--neon-cyan); color: white; box-shadow: 0 0 15px rgba(0, 240, 255, 0.3); } .control-btn::before { content: ''; position: absolute; top: -2px; left: -2px; width: calc(100% + 4px); height: calc(100% + 4px); background: linear-gradient(45deg, transparent 20%, rgba(0, 240, 255, 0.6), transparent 80%); border-radius: 10px; opacity: 0; transition: opacity 0.3s ease; z-index: -1; } .control-btn:hover::before { opacity: 1; } .control-btn.active { background-color: rgba(0, 240, 255, 0.2); box-shadow: 0 0 20px rgba(0, 240, 255, 0.5); } .indicators { display: flex; justify-content: space-between; padding: 0 10px; margin-top: 15px; position: relative; z-index: 1; } .indicator { display: flex; align-items: center; gap: 5px; font-size: 0.7rem; color: rgba(255, 255, 255, 0.7); } .indicator-dot { width: 8px; height: 8px; border-radius: 50%; } .indicator-dot.bass { background-color: var(--neon-pink); box-shadow: 0 0 8px var(--neon-pink); } .indicator-dot.mid { background-color: var(--neon-blue); box-shadow: 0 0 8px var(--neon-blue); } .indicator-dot.treble { background-color: var(--neon-cyan); box-shadow: 0 0 8px var(--neon-cyan); } .value-display { position: absolute; background-color: rgba(10, 10, 18, 0.9); border: 1px solid var(--neon-cyan); color: white; padding: 3px 8px; border-radius: 4px; font-size: 0.75rem; transform: translateX(-50%); box-shadow: 0 0 8px rgba(0, 240, 255, 0.5); pointer-events: none; opacity: 0; transition: opacity 0.2s ease; z-index: 10; } /* Animations */ @keyframes pulse { 0% { box-shadow: 0 0 5px rgba(0, 240, 255, 0.5); } 50% { box-shadow: 0 0 15px rgba(0, 240, 255, 0.8); } 100% { box-shadow: 0 0 5px rgba(0, 240, 255, 0.5); } } @keyframes glow { 0% { text-shadow: 0 0 5px rgba(0, 240, 255, 0.7); } 50% { text-shadow: 0 0 10px rgba(0, 240, 255, 0.9), 0 0 20px rgba(0, 240, 255, 0.5); } 100% { text-shadow: 0 0 5px rgba(0, 240, 255, 0.7); } } @keyframes float { 0% { transform: translateY(0px); } 50% { transform: translateY(-3px); } 100% { transform: translateY(0px); } } .slider-container { animation: pulse 3s infinite; } .title { animation: glow 4s infinite; } .frequency-bar { animation: float 2s infinite; animation-delay: calc(var(--bar-index) * 0.1s); } /* Responsive adjustments */ @media (max-width: 600px) { .container { padding: 15px; } .title { font-size: 1.5rem; } .eq-presets { flex-wrap: wrap; } .preset-btn { flex: 1 0 40%; font-size: 0.65rem; padding: 6px 8px; } .frequency-visualization { height: 80px; } .controls { flex-wrap: wrap; } .control-btn { flex: 1 0 40%; font-size: 0.8rem; padding: 8px; } } </style> </head> <body> <div class="container"> <div class="grid-background"></div> <h1 class="title">SONIC <span>WAVEFORM</span> EQ</h1> <div class="slider-container"> <div class="frequency-band"> <span>32Hz</span> <span>64Hz</span> <span>125Hz</span> <span>250Hz</span> <span>500Hz</span> <span>1kHz</span> <span>2kHz</span> <span>4kHz</span> <span>8kHz</span> <span>16kHz</span> </div> <input type="range" min="0" max="100" value="50" class="slider" id="main-slider"> <div class="frequency-marks"> <span>0</span> <span>1</span> <span>2</span> <span>3</span> <span>4</span> <span>5</span> <span>6</span> <span>7</span> <span>8</span> <span>9</span> <span>10</span> </div> <div id="value-display" class="value-display">50</div> </div> <div class="equalizer-container"> <div class="frequency-visualization" id="visualization"> <!-- Frequency bars will be added dynamically --> </div> <div class="indicators"> <div class="indicator"> <div class="indicator-dot bass"></div> <span>BASS</span> </div> <div class="indicator"> <div class="indicator-dot mid"></div> <span>MIDS</span> </div> <div class="indicator"> <div class="indicator-dot treble"></div> <span>TREBLE</span> </div> </div> <div class="eq-presets"> <button class="preset-btn" data-preset="flat">FLAT</button> <button class="preset-btn" data-preset="bass">BASS BOOST</button> <button class="preset-btn" data-preset="vocal">VOCAL ENHANCE</button> <button class="preset-btn" data-preset="electronic">ELECTRONIC</button> </div> <div class="controls"> <button class="control-btn" id="reset-btn">RESET EQ</button> <button class="control-btn" id="toggle-btn">BYPASS EQ</button> </div> </div> </div> <script> document.addEventListener('DOMContentLoaded', function() { // Create frequency visualization bars const visualization = document.getElementById('visualization'); const numBars = 32; for (let i = 0; i < numBars; i++) { const bar = document.createElement('div'); bar.className = 'frequency-bar'; bar.style.setProperty('--bar-index', i); visualization.appendChild(bar); } // Initialize bars with random heights animateBars(); // Set up main slider const mainSlider = document.getElementById('main-slider'); const valueDisplay = document.getElementById('value-display'); mainSlider.addEventListener('input', function() { updateValueDisplay(this, valueDisplay); animateBars(); }); mainSlider.addEventListener('mousedown', function() { valueDisplay.style.opacity = '1'; updateValueDisplay(this, valueDisplay); }); mainSlider.addEventListener('mouseup', function() { setTimeout(() => { valueDisplay.style.opacity = '0'; }, 1000); }); mainSlider.addEventListener('mousemove', function(e) { if (e.buttons === 1) { // If mouse button is pressed updateValueDisplay(this, valueDisplay); } }); // Preset buttons functionality const presetButtons = document.querySelectorAll('.preset-btn'); presetButtons.forEach(btn => { btn.addEventListener('click', function() { // Remove active class from all preset buttons presetButtons.forEach(b => b.classList.remove('active')); // Add active class to clicked button this.classList.add('active'); // Apply preset const preset = this.getAttribute('data-preset'); applyPreset(preset); }); }); // Control buttons functionality const resetBtn = document.getElementById('reset-btn'); const toggleBtn = document.getElementById('toggle-btn'); resetBtn.addEventListener('click', function() { mainSlider.value = 50; updateValueDisplay(mainSlider, valueDisplay); animateBars(); // Show and hide the value display valueDisplay.style.opacity = '1'; setTimeout(() => { valueDisplay.style.opacity = '0'; }, 1000); // Remove active class from all preset buttons presetButtons.forEach(b => b.classList.remove('active')); }); toggleBtn.addEventListener('click', function() { this.classList.toggle('active'); if (this.classList.contains('active')) { this.textContent = 'EQ BYPASSED'; // Simulate bypass by reducing bar heights document.querySelectorAll('.frequency-bar').forEach(bar => { bar.style.height = '10px'; }); } else { this.textContent = 'BYPASS EQ'; // Restore normal operation animateBars(); } }); // Helper Functions function updateValueDisplay(slider, display) { const value = slider.value; display.textContent = value; // Position the value display above the thumb const percent = (value - slider.min) / (slider.max - slider.min); const thumbPosition = percent * (slider.offsetWidth - 22) + 11; // 22px is thumb width display.style.left = `${thumbPosition}px`; display.style.top = `${slider.offsetTop - 25}px`; } function animateBars() { const isEqActive = !document.getElementById('toggle-btn').classList.contains('active'); if (!isEqActive) return; const sliderValue = parseInt(mainSlider.value); const bars = document.querySelectorAll('.frequency-bar'); bars.forEach((bar, index) => { // Calculate height based on slider value and some randomness let height; // Create a waveform pattern based on the index const baseHeight = 20 + Math.sin(index * 0.2) * 30; const randomFactor = Math.random() * 10 - 5; // Adjust height based on slider value const adjustmentFactor = (sliderValue - 50) / 50; // -1 to 1 const adjustedHeight = baseHeight + (baseHeight * adjustmentFactor); height = Math.max(5, Math.min(95, adjustedHeight + randomFactor)); bar.style.height = `${height}px`; }); } function applyPreset(preset) { switch(preset) { case 'flat': mainSlider.value = 50; break; case 'bass': mainSlider.value = 75; break; case 'vocal': mainSlider.value = 60; break; case 'electronic': mainSlider.value = 85; break; } updateValueDisplay(mainSlider, valueDisplay); animateBars(); // Show and hide the value display valueDisplay.style.opacity = '1'; setTimeout(() => { valueDisplay.style.opacity = '0'; }, 1000); } // Periodically animate bars to simulate audio response setInterval(animateBars, 200); }); </script> </body> </html>
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Product Filter Range Slider</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; } body { background-color: #f8f9fa; padding: 20px; display: flex; flex-direction: column; height: 100vh; color: #333; } .container { max-width: 700px; margin: 0 auto; background-color: #fff; border-radius: 18px; padding: 30px; box-shadow: 0 8px 30px rgba(0, 0, 0, 0.05); position: relative; overflow: hidden; } h1 { font-size: 28px; margin-bottom: 10px; color: #30336b; font-weight: 600; } p.subtitle { color: #6c7a89; margin-bottom: 30px; font-size: 16px; line-height: 1.5; } .filter-section { margin-bottom: 40px; } .filter-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 15px; } .filter-title { font-size: 18px; font-weight: 600; color: #30336b; } .range-values { display: flex; justify-content: space-between; font-size: 15px; color: #6c7a89; margin-bottom: 8px; } .slider-container { position: relative; height: 50px; padding: 10px 0; } .slider-track { position: absolute; top: 50%; transform: translateY(-50%); height: 6px; width: 100%; background: #e0e7ff; border-radius: 10px; } .slider-range { position: absolute; top: 50%; transform: translateY(-50%); height: 6px; background: #818cf8; border-radius: 10px; transition: width 0.3s ease, left 0.3s ease; } .slider-thumb { position: absolute; top: 50%; width: 24px; height: 24px; border-radius: 50%; background: white; box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); transform: translate(-50%, -50%); cursor: grab; transition: transform 0.2s ease, box-shadow 0.2s ease; z-index: 2; border: 3px solid #818cf8; } .slider-thumb:hover { transform: translate(-50%, -50%) scale(1.1); box-shadow: 0 3px 12px rgba(0, 0, 0, 0.15); } .slider-thumb.active { cursor: grabbing; transform: translate(-50%, -50%) scale(1.15); box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2); } .slider-thumb::after { content: ""; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 6px; height: 6px; background: #818cf8; border-radius: 50%; } .bubble { position: absolute; top: -35px; transform: translateX(-50%); background: #818cf8; color: white; padding: 4px 12px; border-radius: 12px; font-size: 12px; font-weight: 600; opacity: 0; transition: opacity 0.3s ease, transform 0.3s ease; pointer-events: none; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); } .bubble::after { content: ""; position: absolute; top: 100%; left: 50%; transform: translateX(-50%); border-width: 5px; border-style: solid; border-color: #818cf8 transparent transparent transparent; } .slider-thumb:hover .bubble, .slider-thumb.active .bubble { opacity: 1; transform: translateX(-50%) translateY(-5px); } .product-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 20px; margin-top: 30px; } .product-card { background: white; border-radius: 12px; overflow: hidden; box-shadow: 0 4px 15px rgba(0, 0, 0, 0.05); transition: transform 0.3s ease, box-shadow 0.3s ease; position: relative; } .product-card:hover { transform: translateY(-5px); box-shadow: 0 8px 25px rgba(0, 0, 0, 0.1); } .product-image { height: 160px; overflow: hidden; background-color: #f8f7ff; position: relative; } .product-image img { width: 100%; height: 100%; object-fit: cover; transition: transform 0.5s ease; } .product-card:hover .product-image img { transform: scale(1.05); } .product-details { padding: 15px; } .product-name { font-size: 16px; font-weight: 600; margin-bottom: 5px; color: #333; } .product-price { font-size: 18px; font-weight: 700; color: #30336b; margin-bottom: 8px; } .product-rating { display: flex; align-items: center; margin-bottom: 8px; } .stars { color: #ffc107; font-size: 14px; margin-right: 5px; } .rating-count { font-size: 12px; color: #6c7a89; } .tag { position: absolute; top: 10px; right: 10px; background-color: #e1f5fe; color: #0288d1; padding: 4px 10px; border-radius: 20px; font-size: 11px; font-weight: 600; box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1); } .tag.sale { background-color: #fff8e1; color: #ffa000; } .tag.new { background-color: #e8f5e9; color: #43a047; } .filter-button { display: inline-block; padding: 12px 20px; background-color: #818cf8; color: white; border: none; border-radius: 25px; font-size: 15px; font-weight: 600; cursor: pointer; transition: all 0.3s ease; box-shadow: 0 3px 10px rgba(129, 140, 248, 0.3); outline: none; } .filter-button:hover { background-color: #6470f3; box-shadow: 0 5px 15px rgba(129, 140, 248, 0.4); transform: translateY(-2px); } .filter-button:active { transform: translateY(0); box-shadow: 0 2px 8px rgba(129, 140, 248, 0.3); } .products-found { margin-top: 20px; font-size: 15px; color: #30336b; font-weight: 500; } .filter-badge { display: inline-flex; align-items: center; background-color: #f0f1fe; border-radius: 20px; padding: 5px 12px; margin-right: 8px; margin-bottom: 8px; font-size: 13px; color: #6470f3; transition: all 0.2s ease; } .filter-badge:hover { background-color: #e4e6fe; } .filter-badge .remove { margin-left: 6px; font-size: 16px; font-weight: bold; cursor: pointer; } .badges-container { display: flex; flex-wrap: wrap; margin-bottom: 20px; } .ripple { position: absolute; border-radius: 50%; background-color: rgba(129, 140, 248, 0.4); transform: scale(0); animation: ripple 0.8s linear; pointer-events: none; } @keyframes ripple { to { transform: scale(2); opacity: 0; } } /* Animation for cards loading */ @keyframes fadeIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } } .product-card { animation: fadeIn 0.5s ease forwards; } .product-card:nth-child(2) { animation-delay: 0.1s; } .product-card:nth-child(3) { animation-delay: 0.2s; } .product-card:nth-child(4) { animation-delay: 0.3s; } .product-card:nth-child(5) { animation-delay: 0.4s; } .product-card:nth-child(6) { animation-delay: 0.5s; } /* Pastel color scheme */ .color-accent-1 { color: #818cf8; } .bg-accent-1 { background-color: #818cf8; } .color-accent-2 { color: #c084fc; } .bg-accent-2 { background-color: #c084fc; } /* Responsive styles */ @media (max-width: 700px) { .container { padding: 20px; border-radius: 12px; } h1 { font-size: 24px; } .product-grid { grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); gap: 15px; } .product-image { height: 120px; } .product-details { padding: 10px; } .product-name { font-size: 14px; } .product-price { font-size: 16px; } } @media (max-width: 480px) { .product-grid { grid-template-columns: repeat(2, 1fr); } } /* Enhanced focus states for accessibility */ button:focus, .slider-thumb:focus { outline: 2px solid #818cf8; outline-offset: 2px; } /* Custom scrollbar */ ::-webkit-scrollbar { width: 8px; } ::-webkit-scrollbar-track { background: #f1f1f1; border-radius: 10px; } ::-webkit-scrollbar-thumb { background: #c7d2fe; border-radius: 10px; } ::-webkit-scrollbar-thumb:hover { background: #818cf8; } </style> </head> <body> <div class="container"> <h1>Stylish Finds, <span class="color-accent-1">Smart Filters</span></h1> <p class="subtitle">Narrow down our collection to discover exactly what you're looking for with our intuitive price filter.</p> <div class="badges-container"> <div class="filter-badge">Current: $<span id="currentMin">20</span> - $<span id="currentMax">180</span> <span class="remove" id="resetPrice">×</span></div> </div> <div class="filter-section"> <div class="filter-header"> <div class="filter-title">Price Range</div> <div>$<span id="minPrice">20</span> - $<span id="maxPrice">180</span></div> </div> <div class="slider-container"> <div class="slider-track"></div> <div class="slider-range" id="slider-range"></div> <div class="slider-thumb" id="minThumb" tabindex="0"> <div class="bubble" id="minBubble">$20</div> </div> <div class="slider-thumb" id="maxThumb" tabindex="0"> <div class="bubble" id="maxBubble">$180</div> </div> </div> </div> <p class="products-found">Showing <span id="productCount">6</span> products</p> <div class="product-grid" id="productGrid"> <!-- Products will be added here by JavaScript --> </div> </div> <script> document.addEventListener('DOMContentLoaded', function() { // Initial price range const priceRange = { min: 20, max: 180, currentMin: 20, currentMax: 180 }; const products = [ { name: "Minimalist Ceramic Mug", price: 29.99, rating: 4.8, reviews: 142, image: "https://images.unsplash.com/photo-1577918373589-c21906bf4c51?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=500&q=80", tag: "bestseller" }, { name: "Natural Linen Cushion", price: 49.95, rating: 4.5, reviews: 87, image: "https://images.unsplash.com/photo-1584346133934-5a4b7a138464?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=500&q=80", tag: "new" }, { name: "Scandinavian Side Table", price: 89.00, rating: 4.7, reviews: 65, image: "https://images.unsplash.com/photo-1533090481720-856c6e3c1fdc?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=500&q=80", tag: "sale" }, { name: "Artisan Coffee Grinder", price: 119.50, rating: 4.9, reviews: 218, image: "https://images.unsplash.com/photo-1591892250008-375fb4c2b497?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=500&q=80", tag: "bestseller" }, { name: "Geometric Pendant Light", price: 159.00, rating: 4.6, reviews: 42, image: "https://images.unsplash.com/photo-1611486212355-d276af4581c0?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=500&q=80", tag: "new" }, { name: "Sustainable Bamboo Chair", price: 199.95, rating: 4.4, reviews: 31, image: "https://images.unsplash.com/photo-1598300042247-d088f8ab3a91?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=500&q=80", tag: "eco" } ]; // DOM elements const sliderRange = document.getElementById('slider-range'); const minThumb = document.getElementById('minThumb'); const maxThumb = document.getElementById('maxThumb'); const minBubble = document.getElementById('minBubble'); const maxBubble = document.getElementById('maxBubble'); const sliderTrack = document.querySelector('.slider-track'); const minPriceEl = document.getElementById('minPrice'); const maxPriceEl = document.getElementById('maxPrice'); const currentMinEl = document.getElementById('currentMin'); const currentMaxEl = document.getElementById('currentMax'); const productGrid = document.getElementById('productGrid'); const productCount = document.getElementById('productCount'); const resetPrice = document.getElementById('resetPrice'); // Initialize the slider positions updateSliderPosition(); renderProducts(); // Event listeners for both thumbs let isDragging = false; let currentThumb = null; function startDrag(e, thumb) { isDragging = true; currentThumb = thumb; thumb.classList.add('active'); document.addEventListener('mousemove', onDrag); document.addEventListener('mouseup', endDrag); document.addEventListener('touchmove', onDrag); document.addEventListener('touchend', endDrag); // Create ripple effect createRipple(e, thumb); } function onDrag(e) { if (!isDragging) return; const rect = sliderTrack.getBoundingClientRect(); const trackWidth = rect.width; // Calculate position (clientX for mouse, touches[0].clientX for touch) let clientX = e.clientX; if (e.type === 'touchmove') { clientX = e.touches[0].clientX; } let position = (clientX - rect.left) / trackWidth; position = Math.max(0, Math.min(position, 1)); const range = priceRange.max - priceRange.min; const valueAtPosition = priceRange.min + (range * position); if (currentThumb === minThumb) { // Min thumb logic priceRange.currentMin = Math.min(valueAtPosition, priceRange.currentMax - 10); priceRange.currentMin = Math.max(priceRange.min, priceRange.currentMin); minBubble.textContent = `$${Math.round(priceRange.currentMin)}`; minPriceEl.textContent = Math.round(priceRange.currentMin); currentMinEl.textContent = Math.round(priceRange.currentMin); } else if (currentThumb === maxThumb) { // Max thumb logic priceRange.currentMax = Math.max(valueAtPosition, priceRange.currentMin + 10); priceRange.currentMax = Math.min(priceRange.max, priceRange.currentMax); maxBubble.textContent = `$${Math.round(priceRange.currentMax)}`; maxPriceEl.textContent = Math.round(priceRange.currentMax); currentMaxEl.textContent = Math.round(priceRange.currentMax); } updateSliderPosition(); renderProducts(); } function endDrag() { isDragging = false; if (currentThumb) { currentThumb.classList.remove('active'); currentThumb = null; } document.removeEventListener('mousemove', onDrag); document.removeEventListener('mouseup', endDrag); document.removeEventListener('touchmove', onDrag); document.removeEventListener('touchend', endDrag); } function updateSliderPosition() { const range = priceRange.max - priceRange.min; const minPos = ((priceRange.currentMin - priceRange.min) / range) * 100; const maxPos = ((priceRange.currentMax - priceRange.min) / range) * 100; minThumb.style.left = `${minPos}%`; maxThumb.style.left = `${maxPos}%`; sliderRange.style.left = `${minPos}%`; sliderRange.style.width = `${maxPos - minPos}%`; } function renderProducts() { const filteredProducts = products.filter(product => product.price >= priceRange.currentMin && product.price <= priceRange.currentMax ); productCount.textContent = filteredProducts.length; productGrid.innerHTML = ''; filteredProducts.forEach(product => { // Generate stars based on rating let stars = ''; const fullStars = Math.floor(product.rating); const halfStar = product.rating % 1 >= 0.5; for (let i = 0; i < fullStars; i++) { stars += '★'; } if (halfStar) { stars += '☆'; } const productEl = document.createElement('div'); productEl.className = 'product-card'; productEl.innerHTML = ` <div class="product-image"> <img src="${product.image}" alt="${product.name}"> ${product.tag ? `<div class="tag ${product.tag === 'sale' ? 'sale' : product.tag === 'new' ? 'new' : ''}">${product.tag}</div>` : ''} </div> <div class="product-details"> <div class="product-name">${product.name}</div> <div class="product-price">$${product.price.toFixed(2)}</div> <div class="product-rating"> <div class="stars">${stars}</div> <div class="rating-count">(${product.reviews})</div> </div> </div> `; productGrid.appendChild(productEl); }); } // Ripple effect on click/touch function createRipple(e, element) { const ripple = document.createElement('span'); ripple.classList.add('ripple'); const rect = element.getBoundingClientRect(); const size = Math.max(rect.width, rect.height); ripple.style.width = ripple.style.height = `${size}px`; ripple.style.left = `${e.clientX - rect.left - size/2}px`; ripple.style.top = `${e.clientY - rect.top - size/2}px`; element.appendChild(ripple); setTimeout(() => { ripple.remove(); }, 800); } // Event listeners for slider thumbs minThumb.addEventListener('mousedown', (e) => startDrag(e, minThumb)); maxThumb.addEventListener('mousedown', (e) => startDrag(e, maxThumb)); minThumb.addEventListener('touchstart', (e) => { e.preventDefault(); startDrag(e.touches[0], minThumb); }); maxThumb.addEventListener('touchstart', (e) => { e.preventDefault(); startDrag(e.touches[0], maxThumb); }); // Reset price filter resetPrice.addEventListener('click', function() { priceRange.currentMin = priceRange.min; priceRange.currentMax = priceRange.max; minPriceEl.textContent = priceRange.min; maxPriceEl.textContent = priceRange.max; currentMinEl.textContent = priceRange.min; currentMaxEl.textContent = priceRange.max; minBubble.textContent = `$${priceRange.min}`; maxBubble.textContent = `$${priceRange.max}`; updateSliderPosition(); renderProducts(); }); // Keyboard accessibility minThumb.addEventListener('keydown', (e) => { let newValue = priceRange.currentMin; const step = 5; if (e.key === 'ArrowLeft') { newValue = Math.max(priceRange.min, priceRange.currentMin - step); } else if (e.key === 'ArrowRight') { newValue = Math.min(priceRange.currentMax - 10, priceRange.currentMin + step); } if (newValue !== priceRange.currentMin) { priceRange.currentMin = newValue; minPriceEl.textContent = Math.round(newValue); currentMinEl.textContent = Math.round(newValue); minBubble.textContent = `$${Math.round(newValue)}`; updateSliderPosition(); renderProducts(); } }); maxThumb.addEventListener('keydown', (e) => { let newValue = priceRange.currentMax; const step = 5; if (e.key === 'ArrowLeft') { newValue = Math.max(priceRange.currentMin + 10, priceRange.currentMax - step); } else if (e.key === 'ArrowRight') { newValue = Math.min(priceRange.max, priceRange.currentMax + step); } if (newValue !== priceRange.currentMax) { priceRange.currentMax = newValue; maxPriceEl.textContent = Math.round(newValue); currentMaxEl.textContent = Math.round(newValue); maxBubble.textContent = `$${Math.round(newValue)}`; updateSliderPosition(); renderProducts(); } }); }); </script> </body> </html>
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Data Analytics Time Range Slider</title> <style> :root { --primary-color: #4a6cff; --secondary-color: #ff4a8d; --background-color: #f5f7ff; --dark-text: #1a2242; --light-text: #6e7898; --success-color: #2ecc71; --grid-color: #e0e5f5; } * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; } body { background-color: var(--background-color); color: var(--dark-text); display: flex; justify-content: center; align-items: center; min-height: 700px; padding: 20px; } .dashboard-container { width: 100%; max-width: 700px; background: white; border-radius: 16px; box-shadow: 0 10px 30px rgba(0, 0, 0, 0.08); padding: 30px; overflow: hidden; } .dashboard-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 25px; } .dashboard-title { font-size: 24px; font-weight: 600; color: var(--dark-text); } .dashboard-stats { display: flex; gap: 15px; margin-bottom: 35px; } .stat-card { flex: 1; background: var(--background-color); padding: 15px; border-radius: 10px; transition: transform 0.3s ease, box-shadow 0.3s ease; } .stat-card:hover { transform: translateY(-5px); box-shadow: 0 10px 20px rgba(74, 108, 255, 0.1); } .stat-value { font-size: 28px; font-weight: 700; margin-bottom: 5px; } .stat-label { font-size: 14px; color: var(--light-text); } .revenue .stat-value { color: var(--primary-color); } .conversions .stat-value { color: var(--secondary-color); } .engagement .stat-value { color: var(--success-color); } .filter-section { margin-bottom: 30px; } .filter-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 15px; } .filter-title { font-size: 16px; font-weight: 600; } .range-display { font-size: 14px; color: var(--light-text); font-weight: 500; padding: 6px 12px; background: var(--background-color); border-radius: 6px; display: inline-flex; align-items: center; } .range-display span { color: var(--primary-color); font-weight: 600; } .slider-container { position: relative; height: 80px; padding-top: 40px; } .timeline { position: relative; height: 4px; background: var(--grid-color); border-radius: 2px; margin-bottom: 20px; } .timeline-segment { position: absolute; top: 0; height: 100%; background: var(--primary-color); border-radius: 2px; } .timeline-markers { position: relative; display: flex; justify-content: space-between; margin-top: 10px; } .timeline-marker { position: relative; font-size: 12px; color: var(--light-text); text-align: center; cursor: pointer; transition: color 0.2s ease; } .timeline-marker:hover { color: var(--primary-color); } .timeline-marker::before { content: ''; position: absolute; top: -16px; left: 50%; transform: translateX(-50%); width: 1px; height: 6px; background: var(--grid-color); } .slider-handle { position: absolute; top: 50%; transform: translate(-50%, -50%); width: 20px; height: 20px; background: white; border: 3px solid var(--primary-color); border-radius: 50%; cursor: grab; z-index: 10; transition: box-shadow 0.2s ease, transform 0.2s ease; } .slider-handle:hover { box-shadow: 0 0 0 6px rgba(74, 108, 255, 0.2); } .slider-handle.active { cursor: grabbing; transform: translate(-50%, -50%) scale(1.2); box-shadow: 0 0 0 8px rgba(74, 108, 255, 0.3); } .slider-handle-tooltip { position: absolute; bottom: 100%; left: 50%; transform: translateX(-50%); background: var(--primary-color); color: white; padding: 4px 8px; border-radius: 4px; font-size: 12px; font-weight: 600; white-space: nowrap; margin-bottom: 8px; opacity: 0; transition: opacity 0.2s ease, transform 0.2s ease; pointer-events: none; } .slider-handle:hover .slider-handle-tooltip, .slider-handle.active .slider-handle-tooltip { opacity: 1; transform: translateX(-50%) translateY(-4px); } .slider-handle-tooltip::after { content: ''; position: absolute; top: 100%; left: 50%; transform: translateX(-50%); border-width: 4px; border-style: solid; border-color: var(--primary-color) transparent transparent transparent; } .chart-container { position: relative; height: 240px; margin-top: 20px; overflow: hidden; } .chart { width: 100%; height: 100%; background: linear-gradient(180deg, rgba(74, 108, 255, 0.2) 0%, rgba(74, 108, 255, 0) 100%); border-radius: 8px; position: relative; overflow: hidden; } .chart-line { position: absolute; bottom: 0; left: 0; width: 100%; height: 100%; fill: none; stroke: var(--primary-color); stroke-width: 3; stroke-linecap: round; filter: drop-shadow(0 4px 6px rgba(74, 108, 255, 0.3)); } .chart-area { position: absolute; bottom: 0; left: 0; width: 100%; height: 100%; fill: url(#gradient); opacity: 0.4; } .y-axis, .x-axis { position: absolute; font-size: 12px; color: var(--light-text); } .y-axis { left: 10px; top: 0; height: 100%; display: flex; flex-direction: column; justify-content: space-between; padding: 10px 0; } .x-axis { bottom: 10px; left: 0; width: 100%; display: flex; justify-content: space-between; } .grid-line { position: absolute; left: 0; width: 100%; height: 1px; background: var(--grid-color); } .chart-dots { position: absolute; width: 100%; height: 100%; pointer-events: none; } .chart-dot { position: absolute; width: 8px; height: 8px; background: white; border: 2px solid var(--primary-color); border-radius: 50%; transform: translate(-50%, -50%); transition: transform 0.2s ease, box-shadow 0.2s ease; } .selected-range { position: absolute; top: 0; height: 100%; background-color: rgba(74, 108, 255, 0.1); border-left: 2px dashed var(--primary-color); border-right: 2px dashed var(--primary-color); pointer-events: none; } .preset-filters { display: flex; gap: 10px; margin-top: 20px; } .preset-filter { padding: 8px 16px; background: var(--background-color); border-radius: 6px; font-size: 14px; font-weight: 500; color: var(--light-text); cursor: pointer; transition: all 0.2s ease; border: none; outline: none; } .preset-filter:hover { background: rgba(74, 108, 255, 0.1); color: var(--primary-color); } .preset-filter.active { background: var(--primary-color); color: white; } .data-insights { margin-top: 30px; background: linear-gradient(135deg, #fafbff 0%, #f0f3ff 100%); border-radius: 10px; padding: 20px; position: relative; overflow: hidden; } .insights-title { font-size: 16px; font-weight: 600; margin-bottom: 15px; display: flex; align-items: center; } .insights-title svg { margin-right: 8px; } .insights-content { display: flex; gap: 20px; } .insight-card { background: white; border-radius: 8px; padding: 15px; flex: 1; box-shadow: 0 4px 15px rgba(0, 0, 0, 0.05); transition: transform 0.3s ease; } .insight-card:hover { transform: translateY(-5px); } .insight-label { font-size: 14px; color: var(--light-text); margin-bottom: 8px; } .insight-value { font-size: 20px; font-weight: 700; color: var(--dark-text); display: flex; align-items: center; } .insight-change { font-size: 12px; margin-left: 8px; display: flex; align-items: center; } .insight-change.positive { color: var(--success-color); } .insight-change.negative { color: var(--secondary-color); } .pattern-bg { position: absolute; top: 0; right: 0; width: 140px; height: 140px; opacity: 0.05; pointer-events: none; } @keyframes pulse { 0% { box-shadow: 0 0 0 0 rgba(74, 108, 255, 0.4); } 70% { box-shadow: 0 0 0 10px rgba(74, 108, 255, 0); } 100% { box-shadow: 0 0 0 0 rgba(74, 108, 255, 0); } } .pulsing-dot { position: absolute; width: 8px; height: 8px; background: var(--primary-color); border-radius: 50%; animation: pulse 2s infinite; transform: translate(-50%, -50%); } @media (max-width: 600px) { .dashboard-container { padding: 20px; } .dashboard-stats { flex-direction: column; gap: 10px; } .insights-content { flex-direction: column; gap: 10px; } .preset-filters { flex-wrap: wrap; } .slider-container { height: 60px; } } </style> </head> <body> <div class="dashboard-container"> <div class="dashboard-header"> <h1 class="dashboard-title">Performance Dashboard</h1> <div class="range-display">Current range: <span id="current-range">Mar 1 - Jun 30, 2023</span></div> </div> <div class="dashboard-stats"> <div class="stat-card revenue"> <div class="stat-value">$284,592</div> <div class="stat-label">Revenue</div> </div> <div class="stat-card conversions"> <div class="stat-value">8.74%</div> <div class="stat-label">Conversion Rate</div> </div> <div class="stat-card engagement"> <div class="stat-value">24.2m</div> <div class="stat-label">User Engagement</div> </div> </div> <div class="filter-section"> <div class="filter-header"> <div class="filter-title">Time Range Filter</div> <div class="preset-filters"> <button class="preset-filter" data-range="7">7D</button> <button class="preset-filter" data-range="30">30D</button> <button class="preset-filter active" data-range="90">Quarter</button> <button class="preset-filter" data-range="180">6M</button> <button class="preset-filter" data-range="365">Year</button> </div> </div> <div class="slider-container"> <div class="timeline"> <div class="timeline-segment" id="timeline-segment"></div> </div> <div class="slider-handle" id="start-handle" style="left: 10%;"> <div class="slider-handle-tooltip">Mar 1, 2023</div> </div> <div class="slider-handle" id="end-handle" style="left: 50%;"> <div class="slider-handle-tooltip">Jun 30, 2023</div> </div> <div class="selected-range" id="selected-range" style="left: 10%; width: 40%;"></div> <div class="timeline-markers"> <div class="timeline-marker">Jan</div> <div class="timeline-marker">Feb</div> <div class="timeline-marker">Mar</div> <div class="timeline-marker">Apr</div> <div class="timeline-marker">May</div> <div class="timeline-marker">Jun</div> <div class="timeline-marker">Jul</div> <div class="timeline-marker">Aug</div> <div class="timeline-marker">Sep</div> <div class="timeline-marker">Oct</div> <div class="timeline-marker">Nov</div> <div class="timeline-marker">Dec</div> </div> </div> </div> <div class="chart-container"> <div class="chart" id="chart"> <svg width="100%" height="100%" preserveAspectRatio="none" id="chart-svg"> <defs> <linearGradient id="gradient" x1="0%" y1="0%" x2="0%" y2="100%"> <stop offset="0%" stop-color="rgba(74, 108, 255, 0.6)" /> <stop offset="100%" stop-color="rgba(74, 108, 255, 0)" /> </linearGradient> </defs> <path class="chart-line" id="chart-line" d=""></path> <path class="chart-area" id="chart-area" d=""></path> </svg> <div class="chart-dots" id="chart-dots"></div> <div class="y-axis"> <div>$300k</div> <div>$225k</div> <div>$150k</div> <div>$75k</div> <div>$0</div> </div> <div class="x-axis"> <div>Jan</div> <div>Mar</div> <div>May</div> <div>Jul</div> <div>Sep</div> <div>Nov</div> </div> <div class="grid-line" style="top: 20%;"></div> <div class="grid-line" style="top: 40%;"></div> <div class="grid-line" style="top: 60%;"></div> <div class="grid-line" style="top: 80%;"></div> </div> </div> <div class="data-insights"> <div class="pattern-bg"> <svg width="140" height="140" viewBox="0 0 140 140"> <pattern id="pattern" patternUnits="userSpaceOnUse" width="10" height="10"> <circle cx="2" cy="2" r="1" fill="currentColor" /> </pattern> <rect width="140" height="140" fill="url(#pattern)" /> </svg> </div> <h3 class="insights-title"> <svg width="18" height="18" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M8 16L12 12L16 16M8 8L12 12L16 8" stroke="#4a6cff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> </svg> Selected Range Insights </h3> <div class="insights-content"> <div class="insight-card"> <div class="insight-label">Revenue Growth</div> <div class="insight-value">23.7% <span class="insight-change positive">+6.4%</span></div> </div> <div class="insight-card"> <div class="insight-label">Avg. Order Value</div> <div class="insight-value">$87.21 <span class="insight-change positive">+12.8%</span></div> </div> <div class="insight-card"> <div class="insight-label">Churn Rate</div> <div class="insight-value">3.4% <span class="insight-change negative">+0.5%</span></div> </div> </div> <div class="pulsing-dot" style="top: 70%; left: 80%;"></div> </div> </div> <script> document.addEventListener('DOMContentLoaded', function() { // Data for the chart const monthNames = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]; const data = [ { date: new Date(2023, 0, 1), value: 145000 }, { date: new Date(2023, 1, 1), value: 152000 }, { date: new Date(2023, 2, 1), value: 170000 }, { date: new Date(2023, 3, 1), value: 182000 }, { date: new Date(2023, 4, 1), value: 210000 }, { date: new Date(2023, 5, 1), value: 232000 }, { date: new Date(2023, 6, 1), value: 245000 }, { date: new Date(2023, 7, 1), value: 267000 }, { date: new Date(2023, 8, 1), value: 285000 }, { date: new Date(2023, 9, 1), value: 272000 }, { date: new Date(2023, 10, 1), value: 293000 }, { date: new Date(2023, 11, 1), value: 320000 } ]; // Draw the chart drawChart(); // Range slider functionality const startHandle = document.getElementById('start-handle'); const endHandle = document.getElementById('end-handle'); const timelineSegment = document.getElementById('timeline-segment'); const selectedRange = document.getElementById('selected-range'); const currentRangeText = document.getElementById('current-range'); let activeHandle = null; let handles = [startHandle, endHandle]; let startValue = 10; // percentage let endValue = 50; // percentage // Initialize positions updateHandlePositions(); // Set the initial range text updateRangeText(); // Mouse events for handles handles.forEach(handle => { handle.addEventListener('mousedown', function(e) { activeHandle = handle; handle.classList.add('active'); document.addEventListener('mousemove', handleDrag); document.addEventListener('mouseup', handleRelease); e.preventDefault(); }); handle.addEventListener('touchstart', function(e) { activeHandle = handle; handle.classList.add('active'); document.addEventListener('touchmove', handleTouchDrag); document.addEventListener('touchend', handleTouchRelease); e.preventDefault(); }); }); // Timeline markers click functionality const timelineMarkers = document.querySelectorAll('.timeline-marker'); timelineMarkers.forEach((marker, index) => { marker.addEventListener('click', function() { const percentage = (index / (timelineMarkers.length - 1)) * 100; // Find the closest handle const startDistance = Math.abs(startValue - percentage); const endDistance = Math.abs(endValue - percentage); if (startDistance < endDistance) { startValue = percentage; } else { endValue = percentage; } // Make sure end is always greater than start if (startValue > endValue) { [startValue, endValue] = [endValue, startValue]; } updateHandlePositions(); updateRangeText(); }); }); // Preset filter buttons const presetFilters = document.querySelectorAll('.preset-filter'); presetFilters.forEach(filter => { filter.addEventListener('click', function() { // Remove active class from all filters presetFilters.forEach(f => f.classList.remove('active')); // Add active class to clicked filter this.classList.add('active'); // Set range based on data-range attribute const days = parseInt(this.getAttribute('data-range')); setRangeByDays(days); }); }); function handleDrag(e) { if (!activeHandle) return; const sliderRect = document.querySelector('.timeline').getBoundingClientRect(); let percentage = ((e.clientX - sliderRect.left) / sliderRect.width) * 100; // Constrain to 0-100% percentage = Math.max(0, Math.min(100, percentage)); // Round to nearest 8.33% (12 months) percentage = Math.round(percentage / 8.33) * 8.33; if (activeHandle === startHandle) { startValue = percentage; if (startValue > endValue) { startValue = endValue; } } else { endValue = percentage; if (endValue < startValue) { endValue = startValue; } } updateHandlePositions(); updateRangeText(); } function handleTouchDrag(e) { if (!activeHandle || !e.touches[0]) return; const sliderRect = document.querySelector('.timeline').getBoundingClientRect(); let percentage = ((e.touches[0].clientX - sliderRect.left) / sliderRect.width) * 100; // Constrain to 0-100% percentage = Math.max(0, Math.min(100, percentage)); // Round to nearest 8.33% (12 months) percentage = Math.round(percentage / 8.33) * 8.33; if (activeHandle === startHandle) { startValue = percentage; if (startValue > endValue) { startValue = endValue; } } else { endValue = percentage; if (endValue < startValue) { endValue = startValue; } } updateHandlePositions(); updateRangeText(); } function handleRelease() { if (activeHandle) { activeHandle.classList.remove('active'); activeHandle = null; } document.removeEventListener('mousemove', handleDrag); document.removeEventListener('mouseup', handleRelease); } function handleTouchRelease() { if (activeHandle) { activeHandle.classList.remove('active'); activeHandle = null; } document.removeEventListener('touchmove', handleTouchDrag); document.removeEventListener('touchend', handleTouchRelease); } function updateHandlePositions() { startHandle.style.left = `${startValue}%`; endHandle.style.left = `${endValue}%`; timelineSegment.style.left = `${startValue}%`; timelineSegment.style.width = `${endValue - startValue}%`; selectedRange.style.left = `${startValue}%`; selectedRange.style.width = `${endValue - startValue}%`; highlightChartSection(); } function updateRangeText() { // Calculate dates based on percentage const startMonth = Math.floor((startValue / 100) * 12); const endMonth = Math.floor((endValue / 100) * 12); const startDate = new Date(2023, startMonth, 1); const endDate = new Date(2023, endMonth, 0); // Last day of the month const startFormatted = `${monthNames[startMonth]} ${startDate.getDate()}`; const endFormatted = `${monthNames[endMonth]} ${endDate.getDate()}`; currentRangeText.textContent = `${startFormatted} - ${endFormatted}, 2023`; // Update tooltip texts startHandle.querySelector('.slider-handle-tooltip').textContent = `${monthNames[startMonth]} ${startDate.getDate()}, 2023`; endHandle.querySelector('.slider-handle-tooltip').textContent = `${monthNames[endMonth]} ${endDate.getDate()}, 2023`; // Update insights based on range updateInsights(startMonth, endMonth); } function setRangeByDays(days) { if (days === 7) { startValue = 75; // Oct 1 endValue = 83.33; // Oct 7 } else if (days === 30) { startValue = 75; // Oct 1 endValue = 91.67; // Nov 1 } else if (days === 90) { startValue = 16.67; // Mar 1 endValue = 50; // Jun 30 } else if (days === 180) { startValue = 0; // Jan 1 endValue = 50; // Jun 30 } else if (days === 365) { startValue = 0; // Jan 1 endValue = 100; // Dec 31 } updateHandlePositions(); updateRangeText(); } function drawChart() { const svg = document.getElementById('chart-svg'); const chartLine = document.getElementById('chart-line'); const chartArea = document.getElementById('chart-area'); const chartDots = document.getElementById('chart-dots'); const height = svg.clientHeight; const width = svg.clientWidth; // Find max value for scaling const maxValue = Math.max(...data.map(d => d.value)); // Build SVG path let linePath = ''; let areaPath = ''; data.forEach((point, i) => { const x = (i / (data.length - 1)) * width; const y = height - (point.value / maxValue) * height * 0.8; if (i === 0) { linePath = `M ${x},${y} `; areaPath = `M ${x},${height} L ${x},${y} `; } else { linePath += `L ${x},${y} `; areaPath += `L ${x},${y} `; } // Add dots const dot = document.createElement('div'); dot.className = 'chart-dot'; dot.style.left = `${(i / (data.length - 1)) * 100}%`; dot.style.top = `${(y / height) * 100}%`; dot.setAttribute('data-month', i); chartDots.appendChild(dot); }); // Complete area path areaPath += `L ${width},${height} Z`; // Set paths chartLine.setAttribute('d', linePath); chartArea.setAttribute('d', areaPath); } function highlightChartSection() { const dots = document.querySelectorAll('.chart-dot'); dots.forEach((dot, index) => { const position = (index / (dots.length - 1)) * 100; if (position >= startValue && position <= endValue) { dot.style.transform = 'translate(-50%, -50%) scale(1.5)'; dot.style.boxShadow = '0 0 0 4px rgba(74, 108, 255, 0.2)'; } else { dot.style.transform = 'translate(-50%, -50%)'; dot.style.boxShadow = 'none'; } }); } function updateInsights(startMonth, endMonth) { // Calculate selected data let selectedData = data.filter((d, i) => i >= startMonth && i <= endMonth); if (selectedData.length === 0) { return; } // Calculate revenue growth const startRevenue = selectedData[0].value; const endRevenue = selectedData[selectedData.length - 1].value; const growthPercentage = ((endRevenue - startRevenue) / startRevenue) * 100; // Update insight values with some randomization for demo purposes const growthElement = document.querySelector('.insight-card:nth-child(1) .insight-value'); growthElement.innerHTML = `${growthPercentage.toFixed(1)}% <span class="insight-change ${growthPercentage > 0 ? 'positive' : 'negative'}">${growthPercentage > 0 ? '+' : ''}${(growthPercentage * 0.27).toFixed(1)}%</span>`; // Calculate average order value based on range const avgOrderBase = 65 + (endMonth - startMonth) * 2.5; const avgOrderElement = document.querySelector('.insight-card:nth-child(2) .insight-value'); avgOrderElement.innerHTML = `$${avgOrderBase.toFixed(2)} <span class="insight-change positive">+${(avgOrderBase * 0.15).toFixed(1)}%</span>`; // Calculate churn rate based on range (lower is better) const churnRate = 5 - (endMonth - startMonth) * 0.2; const churnTrend = startMonth < 6 ? '+0.5%' : '-0.3%'; const churnElement = document.querySelector('.insight-card:nth-child(3) .insight-value'); churnElement.innerHTML = `${Math.max(1.5, churnRate).toFixed(1)}% <span class="insight-change ${churnTrend.includes('+') ? 'negative' : 'positive'}">${churnTrend}</span>`; } }); </script> </body> </html>
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>PowerPulse Fitness Tracker</title> <style> :root { --primary: #FF5E5B; --secondary: #00CEB8; --accent: #FF9D00; --dark: #2E3A59; --light: #F7F9FC; --gradient-start: #FF5E5B; --gradient-end: #FF9D00; } * { box-sizing: border-box; margin: 0; padding: 0; font-family: 'Poppins', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; } body { background-color: var(--light); display: flex; justify-content: center; align-items: center; min-height: 700px; overflow-x: hidden; color: var(--dark); } .container { width: 100%; max-width: 650px; padding: 2rem; position: relative; overflow: hidden; border-radius: 20px; background-color: white; box-shadow: 0 10px 30px rgba(46, 58, 89, 0.1); } h1 { font-size: 2rem; font-weight: 700; margin-bottom: 0.5rem; color: var(--dark); position: relative; z-index: 1; } h1::after { content: ''; position: absolute; width: 40px; height: 8px; background: linear-gradient(to right, var(--gradient-start), var(--gradient-end)); bottom: -5px; left: 0; border-radius: 4px; } .subtitle { font-size: 1rem; color: #5D6B89; margin-bottom: 2rem; } .workout-selector { display: flex; gap: 1rem; margin-bottom: 2rem; flex-wrap: wrap; } .workout-type { background-color: #F0F4F9; padding: 12px 20px; border-radius: 12px; cursor: pointer; transition: all 0.3s ease; font-weight: 600; font-size: 0.9rem; flex: 1; min-width: 100px; text-align: center; display: flex; align-items: center; justify-content: center; gap: 8px; } .workout-type:hover { transform: translateY(-3px); box-shadow: 0 5px 15px rgba(46, 58, 89, 0.1); } .workout-type.active { background: linear-gradient(to right, var(--gradient-start), var(--gradient-end)); color: white; box-shadow: 0 5px 15px rgba(255, 94, 91, 0.3); } .workout-icon { width: 20px; height: 20px; } .slider-container { margin-bottom: 2.5rem; position: relative; } .slider-label { display: flex; justify-content: space-between; align-items: center; margin-bottom: 1rem; } .slider-title { font-weight: 600; font-size: 1.1rem; } .slider-value { font-weight: 700; font-size: 1.1rem; color: var(--primary); background: rgba(255, 94, 91, 0.1); padding: 5px 12px; border-radius: 20px; transition: all 0.3s ease; } .slider-tooltip { position: absolute; bottom: 100%; left: 0; transform: translateX(-50%); background: var(--dark); color: white; padding: 5px 10px; border-radius: 5px; font-size: 0.8rem; opacity: 0; transition: opacity 0.3s; pointer-events: none; white-space: nowrap; } .slider-tooltip::after { content: ''; position: absolute; top: 100%; left: 50%; margin-left: -5px; border-width: 5px; border-style: solid; border-color: var(--dark) transparent transparent transparent; } .range-slider { -webkit-appearance: none; appearance: none; width: 100%; height: 10px; background: #E0E7EF; border-radius: 10px; outline: none; margin-bottom: 0.5rem; } .range-slider::-webkit-slider-thumb { -webkit-appearance: none; appearance: none; width: 30px; height: 30px; border-radius: 50%; background: linear-gradient(to right bottom, var(--gradient-start), var(--gradient-end)); cursor: pointer; box-shadow: 0 2px 10px rgba(255, 94, 91, 0.3); transition: all 0.2s ease; transform-origin: center; position: relative; z-index: 2; } .range-slider::-moz-range-thumb { width: 30px; height: 30px; border-radius: 50%; background: linear-gradient(to right bottom, var(--gradient-start), var(--gradient-end)); cursor: pointer; box-shadow: 0 2px 10px rgba(255, 94, 91, 0.3); transition: all 0.2s ease; border: none; } .range-slider::-webkit-slider-thumb:hover, .range-slider:active::-webkit-slider-thumb { transform: scale(1.1); box-shadow: 0 3px 15px rgba(255, 94, 91, 0.4); } .range-slider::-moz-range-thumb:hover, .range-slider:active::-moz-range-thumb { transform: scale(1.1); box-shadow: 0 3px 15px rgba(255, 94, 91, 0.4); } .slider-progress { height: 10px; background: linear-gradient(to right, var(--gradient-start), var(--gradient-end)); border-radius: 10px; position: relative; top: -16px; pointer-events: none; transition: width 0.2s ease; } .slider-marks { display: flex; justify-content: space-between; margin-top: 0.5rem; position: relative; top: -5px; } .slider-mark { font-size: 0.8rem; color: #8A94A6; position: relative; width: 20%; text-align: center; } .slider-mark::before { content: ''; position: absolute; width: 2px; height: 8px; background-color: #E0E7EF; left: 50%; top: -15px; transform: translateX(-50%); } .slider-mark.active { color: var(--primary); font-weight: 500; } .slider-mark.active::before { background-color: var(--primary); } .tracking-container { background-color: #F7F9FC; padding: 1.5rem; border-radius: 15px; margin-bottom: 2rem; } .stats-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 1rem; } .stat-card { background-color: white; padding: 1rem; border-radius: 12px; box-shadow: 0 5px 15px rgba(46, 58, 89, 0.05); transition: all 0.3s ease; } .stat-card:hover { transform: translateY(-3px); box-shadow: 0 8px 20px rgba(46, 58, 89, 0.1); } .stat-title { font-size: 0.8rem; color: #8A94A6; margin-bottom: 0.5rem; } .stat-value { font-size: 1.5rem; font-weight: 700; color: var(--dark); margin-bottom: 0.25rem; } .stat-comparison { font-size: 0.75rem; color: var(--secondary); display: flex; align-items: center; gap: 4px; } .start-button { background: linear-gradient(to right, var(--gradient-start), var(--gradient-end)); color: white; border: none; border-radius: 30px; padding: 15px 30px; font-size: 1rem; font-weight: 600; cursor: pointer; transition: all 0.3s ease; display: block; width: 100%; box-shadow: 0 5px 15px rgba(255, 94, 91, 0.2); position: relative; overflow: hidden; } .start-button::before { content: ''; position: absolute; top: 0; left: -100%; width: 100%; height: 100%; background: linear-gradient(to right, rgba(255,255,255,0) 0%, rgba(255,255,255,0.2) 50%, rgba(255,255,255,0) 100%); transition: all 0.6s ease; } .start-button:hover { transform: translateY(-3px); box-shadow: 0 8px 25px rgba(255, 94, 91, 0.3); } .start-button:hover::before { left: 100%; } .decorative-circle { position: absolute; border-radius: 50%; opacity: 0.05; z-index: 0; } .circle-1 { width: 150px; height: 150px; background-color: var(--primary); top: -50px; right: -50px; } .circle-2 { width: 100px; height: 100px; background-color: var(--secondary); bottom: 30px; left: -30px; } .pulse-animation { animation: pulse 2s infinite; } @keyframes pulse { 0% { transform: scale(1); } 50% { transform: scale(1.05); } 100% { transform: scale(1); } } @media (max-width: 500px) { .container { padding: 1.5rem; } h1 { font-size: 1.5rem; } .workout-selector { flex-direction: column; gap: 0.5rem; } .workout-type { width: 100%; } .stats-grid { grid-template-columns: 1fr; } } </style> </head> <body> <div class="container"> <div class="decorative-circle circle-1"></div> <div class="decorative-circle circle-2"></div> <h1>PowerPulse</h1> <p class="subtitle">Personalize your workout intensity to reach your fitness goals</p> <div class="workout-selector"> <div class="workout-type active" data-type="cardio"> <svg class="workout-icon" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"> <path d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z"></path> </svg> Cardio </div> <div class="workout-type" data-type="strength"> <svg class="workout-icon" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"> <path fill-rule="evenodd" d="M10 5a1 1 0 011 1v3h3a1 1 0 110 2h-3v3a1 1 0 11-2 0v-3H6a1 1 0 110-2h3V6a1 1 0 011-1z" clip-rule="evenodd"></path> </svg> Strength </div> <div class="workout-type" data-type="hiit"> <svg class="workout-icon" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"> <path fill-rule="evenodd" d="M12.395 2.553a1 1 0 00-1.45-.385c-.345.23-.614.558-.822.88-.214.33-.403.713-.57 1.116-.334.804-.614 1.768-.84 2.734a31.365 31.365 0 00-.613 3.58 2.64 2.64 0 01-.945-1.067c-.328-.68-.398-1.534-.398-2.654A1 1 0 005.05 6.05 6.981 6.981 0 003 11a7 7 0 1011.95-4.95c-.592-.591-.98-.985-1.348-1.467-.363-.476-.724-1.063-1.207-2.03zM12.12 15.12A3 3 0 017 13s.879.5 2.5.5c0-1 .5-4 1.25-4.5.5 1 .786 1.293 1.371 1.879A2.99 2.99 0 0113 13a2.99 2.99 0 01-.879 2.121z" clip-rule="evenodd"></path> </svg> HIIT </div> </div> <!-- Duration Slider --> <div class="slider-container"> <div class="slider-label"> <span class="slider-title">Duration (min)</span> <span class="slider-value" id="duration-value">30</span> </div> <input type="range" min="5" max="120" value="30" step="5" class="range-slider" id="duration-slider"> <div class="slider-progress" id="duration-progress" style="width: 22%;"></div> <div class="slider-marks"> <div class="slider-mark active">5</div> <div class="slider-mark">30</div> <div class="slider-mark">60</div> <div class="slider-mark">90</div> <div class="slider-mark">120</div> </div> </div> <!-- Intensity Slider --> <div class="slider-container"> <div class="slider-label"> <span class="slider-title">Intensity Level</span> <span class="slider-value" id="intensity-value">Medium</span> </div> <input type="range" min="1" max="5" value="3" step="1" class="range-slider" id="intensity-slider"> <div class="slider-progress" id="intensity-progress" style="width: 50%;"></div> <div class="slider-marks"> <div class="slider-mark">Light</div> <div class="slider-mark">Easy</div> <div class="slider-mark active">Medium</div> <div class="slider-mark">Hard</div> <div class="slider-mark">Max</div> </div> </div> <!-- Workout Stats --> <div class="tracking-container"> <div class="stats-grid"> <div class="stat-card"> <div class="stat-title">Est. Calories</div> <div class="stat-value" id="calories-value">350</div> <div class="stat-comparison">+15% from last workout</div> </div> <div class="stat-card"> <div class="stat-title">Heart Rate Zone</div> <div class="stat-value" id="heart-rate-value">130-150</div> <div class="stat-comparison">Aerobic Zone</div> </div> </div> </div> <button class="start-button pulse-animation">Start Workout</button> </div> <script> document.addEventListener('DOMContentLoaded', function() { // Workout type selection const workoutTypes = document.querySelectorAll('.workout-type'); workoutTypes.forEach(type => { type.addEventListener('click', function() { workoutTypes.forEach(t => t.classList.remove('active')); this.classList.add('active'); updateStats(); }); }); // Duration slider functionality const durationSlider = document.getElementById('duration-slider'); const durationValue = document.getElementById('duration-value'); const durationProgress = document.getElementById('duration-progress'); durationSlider.addEventListener('input', function() { // Update display value durationValue.textContent = this.value; // Update progress bar const percent = ((this.value - this.min) / (this.max - this.min)) * 100; durationProgress.style.width = percent + '%'; // Update marks updateSliderMarks('duration', this.value); // Update stats based on new duration updateStats(); // Animate the value display durationValue.classList.add('pulse-animation'); setTimeout(() => { durationValue.classList.remove('pulse-animation'); }, 300); }); // Intensity slider functionality const intensitySlider = document.getElementById('intensity-slider'); const intensityValue = document.getElementById('intensity-value'); const intensityProgress = document.getElementById('intensity-progress'); const intensityLabels = ['Light', 'Easy', 'Medium', 'Hard', 'Max']; intensitySlider.addEventListener('input', function() { // Update display value with text label const labelIndex = parseInt(this.value) - 1; intensityValue.textContent = intensityLabels[labelIndex]; // Update progress bar const percent = ((this.value - this.min) / (this.max - this.min)) * 100; intensityProgress.style.width = percent + '%'; // Update marks updateSliderMarks('intensity', this.value); // Update stats based on new intensity updateStats(); // Animate the value display intensityValue.classList.add('pulse-animation'); setTimeout(() => { intensityValue.classList.remove('pulse-animation'); }, 300); }); // Function to update slider marks function updateSliderMarks(sliderType, currentValue) { const container = document.getElementById(`${sliderType}-slider`).parentNode; const marks = container.querySelectorAll('.slider-mark'); marks.forEach((mark, index) => { mark.classList.remove('active'); if (sliderType === 'duration') { const markValues = [5, 30, 60, 90, 120]; if (currentValue >= markValues[index] && (index === marks.length - 1 || currentValue < markValues[index + 1])) { mark.classList.add('active'); } } else if (sliderType === 'intensity') { if (index === parseInt(currentValue) - 1) { mark.classList.add('active'); } } }); } // Function to update estimated stats function updateStats() { const activeWorkout = document.querySelector('.workout-type.active').dataset.type; const duration = parseInt(durationSlider.value); const intensity = parseInt(intensitySlider.value); // Calculate calories based on workout type, duration, and intensity let baseCalories; let heartRateMin, heartRateMax; switch(activeWorkout) { case 'cardio': baseCalories = 7; heartRateMin = 110 + (intensity * 5); heartRateMax = 130 + (intensity * 5); break; case 'strength': baseCalories = 5; heartRateMin = 100 + (intensity * 6); heartRateMax = 120 + (intensity * 6); break; case 'hiit': baseCalories = 10; heartRateMin = 120 + (intensity * 7); heartRateMax = 140 + (intensity * 7); break; default: baseCalories = 6; heartRateMin = 110 + (intensity * 5); heartRateMax = 130 + (intensity * 5); } const calories = Math.round(baseCalories * duration * intensity); // Update the UI with the new values document.getElementById('calories-value').textContent = calories; document.getElementById('heart-rate-value').textContent = `${heartRateMin}-${heartRateMax}`; // Determine and update heart rate zone description let heartRateZone; if (heartRateMax < 130) heartRateZone = 'Fat Burn Zone'; else if (heartRateMax < 150) heartRateZone = 'Aerobic Zone'; else heartRateZone = 'Anaerobic Zone'; document.querySelector('.stat-card:nth-child(2) .stat-comparison').textContent = heartRateZone; } // Start button animation const startButton = document.querySelector('.start-button'); startButton.addEventListener('click', function() { this.textContent = 'Workout Started!'; this.style.background = 'linear-gradient(to right, var(--secondary), #00A896)'; // Add some interactive feedback const container = document.querySelector('.container'); container.style.boxShadow = '0 10px 50px rgba(0, 206, 184, 0.3)'; setTimeout(() => { this.textContent = 'Start Workout'; this.style.background = 'linear-gradient(to right, var(--gradient-start), var(--gradient-end))'; container.style.boxShadow = '0 10px 30px rgba(46, 58, 89, 0.1)'; }, 2000); }); // Initialize the UI updateSliderMarks('duration', durationSlider.value); updateSliderMarks('intensity', intensitySlider.value); updateStats(); }); </script> </body> </html>
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <style> :root { --primary: #4d6de3; --primary-light: #7a94ff; --text-light: #f0f4fc; --text-dark: #1a1d2a; --bg-light: #f5f7ff; --bg-dark: #121420; --shadow-light: 0 10px 25px rgba(77, 109, 227, 0.12); --shadow-dark: 0 10px 25px rgba(0, 0, 0, 0.25); --track-light: #e1e6f9; --track-dark: #282b3e; } * { box-sizing: border-box; margin: 0; padding: 0; transition: background-color 0.4s ease, color 0.4s ease, box-shadow 0.4s ease; } body { font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; display: flex; justify-content: center; align-items: center; height: 100vh; background-color: var(--bg-light); color: var(--text-dark); } body.dark-mode { background-color: var(--bg-dark); color: var(--text-light); } .container { width: 100%; max-width: 550px; padding: 2.5rem; border-radius: 20px; background-color: white; box-shadow: var(--shadow-light); position: relative; overflow: hidden; } body.dark-mode .container { background-color: #1e2235; box-shadow: var(--shadow-dark); } .bg-gradient { position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: linear-gradient(135deg, rgba(122, 148, 255, 0.08), rgba(77, 109, 227, 0.02)); opacity: 0.7; z-index: 0; transition: opacity 0.6s ease; pointer-events: none; } body.dark-mode .bg-gradient { background: linear-gradient(135deg, rgba(30, 34, 53, 0.8), rgba(18, 20, 32, 0.9)); opacity: 0.9; } .content { position: relative; z-index: 1; } h1 { font-size: 1.5rem; font-weight: 700; margin-bottom: 0.75rem; display: flex; align-items: center; } h1 svg { margin-right: 12px; } .subtitle { color: #5b6987; font-size: 0.95rem; margin-bottom: 2.5rem; line-height: 1.6; } body.dark-mode .subtitle { color: #a4b0d0; } .slider-container { margin-bottom: 2.5rem; } .brightness-track { width: 100%; height: 6px; background: var(--track-light); position: relative; border-radius: 10px; margin-bottom: 2rem; } body.dark-mode .brightness-track { background: var(--track-dark); } .brightness-fill { position: absolute; height: 100%; border-radius: 10px; background: linear-gradient(to right, #4d6de3, #7a94ff); transition: width 0.3s ease; } .slider-thumb { width: 28px; height: 28px; border-radius: 50%; background: #fff; border: 3px solid var(--primary); position: absolute; top: 50%; transform: translate(-50%, -50%); cursor: pointer; box-shadow: 0 2px 10px rgba(77, 109, 227, 0.2); z-index: 2; transition: transform 0.2s ease, box-shadow 0.2s ease; } .slider-thumb:hover { transform: translate(-50%, -50%) scale(1.1); box-shadow: 0 4px 15px rgba(77, 109, 227, 0.3); } .slider-thumb.dragging { transform: translate(-50%, -50%) scale(1.15); box-shadow: 0 6px 20px rgba(77, 109, 227, 0.4); } body.dark-mode .slider-thumb { background: #2d3245; border-color: var(--primary-light); box-shadow: 0 2px 10px rgba(0, 0, 0, 0.3); } body.dark-mode .slider-thumb:hover { box-shadow: 0 4px 15px rgba(0, 0, 0, 0.5); } .brightness-markers { display: flex; justify-content: space-between; margin-top: 10px; font-size: 0.85rem; color: #5b6987; } body.dark-mode .brightness-markers { color: #a4b0d0; } .brightness-value { display: flex; justify-content: space-between; align-items: center; margin-top: 1rem; } .value-display { font-size: 2.2rem; font-weight: 700; color: var(--primary); transition: color 0.3s ease; } body.dark-mode .value-display { color: var(--primary-light); } .theme-toggle { display: flex; align-items: center; margin-top: 2rem; justify-content: space-between; } .theme-info { display: flex; align-items: center; } .theme-icon { width: 48px; height: 48px; display: flex; align-items: center; justify-content: center; border-radius: 12px; background: var(--track-light); margin-right: 1rem; } body.dark-mode .theme-icon { background: var(--track-dark); } .theme-label { font-weight: 600; } .theme-desc { color: #5b6987; font-size: 0.85rem; margin-top: 0.25rem; } body.dark-mode .theme-desc { color: #a4b0d0; } .toggle-switch { position: relative; width: 52px; height: 30px; } .toggle-switch input { opacity: 0; width: 0; height: 0; } .toggle-slider { position: absolute; cursor: pointer; top: 0; left: 0; right: 0; bottom: 0; background-color: var(--track-light); transition: 0.4s; border-radius: 34px; } .toggle-slider:before { position: absolute; content: ""; height: 22px; width: 22px; left: 4px; bottom: 4px; background-color: white; transition: 0.4s; border-radius: 50%; } input:checked + .toggle-slider { background-color: var(--primary); } input:checked + .toggle-slider:before { transform: translateX(22px); } body.dark-mode .toggle-slider { background-color: var(--track-dark); } body.dark-mode input:checked + .toggle-slider { background-color: var(--primary-light); } body.dark-mode input:checked + .toggle-slider:before { background-color: #2d3245; } .preview-window { width: 100%; height: 130px; border-radius: 14px; margin-bottom: 2rem; overflow: hidden; position: relative; transition: opacity 0.5s ease; } .preview-content { display: flex; flex-direction: column; padding: 1rem; height: 100%; background-color: white; transition: opacity 0.5s ease, background-color 0.5s ease; } body.dark-mode .preview-content { background-color: #1e2235; } .preview-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 0.75rem; } .preview-title { font-weight: 600; font-size: 0.9rem; } .preview-icons { display: flex; gap: 0.75rem; } .preview-icon { width: 8px; height: 8px; border-radius: 50%; background-color: #ddd; } .preview-text { font-size: 0.8rem; line-height: 1.5; color: #5b6987; opacity: 0.9; } body.dark-mode .preview-text { color: #a4b0d0; } .loading-pulse { width: 50%; height: 10px; border-radius: 5px; background-color: #eaecf5; margin-bottom: 8px; } body.dark-mode .loading-pulse { background-color: #2d3245; } .loading-pulse.sm { width: 30%; } @keyframes pulseAnimation { 0% { transform: scale(1); opacity: 1; } 50% { transform: scale(1.02); opacity: 0.7; } 100% { transform: scale(1); opacity: 1; } } .pulse-effect { animation: pulseAnimation 2s infinite ease-in-out; } .preview-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(0, 0, 0, 0); transition: background-color 0.5s ease; } @media (max-width: 600px) { .container { padding: 1.5rem; border-radius: 15px; } h1 { font-size: 1.3rem; } .subtitle { font-size: 0.9rem; margin-bottom: 2rem; } .preview-window { height: 100px; } .value-display { font-size: 1.8rem; } .theme-toggle { flex-direction: column; align-items: flex-start; } .toggle-switch { margin-top: 1rem; } } </style> </head> <body> <div class="container"> <div class="bg-gradient"></div> <div class="content"> <h1> <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M12 18C15.3137 18 18 15.3137 18 12C18 8.68629 15.3137 6 12 6C8.68629 6 6 8.68629 6 12C6 15.3137 8.68629 18 12 18Z" stroke="#4d6de3" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> <path d="M12 2V4" stroke="#4d6de3" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> <path d="M12 20V22" stroke="#4d6de3" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> <path d="M4.93 4.93L6.34 6.34" stroke="#4d6de3" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> <path d="M17.66 17.66L19.07 19.07" stroke="#4d6de3" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> <path d="M2 12H4" stroke="#4d6de3" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> <path d="M20 12H22" stroke="#4d6de3" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> <path d="M6.34 17.66L4.93 19.07" stroke="#4d6de3" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> <path d="M19.07 4.93L17.66 6.34" stroke="#4d6de3" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> </svg> Brightness Control </h1> <p class="subtitle">Adjust your screen brightness to match your environment and reduce eye strain. Ideal for working in changing light conditions.</p> <div class="preview-window"> <div class="preview-content"> <div class="preview-header"> <div class="preview-title">Screen Preview</div> <div class="preview-icons"> <div class="preview-icon"></div> <div class="preview-icon"></div> <div class="preview-icon"></div> </div> </div> <div class="loading-pulse"></div> <div class="loading-pulse sm"></div> <div class="preview-text">This is how your content will appear at the current brightness level.</div> </div> <div class="preview-overlay"></div> </div> <div class="slider-container"> <div class="brightness-track"> <div class="brightness-fill" style="width: 50%"></div> <div class="slider-thumb" style="left: 50%"></div> </div> <div class="brightness-markers"> <span>Low</span> <span>Medium</span> <span>High</span> </div> <div class="brightness-value"> <span>Brightness</span> <span class="value-display">50%</span> </div> </div> <div class="theme-toggle"> <div class="theme-info"> <div class="theme-icon"> <svg id="theme-icon-svg" width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M12 16C14.2091 16 16 14.2091 16 12C16 9.79086 14.2091 8 12 8C9.79086 8 8 9.79086 8 12C8 14.2091 9.79086 16 12 16Z" stroke="#4d6de3" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> <path d="M12 2V4" stroke="#4d6de3" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> <path d="M12 20V22" stroke="#4d6de3" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> <path d="M4.93 4.93L6.34 6.34" stroke="#4d6de3" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> <path d="M17.66 17.66L19.07 19.07" stroke="#4d6de3" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> <path d="M2 12H4" stroke="#4d6de3" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> <path d="M20 12H22" stroke="#4d6de3" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> <path d="M6.34 17.66L4.93 19.07" stroke="#4d6de3" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> <path d="M19.07 4.93L17.66 6.34" stroke="#4d6de3" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> </svg> </div> <div> <div class="theme-label">Light Mode</div> <div class="theme-desc">Default setting for daytime use</div> </div> </div> <label class="toggle-switch"> <input type="checkbox" id="theme-toggle"> <span class="toggle-slider"></span> </label> </div> </div> </div> <script> // Slider functionality const track = document.querySelector('.brightness-track'); const fill = document.querySelector('.brightness-fill'); const thumb = document.querySelector('.slider-thumb'); const valueDisplay = document.querySelector('.value-display'); const previewOverlay = document.querySelector('.preview-overlay'); let isDragging = false; let currentBrightness = 50; // Initial value // Function to update the brightness function updateBrightness(clientX) { const trackRect = track.getBoundingClientRect(); let newPosition = (clientX - trackRect.left) / trackRect.width; // Constrain the value between 0 and 1 newPosition = Math.max(0, Math.min(1, newPosition)); // Convert to percentage (0-100) currentBrightness = Math.round(newPosition * 100); // Update the UI fill.style.width = `${currentBrightness}%`; thumb.style.left = `${currentBrightness}%`; valueDisplay.textContent = `${currentBrightness}%`; // Update the preview darkness const darknessLevel = 1 - (currentBrightness / 100); previewOverlay.style.backgroundColor = `rgba(0, 0, 0, ${darknessLevel * 0.85})`; } // Mouse events for the slider thumb.addEventListener('mousedown', () => { isDragging = true; thumb.classList.add('dragging'); }); track.addEventListener('mousedown', (e) => { updateBrightness(e.clientX); isDragging = true; thumb.classList.add('dragging'); }); document.addEventListener('mousemove', (e) => { if (isDragging) { updateBrightness(e.clientX); } }); document.addEventListener('mouseup', () => { isDragging = false; thumb.classList.remove('dragging'); }); // Touch events for mobile support thumb.addEventListener('touchstart', (e) => { isDragging = true; thumb.classList.add('dragging'); e.preventDefault(); }); track.addEventListener('touchstart', (e) => { updateBrightness(e.touches[0].clientX); isDragging = true; thumb.classList.add('dragging'); }); document.addEventListener('touchmove', (e) => { if (isDragging) { updateBrightness(e.touches[0].clientX); } }); document.addEventListener('touchend', () => { isDragging = false; thumb.classList.remove('dragging'); }); // Theme toggle functionality const themeToggle = document.getElementById('theme-toggle'); const body = document.body; const themeLabel = document.querySelector('.theme-label'); const themeDesc = document.querySelector('.theme-desc'); const themeIconSvg = document.getElementById('theme-icon-svg'); themeToggle.addEventListener('change', () => { if (themeToggle.checked) { body.classList.add('dark-mode'); themeLabel.textContent = 'Dark Mode'; themeDesc.textContent = 'Reduced brightness for nighttime'; // Change to moon icon themeIconSvg.innerHTML = ` <path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z" stroke="#7a94ff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> `; } else { body.classList.remove('dark-mode'); themeLabel.textContent = 'Light Mode'; themeDesc.textContent = 'Default setting for daytime use'; // Change back to sun icon themeIconSvg.innerHTML = ` <path d="M12 16C14.2091 16 16 14.2091 16 12C16 9.79086 14.2091 8 12 8C9.79086 8 8 9.79086 8 12C8 14.2091 9.79086 16 12 16Z" stroke="#4d6de3" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> <path d="M12 2V4" stroke="#4d6de3" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> <path d="M12 20V22" stroke="#4d6de3" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> <path d="M4.93 4.93L6.34 6.34" stroke="#4d6de3" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> <path d="M17.66 17.66L19.07 19.07" stroke="#4d6de3" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> <path d="M2 12H4" stroke="#4d6de3" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> <path d="M20 12H22" stroke="#4d6de3" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> <path d="M6.34 17.66L4.93 19.07" stroke="#4d6de3" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> <path d="M19.07 4.93L17.66 6.34" stroke="#4d6de3" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> `; } }); // Add loading pulse effect to preview const loadingPulses = document.querySelectorAll('.loading-pulse'); loadingPulses.forEach(pulse => { pulse.classList.add('pulse-effect'); }); </script> </body> </html>
<html> <head> <style> * { 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: #1A1F2B; color: #E0E5F0; display: flex; justify-content: center; align-items: center; height: 100vh; overflow: hidden; } .container { width: 650px; height: 650px; background-color: #121620; border-radius: 20px; padding: 30px; box-shadow: 0 20px 50px rgba(0, 0, 0, 0.5); display: flex; flex-direction: column; position: relative; overflow: hidden; } .header { margin-bottom: 40px; } .header h1 { font-weight: 700; font-size: 28px; margin-bottom: 12px; background: linear-gradient(90deg, #4D8DFF, #61DBFC); -webkit-background-clip: text; -webkit-text-fill-color: transparent; display: inline-block; } .header p { color: #8A97B1; font-size: 16px; line-height: 1.4; max-width: 90%; } .metrics-container { display: flex; flex-direction: column; gap: 35px; flex-grow: 1; position: relative; } .metric-section { position: relative; } .metric-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; } .metric-title { font-size: 18px; font-weight: 600; color: #E0E5F0; display: flex; align-items: center; gap: 8px; } .info-icon { width: 18px; height: 18px; border-radius: 50%; background-color: #2D364D; display: inline-flex; align-items: center; justify-content: center; font-size: 12px; cursor: pointer; transition: all 0.3s ease; } .info-icon:hover { background-color: #4D8DFF; } .range-values { display: flex; gap: 12px; align-items: center; color: #8A97B1; font-size: 15px; } .value-display { background-color: #2D364D; padding: 6px 12px; border-radius: 6px; color: #E0E5F0; font-weight: 500; min-width: 70px; text-align: center; transition: all 0.3s ease; } .range-slider { width: 100%; position: relative; height: 6px; background: #2D364D; border-radius: 5px; margin: 10px 0; } .range-progress { position: absolute; height: 100%; background: linear-gradient(90deg, #4D8DFF, #61DBFC); border-radius: 5px; transition: width 0.3s ease; } .range-input { width: 100%; position: absolute; top: 0; height: 6px; -webkit-appearance: none; appearance: none; background: transparent; pointer-events: none; } .range-input::-webkit-slider-thumb { -webkit-appearance: none; height: 20px; width: 20px; border-radius: 50%; background: #4D8DFF; box-shadow: 0 0 0 4px rgba(77, 141, 255, 0.2), 0 0 10px rgba(0, 0, 0, 0.5); cursor: pointer; pointer-events: auto; transition: transform 0.2s ease, box-shadow 0.2s ease; } .range-input::-webkit-slider-thumb:hover { transform: scale(1.1); box-shadow: 0 0 0 6px rgba(77, 141, 255, 0.3), 0 0 15px rgba(0, 0, 0, 0.6); } .range-input::-moz-range-thumb { height: 20px; width: 20px; border: none; border-radius: 50%; background: #4D8DFF; box-shadow: 0 0 0 4px rgba(77, 141, 255, 0.2), 0 0 10px rgba(0, 0, 0, 0.5); cursor: pointer; pointer-events: auto; transition: transform 0.2s ease, box-shadow 0.2s ease; } .range-input::-moz-range-thumb:hover { transform: scale(1.1); box-shadow: 0 0 0 6px rgba(77, 141, 255, 0.3), 0 0 15px rgba(0, 0, 0, 0.6); } .tooltip { position: absolute; top: -50px; left: 0; transform: translateX(-50%); background: #1A1F2B; color: #E0E5F0; padding: 8px 12px; border-radius: 6px; font-size: 13px; opacity: 0; pointer-events: none; transition: opacity 0.3s ease; z-index: 100; box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3); white-space: nowrap; } .tooltip::after { content: ''; position: absolute; bottom: -5px; left: 50%; transform: translateX(-50%); border-width: 5px 5px 0; border-style: solid; border-color: #1A1F2B transparent transparent; } .info-icon:hover + .tooltip { opacity: 1; } .filter-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 15px; margin-top: 40px; } .filter-item { background-color: #1D2535; border-radius: 10px; padding: 15px; cursor: pointer; transition: all 0.3s ease; display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center; opacity: 0.7; } .filter-item:hover { background-color: #253047; transform: translateY(-3px); opacity: 1; } .filter-item.active { background-color: #2D4063; border: 2px solid #4D8DFF; opacity: 1; } .filter-item h3 { font-size: 15px; margin-bottom: 8px; font-weight: 600; } .filter-item p { font-size: 12px; color: #8A97B1; } .apply-button { margin-top: 40px; background: linear-gradient(90deg, #4D8DFF, #61DBFC); border: none; color: white; padding: 14px 28px; border-radius: 10px; font-weight: 600; font-size: 16px; cursor: pointer; transition: all 0.3s ease; box-shadow: 0 4px 15px rgba(77, 141, 255, 0.3); align-self: center; } .apply-button:hover { transform: translateY(-3px); box-shadow: 0 6px 20px rgba(77, 141, 255, 0.4); } .apply-button:active { transform: translateY(-1px); } .animation-dot { position: absolute; width: 150px; height: 150px; border-radius: 50%; background: radial-gradient(circle, rgba(77, 141, 255, 0.2) 0%, rgba(97, 219, 252, 0) 70%); z-index: -1; animation: float 10s infinite ease-in-out; } .dot-1 { top: 10%; left: 10%; animation-delay: 0s; } .dot-2 { bottom: 20%; right: 15%; width: 200px; height: 200px; animation-delay: 2s; } .dot-3 { bottom: 10%; left: 30%; width: 100px; height: 100px; animation-delay: 4s; } @keyframes float { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-20px); } } @media screen and (max-width: 700px) { .container { width: 95%; height: auto; min-height: 650px; padding: 20px; } .header h1 { font-size: 24px; } .header p { max-width: 100%; font-size: 14px; } .filter-grid { grid-template-columns: repeat(2, 1fr); } } </style> </head> <body> <div class="container"> <div class="animation-dot dot-1"></div> <div class="animation-dot dot-2"></div> <div class="animation-dot dot-3"></div> <div class="header"> <h1>QuantEdge Metrics Filter</h1> <p>Fine-tune your stock discovery with precision metrics to target opportunities aligned with your risk profile and market outlook.</p> </div> <div class="metrics-container"> <div class="metric-section"> <div class="metric-header"> <div class="metric-title"> Volatility Range (Beta) <div class="info-icon">i</div> <div class="tooltip">Measures a stock's sensitivity to market movements relative to S&P 500</div> </div> <div class="range-values"> <span>From</span> <span class="value-display min-value">0.5</span> <span>to</span> <span class="value-display max-value">1.5</span> </div> </div> <div class="range-slider"> <div class="range-progress"></div> <input type="range" class="range-input min" min="0" max="3" step="0.1" value="0.5"> <input type="range" class="range-input max" min="0" max="3" step="0.1" value="1.5"> </div> </div> <div class="metric-section"> <div class="metric-header"> <div class="metric-title"> Price-to-Earnings Ratio <div class="info-icon">i</div> <div class="tooltip">Valuation metric comparing current price to earnings per share</div> </div> <div class="range-values"> <span>From</span> <span class="value-display min-value">10</span> <span>to</span> <span class="value-display max-value">30</span> </div> </div> <div class="range-slider"> <div class="range-progress"></div> <input type="range" class="range-input min" min="0" max="100" step="1" value="10"> <input type="range" class="range-input max" min="0" max="100" step="1" value="30"> </div> </div> <div class="metric-section"> <div class="metric-header"> <div class="metric-title"> 52-Week Performance (%) <div class="info-icon">i</div> <div class="tooltip">Percentage gain/loss over the past 52 weeks</div> </div> <div class="range-values"> <span>From</span> <span class="value-display min-value">-20</span> <span>to</span> <span class="value-display max-value">50</span> </div> </div> <div class="range-slider"> <div class="range-progress"></div> <input type="range" class="range-input min" min="-100" max="200" step="1" value="-20"> <input type="range" class="range-input max" min="-100" max="200" step="1" value="50"> </div> </div> <div class="filter-grid"> <div class="filter-item"> <h3>High Growth</h3> <p>20%+ revenue growth</p> </div> <div class="filter-item active"> <h3>Dividend Yield</h3> <p>3%+ annual yield</p> </div> <div class="filter-item"> <h3>Value Stocks</h3> <p>Low P/E & P/B ratios</p> </div> <div class="filter-item"> <h3>ESG Leaders</h3> <p>Top sustainability ratings</p> </div> <div class="filter-item"> <h3>Momentum</h3> <p>Strong 6-month uptrend</p> </div> <div class="filter-item"> <h3>High Liquidity</h3> <p>$50M+ daily volume</p> </div> </div> <button class="apply-button">Apply Filters</button> </div> </div> <script> document.addEventListener('DOMContentLoaded', function() { const ranges = document.querySelectorAll('.metric-section'); ranges.forEach(range => { const minInput = range.querySelector('.range-input.min'); const maxInput = range.querySelector('.range-input.max'); const progress = range.querySelector('.range-progress'); const minValueDisplay = range.querySelector('.min-value'); const maxValueDisplay = range.querySelector('.max-value'); // Set initial progress updateProgress(minInput, maxInput, progress); // Update when inputs change minInput.addEventListener('input', () => { if (parseInt(minInput.value) > parseInt(maxInput.value)) { minInput.value = maxInput.value; } updateProgress(minInput, maxInput, progress); minValueDisplay.textContent = minInput.value; // Add pulse effect to updated value minValueDisplay.style.backgroundColor = '#4D8DFF'; setTimeout(() => { minValueDisplay.style.backgroundColor = '#2D364D'; }, 300); }); maxInput.addEventListener('input', () => { if (parseInt(maxInput.value) < parseInt(minInput.value)) { maxInput.value = minInput.value; } updateProgress(minInput, maxInput, progress); maxValueDisplay.textContent = maxInput.value; // Add pulse effect to updated value maxValueDisplay.style.backgroundColor = '#4D8DFF'; setTimeout(() => { maxValueDisplay.style.backgroundColor = '#2D364D'; }, 300); }); }); function updateProgress(minInput, maxInput, progress) { const min = parseInt(minInput.min); const max = parseInt(maxInput.max); const minVal = parseInt(minInput.value) - min; const maxVal = parseInt(maxInput.value) - min; const range = max - min; const leftPercent = (minVal / range) * 100; const widthPercent = ((maxVal - minVal) / range) * 100; progress.style.left = `${leftPercent}%`; progress.style.width = `${widthPercent}%`; } // Toggle active state for filter items const filterItems = document.querySelectorAll('.filter-item'); filterItems.forEach(item => { item.addEventListener('click', () => { item.classList.toggle('active'); }); }); // Apply button animation const applyButton = document.querySelector('.apply-button'); applyButton.addEventListener('click', function() { this.textContent = "Filters Applied"; this.style.background = 'linear-gradient(90deg, #32CD32, #7CFC00)'; // Reset after 2 seconds setTimeout(() => { this.textContent = "Apply Filters"; this.style.background = 'linear-gradient(90deg, #4D8DFF, #61DBFC)'; }, 2000); // Create ripple effect const ripple = document.createElement('div'); ripple.style.position = 'fixed'; ripple.style.top = '50%'; ripple.style.left = '50%'; ripple.style.transform = 'translate(-50%, -50%)'; ripple.style.width = '10px'; ripple.style.height = '10px'; ripple.style.borderRadius = '50%'; ripple.style.backgroundColor = 'rgba(77, 141, 255, 0.2)'; ripple.style.zIndex = '-1'; ripple.style.transition = 'all 1s ease-out'; document.body.appendChild(ripple); setTimeout(() => { ripple.style.width = '2000px'; ripple.style.height = '2000px'; ripple.style.opacity = '0'; }, 10); setTimeout(() => { document.body.removeChild(ripple); }, 1000); }); }); </script> </body> </html>
<html> <head> <style> @import url('https://fonts.googleapis.com/css2?family=Orbitron:wght@400;500;700&display=swap'); * { margin: 0; padding: 0; box-sizing: border-box; } body { display: flex; justify-content: center; align-items: center; min-height: 100vh; background-color: #0f0f1a; font-family: 'Orbitron', sans-serif; color: #e1e1ff; overflow: hidden; } .container { width: 90%; max-width: 600px; padding: 30px; background: rgba(16, 16, 32, 0.7); border-radius: 20px; box-shadow: 0 0 40px rgba(0, 255, 255, 0.2), 0 0 20px rgba(128, 0, 255, 0.2) inset; backdrop-filter: blur(10px); border: 1px solid rgba(65, 214, 255, 0.3); position: relative; } .container::before { content: ''; position: absolute; top: -2px; left: -2px; right: -2px; bottom: -2px; background: linear-gradient(45deg, #00ffff, #ff00ff, #00ffff); z-index: -1; border-radius: 22px; opacity: 0.5; filter: blur(5px); } h1 { text-align: center; font-size: 1.8rem; margin-bottom: 20px; text-transform: uppercase; letter-spacing: 2px; color: #00ffff; text-shadow: 0 0 10px rgba(0, 255, 255, 0.7); } .volume-container { position: relative; padding: 30px 0; } .slider-container { position: relative; height: 40px; width: 100%; margin-bottom: 40px; } .slider { -webkit-appearance: none; width: 100%; height: 6px; background: linear-gradient(to right, #1a1a2e, #1a1a2e); border-radius: 5px; outline: none; position: relative; z-index: 2; } .slider-track { position: absolute; top: 19px; left: 0; height: 6px; border-radius: 5px; background: linear-gradient(90deg, #00ffff, #ff00ff); width: 50%; transition: width 0.3s ease; z-index: 1; box-shadow: 0 0 15px rgba(0, 255, 255, 0.7); } .slider-track::after { content: ''; position: absolute; width: 100%; height: 100%; left: 0; top: 0; background: linear-gradient(90deg, rgba(0, 255, 255, 0) 0%, rgba(0, 255, 255, 0.4) 50%, rgba(255, 0, 255, 0) 100%); filter: blur(4px); animation: pulse 3s infinite; } @keyframes pulse { 0%, 100% { opacity: 0.3; } 50% { opacity: 0.8; } } .slider::-webkit-slider-thumb { -webkit-appearance: none; width: 30px; height: 30px; border-radius: 50%; background: #e1e1ff; cursor: pointer; border: 4px solid rgba(0, 255, 255, 0.8); box-shadow: 0 0 15px rgba(0, 255, 255, 0.8), 0 0 5px rgba(255, 0, 255, 0.8) inset; transition: all 0.3s ease; position: relative; z-index: 3; } .slider::-webkit-slider-thumb:hover { transform: scale(1.1); } .slider::-webkit-slider-thumb:active { transform: scale(0.95); background: rgba(255, 0, 255, 0.8); border-color: #e1e1ff; } .slider::-moz-range-thumb { width: 30px; height: 30px; border-radius: 50%; background: #e1e1ff; cursor: pointer; border: 4px solid rgba(0, 255, 255, 0.8); box-shadow: 0 0 15px rgba(0, 255, 255, 0.8), 0 0 5px rgba(255, 0, 255, 0.8) inset; transition: all 0.3s ease; } .volume-display { display: flex; justify-content: space-between; align-items: center; margin-top: 20px; gap: 20px; } .digital-readout { font-size: 2.5rem; font-weight: 700; color: #ff00ff; text-shadow: 0 0 10px rgba(255, 0, 255, 0.7); transition: all 0.2s ease; background: rgba(26, 26, 46, 0.7); padding: 5px 15px; border-radius: 10px; border: 1px solid rgba(255, 0, 255, 0.3); box-shadow: 0 0 10px rgba(0, 255, 255, 0.3) inset; min-width: 100px; text-align: center; } .volume-visualization { display: flex; align-items: flex-end; height: 60px; flex-grow: 1; gap: 3px; padding: 0 10px; } .bar { flex-grow: 1; height: 5px; background: #00ffff; border-radius: 3px; transition: height 0.2s ease; box-shadow: 0 0 5px #00ffff; max-width: 10px; } .presets { display: flex; justify-content: space-between; margin-top: 40px; } .preset-btn { padding: 10px 15px; background: rgba(26, 26, 46, 0.7); border: 1px solid rgba(0, 255, 255, 0.3); color: #e1e1ff; font-family: 'Orbitron', sans-serif; font-size: 0.9rem; border-radius: 5px; cursor: pointer; transition: all 0.3s ease; text-transform: uppercase; font-weight: bold; letter-spacing: 1px; position: relative; overflow: hidden; } .preset-btn::before { content: ''; position: absolute; top: 0; left: -100%; width: 100%; height: 100%; background: linear-gradient( 90deg, transparent, rgba(0, 255, 255, 0.2), transparent ); transition: 0.5s; } .preset-btn:hover { background: rgba(65, 65, 90, 0.8); transform: translateY(-3px); box-shadow: 0 0 15px rgba(0, 255, 255, 0.5); } .preset-btn:hover::before { left: 100%; } .preset-btn:active { transform: translateY(0); } .mode-toggle { position: absolute; top: 20px; right: 20px; font-size: 0.8rem; background: rgba(26, 26, 46, 0.7); border: 1px solid rgba(0, 255, 255, 0.3); color: #00ffff; padding: 5px 10px; border-radius: 15px; cursor: pointer; transition: all 0.3s ease; } .mode-toggle:hover { background: rgba(65, 65, 90, 0.8); box-shadow: 0 0 10px rgba(0, 255, 255, 0.5); } .audio-categories { margin-top: 30px; } .category { display: flex; align-items: center; justify-content: space-between; margin-bottom: 10px; padding: 5px; border-radius: 5px; transition: all 0.3s ease; } .category:hover { background: rgba(65, 65, 90, 0.3); } .category.active { border-left: 3px solid #00ffff; padding-left: 10px; } .category-name { font-size: 0.9rem; font-weight: bold; color: #e1e1ff; } .category-indicator { width: 10px; height: 10px; border-radius: 50%; background: #555; } .category-indicator.active { background: #00ffff; box-shadow: 0 0 10px rgba(0, 255, 255, 0.7); } .feedback-prompt { position: absolute; bottom: -50px; left: 50%; transform: translateX(-50%); background: rgba(255, 0, 255, 0.2); padding: 10px 20px; border-radius: 20px; font-size: 0.9rem; opacity: 0; transition: all 0.5s ease; text-align: center; width: 90%; max-width: 400px; box-shadow: 0 0 15px rgba(255, 0, 255, 0.3); } @media (max-width: 600px) { .container { padding: 20px 15px; } h1 { font-size: 1.3rem; } .preset-btn { padding: 8px 10px; font-size: 0.7rem; } .digital-readout { font-size: 1.8rem; min-width: 70px; } .slider::-webkit-slider-thumb { width: 24px; height: 24px; } .slider::-moz-range-thumb { width: 24px; height: 24px; } } .particles { position: fixed; top: 0; left: 0; width: 100%; height: 100%; z-index: -1; pointer-events: none; } .particle { position: absolute; width: 2px; height: 2px; background-color: #00ffff; border-radius: 50%; opacity: 0.6; animation: float 10s infinite linear; } @keyframes float { 0% { transform: translateY(0) translateX(0); opacity: 0; } 10% { opacity: 0.8; } 90% { opacity: 0.2; } 100% { transform: translateY(-100vh) translateX(50px); opacity: 0; } } </style> </head> <body> <div class="particles" id="particles"></div> <div class="container"> <h1>Quantum Audio Matrix</h1> <button class="mode-toggle" id="modeToggle">3D AUDIO</button> <div class="volume-container"> <div class="slider-container"> <div class="slider-track" id="sliderTrack"></div> <input type="range" min="0" max="100" value="50" class="slider" id="volumeSlider"> </div> <div class="volume-display"> <div class="digital-readout" id="volumeReadout">50</div> <div class="volume-visualization" id="visualization"></div> </div> <div class="audio-categories"> <div class="category active" data-category="main"> <span class="category-name">MAIN VOLUME</span> <div class="category-indicator active"></div> </div> <div class="category" data-category="sfx"> <span class="category-name">COMBAT EFFECTS</span> <div class="category-indicator"></div> </div> <div class="category" data-category="music"> <span class="category-name">SOUNDTRACK</span> <div class="category-indicator"></div> </div> <div class="category" data-category="ambient"> <span class="category-name">ENVIRONMENT</span> <div class="category-indicator"></div> </div> </div> <div class="presets"> <button class="preset-btn" data-value="0">MUTE</button> <button class="preset-btn" data-value="25">STEALTH</button> <button class="preset-btn" data-value="50">BALANCED</button> <button class="preset-btn" data-value="75">IMMERSIVE</button> <button class="preset-btn" data-value="100">MAXIMUM</button> </div> </div> <div class="feedback-prompt" id="feedbackPrompt">Audio calibrated to your neural profile</div> </div> <script> document.addEventListener('DOMContentLoaded', function() { const slider = document.getElementById('volumeSlider'); const readout = document.getElementById('volumeReadout'); const sliderTrack = document.getElementById('sliderTrack'); const visualization = document.getElementById('visualization'); const presetButtons = document.querySelectorAll('.preset-btn'); const feedbackPrompt = document.getElementById('feedbackPrompt'); const modeToggle = document.getElementById('modeToggle'); const categories = document.querySelectorAll('.category'); // Create volume bars const barCount = 16; for (let i = 0; i < barCount; i++) { const bar = document.createElement('div'); bar.className = 'bar'; visualization.appendChild(bar); } const bars = document.querySelectorAll('.bar'); // Update volume visualization function updateVisualization(volume) { const barCount = bars.length; const activeBars = Math.ceil(volume / 100 * barCount); bars.forEach((bar, index) => { // Calculate a height between 5px and 60px based on volume and position let height = 5; const maxHeight = 60; if (index < activeBars) { // For active bars, calculate a dynamic height // This creates a wave-like pattern that's also responsive to volume if (index < barCount / 4) { height = (index + 1) / (barCount / 4) * maxHeight * (volume / 100); } else if (index < barCount / 2) { height = maxHeight * (volume / 100); } else if (index < 3 * barCount / 4) { height = (1 - (index - barCount / 2) / (barCount / 4)) * maxHeight * (volume / 100); } else { height = (1 - (index - 3 * barCount / 4) / (barCount / 4)) * maxHeight * (volume / 100) * 0.7; } // Add a slight random variation for natural effect height += Math.random() * 5 - 2.5; } bar.style.height = `${Math.max(5, height)}px`; // Color gradients based on volume if (volume < 30) { bar.style.background = '#00ffff'; bar.style.boxShadow = '0 0 5px #00ffff'; } else if (volume < 70) { bar.style.background = '#00ffaa'; bar.style.boxShadow = '0 0 5px #00ffaa'; } else { bar.style.background = '#ff00ff'; bar.style.boxShadow = '0 0 5px #ff00ff'; } // Dim inactive bars if (index >= activeBars) { bar.style.opacity = '0.2'; } else { bar.style.opacity = '1'; } }); } // Function to update slider track function updateSliderTrack(value) { sliderTrack.style.width = `${value}%`; } // Show feedback when volume changes function showFeedback(message) { feedbackPrompt.textContent = message; feedbackPrompt.style.bottom = '20px'; feedbackPrompt.style.opacity = '1'; setTimeout(function() { feedbackPrompt.style.bottom = '-50px'; feedbackPrompt.style.opacity = '0'; }, 2000); } // Handle slider input slider.addEventListener('input', function() { const value = this.value; readout.textContent = value; updateSliderTrack(value); updateVisualization(value); // Flash effect on readout readout.style.transform = 'scale(1.1)'; readout.style.color = `hsl(${280 + (value/100) * 60}, 100%, 60%)`; setTimeout(function() { readout.style.transform = 'scale(1)'; }, 150); }); // Tactile feedback on value change let lastValue = slider.value; slider.addEventListener('input', function() { const value = parseInt(this.value); // Provide visual feedback for significant changes if (Math.abs(value - lastValue) >= 5) { const feedbackMessages = [ "Neural audio mapping optimized", "Frequency pattern adjusted", "Quantum harmonics calibrated", "Sensory interface synchronized", "Bio-adaptive audio matrix updated" ]; showFeedback(feedbackMessages[Math.floor(Math.random() * feedbackMessages.length)]); lastValue = value; } }); // Preset buttons presetButtons.forEach(button => { button.addEventListener('click', function() { const value = this.getAttribute('data-value'); slider.value = value; readout.textContent = value; updateSliderTrack(value); updateVisualization(value); // Flash effect with delay setTimeout(() => { readout.style.transform = 'scale(1.2)'; readout.style.color = `hsl(${280 + (value/100) * 60}, 100%, 60%)`; setTimeout(function() { readout.style.transform = 'scale(1)'; }, 200); }, 50); // Show feedback const presetMessages = { "0": "Stealth mode activated: All audio suppressed", "25": "Low profile audio configuration enabled", "50": "Balanced audio profile calibrated", "75": "Enhanced audio immersion activated", "100": "Maximum sensory amplification enabled" }; showFeedback(presetMessages[value]); }); }); // Toggle audio mode let isDMode = false; modeToggle.addEventListener('click', function() { isDMode = !isDMode; this.textContent = isDMode ? 'QUANTUM AUDIO' : '3D AUDIO'; this.style.color = isDMode ? '#ff00ff' : '#00ffff'; showFeedback(isDMode ? "Quantum audio processing engaged" : "Standard 3D audio matrix restored"); }); // Category selection categories.forEach(category => { category.addEventListener('click', function() { // Deactivate all categories categories.forEach(cat => { cat.classList.remove('active'); cat.querySelector('.category-indicator').classList.remove('active'); }); // Activate selected category this.classList.add('active'); this.querySelector('.category-indicator').classList.add('active'); const categoryName = this.getAttribute('data-category'); const categoryMessages = { "main": "Main volume channel selected", "sfx": "Combat effects channel selected", "music": "Soundtrack channel selected", "ambient": "Environmental audio channel selected" }; showFeedback(categoryMessages[categoryName]); }); }); // Background particle effect const particlesContainer = document.getElementById('particles'); const particleCount = 30; for (let i = 0; i < particleCount; i++) { createParticle(); } function createParticle() { const particle = document.createElement('div'); particle.className = 'particle'; // Random positions and sizes const size = Math.random() * 3 + 1; const left = Math.random() * 100; const duration = Math.random() * 15 + 5; const delay = Math.random() * 5; particle.style.width = `${size}px`; particle.style.height = `${size}px`; particle.style.left = `${left}vw`; particle.style.bottom = '-10px'; particle.style.animationDuration = `${duration}s`; particle.style.animationDelay = `${delay}s`; // Random color between cyan and magenta const hue = Math.random() * 60 + 280; particle.style.backgroundColor = `hsl(${hue}, 100%, 70%)`; particlesContainer.appendChild(particle); // Remove and recreate particles setTimeout(() => { particle.remove(); createParticle(); }, (duration + delay) * 1000); } // Initialize visualization updateVisualization(slider.value); updateSliderTrack(slider.value); }); </script> </body> </html>
<html> <head> <style> * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Inter', sans-serif; } body { display: flex; justify-content: center; align-items: center; min-height: 700px; background: #f9f9f9; overflow: hidden; } .thermostat-container { width: 100%; max-width: 600px; height: 600px; background: linear-gradient(135deg, #ffffff, #f0f0f0); border-radius: 30px; box-shadow: 0 20px 60px rgba(0, 0, 0, 0.1), 0 10px 25px rgba(0, 0, 0, 0.05); padding: 40px; position: relative; overflow: hidden; } .thermostat-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 30px; } .thermostat-title { font-size: 28px; font-weight: 700; color: #333; } .current-temp { font-size: 18px; color: #555; background: rgba(255, 255, 255, 0.6); padding: 10px 20px; border-radius: 20px; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05); backdrop-filter: blur(5px); } .slider-container { position: relative; height: 350px; display: flex; justify-content: center; align-items: center; margin-bottom: 30px; } .temp-slider { position: relative; width: 100%; height: 10px; background: linear-gradient(to right, #4794FF, #FF6B6B); border-radius: 10px; cursor: pointer; } .slider-handle { position: absolute; width: 30px; height: 30px; top: 50%; transform: translate(-50%, -50%); background: #fff; border-radius: 50%; box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2); cursor: grab; transition: box-shadow 0.2s, transform 0.1s; z-index: 10; } .slider-handle:hover, .slider-handle.active { box-shadow: 0 4px 15px rgba(0, 0, 0, 0.3); transform: translate(-50%, -50%) scale(1.1); } .slider-handle:active { cursor: grabbing; } .slider-handle::after { content: ""; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 12px; height: 12px; background: #555; border-radius: 50%; transition: background 0.3s; } .temperature-display { position: absolute; top: -60px; left: 50%; transform: translateX(-50%); font-size: 36px; font-weight: 700; color: #333; background: white; padding: 15px 25px; border-radius: 20px; box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1); opacity: 0; transition: opacity 0.3s, transform 0.3s; } .slider-handle.active + .temperature-display { opacity: 1; transform: translateX(-50%) translateY(-5px); } .temperature-range { display: flex; justify-content: space-between; margin-top: 15px; position: relative; } .temp-min, .temp-max { font-size: 16px; font-weight: 600; padding: 8px 15px; border-radius: 12px; transition: transform 0.3s, background 0.3s; } .temp-min { color: #4794FF; background: rgba(71, 148, 255, 0.1); } .temp-max { color: #FF6B6B; background: rgba(255, 107, 107, 0.1); } .ambient-effect { position: absolute; width: 100%; height: 100%; top: 0; left: 0; pointer-events: none; opacity: 0.7; z-index: -1; } .info-section { margin-top: 40px; background: rgba(255, 255, 255, 0.8); padding: 25px; border-radius: 20px; box-shadow: 0 5px 15px rgba(0, 0, 0, 0.05); } .info-title { font-size: 18px; font-weight: 600; color: #333; margin-bottom: 10px; } .info-desc { font-size: 14px; color: #666; line-height: 1.5; } .mode-selector { display: flex; justify-content: space-between; margin-top: 25px; } .mode-btn { flex: 1; margin: 0 5px; padding: 12px; border: none; border-radius: 15px; background: rgba(255, 255, 255, 0.7); box-shadow: 0 4px 10px rgba(0, 0, 0, 0.05); font-weight: 600; cursor: pointer; transition: all 0.3s ease; } .mode-btn:hover { background: rgba(255, 255, 255, 0.9); transform: translateY(-2px); box-shadow: 0 6px 12px rgba(0, 0, 0, 0.1); } .mode-btn.active { background: #333; color: white; } .heat { color: #FF6B6B; } .cool { color: #4794FF; } .auto { color: #56C271; } .mode-btn.active.heat { background: #FF6B6B; color: white; } .mode-btn.active.cool { background: #4794FF; color: white; } .mode-btn.active.auto { background: #56C271; color: white; } .slider-animation { position: absolute; width: 100%; height: 100%; top: 0; left: 0; pointer-events: none; opacity: 0; transition: opacity 0.5s; } .particles { position: absolute; width: 6px; height: 6px; border-radius: 50%; opacity: 0; pointer-events: none; } @media (max-width: 700px) { .thermostat-container { padding: 30px; height: auto; } .thermostat-title { font-size: 24px; } .current-temp { font-size: 16px; } .slider-container { height: 250px; } .info-section { margin-top: 30px; padding: 20px; } .mode-btn { padding: 10px 8px; font-size: 14px; } } </style> </head> <body> <div class="thermostat-container"> <div class="thermostat-header"> <h1 class="thermostat-title">ClimateSync</h1> <div class="current-temp">Room: 72°F</div> </div> <div class="slider-container"> <div class="temp-slider" id="temp-slider"> <div class="slider-handle" id="slider-handle"></div> <div class="temperature-display" id="temp-display">72°F</div> </div> <div class="ambient-effect" id="ambient-effect"></div> <div class="slider-animation" id="slider-animation"></div> </div> <div class="temperature-range"> <div class="temp-min">60°F</div> <div class="temp-max">90°F</div> </div> <div class="info-section"> <h3 class="info-title">Smart Adjustment</h3> <p class="info-desc">Set to 72°F – optimal for comfort while saving 5% on energy costs. System will adjust based on home occupancy and outdoor temperature patterns.</p> <div class="mode-selector"> <button class="mode-btn heat">Heat</button> <button class="mode-btn cool active">Cool</button> <button class="mode-btn auto">Auto</button> </div> </div> </div> <script> document.addEventListener('DOMContentLoaded', function() { const slider = document.getElementById('temp-slider'); const handle = document.getElementById('slider-handle'); const tempDisplay = document.getElementById('temp-display'); const ambientEffect = document.getElementById('ambient-effect'); const sliderAnimation = document.getElementById('slider-animation'); const modeButtons = document.querySelectorAll('.mode-btn'); const minTemp = 60; const maxTemp = 90; let isDragging = false; let currentTemp = 72; // Initialize handle position updateHandlePosition((currentTemp - minTemp) / (maxTemp - minTemp)); // Update ambient background based on temperature function updateAmbientEffect(percentage) { const hue = 210 - (percentage * 150); // From blue (210) to red (0) ambientEffect.style.background = `radial-gradient(circle at ${percentage * 100}% 50%, hsla(${hue}, 100%, 70%, 0.3), hsla(${hue}, 100%, 70%, 0.1) 40%, transparent 60%)`; } // Create temperature particles function createParticles(x, temp) { const particleCount = 8; const isCool = temp < 75; for (let i = 0; i < particleCount; i++) { const particle = document.createElement('div'); particle.classList.add('particles'); // Set particle color based on temperature particle.style.background = isCool ? `rgba(71, 148, 255, ${Math.random() * 0.5 + 0.5})` : `rgba(255, 107, 107, ${Math.random() * 0.5 + 0.5})`; // Random position near the handle const posX = x + (Math.random() * 40 - 20); const posY = 5 + (Math.random() * 10 - 5); // Random size const size = Math.random() * 5 + 3; // Apply styles particle.style.left = `${posX}px`; particle.style.top = `${posY}px`; particle.style.width = `${size}px`; particle.style.height = `${size}px`; // Add to DOM sliderAnimation.appendChild(particle); // Animate the particle setTimeout(() => { particle.style.transition = `all ${Math.random() * 1 + 0.5}s ease-out`; particle.style.opacity = '1'; particle.style.transform = `translateY(${isCool ? 20 : -20}px) translateX(${Math.random() * 30 - 15}px)`; // Remove particle after animation setTimeout(() => { particle.style.opacity = '0'; setTimeout(() => particle.remove(), 500); }, 500); }, Math.random() * 100); } } // Position the handle and update temperature function updateHandlePosition(percentage) { // Clamp percentage between 0 and 1 percentage = Math.max(0, Math.min(1, percentage)); // Update handle position handle.style.left = `${percentage * 100}%`; // Calculate and update temperature currentTemp = Math.round(minTemp + (maxTemp - minTemp) * percentage); tempDisplay.textContent = `${currentTemp}°F`; // Update ambient effect updateAmbientEffect(percentage); // Show particle effects const handleRect = handle.getBoundingClientRect(); const sliderRect = slider.getBoundingClientRect(); createParticles(handleRect.left - sliderRect.left, currentTemp); // Show slider animation container sliderAnimation.style.opacity = '1'; // Update info text based on temperature const infoTitle = document.querySelector('.info-title'); const infoDesc = document.querySelector('.info-desc'); if (currentTemp < 68) { infoTitle.textContent = 'Energy Saving Mode'; infoDesc.textContent = `Set to ${currentTemp}°F – ideal for sleeping or when away. Reducing temperature by just 5°F overnight can save up to 10% annually on heating costs.`; } else if (currentTemp >= 68 && currentTemp < 75) { infoTitle.textContent = 'Smart Adjustment'; infoDesc.textContent = `Set to ${currentTemp}°F – optimal for comfort while saving 5% on energy costs. System will adjust based on home occupancy and outdoor temperature patterns.`; } else { infoTitle.textContent = 'High Comfort Setting'; infoDesc.textContent = `Set to ${currentTemp}°F – maximum comfort setting. Your smart system will balance this with efficiency by adjusting fan speeds and utilizing zoned cooling when possible.`; } } // Event listeners for mouse interactions slider.addEventListener('mousedown', function(e) { isDragging = true; handle.classList.add('active'); const percentage = (e.clientX - slider.getBoundingClientRect().left) / slider.offsetWidth; updateHandlePosition(percentage); }); document.addEventListener('mousemove', function(e) { if (isDragging) { const percentage = (e.clientX - slider.getBoundingClientRect().left) / slider.offsetWidth; updateHandlePosition(percentage); } }); document.addEventListener('mouseup', function() { isDragging = false; handle.classList.remove('active'); // Hide animation container after dragging setTimeout(() => { sliderAnimation.style.opacity = '0'; }, 500); }); // Event listeners for touch interactions slider.addEventListener('touchstart', function(e) { isDragging = true; handle.classList.add('active'); const touch = e.touches[0]; const percentage = (touch.clientX - slider.getBoundingClientRect().left) / slider.offsetWidth; updateHandlePosition(percentage); e.preventDefault(); }); document.addEventListener('touchmove', function(e) { if (isDragging) { const touch = e.touches[0]; const percentage = (touch.clientX - slider.getBoundingClientRect().left) / slider.offsetWidth; updateHandlePosition(percentage); e.preventDefault(); } }); document.addEventListener('touchend', function() { isDragging = false; handle.classList.remove('active'); // Hide animation container after dragging setTimeout(() => { sliderAnimation.style.opacity = '0'; }, 500); }); // Mode button interaction modeButtons.forEach(button => { button.addEventListener('click', function() { modeButtons.forEach(btn => btn.classList.remove('active')); this.classList.add('active'); // Change slider gradient based on mode if (this.classList.contains('heat')) { slider.style.background = 'linear-gradient(to right, #FF9853, #FF6B6B)'; } else if (this.classList.contains('cool')) { slider.style.background = 'linear-gradient(to right, #4794FF, #47C1FF)'; } else { slider.style.background = 'linear-gradient(to right, #4794FF, #FF6B6B)'; } }); }); // Initial ambient effect updateAmbientEffect((currentTemp - minTemp) / (maxTemp - minTemp)); }); </script> </body> </html>