Animated counters are a dynamic way to display numerical data, adding a touch of interactivity to your web design. They can effectively capture user attention and make statistics more engaging.
In this article, we will explore 10 stunning examples of animated counters that can elevate your UI design. Each example showcases unique styles and functionalities to inspire your next project.
CODE1
Here's the code:
CODETEXT1
CODE2
Here's the code:
CODETEXT2
CODE3
Here's the code:
CODETEXT3
CODE4
Here's the code:
CODETEXT4
CODE5
Here's the code:
CODETEXT5
Subframe's drag-and-drop interface and intuitive, responsive canvas make it effortless to design pixel-perfect animated counters. Loved by designers and developers alike, Subframe ensures your UI is both stunning and functional.
Start for free and elevate your design game 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? With Subframe, you can create pixel-perfect interfaces, including stunning animated counters, in minutes. Our drag-and-drop editor ensures efficiency and precision.
Don't wait—start for free and begin designing immediately. Experience the ease and power of Subframe today!
<html> <head> <title>KPI Analytics Dashboard</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; } body { background-color: #f5f7fa; color: #2c3e50; width: 100%; height: 100vh; overflow-x: hidden; } .dashboard-container { max-width: 700px; margin: 0 auto; padding: 30px 20px; } .dashboard-header { margin-bottom: 40px; position: relative; } .dashboard-header h1 { font-size: 28px; font-weight: 700; color: #1a3b5d; margin-bottom: 10px; } .dashboard-header p { font-size: 16px; color: #5e6e82; line-height: 1.5; } .dashboard-header::after { content: ''; position: absolute; bottom: -20px; left: 0; width: 60px; height: 4px; background: linear-gradient(90deg, #3498db, #2980b9); border-radius: 2px; } .kpi-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 25px; margin-bottom: 40px; } .kpi-card { background-color: #fff; border-radius: 12px; padding: 24px; box-shadow: 0 8px 30px rgba(0, 0, 0, 0.05); transition: transform 0.3s ease, box-shadow 0.3s ease; position: relative; overflow: hidden; opacity: 0; transform: translateY(20px); animation: fadeIn 0.6s ease forwards; } .kpi-card:hover { transform: translateY(-5px); box-shadow: 0 12px 40px rgba(0, 0, 0, 0.08); } .kpi-card::before { content: ''; position: absolute; top: 0; left: 0; width: 5px; height: 100%; background: linear-gradient(to bottom, #3498db, #2980b9); border-top-left-radius: 12px; border-bottom-left-radius: 12px; } .kpi-label { font-size: 16px; font-weight: 600; color: #5e6e82; margin-bottom: 15px; display: flex; align-items: center; } .kpi-icon { margin-right: 12px; background: rgba(41, 128, 185, 0.1); width: 32px; height: 32px; border-radius: 8px; display: flex; align-items: center; justify-content: center; } .kpi-icon svg { width: 18px; height: 18px; fill: #3498db; } .kpi-value { font-size: 42px; font-weight: 700; color: #1a3b5d; margin-bottom: 15px; position: relative; } .kpi-value .suffix { font-size: 22px; opacity: 0.8; margin-left: 3px; } .kpi-trend { display: flex; align-items: center; font-size: 14px; font-weight: 500; } .trend-positive { color: #27ae60; } .trend-negative { color: #e74c3c; } .trend-icon { margin-right: 5px; transform: scale(1.2); } .trend-period { color: #7f8c8d; margin-left: 5px; } .chart-container { background-color: #fff; border-radius: 12px; padding: 24px; box-shadow: 0 8px 30px rgba(0, 0, 0, 0.05); margin-bottom: 30px; opacity: 0; transform: translateY(20px); animation: fadeIn 0.8s ease forwards 0.3s; } .chart-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; } .chart-title { font-size: 18px; font-weight: 600; color: #1a3b5d; } .chart-legend { display: flex; gap: 15px; } .legend-item { display: flex; align-items: center; font-size: 14px; color: #5e6e82; } .legend-color { width: 12px; height: 12px; border-radius: 50%; margin-right: 6px; } .legend-color-1 { background-color: #3498db; } .legend-color-2 { background-color: #95a5a6; } .chart { height: 200px; display: flex; align-items: flex-end; padding-top: 20px; position: relative; } .chart::before { content: ''; position: absolute; top: 0; left: 0; width: 100%; height: 1px; background-color: #ecf0f1; } .chart-bar-group { flex: 1; display: flex; justify-content: center; gap: 10px; position: relative; } .chart-bar { width: 12px; border-radius: 6px 6px 0 0; background-color: #3498db; transition: height 1s cubic-bezier(0.4, 0, 0.2, 1); height: 0; } .chart-bar-secondary { background-color: #95a5a6; } .chart-label { position: absolute; bottom: -25px; font-size: 13px; color: #7f8c8d; transform: translateX(-50%); left: 50%; } .dashboard-footer { text-align: center; margin-top: 40px; padding-top: 20px; border-top: 1px solid #ecf0f1; color: #95a5a6; font-size: 14px; opacity: 0; transform: translateY(20px); animation: fadeIn 0.8s ease forwards 0.6s; } .last-updated { display: flex; align-items: center; justify-content: center; margin-top: 8px; font-size: 13px; } .last-updated-icon { width: 14px; height: 14px; fill: #95a5a6; margin-right: 5px; } @keyframes fadeIn { to { opacity: 1; transform: translateY(0); } } @keyframes pulse { 0% { box-shadow: 0 0 0 0 rgba(52, 152, 219, 0.4); } 70% { box-shadow: 0 0 0 10px rgba(52, 152, 219, 0); } 100% { box-shadow: 0 0 0 0 rgba(52, 152, 219, 0); } } .activity-indicator { position: absolute; top: 15px; right: 15px; width: 8px; height: 8px; border-radius: 50%; background-color: #3498db; animation: pulse 2s infinite; } .toggle-view { background-color: #f5f7fa; border: 1px solid #dce1e8; border-radius: 8px; display: inline-flex; padding: 3px; margin-left: 10px; } .toggle-option { font-size: 12px; padding: 5px 10px; border-radius: 6px; cursor: pointer; transition: all 0.2s ease; } .toggle-option.active { background-color: #3498db; color: white; } /* Animation for number counters */ @keyframes countUp { from { opacity: 0.3; } to { opacity: 1; } } .counter-animation { animation: countUp 0.8s ease-out; } /* Responsive adjustments */ @media (max-width: 600px) { .dashboard-header h1 { font-size: 24px; } .kpi-grid { grid-template-columns: 1fr; } .kpi-value { font-size: 38px; } .chart-header { flex-direction: column; align-items: flex-start; } .chart-legend { margin-top: 10px; } } </style> </head> <body> <div class="dashboard-container"> <header class="dashboard-header"> <h1>Performance Analytics</h1> <p>Q2 2023 Key Performance Indicators for Nexus Technologies</p> <div class="activity-indicator"></div> </header> <div class="kpi-grid"> <div class="kpi-card" data-aos="fade-up"> <div class="kpi-label"> <div class="kpi-icon"> <svg viewBox="0 0 24 24"> <path d="M16,11.78L20.24,4.45L21.97,5.45L16.74,14.5L10.23,10.75L5.46,19H22V21H2V3H4V17.54L9.5,8L16,11.78Z"></path> </svg> </div> Revenue Growth </div> <div class="kpi-value" id="revenue-counter">0<span class="suffix">%</span></div> <div class="kpi-trend trend-positive"> <span class="trend-icon">↑</span> <span>12.4% increase</span> <span class="trend-period">vs previous quarter</span> </div> </div> <div class="kpi-card" data-aos="fade-up"> <div class="kpi-label"> <div class="kpi-icon"> <svg viewBox="0 0 24 24"> <path d="M12,5.5A3.5,3.5 0 0,1 15.5,9A3.5,3.5 0 0,1 12,12.5A3.5,3.5 0 0,1 8.5,9A3.5,3.5 0 0,1 12,5.5M5,8C5.56,8 6.08,8.15 6.53,8.42C6.38,9.85 6.8,11.27 7.66,12.38C7.16,13.34 6.16,14 5,14A3,3 0 0,1 2,11A3,3 0 0,1 5,8M19,8A3,3 0 0,1 22,11A3,3 0 0,1 19,14C17.84,14 16.84,13.34 16.34,12.38C17.2,11.27 17.62,9.85 17.47,8.42C17.92,8.15 18.44,8 19,8M5.5,18.25C5.5,16.18 8.41,14.5 12,14.5C15.59,14.5 18.5,16.18 18.5,18.25V20H5.5V18.25M0,20V18.5C0,17.11 1.89,15.94 4.45,15.6C3.86,16.28 3.5,17.22 3.5,18.25V20H0M24,20H20.5V18.25C20.5,17.22 20.14,16.28 19.55,15.6C22.11,15.94 24,17.11 24,18.5V20Z"></path> </svg> </div> User Acquisition </div> <div class="kpi-value" id="user-counter">0<span class="suffix">K</span></div> <div class="kpi-trend trend-positive"> <span class="trend-icon">↑</span> <span>28.7% increase</span> <span class="trend-period">vs target</span> </div> </div> <div class="kpi-card" data-aos="fade-up"> <div class="kpi-label"> <div class="kpi-icon"> <svg viewBox="0 0 24 24"> <path d="M7,2H17A2,2 0 0,1 19,4V20A2,2 0 0,1 17,22H7A2,2 0 0,1 5,20V4A2,2 0 0,1 7,2M7,4V20H17V4H7M9,6H15V10H9V6M9,12H15V14H9V12M9,16H13V18H9V16Z"></path> </svg> </div> Task Completion </div> <div class="kpi-value" id="task-counter">0<span class="suffix">%</span></div> <div class="kpi-trend trend-negative"> <span class="trend-icon">↓</span> <span>2.3% decrease</span> <span class="trend-period">vs previous month</span> </div> </div> <div class="kpi-card" data-aos="fade-up"> <div class="kpi-label"> <div class="kpi-icon"> <svg viewBox="0 0 24 24"> <path d="M17.45,15.18L22,7.31V19L22,21H2V3H4V15.54L9.5,6L16,9.78L20.24,2.45L21.97,3.45L16.74,12.5L10.23,8.75L4.31,19H6.57L10.96,11.44L17.45,15.18Z"></path> </svg> </div> Conversion Rate </div> <div class="kpi-value" id="conversion-counter">0<span class="suffix">%</span></div> <div class="kpi-trend trend-positive"> <span class="trend-icon">↑</span> <span>5.8% increase</span> <span class="trend-period">vs industry average</span> </div> </div> </div> <div class="chart-container"> <div class="chart-header"> <div class="chart-title"> Monthly Performance <div class="toggle-view"> <div class="toggle-option active">2023</div> <div class="toggle-option">2022</div> </div> </div> <div class="chart-legend"> <div class="legend-item"> <div class="legend-color legend-color-1"></div> <span>Performance</span> </div> <div class="legend-item"> <div class="legend-color legend-color-2"></div> <span>Benchmark</span> </div> </div> </div> <div class="chart"> <div class="chart-bar-group"> <div class="chart-bar" style="height:0%"></div> <div class="chart-bar chart-bar-secondary" style="height:0%"></div> <div class="chart-label">Jan</div> </div> <div class="chart-bar-group"> <div class="chart-bar" style="height:0%"></div> <div class="chart-bar chart-bar-secondary" style="height:0%"></div> <div class="chart-label">Feb</div> </div> <div class="chart-bar-group"> <div class="chart-bar" style="height:0%"></div> <div class="chart-bar chart-bar-secondary" style="height:0%"></div> <div class="chart-label">Mar</div> </div> <div class="chart-bar-group"> <div class="chart-bar" style="height:0%"></div> <div class="chart-bar chart-bar-secondary" style="height:0%"></div> <div class="chart-label">Apr</div> </div> <div class="chart-bar-group"> <div class="chart-bar" style="height:0%"></div> <div class="chart-bar chart-bar-secondary" style="height:0%"></div> <div class="chart-label">May</div> </div> <div class="chart-bar-group"> <div class="chart-bar" style="height:0%"></div> <div class="chart-bar chart-bar-secondary" style="height:0%"></div> <div class="chart-label">Jun</div> </div> </div> </div> <div class="dashboard-footer"> <div>Nexus Technologies Performance Dashboard</div> <div class="last-updated"> <svg class="last-updated-icon" viewBox="0 0 24 24"> <path d="M12,20A8,8 0 0,0 20,12A8,8 0 0,0 12,4A8,8 0 0,0 4,12A8,8 0 0,0 12,20M12,2A10,10 0 0,1 22,12A10,10 0 0,1 12,22C6.47,22 2,17.5 2,12A10,10 0 0,1 12,2M12.5,7V12.25L17,14.92L16.25,16.15L11,13V7H12.5Z"></path> </svg> Last updated: Today at 09:45 AM </div> </div> </div> <script> document.addEventListener('DOMContentLoaded', function() { // Elements to track for scrolling animation const kpiCards = document.querySelectorAll('.kpi-card'); const chartContainer = document.querySelector('.chart-container'); const chartBars = document.querySelectorAll('.chart-bar'); // Counter targets const counterTargets = { 'revenue-counter': 27, // 27% 'user-counter': 42, // 42K 'task-counter': 94, // 94% 'conversion-counter': 8.7 // 8.7% }; // Chart data const performanceData = [65, 78, 70, 85, 92, 88]; const benchmarkData = [60, 65, 62, 70, 75, 72]; // Animation function for counters function animateCounter(element, targetValue, duration = 2000, decimalPlaces = 0) { if (!element) return; const startValue = 0; const increment = targetValue / (duration / 16); let currentValue = startValue; // Add animation class element.classList.add('counter-animation'); const counterAnimation = setInterval(() => { currentValue += increment; if (currentValue >= targetValue) { clearInterval(counterAnimation); currentValue = targetValue; } // Format with decimal places if needed element.textContent = decimalPlaces > 0 ? currentValue.toFixed(decimalPlaces) : Math.floor(currentValue); // Add suffix back const suffix = element.querySelector('.suffix'); if (suffix) { element.appendChild(suffix); } }, 16); } // Animation for chart bars function animateChartBars() { chartBars.forEach((bar, index) => { const isSecondary = bar.classList.contains('chart-bar-secondary'); const data = isSecondary ? benchmarkData : performanceData; const dataIndex = Math.floor(index / 2); setTimeout(() => { bar.style.height = `${data[dataIndex]}%`; }, 100 * index); }); } // Check if element is in viewport function isInViewport(element) { const rect = element.getBoundingClientRect(); return ( rect.top <= (window.innerHeight || document.documentElement.clientHeight) * 0.85 && rect.bottom >= 0 ); } // Scroll handler for animations function handleScroll() { let allAnimated = true; // Check KPI cards kpiCards.forEach(card => { if (!card.dataset.animated && isInViewport(card)) { card.dataset.animated = true; const counterId = card.querySelector('.kpi-value').id; const targetValue = counterTargets[counterId]; // Use decimal places for specific counters const decimalPlaces = counterId === 'conversion-counter' ? 1 : 0; animateCounter(document.getElementById(counterId), targetValue, 2000, decimalPlaces); } else if (!card.dataset.animated) { allAnimated = false; } }); // Check chart if (!chartContainer.dataset.animated && isInViewport(chartContainer)) { chartContainer.dataset.animated = true; animateChartBars(); } else if (!chartContainer.dataset.animated) { allAnimated = false; } // If all elements have been animated, remove scroll listener if (allAnimated) { window.removeEventListener('scroll', handleScroll); } } // Add scroll listener window.addEventListener('scroll', handleScroll); // Trigger initial check (for elements already in viewport) handleScroll(); // Toggle view functionality const toggleOptions = document.querySelectorAll('.toggle-option'); toggleOptions.forEach(option => { option.addEventListener('click', function() { toggleOptions.forEach(opt => opt.classList.remove('active')); this.classList.add('active'); // Change chart data based on selected year if (this.textContent.trim() === '2022') { // Show different data for 2022 setTimeout(() => { chartBars.forEach((bar, index) => { const isSecondary = bar.classList.contains('chart-bar-secondary'); // Different data for 2022 const data2022 = isSecondary ? [50, 55, 60, 65, 58, 60] : [55, 60, 65, 70, 75, 68]; const dataIndex = Math.floor(index / 2); bar.style.height = `${data2022[dataIndex]}%`; }); }, 100); } else { // Restore original 2023 data setTimeout(() => { chartBars.forEach((bar, index) => { const isSecondary = bar.classList.contains('chart-bar-secondary'); const data = isSecondary ? benchmarkData : performanceData; const dataIndex = Math.floor(index / 2); bar.style.height = `${data[dataIndex]}%`; }); }, 100); } }); }); }); </script> </body> </html>
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>E-commerce Metrics Dashboard</title> <style> :root { --primary-color: #121212; --secondary-color: #f5f5f5; --accent-color: #ff3e55; --accent-color-2: #4a9fff; --accent-color-3: #50e3c2; --text-color: #f5f5f5; --transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1); } * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif; } body { background-color: var(--primary-color); color: var(--text-color); min-height: 100vh; display: flex; flex-direction: column; align-items: center; justify-content: center; overflow-x: hidden; padding: 20px; } .dashboard { width: 100%; max-width: 700px; margin: 0 auto; padding: 30px; background-color: var(--primary-color); border-radius: 12px; box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2); position: relative; overflow: hidden; } .dashboard::before { content: ""; position: absolute; top: 0; left: 0; width: 100%; height: 4px; background: linear-gradient(to right, var(--accent-color), var(--accent-color-2), var(--accent-color-3)); z-index: 1; } .header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 40px; position: relative; } .logo { font-size: 1.5rem; font-weight: 700; letter-spacing: -0.5px; display: flex; align-items: center; gap: 8px; } .logo-dot { display: inline-block; width: 10px; height: 10px; border-radius: 50%; background-color: var(--accent-color); } .time-display { font-size: 0.9rem; font-weight: 500; opacity: 0.7; letter-spacing: 0.5px; } .metrics-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 20px; margin-bottom: 30px; } .metric-card { background-color: rgba(255, 255, 255, 0.05); padding: 24px; border-radius: 10px; cursor: pointer; transition: var(--transition); position: relative; overflow: hidden; } .metric-card:hover { transform: translateY(-5px); background-color: rgba(255, 255, 255, 0.08); box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04); } .metric-card::after { content: ""; position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: radial-gradient(circle at center, rgba(255, 255, 255, 0.1) 0%, transparent 70%); opacity: 0; transition: var(--transition); pointer-events: none; } .metric-card:hover::after { opacity: 1; } .metric-title { font-size: 0.85rem; font-weight: 500; text-transform: uppercase; letter-spacing: 1px; margin-bottom: 10px; display: flex; align-items: center; gap: 8px; } .metric-icon { width: 18px; height: 18px; display: flex; align-items: center; justify-content: center; } .counter-wrapper { display: flex; align-items: baseline; gap: 5px; } .counter { font-size: 2.5rem; font-weight: 700; letter-spacing: -1px; line-height: 1; transition: var(--transition); background: linear-gradient(45deg, var(--text-color), rgba(255, 255, 255, 0.7)); -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent; } .metric-card:hover .counter { transform: scale(1.05); } .counter-unit { font-size: 0.9rem; opacity: 0.7; } .metric-trend { display: flex; align-items: center; gap: 5px; margin-top: 12px; font-size: 0.85rem; } .trend-up { color: var(--accent-color-3); } .trend-down { color: var(--accent-color); } .daily-stats { margin-top: 30px; } .section-title { font-size: 1rem; font-weight: 600; margin-bottom: 15px; display: flex; align-items: center; gap: 8px; } .stats-container { background-color: rgba(255, 255, 255, 0.05); border-radius: 10px; padding: 20px; position: relative; overflow: hidden; } .stats-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 15px; } .stat-item { padding: 10px; display: flex; flex-direction: column; gap: 5px; transition: var(--transition); border-radius: 6px; cursor: pointer; } .stat-item:hover { background-color: rgba(255, 255, 255, 0.08); } .stat-label { font-size: 0.8rem; opacity: 0.7; } .stat-value { font-size: 1.3rem; font-weight: 600; } .pulse { width: 10px; height: 10px; border-radius: 50%; background-color: var(--accent-color); position: relative; } .pulse::before { content: ""; position: absolute; border: 1px solid var(--accent-color); width: 100%; height: 100%; border-radius: 50%; animation: pulse 2s infinite; } .bars-container { display: flex; justify-content: space-between; align-items: flex-end; height: 100px; margin-top: 20px; padding: 0 10px; } .bar { width: 10px; background-color: rgba(255, 255, 255, 0.2); border-radius: 4px 4px 0 0; position: relative; transition: var(--transition); cursor: pointer; } .bar:hover { background-color: var(--accent-color-2); } .bar-tooltip { position: absolute; bottom: calc(100% + 10px); left: 50%; transform: translateX(-50%); background-color: var(--accent-color-2); color: var(--primary-color); padding: 4px 8px; border-radius: 4px; font-size: 0.8rem; white-space: nowrap; opacity: 0; transition: var(--transition); pointer-events: none; } .bar:hover .bar-tooltip { opacity: 1; } .time-labels { display: flex; justify-content: space-between; margin-top: 10px; font-size: 0.7rem; opacity: 0.6; padding: 0 5px; } @keyframes pulse { 0% { transform: scale(1); opacity: 1; } 100% { transform: scale(3); opacity: 0; } } @keyframes count-up { from { transform: translateY(10px); opacity: 0; } to { transform: translateY(0); opacity: 1; } } .loading .counter { animation: count-up 0.5s ease-out forwards; } .metric-highlight { color: var(--accent-color); } @media (max-width: 600px) { .metrics-grid { grid-template-columns: 1fr; } .stats-grid { grid-template-columns: repeat(2, 1fr); } .counter { font-size: 2rem; } .dashboard { padding: 20px; } } </style> </head> <body> <div class="dashboard loading"> <div class="header"> <div class="logo"> <span class="logo-dot"></span> PULSE<span class="metric-highlight">METRICS</span> </div> <div class="time-display" id="time-display">Live Data • Updating</div> </div> <div class="metrics-grid"> <div class="metric-card" data-start="0" data-end="7489" data-increment="1" data-speed="20"> <div class="metric-title"> <div class="pulse"></div> Today's Sales </div> <div class="counter-wrapper"> <div class="counter" id="counter-1">0</div> <span class="counter-unit">orders</span> </div> <div class="metric-trend trend-up"> <svg width="12" height="12" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M18 15L12 9L6 15" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> </svg> <span>12.4% from yesterday</span> </div> </div> <div class="metric-card" data-start="0" data-end="843217" data-increment="100" data-speed="5"> <div class="metric-title"> <div class="pulse"></div> Revenue </div> <div class="counter-wrapper"> <span class="counter-unit">$</span> <div class="counter" id="counter-2">0</div> </div> <div class="metric-trend trend-up"> <svg width="12" height="12" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M18 15L12 9L6 15" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> </svg> <span>8.7% from yesterday</span> </div> </div> <div class="metric-card" data-start="0" data-end="112" data-increment="1" data-speed="50"> <div class="metric-title"> <div class="pulse"></div> Average Order Value </div> <div class="counter-wrapper"> <span class="counter-unit">$</span> <div class="counter" id="counter-3">0</div> </div> <div class="metric-trend trend-down"> <svg width="12" height="12" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M6 9L12 15L18 9" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> </svg> <span>3.2% from yesterday</span> </div> </div> <div class="metric-card" data-start="0" data-end="5432" data-increment="1" data-speed="20"> <div class="metric-title"> <div class="pulse"></div> Active Visitors </div> <div class="counter-wrapper"> <div class="counter" id="counter-4">0</div> <span class="counter-unit">users</span> </div> <div class="metric-trend trend-up"> <svg width="12" height="12" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M18 15L12 9L6 15" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> </svg> <span>21.8% from last hour</span> </div> </div> </div> <div class="daily-stats"> <div class="section-title"> <svg width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M21 21H3V3" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> <path d="M21 9L13 15L9 11L3 16" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> </svg> Today's Performance </div> <div class="stats-container"> <div class="stats-grid"> <div class="stat-item"> <div class="stat-label">Conversion Rate</div> <div class="stat-value">4.8%</div> </div> <div class="stat-item"> <div class="stat-label">Cart Abandonment</div> <div class="stat-value">22.3%</div> </div> <div class="stat-item"> <div class="stat-label">New Customers</div> <div class="stat-value">1,872</div> </div> </div> <div class="bars-container" id="bars-container"> <!-- Bars will be generated by JS --> </div> <div class="time-labels"> <span>12 AM</span> <span>6 AM</span> <span>12 PM</span> <span>6 PM</span> <span>11 PM</span> </div> </div> </div> </div> <script> document.addEventListener('DOMContentLoaded', function() { // Setup counters const counterElements = document.querySelectorAll('.metric-card'); counterElements.forEach((card, index) => { const counter = card.querySelector('.counter'); const startValue = parseInt(card.getAttribute('data-start')); const endValue = parseInt(card.getAttribute('data-end')); const increment = parseInt(card.getAttribute('data-increment')); const speed = parseInt(card.getAttribute('data-speed')); let currentValue = startValue; const updateCounter = () => { if (currentValue + increment >= endValue) { currentValue = endValue; counter.textContent = formatNumber(currentValue); return; } currentValue += increment; counter.textContent = formatNumber(currentValue); setTimeout(updateCounter, speed); }; setTimeout(() => { updateCounter(); }, 500 + index * 200); }); // Format numbers with commas function formatNumber(num) { return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ","); } // Update real-time display function updateTimeDisplay() { const timeDisplay = document.getElementById('time-display'); const now = new Date(); const hours = now.getHours().toString().padStart(2, '0'); const minutes = now.getMinutes().toString().padStart(2, '0'); const seconds = now.getSeconds().toString().padStart(2, '0'); timeDisplay.innerHTML = `Live Data • ${hours}:${minutes}:${seconds}`; } setInterval(updateTimeDisplay, 1000); updateTimeDisplay(); // Generate hourly sales chart const barsContainer = document.getElementById('bars-container'); const hourlyData = [ { hour: "12 AM", sales: 212, tooltip: "212 orders at 12 AM" }, { hour: "1 AM", sales: 170, tooltip: "170 orders at 1 AM" }, { hour: "2 AM", sales: 145, tooltip: "145 orders at 2 AM" }, { hour: "3 AM", sales: 132, tooltip: "132 orders at 3 AM" }, { hour: "4 AM", sales: 118, tooltip: "118 orders at 4 AM" }, { hour: "5 AM", sales: 130, tooltip: "130 orders at 5 AM" }, { hour: "6 AM", sales: 180, tooltip: "180 orders at 6 AM" }, { hour: "7 AM", sales: 230, tooltip: "230 orders at 7 AM" }, { hour: "8 AM", sales: 290, tooltip: "290 orders at 8 AM" }, { hour: "9 AM", sales: 340, tooltip: "340 orders at 9 AM" }, { hour: "10 AM", sales: 390, tooltip: "390 orders at 10 AM" }, { hour: "11 AM", sales: 420, tooltip: "420 orders at 11 AM" }, { hour: "12 PM", sales: 460, tooltip: "460 orders at 12 PM" }, { hour: "1 PM", sales: 475, tooltip: "475 orders at 1 PM" }, { hour: "2 PM", sales: 490, tooltip: "490 orders at 2 PM" }, { hour: "3 PM", sales: 520, tooltip: "520 orders at 3 PM" }, { hour: "4 PM", sales: 515, tooltip: "515 orders at 4 PM" }, { hour: "5 PM", sales: 490, tooltip: "490 orders at 5 PM" }, { hour: "6 PM", sales: 470, tooltip: "470 orders at 6 PM" }, { hour: "7 PM", sales: 445, tooltip: "445 orders at 7 PM" }, { hour: "8 PM", sales: 400, tooltip: "400 orders at 8 PM" }, { hour: "9 PM", sales: 350, tooltip: "350 orders at 9 PM" }, { hour: "10 PM", sales: 290, tooltip: "290 orders at 10 PM" }, { hour: "11 PM", sales: 250, tooltip: "250 orders at 11 PM" } ]; const maxSales = Math.max(...hourlyData.map(d => d.sales)); hourlyData.forEach((data, index) => { const height = (data.sales / maxSales) * 100; const bar = document.createElement('div'); bar.className = 'bar'; bar.style.height = `${height}px`; // Highlight the current hour const currentHour = new Date().getHours(); if (index === currentHour) { bar.style.backgroundColor = 'var(--accent-color)'; } const tooltip = document.createElement('div'); tooltip.className = 'bar-tooltip'; tooltip.textContent = data.tooltip; bar.appendChild(tooltip); barsContainer.appendChild(bar); }); // Simulate occasional live updates to the counters function simulateRealTimeUpdates() { const randomCounter = Math.floor(Math.random() * counterElements.length); const card = counterElements[randomCounter]; const counter = card.querySelector('.counter'); let currentValue = parseInt(counter.textContent.replace(/,/g, '')); const increment = Math.floor(Math.random() * 5) + 1; currentValue += increment; counter.textContent = formatNumber(currentValue); // Add a flash effect counter.style.color = 'var(--accent-color)'; setTimeout(() => { counter.style.color = ''; }, 300); // Schedule next update setTimeout(simulateRealTimeUpdates, Math.random() * 5000 + 2000); } setTimeout(simulateRealTimeUpdates, 5000); }); </script> </body> </html>
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Hope Harvest - Community Fundraising</title> <style> @import url('https://fonts.googleapis.com/css2?family=Quicksand:wght@400;500;600;700&family=Indie+Flower&display=swap'); * { margin: 0; padding: 0; box-sizing: border-box; } :root { --primary: #e67e22; --secondary: #27ae60; --accent: #8e44ad; --dark: #34495e; --light: #ecf0f1; --success: #2ecc71; } body { font-family: 'Quicksand', sans-serif; background-color: var(--light); color: var(--dark); padding: 1.5rem; max-width: 700px; margin: 0 auto; overflow-x: hidden; } .container { max-width: 100%; margin: 0 auto; padding: 1rem; border-radius: 1rem; background: white; box-shadow: 0 8px 32px rgba(0, 0, 0, 0.08); } header { text-align: center; margin-bottom: 2rem; position: relative; } h1 { font-size: 2.2rem; margin-bottom: 0.5rem; color: var(--primary); position: relative; display: inline-block; } h1::after { content: ""; position: absolute; height: 8px; width: 100%; bottom: 0; left: 0; background: url("data:image/svg+xml,%3Csvg width='100' height='8' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M0,4 C15,0 35,8 50,4 C65,0 85,8 100,4' stroke='%23e67e22' stroke-width='2' fill='none' /%3E%3C/svg%3E") repeat-x; background-size: 100px 8px; } .subtitle { font-family: 'Indie Flower', cursive; font-size: 1.2rem; color: var(--secondary); margin-bottom: 1rem; } .campaign-info { font-size: 1rem; line-height: 1.6; max-width: 600px; margin: 0 auto 2rem; padding: 1rem; border-radius: 0.5rem; background: #f9f9f9; position: relative; } .campaign-info::before { content: ""; position: absolute; top: -8px; left: 20px; width: 16px; height: 16px; background: #f9f9f9; transform: rotate(45deg); } .counters { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 1.5rem; margin-bottom: 2rem; } .counter-card { background: white; border-radius: 1rem; padding: 1.5rem; text-align: center; box-shadow: 0 4px 16px rgba(0, 0, 0, 0.06); transition: transform 0.3s ease, box-shadow 0.3s ease; position: relative; overflow: hidden; border: 2px solid transparent; } .counter-card:hover { transform: translateY(-5px); box-shadow: 0 8px 24px rgba(0, 0, 0, 0.09); border-color: var(--primary); } .counter-card::before { content: ""; position: absolute; top: 0; left: 0; width: 100%; height: 100%; background-size: 20px 20px; opacity: 0.03; background-image: url("data:image/svg+xml,%3Csvg width='20' height='20' xmlns='http://www.w3.org/2000/svg'%3E%3Ccircle cx='10' cy='10' r='2' fill='%23000' /%3E%3C/svg%3E"); } .counter-icon { font-size: 2rem; margin-bottom: 0.5rem; display: inline-block; color: var(--primary); } .counter-title { font-size: 1rem; margin-bottom: 1rem; color: var(--dark); font-weight: 600; } .counter-value { font-size: 2.5rem; font-weight: 700; margin-bottom: 0.5rem; color: var(--secondary); font-family: 'Quicksand', sans-serif; position: relative; display: inline-block; } .counter-value.dollars::before { content: "$"; font-size: 1.5rem; position: absolute; top: 0.5rem; left: -1rem; color: var(--secondary); opacity: 0.8; } .counter-description { font-size: 0.9rem; color: var(--dark); opacity: 0.8; } .progress-container { background: rgba(0, 0, 0, 0.05); height: 1.5rem; border-radius: 1rem; margin-top: 1rem; position: relative; overflow: hidden; } .progress-bar { background: var(--secondary); height: 100%; border-radius: 1rem; width: 0; position: relative; transition: width 2s cubic-bezier(0.25, 0.46, 0.45, 0.94); } .progress-bar::after { content: ""; position: absolute; top: 0; left: 0; right: 0; bottom: 0; background-image: linear-gradient( -45deg, rgba(255, 255, 255, 0.2) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.2) 50%, rgba(255, 255, 255, 0.2) 75%, transparent 75%, transparent ); background-size: 30px 30px; animation: progress-animation 2s linear infinite; border-radius: 1rem; } @keyframes progress-animation { 0% { background-position: 0 0; } 100% { background-position: 30px 0; } } .milestone-markers { position: relative; height: 30px; margin-top: 5px; } .milestone { position: absolute; transform: translateX(-50%); width: 12px; height: 12px; border-radius: 50%; background: var(--dark); top: 0; } .milestone::after { content: attr(data-amount); position: absolute; top: 15px; left: 50%; transform: translateX(-50%); font-size: 0.75rem; white-space: nowrap; } .milestone.achieved { background: var(--success); } .recent-donations { margin-top: 2.5rem; } .recent-title { font-size: 1.25rem; margin-bottom: 1rem; position: relative; color: var(--dark); font-weight: 600; display: inline-block; } .recent-title::after { content: ""; position: absolute; left: 0; bottom: -5px; height: 3px; width: 100%; background: var(--primary); border-radius: 3px; } .donation-list { max-height: 180px; overflow-y: auto; padding-right: 5px; } .donation-item { display: flex; align-items: center; padding: 0.75rem; border-radius: 0.5rem; margin-bottom: 0.5rem; background: white; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05); transform: translateX(-100%); opacity: 0; transition: transform 0.5s ease, opacity 0.5s ease; border-left: 4px solid var(--primary); } .donation-item.animate-in { transform: translateX(0); opacity: 1; } .donation-avatar { width: 2.5rem; height: 2.5rem; border-radius: 50%; margin-right: 1rem; background-color: #f1f1f1; display: flex; align-items: center; justify-content: center; font-weight: bold; color: var(--primary); position: relative; } .donation-avatar::after { content: "🌱"; position: absolute; bottom: -3px; right: -3px; font-size: 0.75rem; } .donation-info { flex: 1; } .donation-name { font-weight: 600; margin-bottom: 0.25rem; color: var(--dark); } .donation-message { font-size: 0.8rem; color: var(--dark); opacity: 0.8; } .donation-amount { font-weight: 700; color: var(--secondary); font-size: 1.1rem; margin-left: 0.5rem; } .cta-section { margin-top: 2rem; text-align: center; } .cta-button { background: var(--primary); color: white; border: none; padding: 0.75rem 1.5rem; border-radius: 2rem; font-size: 1rem; font-weight: 600; cursor: pointer; transition: all 0.3s ease; box-shadow: 0 4px 12px rgba(230, 126, 34, 0.3); position: relative; overflow: hidden; outline: none; font-family: 'Quicksand', sans-serif; } .cta-button:hover { transform: translateY(-2px); box-shadow: 0 6px 16px rgba(230, 126, 34, 0.4); background: #d35400; } .cta-button:active { transform: translateY(0); } .cta-button::after { content: ""; position: absolute; width: 100%; height: 100%; top: 0; left: -100%; background: linear-gradient( 90deg, transparent, rgba(255, 255, 255, 0.2), transparent ); transition: 0.5s; } .cta-button:hover::after { left: 100%; } .impact-stats { display: flex; justify-content: space-around; margin-top: 2rem; flex-wrap: wrap; gap: 1rem; } .impact-item { text-align: center; flex: 1; min-width: 100px; padding: 0.5rem; opacity: 0; transform: translateY(20px); transition: opacity 0.5s ease, transform 0.5s ease; } .impact-item.visible { opacity: 1; transform: translateY(0); } .impact-value { font-size: 1.75rem; font-weight: 700; color: var(--accent); margin-bottom: 0.25rem; } .impact-label { font-size: 0.85rem; color: var(--dark); } .heart-animation { display: inline-block; position: relative; top: 3px; animation: heartbeat 1.5s infinite; } @keyframes heartbeat { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.3); } } .loading-overlay { position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: var(--light); display: flex; align-items: center; justify-content: center; z-index: 1000; opacity: 1; transition: opacity 0.5s ease; } .loading-spinner { width: 60px; height: 60px; border: 8px solid rgba(230, 126, 34, 0.3); border-radius: 50%; border-top-color: var(--primary); animation: spin 1s ease-in-out infinite; } @keyframes spin { to { transform: rotate(360deg); } } .loading-overlay.hidden { opacity: 0; pointer-events: none; } .tooltip { position: absolute; background: rgba(52, 73, 94, 0.9); color: white; padding: 0.5rem 1rem; border-radius: 0.5rem; font-size: 0.85rem; max-width: 200px; z-index: 100; text-align: center; box-shadow: 0 4px 10px rgba(0, 0, 0, 0.2); opacity: 0; transform: translateY(10px); transition: opacity 0.3s ease, transform 0.3s ease; pointer-events: none; } .tooltip.visible { opacity: 1; transform: translateY(0); } .tooltip::after { content: ''; position: absolute; bottom: -6px; left: 50%; transform: translateX(-50%); width: 0; height: 0; border-left: 6px solid transparent; border-right: 6px solid transparent; border-top: 6px solid rgba(52, 73, 94, 0.9); } @media (max-width: 600px) { h1 { font-size: 1.8rem; } .counter-value { font-size: 2rem; } .donation-item { padding: 0.5rem; } .donation-avatar { width: 2rem; height: 2rem; } .impact-value { font-size: 1.5rem; } } .confetti { position: absolute; width: 10px; height: 10px; background-color: #f39c12; opacity: 0; pointer-events: none; } @keyframes fall { 0% { transform: translateY(-100px) rotate(0deg); opacity: 1; } 100% { transform: translateY(100px) rotate(360deg); opacity: 0; } } </style> </head> <body> <div class="loading-overlay"> <div class="loading-spinner"></div> </div> <div class="tooltip" id="tooltip"></div> <div class="container"> <header> <h1>Hope Harvest Initiative</h1> <div class="subtitle">Planting seeds of change in our community</div> </header> <div class="campaign-info"> <p>Our community garden project is transforming vacant lots into flourishing food sources for local food banks. Every dollar helps provide fresh produce to families in need, educate local schools on sustainable farming, and build green spaces in urban neighborhoods.</p> </div> <div class="counters"> <div class="counter-card" data-tooltip="From 342 amazing supporters like you!"> <div class="counter-icon">💰</div> <div class="counter-title">Total Raised</div> <div class="counter-value dollars" id="total-raised">0</div> <div class="counter-description">of $25,000 goal</div> <div class="progress-container"> <div class="progress-bar" id="main-progress"></div> </div> <div class="milestone-markers"> <div class="milestone" data-amount="$5k" style="left: 20%;"></div> <div class="milestone" data-amount="$10k" style="left: 40%;"></div> <div class="milestone" data-amount="$15k" style="left: 60%;"></div> <div class="milestone" data-amount="$20k" style="left: 80%;"></div> </div> </div> <div class="counter-card" data-tooltip="Thank you for your generosity!"> <div class="counter-icon">🌟</div> <div class="counter-title">Average Donation</div> <div class="counter-value dollars" id="avg-donation">0</div> <div class="counter-description">Growing community impact</div> </div> </div> <div class="recent-donations"> <h2 class="recent-title">Recent Supporters</h2> <div class="donation-list" id="donation-list"> <!-- Donation items will be added dynamically --> </div> </div> <div class="impact-stats"> <div class="impact-item"> <div class="impact-value" id="impact-gardens">0</div> <div class="impact-label">Community Gardens</div> </div> <div class="impact-item"> <div class="impact-value" id="impact-meals">0</div> <div class="impact-label">Fresh Meals Provided</div> </div> <div class="impact-item"> <div class="impact-value" id="impact-workshops">0</div> <div class="impact-label">Gardening Workshops</div> </div> </div> <div class="cta-section"> <button class="cta-button" id="donate-button">Donate Now <span class="heart-animation">❤️</span></button> </div> </div> <script> // Simulating loading time for data setTimeout(() => { document.querySelector('.loading-overlay').classList.add('hidden'); startAnimations(); }, 800); // Sample data const donationData = { totalRaised: 14235, goalAmount: 25000, averageDonation: 42, impact: { gardens: 7, meals: 1240, workshops: 24 }, recentDonations: [ { name: "Maria S.", amount: 50, message: "For the children's education program!", avatar: "MS" }, { name: "David L.", amount: 75, message: "Keep up the amazing work!", avatar: "DL" }, { name: "Anonymous", amount: 25, message: "Supporting our community!", avatar: "A" }, { name: "Sarah K.", amount: 150, message: "In memory of my grandmother who loved gardens.", avatar: "SK" }, { name: "Tom B.", amount: 35, message: "Excited to volunteer next month!", avatar: "TB" }, { name: "Elena R.", amount: 100, message: "Can't wait to see the new south side garden!", avatar: "ER" } ] }; // Counter animation function function animateCounter(elementId, target, duration, prefix = '') { const element = document.getElementById(elementId); const start = 0; const startTime = performance.now(); function updateCounter(currentTime) { const elapsedTime = currentTime - startTime; const progress = Math.min(elapsedTime / duration, 1); // Use easeOutQuad for a more natural counting effect const easeProgress = 1 - (1 - progress) * (1 - progress); const currentCount = Math.floor(start + easeProgress * (target - start)); element.textContent = prefix + currentCount.toLocaleString(); if (progress < 1) { requestAnimationFrame(updateCounter); } } requestAnimationFrame(updateCounter); } // Function to animate the progress bar function animateProgressBar(percentage) { const progressBar = document.getElementById('main-progress'); progressBar.style.width = `${percentage}%`; // Update milestones const milestones = document.querySelectorAll('.milestone'); milestones.forEach(milestone => { const milestonePosition = parseFloat(milestone.style.left); if (percentage >= milestonePosition) { milestone.classList.add('achieved'); } }); } // Create recent donation items function createDonationItems(donations) { const donationList = document.getElementById('donation-list'); donations.forEach((donation, index) => { const item = document.createElement('div'); item.classList.add('donation-item'); item.innerHTML = ` <div class="donation-avatar">${donation.avatar}</div> <div class="donation-info"> <div class="donation-name">${donation.name}</div> <div class="donation-message">${donation.message}</div> </div> <div class="donation-amount">$${donation.amount}</div> `; donationList.appendChild(item); // Stagger animation setTimeout(() => { item.classList.add('animate-in'); }, 100 * index); }); } // Start all animations function startAnimations() { // Calculate percentage of goal reached const percentage = (donationData.totalRaised / donationData.goalAmount) * 100; // Animate counters animateCounter('total-raised', donationData.totalRaised, 2000); animateCounter('avg-donation', donationData.averageDonation, 1500); animateCounter('impact-gardens', donationData.impact.gardens, 1000); animateCounter('impact-meals', donationData.impact.meals, 2500); animateCounter('impact-workshops', donationData.impact.workshops, 1800); // Animate progress bar setTimeout(() => { animateProgressBar(percentage); }, 500); // Create donation items createDonationItems(donationData.recentDonations); // Animate impact stats const impactItems = document.querySelectorAll('.impact-item'); setTimeout(() => { impactItems.forEach((item, index) => { setTimeout(() => { item.classList.add('visible'); }, 300 * index); }); }, 1000); // Set up intersection observer for animations when scrolling setupIntersectionObserver(); } // Setup intersection observer for scroll animations function setupIntersectionObserver() { const observer = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { entry.target.classList.add('visible'); observer.unobserve(entry.target); } }); }, { threshold: 0.2 }); document.querySelectorAll('.counter-card, .impact-item, .donation-item').forEach(item => { observer.observe(item); }); } // Tooltip functionality document.querySelectorAll('[data-tooltip]').forEach(element => { element.addEventListener('mouseenter', function(e) { const tooltip = document.getElementById('tooltip'); tooltip.textContent = this.dataset.tooltip; const rect = this.getBoundingClientRect(); tooltip.style.left = `${rect.left + rect.width/2}px`; tooltip.style.top = `${rect.top - 40}px`; tooltip.classList.add('visible'); // Create confetti effect on tooltip show createConfetti(rect.left + rect.width/2, rect.top); }); element.addEventListener('mouseleave', function() { document.getElementById('tooltip').classList.remove('visible'); }); }); // Confetti effect function createConfetti(x, y) { const colors = ['#e67e22', '#27ae60', '#3498db', '#9b59b6', '#f1c40f']; for (let i = 0; i < 15; i++) { const confetti = document.createElement('div'); confetti.className = 'confetti'; confetti.style.backgroundColor = colors[Math.floor(Math.random() * colors.length)]; confetti.style.left = `${x + (Math.random() * 60 - 30)}px`; confetti.style.top = `${y}px`; confetti.style.width = `${Math.random() * 8 + 4}px`; confetti.style.height = `${Math.random() * 8 + 4}px`; confetti.style.opacity = '1'; confetti.style.animation = `fall ${Math.random() * 2 + 1}s linear forwards`; confetti.style.transform = `rotate(${Math.random() * 360}deg)`; document.body.appendChild(confetti); // Remove confetti after animation completes setTimeout(() => { confetti.remove(); }, 3000); } } // CTA button functionality document.getElementById('donate-button').addEventListener('click', function() { // Simulate a donation with animation const totalRaisedElement = document.getElementById('total-raised'); const currentAmount = parseInt(totalRaisedElement.textContent.replace(/,/g, '')); const newDonation = Math.floor(Math.random() * 100) + 20; const newTotal = currentAmount + newDonation; // Animate to new total animateCounter('total-raised', newTotal, 1000); // Update progress const newPercentage = (newTotal / donationData.goalAmount) * 100; animateProgressBar(newPercentage); // Create new donation item const names = ["Jordan", "Taylor", "Alex", "Morgan", "Casey"]; const randomName = names[Math.floor(Math.random() * names.length)]; const messages = [ "Supporting this wonderful cause!", "Happy to help the community garden!", "For a greener neighborhood!", "Keep growing!", "From my family to our community!" ]; const randomMessage = messages[Math.floor(Math.random() * messages.length)]; const donationList = document.getElementById('donation-list'); const newItem = document.createElement('div'); newItem.classList.add('donation-item'); newItem.innerHTML = ` <div class="donation-avatar">${randomName.charAt(0)}</div> <div class="donation-info"> <div class="donation-name">${randomName}</div> <div class="donation-message">${randomMessage}</div> </div> <div class="donation-amount">$${newDonation}</div> `; donationList.insertBefore(newItem, donationList.firstChild); setTimeout(() => { newItem.classList.add('animate-in'); // Create confetti effect on donation createConfetti(event.clientX, event.clientY); }, 100); // Update meals impact const impactMeals = document.getElementById('impact-meals'); const currentMeals = parseInt(impactMeals.textContent.replace(/,/g, '')); const newMeals = currentMeals + Math.floor(newDonation / 5); animateCounter('impact-meals', newMeals, 1000); }); </script> </body> </html>
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>PeakTracker Fitness</title> <style> :root { --primary: #FF4081; --secondary: #00B8D4; --tertiary: #FFD740; --dark: #1A1A2E; --light: #F5F5F7; --success: #2ECC71; } * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; } body { background-color: var(--dark); color: var(--light); display: flex; flex-direction: column; align-items: center; justify-content: center; min-height: 700px; width: 100%; max-width: 700px; margin: 0 auto; overflow-x: hidden; padding: 20px; } header { text-align: center; margin-bottom: 30px; width: 100%; } h1 { font-size: 2.5rem; margin-bottom: 10px; background: linear-gradient(90deg, var(--primary), var(--secondary)); -webkit-background-clip: text; -webkit-text-fill-color: transparent; text-shadow: 0 0 10px rgba(255, 64, 129, 0.3); } .tagline { font-style: italic; color: var(--light); opacity: 0.8; font-size: 1rem; } .dashboard { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 20px; width: 100%; margin-bottom: 30px; } .stat-card { background: rgba(255, 255, 255, 0.05); backdrop-filter: blur(10px); border-radius: 15px; padding: 20px; text-align: center; box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2); border: 1px solid rgba(255, 255, 255, 0.1); position: relative; transition: transform 0.3s ease, box-shadow 0.3s ease; overflow: hidden; } .stat-card:hover { transform: translateY(-5px); box-shadow: 0 15px 30px rgba(0, 0, 0, 0.3); } .stat-card::before { content: ''; position: absolute; top: -50%; left: -50%; width: 200%; height: 200%; background: linear-gradient(45deg, transparent, rgba(255, 255, 255, 0.05), transparent); transform: rotate(45deg); transition: transform 0.6s ease; opacity: 0; } .stat-card:hover::before { animation: shine 1.5s; } @keyframes shine { 0% { opacity: 0; transform: translateX(-100%) rotate(45deg); } 50% { opacity: 1; } 100% { opacity: 0; transform: translateX(100%) rotate(45deg); } } .stat-card h2 { color: var(--light); margin-bottom: 15px; font-size: 1.2rem; } .counter-container { display: flex; justify-content: center; align-items: center; margin: 15px 0; height: 60px; } .counter { font-family: 'Courier New', monospace; font-size: 2.5rem; font-weight: bold; letter-spacing: 2px; display: flex; align-items: center; justify-content: center; } .steps .counter { color: var(--primary); text-shadow: 0 0 15px rgba(255, 64, 129, 0.5); } .calories .counter { color: var(--secondary); text-shadow: 0 0 15px rgba(0, 184, 212, 0.5); } .distance .counter { color: var(--tertiary); text-shadow: 0 0 15px rgba(255, 215, 64, 0.5); } .goal { font-size: 0.9rem; opacity: 0.7; margin-top: 5px; } .progress-container { width: 100%; height: 10px; background-color: rgba(255, 255, 255, 0.1); border-radius: 5px; overflow: hidden; margin-top: 10px; } .progress-bar { height: 100%; border-radius: 5px; width: 0; transition: width 2s cubic-bezier(0.165, 0.84, 0.44, 1); } .steps .progress-bar { background: linear-gradient(90deg, var(--primary), #FF7FAB); } .calories .progress-bar { background: linear-gradient(90deg, var(--secondary), #69F0FF); } .distance .progress-bar { background: linear-gradient(90deg, var(--tertiary), #FFECB3); } .workout-milestones { width: 100%; margin-top: 20px; } .workout-title { text-align: center; margin-bottom: 20px; font-size: 1.5rem; color: var(--light); } .milestone-list { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 15px; width: 100%; } .milestone { background: rgba(255, 255, 255, 0.05); border-radius: 12px; padding: 15px; text-align: center; transition: all 0.3s ease; position: relative; overflow: hidden; border: 1px solid rgba(255, 255, 255, 0.1); } .milestone.achieved { background: linear-gradient(rgba(46, 204, 113, 0.2), rgba(46, 204, 113, 0.05)); border: 1px solid rgba(46, 204, 113, 0.3); } .milestone h3 { font-size: 0.9rem; margin-bottom: 10px; } .milestone-icon { font-size: 1.8rem; margin-bottom: 10px; transition: transform 0.3s ease; } .milestone:hover .milestone-icon { transform: scale(1.2); } .milestone.achieved .milestone-icon { color: var(--success); } .milestone-counter { font-size: 1.2rem; font-weight: bold; font-family: 'Courier New', monospace; margin: 5px 0; } .milestone.achieved .milestone-counter { color: var(--success); } .achievement-badge { position: absolute; top: -5px; right: -5px; background: var(--success); color: white; width: 20px; height: 20px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 0.7rem; box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2); opacity: 0; transform: scale(0); transition: all 0.3s ease; } .milestone.achieved .achievement-badge { opacity: 1; transform: scale(1); } .action-buttons { display: flex; justify-content: center; gap: 15px; margin-top: 30px; width: 100%; } .btn { background: none; border: none; padding: 12px 25px; border-radius: 50px; font-weight: bold; font-size: 1rem; cursor: pointer; transition: all 0.3s ease; position: relative; overflow: hidden; } .btn-primary { background: var(--primary); color: white; box-shadow: 0 5px 15px rgba(255, 64, 129, 0.4); } .btn-secondary { background: rgba(255, 255, 255, 0.1); color: var(--light); border: 1px solid rgba(255, 255, 255, 0.2); } .btn:hover { transform: translateY(-3px); box-shadow: 0 8px 20px rgba(0, 0, 0, 0.3); } .btn:active { transform: translateY(0); } .btn-ripple { position: absolute; border-radius: 50%; background: rgba(255, 255, 255, 0.3); animation: ripple 0.8s ease-out; transform: scale(0); } @keyframes ripple { to { transform: scale(2.5); opacity: 0; } } .date-display { margin-top: 20px; text-align: center; font-size: 0.9rem; opacity: 0.7; } @media (max-width: 600px) { h1 { font-size: 2rem; } .dashboard { grid-template-columns: 1fr; } .milestone-list { grid-template-columns: repeat(2, 1fr); } } /* Animated Pulse for stat cards */ @keyframes pulse { 0% { box-shadow: 0 0 0 0 rgba(255, 64, 129, 0.4); } 70% { box-shadow: 0 0 0 10px rgba(255, 64, 129, 0); } 100% { box-shadow: 0 0 0 0 rgba(255, 64, 129, 0); } } .pulse { animation: pulse 1.5s infinite; } /* Digit flip animation */ @keyframes flip { 0% { transform: rotateX(0deg); } 50% { transform: rotateX(90deg); } 100% { transform: rotateX(0deg); } } .digit-flip { display: inline-block; animation: flip 0.5s; } </style> </head> <body> <header> <h1>PeakTracker</h1> <p class="tagline">Visualize your progress. Maximize your potential.</p> </header> <div class="dashboard"> <div class="stat-card steps"> <h2>DAILY STEPS</h2> <div class="counter-container"> <div class="counter" id="steps-counter">0</div> </div> <p class="goal">Goal: 10,000 steps</p> <div class="progress-container"> <div class="progress-bar" id="steps-progress"></div> </div> </div> <div class="stat-card calories"> <h2>CALORIES BURNED</h2> <div class="counter-container"> <div class="counter" id="calories-counter">0</div> </div> <p class="goal">Goal: 500 calories</p> <div class="progress-container"> <div class="progress-bar" id="calories-progress"></div> </div> </div> <div class="stat-card distance"> <h2>DISTANCE (KM)</h2> <div class="counter-container"> <div class="counter" id="distance-counter">0</div> </div> <p class="goal">Goal: 5 kilometers</p> <div class="progress-container"> <div class="progress-bar" id="distance-progress"></div> </div> </div> </div> <div class="workout-milestones"> <h2 class="workout-title">Workout Milestones</h2> <div class="milestone-list"> <div class="milestone" id="milestone-1"> <div class="milestone-icon">🏃</div> <h3>5k Run</h3> <div class="milestone-counter" id="milestone-1-counter">0/1</div> <div class="achievement-badge">✓</div> </div> <div class="milestone" id="milestone-2"> <div class="milestone-icon">💪</div> <h3>Strength Session</h3> <div class="milestone-counter" id="milestone-2-counter">0/3</div> <div class="achievement-badge">✓</div> </div> <div class="milestone" id="milestone-3"> <div class="milestone-icon">🧘</div> <h3>Yoga Practice</h3> <div class="milestone-counter" id="milestone-3-counter">0/2</div> <div class="achievement-badge">✓</div> </div> <div class="milestone" id="milestone-4"> <div class="milestone-icon">🚴</div> <h3>Cycling</h3> <div class="milestone-counter" id="milestone-4-counter">0/2</div> <div class="achievement-badge">✓</div> </div> </div> </div> <div class="action-buttons"> <button class="btn btn-primary" id="update-btn">Update Stats</button> <button class="btn btn-secondary" id="reset-btn">Reset</button> </div> <div class="date-display" id="date-display"></div> <script> document.addEventListener('DOMContentLoaded', function() { // Display current date const dateOptions = { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' }; document.getElementById('date-display').textContent = new Date().toLocaleDateString('en-US', dateOptions); // Initial values let stepsCount = 0; let caloriesCount = 0; let distanceCount = 0; const milestoneStatus = { milestone1: { current: 0, target: 1 }, milestone2: { current: 0, target: 3 }, milestone3: { current: 0, target: 2 }, milestone4: { current: 0, target: 2 } }; // Goals const stepsGoal = 10000; const caloriesGoal = 500; const distanceGoal = 5; // Elements const stepsCounter = document.getElementById('steps-counter'); const caloriesCounter = document.getElementById('calories-counter'); const distanceCounter = document.getElementById('distance-counter'); const stepsProgress = document.getElementById('steps-progress'); const caloriesProgress = document.getElementById('calories-progress'); const distanceProgress = document.getElementById('distance-progress'); const updateBtn = document.getElementById('update-btn'); const resetBtn = document.getElementById('reset-btn'); // Animate counter function function animateCounter(element, start, end, duration, isDistance = false) { let startTimestamp = null; const step = (timestamp) => { if (!startTimestamp) startTimestamp = timestamp; const progress = Math.min((timestamp - startTimestamp) / duration, 1); const currentValue = Math.floor(progress * (end - start) + start); // Handle different formats (steps vs distance with decimal) if (isDistance) { element.textContent = (currentValue / 10).toFixed(1); } else { element.textContent = currentValue.toLocaleString(); } // Add flip animation to changing digits element.classList.add('digit-flip'); setTimeout(() => { element.classList.remove('digit-flip'); }, 500); if (progress < 1) { window.requestAnimationFrame(step); } }; window.requestAnimationFrame(step); } // Update progress bars function updateProgressBar(element, value, total) { const percentage = Math.min((value / total) * 100, 100); element.style.width = `${percentage}%`; } // Update milestone status function updateMilestone(id, current, target) { const milestoneElement = document.getElementById(`milestone-${id}`); const counterElement = document.getElementById(`milestone-${id}-counter`); counterElement.textContent = `${current}/${target}`; if (current >= target) { milestoneElement.classList.add('achieved'); // Add pulse animation to highlight achievement milestoneElement.classList.add('pulse'); setTimeout(() => { milestoneElement.classList.remove('pulse'); }, 3000); } else { milestoneElement.classList.remove('achieved'); } } // Initialize values on load with some random data function initialize() { stepsCount = Math.floor(Math.random() * 5000) + 2000; caloriesCount = Math.floor(Math.random() * 200) + 100; distanceCount = Math.floor(Math.random() * 20) + 10; // Divided by 10 later for decimal // Animate initial counters animateCounter(stepsCounter, 0, stepsCount, 1500); animateCounter(caloriesCounter, 0, caloriesCount, 1500); animateCounter(distanceCounter, 0, distanceCount, 1500, true); // Set initial progress bars updateProgressBar(stepsProgress, stepsCount, stepsGoal); updateProgressBar(caloriesProgress, caloriesCount, caloriesGoal); updateProgressBar(distanceProgress, distanceCount/10, distanceGoal); // Set initial milestone status milestoneStatus.milestone1.current = Math.floor(Math.random() * 2); milestoneStatus.milestone2.current = Math.floor(Math.random() * 4); milestoneStatus.milestone3.current = Math.floor(Math.random() * 3); milestoneStatus.milestone4.current = Math.floor(Math.random() * 3); updateMilestone(1, milestoneStatus.milestone1.current, milestoneStatus.milestone1.target); updateMilestone(2, milestoneStatus.milestone2.current, milestoneStatus.milestone2.target); updateMilestone(3, milestoneStatus.milestone3.current, milestoneStatus.milestone3.target); updateMilestone(4, milestoneStatus.milestone4.current, milestoneStatus.milestone4.target); } // Button ripple effect function createRipple(event) { const button = event.currentTarget; const circle = document.createElement('span'); const diameter = Math.max(button.clientWidth, button.clientHeight); const radius = diameter / 2; circle.style.width = circle.style.height = `${diameter}px`; circle.style.left = `${event.clientX - button.getBoundingClientRect().left - radius}px`; circle.style.top = `${event.clientY - button.getBoundingClientRect().top - radius}px`; circle.classList.add('btn-ripple'); const ripple = button.getElementsByClassName('btn-ripple')[0]; if (ripple) { ripple.remove(); } button.appendChild(circle); } // Update button click handler updateBtn.addEventListener('click', function(e) { createRipple(e); // Generate random increments const stepsIncrement = Math.floor(Math.random() * 2000) + 500; const caloriesIncrement = Math.floor(Math.random() * 100) + 50; const distanceIncrement = Math.floor(Math.random() * 10) + 5; const oldStepsCount = stepsCount; const oldCaloriesCount = caloriesCount; const oldDistanceCount = distanceCount; stepsCount += stepsIncrement; caloriesCount += caloriesIncrement; distanceCount += distanceIncrement; // Animate counters from old to new values animateCounter(stepsCounter, oldStepsCount, stepsCount, 1500); animateCounter(caloriesCounter, oldCaloriesCount, caloriesCount, 1500); animateCounter(distanceCounter, oldDistanceCount, distanceCount, 1500, true); // Update progress bars updateProgressBar(stepsProgress, stepsCount, stepsGoal); updateProgressBar(caloriesProgress, caloriesCount, caloriesGoal); updateProgressBar(distanceProgress, distanceCount/10, distanceGoal); // Maybe complete some milestones if (Math.random() > 0.7 && milestoneStatus.milestone1.current < milestoneStatus.milestone1.target) { milestoneStatus.milestone1.current += 1; } if (Math.random() > 0.6 && milestoneStatus.milestone2.current < milestoneStatus.milestone2.target) { milestoneStatus.milestone2.current += 1; } if (Math.random() > 0.7 && milestoneStatus.milestone3.current < milestoneStatus.milestone3.target) { milestoneStatus.milestone3.current += 1; } if (Math.random() > 0.6 && milestoneStatus.milestone4.current < milestoneStatus.milestone4.target) { milestoneStatus.milestone4.current += 1; } updateMilestone(1, milestoneStatus.milestone1.current, milestoneStatus.milestone1.target); updateMilestone(2, milestoneStatus.milestone2.current, milestoneStatus.milestone2.target); updateMilestone(3, milestoneStatus.milestone3.current, milestoneStatus.milestone3.target); updateMilestone(4, milestoneStatus.milestone4.current, milestoneStatus.milestone4.target); }); // Reset button click handler resetBtn.addEventListener('click', function(e) { createRipple(e); const oldStepsCount = stepsCount; const oldCaloriesCount = caloriesCount; const oldDistanceCount = distanceCount; stepsCount = 0; caloriesCount = 0; distanceCount = 0; // Animate counters to zero animateCounter(stepsCounter, oldStepsCount, 0, 1000); animateCounter(caloriesCounter, oldCaloriesCount, 0, 1000); animateCounter(distanceCounter, oldDistanceCount, 0, 1000, true); // Update progress bars updateProgressBar(stepsProgress, 0, stepsGoal); updateProgressBar(caloriesProgress, 0, caloriesGoal); updateProgressBar(distanceProgress, 0, distanceGoal); // Reset milestones for (let i = 1; i <= 4; i++) { milestoneStatus[`milestone${i}`].current = 0; updateMilestone(i, 0, milestoneStatus[`milestone${i}`].target); } }); // Add button ripple effect listeners const buttons = document.getElementsByClassName('btn'); for (const button of buttons) { button.addEventListener('click', createRipple); } // Initialize on load initialize(); }); </script> </body> </html>
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Sofia Chen - UX/UI Portfolio</title> <style> @import url('https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@300;400;500;600;700&display=swap'); :root { --primary: #2A2A5A; --secondary: #5A5ABA; --accent: #FAB68A; --light: #F8F7FF; --dark: #1A1A2E; --transition: all 0.4s cubic-bezier(0.16, 1, 0.3, 1); } * { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: 'Space Grotesk', sans-serif; background: linear-gradient(145deg, var(--light), #F0EEFF); color: var(--dark); line-height: 1.6; overflow-x: hidden; height: 100vh; display: flex; flex-direction: column; } .container { max-width: 650px; margin: 0 auto; padding: 20px; height: 100%; display: flex; flex-direction: column; } header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 30px; } .logo { font-weight: 700; font-size: 1.2rem; color: var(--primary); display: flex; align-items: center; gap: 8px; } .logo-dot { display: inline-block; width: 10px; height: 10px; background-color: var(--accent); border-radius: 50%; } nav ul { display: flex; list-style-type: none; gap: 20px; } nav a { text-decoration: none; color: var(--primary); font-weight: 500; font-size: 0.9rem; opacity: 0.8; transition: var(--transition); position: relative; } nav a:hover { opacity: 1; } nav a::after { content: ""; position: absolute; bottom: -4px; left: 0; width: 0; height: 2px; background-color: var(--accent); transition: var(--transition); } nav a:hover::after { width: 100%; } .hero { display: flex; flex-direction: column; justify-content: center; margin-bottom: 40px; flex: 1; } h1 { font-size: 2.5rem; margin-bottom: 20px; line-height: 1.2; color: var(--primary); position: relative; z-index: 1; } h1 span { position: relative; display: inline-block; } h1 span::after { content: ""; position: absolute; left: 0; bottom: 5px; width: 100%; height: 10px; background-color: var(--accent); opacity: 0.3; z-index: -1; } .subtitle { font-size: 1.1rem; color: var(--secondary); margin-bottom: 40px; max-width: 600px; font-weight: 400; } .counters { display: grid; grid-template-columns: repeat(3, 1fr); gap: 25px; margin-top: 20px; } .counter-card { background: white; border-radius: 12px; padding: 25px; box-shadow: 0 10px 30px rgba(42, 42, 90, 0.05); position: relative; overflow: hidden; transition: var(--transition); opacity: 0; transform: translateY(20px); display: flex; flex-direction: column; } .counter-card:hover { transform: translateY(-5px); box-shadow: 0 15px 40px rgba(42, 42, 90, 0.1); } .counter-card::before { content: ""; position: absolute; top: 0; left: 0; width: 5px; height: 100%; background: linear-gradient(180deg, var(--accent), var(--secondary)); opacity: 0.8; } .counter-number { font-size: 2.8rem; font-weight: 700; color: var(--primary); margin-bottom: 5px; position: relative; display: inline-block; } .counter-label { font-size: 0.9rem; color: var(--dark); opacity: 0.7; font-weight: 500; } .portfolio-preview { display: flex; gap: 20px; margin-top: 40px; overflow-x: auto; padding-bottom: 20px; scroll-behavior: smooth; -ms-overflow-style: none; scrollbar-width: none; } .portfolio-preview::-webkit-scrollbar { display: none; } .project-card { flex: 0 0 200px; height: 120px; background: rgba(255, 255, 255, 0.7); border-radius: 10px; display: flex; align-items: center; justify-content: center; position: relative; overflow: hidden; cursor: pointer; box-shadow: 0 5px 15px rgba(42, 42, 90, 0.05); transition: var(--transition); opacity: 0; transform: translateY(20px); } .project-card:hover { transform: translateY(-5px) scale(1.02); box-shadow: 0 10px 25px rgba(42, 42, 90, 0.1); } .project-bg { position: absolute; top: 0; left: 0; width: 100%; height: 100%; background-size: cover; background-position: center; opacity: 0.7; transition: var(--transition); } .project-card:hover .project-bg { opacity: 0.9; transform: scale(1.1); } .project-title { position: relative; z-index: 2; color: white; font-weight: 600; text-shadow: 0 2px 4px rgba(0, 0, 0, 0.4); padding: 10px; text-align: center; font-size: 0.9rem; } .project-card::after { content: ""; position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: linear-gradient(0deg, rgba(26, 26, 46, 0.7) 0%, rgba(26, 26, 46, 0.3) 100%); } .cursor { width: 20px; height: 20px; border-radius: 50%; background-color: var(--accent); position: fixed; pointer-events: none; mix-blend-mode: difference; z-index: 1000; transform: translate(-50%, -50%); opacity: 0.7; transition: transform 0.1s ease, opacity 0.2s ease; } @media (max-width: 768px) { .counters { grid-template-columns: repeat(2, 1fr); } h1 { font-size: 2rem; } .subtitle { font-size: 1rem; } nav ul { gap: 15px; } } @media (max-width: 480px) { .counters { grid-template-columns: 1fr; } .logo { font-size: 1rem; } nav a { font-size: 0.8rem; } h1 { font-size: 1.8rem; } } /* Animation keyframes */ @keyframes fadeInUp { from { opacity: 0; transform: translateY(20px); } to { opacity: 1; transform: translateY(0); } } /* Additional decorative element */ .decoration { position: absolute; z-index: -1; } .deco-circle { width: 300px; height: 300px; border-radius: 50%; background: linear-gradient(135deg, rgba(250, 182, 138, 0.1), rgba(90, 90, 186, 0.1)); top: -150px; right: -150px; } .deco-line { width: 100px; height: 3px; background-color: var(--accent); opacity: 0.2; bottom: 50px; left: 20px; } .marquee { position: fixed; bottom: 0; left: 0; width: 100%; overflow: hidden; height: 30px; background-color: var(--primary); color: white; display: flex; align-items: center; font-size: 0.8rem; letter-spacing: 1px; opacity: 0.9; } .marquee-content { display: flex; animation: marquee 20s linear infinite; white-space: nowrap; } .marquee-item { margin-right: 30px; display: flex; align-items: center; } .marquee-item::before { content: "•"; margin-right: 10px; color: var(--accent); } @keyframes marquee { 0% { transform: translateX(0); } 100% { transform: translateX(-50%); } } </style> </head> <body> <div class="cursor"></div> <div class="decoration deco-circle"></div> <div class="decoration deco-line"></div> <div class="container"> <header> <div class="logo"> <span class="logo-dot"></span> SOFIA CHEN </div> <nav> <ul> <li><a href="#work">Work</a></li> <li><a href="#about">About</a></li> <li><a href="#contact">Contact</a></li> </ul> </nav> </header> <section class="hero"> <h1>Crafting <span>digital</span> experiences with purpose</h1> <p class="subtitle">I specialize in creating accessible and intuitive interfaces that solve real user problems, focusing on fintech and healthcare sectors.</p> <div class="counters"> <div class="counter-card" data-count="42" data-label="Projects Completed"> <div class="counter-number">0</div> <div class="counter-label">Projects Completed</div> </div> <div class="counter-card" data-count="98" data-label="Client Satisfaction"> <div class="counter-number">0</div> <div class="counter-label">Client Satisfaction %</div> </div> <div class="counter-card" data-count="7" data-label="Years Experience"> <div class="counter-number">0</div> <div class="counter-label">Years Experience</div> </div> </div> </section> <section class="portfolio-preview"> <div class="project-card"> <div class="project-bg" style="background-image: url('https://source.unsplash.com/random/400x300?finance,app')"></div> <div class="project-title">FinFlow Banking App</div> </div> <div class="project-card"> <div class="project-bg" style="background-image: url('https://source.unsplash.com/random/400x300?healthcare,dashboard')"></div> <div class="project-title">MediTrack Dashboard</div> </div> <div class="project-card"> <div class="project-bg" style="background-image: url('https://source.unsplash.com/random/400x300?ecommerce')"></div> <div class="project-title">EcoShop Redesign</div> </div> <div class="project-card"> <div class="project-bg" style="background-image: url('https://source.unsplash.com/random/400x300?travel,app')"></div> <div class="project-title">Wanderlust App</div> </div> </section> </div> <div class="marquee"> <div class="marquee-content"> <div class="marquee-item">Mobile-first approach</div> <div class="marquee-item">Accessible design advocate</div> <div class="marquee-item">Design systems expert</div> <div class="marquee-item">User research enthusiast</div> <div class="marquee-item">Problem solver</div> <div class="marquee-item">Micro-interaction specialist</div> <div class="marquee-item">Mobile-first approach</div> <div class="marquee-item">Accessible design advocate</div> <div class="marquee-item">Design systems expert</div> <div class="marquee-item">User research enthusiast</div> <div class="marquee-item">Problem solver</div> <div class="marquee-item">Micro-interaction specialist</div> </div> </div> <script> // Custom cursor const cursor = document.querySelector('.cursor'); document.addEventListener('mousemove', (e) => { cursor.style.left = e.clientX + 'px'; cursor.style.top = e.clientY + 'px'; }); document.addEventListener('mousedown', () => { cursor.style.transform = 'translate(-50%, -50%) scale(0.7)'; }); document.addEventListener('mouseup', () => { cursor.style.transform = 'translate(-50%, -50%) scale(1)'; }); document.addEventListener('mouseleave', () => { cursor.style.opacity = '0'; }); document.addEventListener('mouseenter', () => { cursor.style.opacity = '0.7'; }); // Animated Counters const startCounterAnimation = () => { const counters = document.querySelectorAll('.counter-card'); counters.forEach((counter, index) => { // Delayed animation for each counter setTimeout(() => { counter.style.animation = 'fadeInUp 0.8s ease forwards'; const targetCount = parseInt(counter.dataset.count); const counterDisplay = counter.querySelector('.counter-number'); const duration = 2000; // ms const steps = 50; const increment = targetCount / steps; let currentCount = 0; const updateCounter = () => { if (currentCount < targetCount) { currentCount += increment; if (currentCount > targetCount) currentCount = targetCount; // Display integer for years experience, otherwise show one decimal if (counter.dataset.label.includes('Years')) { counterDisplay.textContent = Math.floor(currentCount); } else { counterDisplay.textContent = Math.round(currentCount); } setTimeout(updateCounter, duration / steps); } else { counterDisplay.textContent = targetCount; } }; setTimeout(updateCounter, 400); // Delay counter start for better visual }, index * 200); // Stagger each counter's appearance }); }; // Project cards animation const animateProjectCards = () => { const projectCards = document.querySelectorAll('.project-card'); projectCards.forEach((card, index) => { setTimeout(() => { card.style.animation = 'fadeInUp 0.8s ease forwards'; }, 1000 + (index * 150)); // Start after counters with staggered delay }); }; // Initialize animations when page is loaded document.addEventListener('DOMContentLoaded', () => { setTimeout(() => { startCounterAnimation(); setTimeout(animateProjectCards, 800); }, 500); }); // Marquee duplication for smooth looping document.addEventListener('DOMContentLoaded', () => { const marqueeContent = document.querySelector('.marquee-content'); const marqueeItems = document.querySelectorAll('.marquee-item'); // Clone items to ensure smooth looping marqueeItems.forEach(item => { const clone = item.cloneNode(true); marqueeContent.appendChild(clone); }); }); // Hover effect for project cards document.querySelectorAll('.project-card').forEach(card => { card.addEventListener('mouseenter', () => { cursor.style.transform = 'translate(-50%, -50%) scale(1.5)'; }); card.addEventListener('mouseleave', () => { cursor.style.transform = 'translate(-50%, -50%) scale(1)'; }); }); </script> </body> </html>
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Quantum Metrics</title> <style> @import url('https://fonts.googleapis.com/css2?family=Orbitron:wght@400;500;700;900&family=Roboto+Mono:wght@300;400;500&display=swap'); :root { --neon-blue: #00f0ff; --neon-purple: #9d00ff; --neon-green: #00ff8c; --dark-bg: #0a0a12; --darker-bg: #050508; --panel-bg: rgba(30, 30, 50, 0.3); } * { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: 'Roboto Mono', monospace; background-color: var(--dark-bg); color: white; overflow-x: hidden; background-image: radial-gradient(circle at 10% 20%, rgba(0, 240, 255, 0.05) 0%, transparent 20%), radial-gradient(circle at 90% 80%, rgba(157, 0, 255, 0.05) 0%, transparent 20%); } .container { max-width: 700px; min-height: 700px; margin: 0 auto; padding: 2rem 1rem; position: relative; } header { text-align: center; margin-bottom: 2rem; position: relative; z-index: 10; } h1 { font-family: 'Orbitron', sans-serif; font-weight: 900; font-size: 2.2rem; margin-bottom: 0.5rem; background: linear-gradient(to right, var(--neon-blue), var(--neon-purple)); -webkit-background-clip: text; -webkit-text-fill-color: transparent; text-transform: uppercase; letter-spacing: 1px; } p.tagline { font-size: 0.9rem; opacity: 0.8; max-width: 500px; margin: 0 auto; color: #ddd; } .grid { display: grid; grid-template-columns: 1fr; gap: 2rem; position: relative; } .metric-card { background: var(--panel-bg); border-radius: 12px; padding: 1.5rem; display: flex; flex-direction: column; opacity: 0; transform: translateY(30px); transition: all 0.8s cubic-bezier(0.2, 0.8, 0.2, 1); backdrop-filter: blur(10px); border: 1px solid rgba(255, 255, 255, 0.1); box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3); position: relative; overflow: hidden; } .metric-card::before { content: ''; position: absolute; top: 0; left: 0; width: 4px; height: 100%; background: linear-gradient(to bottom, var(--neon-blue), var(--neon-purple)); } .metric-card.visible { opacity: 1; transform: translateY(0); } .metric-title { font-family: 'Orbitron', sans-serif; font-size: 0.9rem; margin-bottom: 0.5rem; letter-spacing: 1px; text-transform: uppercase; color: #fff; display: flex; align-items: center; } .metric-icon { margin-right: 8px; color: var(--neon-blue); font-size: 1.2rem; } .metric-value { font-family: 'Orbitron', sans-serif; font-size: 3rem; font-weight: 700; margin: 0.5rem 0; color: #fff; display: flex; align-items: baseline; } .metric-value .prefix { font-size: 1.5rem; margin-right: 5px; opacity: 0.7; } .metric-value .suffix { font-size: 1rem; margin-left: 5px; opacity: 0.7; } .metric-desc { font-size: 0.8rem; opacity: 0.7; margin-top: 0.5rem; line-height: 1.4; } .graph { margin-top: 1rem; height: 40px; width: 100%; position: relative; overflow: hidden; } .graph-line { position: absolute; bottom: 0; left: 0; width: 100%; height: 100%; background: linear-gradient(to right, transparent, var(--neon-blue), var(--neon-purple)); clip-path: polygon(0 100%, 15% 75%, 30% 85%, 45% 60%, 60% 55%, 75% 35%, 90% 25%, 100% 10%, 100% 100%); transform: scaleX(0); transform-origin: left; transition: transform 1.5s cubic-bezier(0.16, 1, 0.3, 1); } .graph-grid { position: absolute; top: 0; left: 0; width: 100%; height: 100%; background-image: linear-gradient(to right, rgba(255,255,255,0.05) 1px, transparent 1px), linear-gradient(to bottom, rgba(255,255,255,0.05) 1px, transparent 1px); background-size: 20px 10px; } .visible .graph-line { transform: scaleX(1); } .card-users { border-top: 1px solid var(--neon-blue); } .card-revenue { border-top: 1px solid var(--neon-purple); } .card-growth { border-top: 1px solid var(--neon-green); } .card-users .metric-value { color: var(--neon-blue); } .card-revenue .metric-value { color: var(--neon-purple); } .card-growth .metric-value { color: var(--neon-green); } .card-users .graph-line { background: linear-gradient(to right, transparent, rgba(0, 240, 255, 0.3), var(--neon-blue)); clip-path: polygon(0 100%, 10% 70%, 25% 60%, 40% 45%, 55% 50%, 70% 30%, 85% 20%, 100% 10%, 100% 100%); } .card-revenue .graph-line { background: linear-gradient(to right, transparent, rgba(157, 0, 255, 0.3), var(--neon-purple)); clip-path: polygon(0 100%, 15% 80%, 30% 75%, 45% 45%, 60% 60%, 75% 30%, 90% 25%, 100% 5%, 100% 100%); } .card-growth .graph-line { background: linear-gradient(to right, transparent, rgba(0, 255, 140, 0.3), var(--neon-green)); clip-path: polygon(0 100%, 15% 60%, 30% 55%, 45% 40%, 60% 25%, 75% 30%, 90% 20%, 100% 10%, 100% 100%); } .data-points { margin-top: 0.5rem; display: flex; font-size: 0.7rem; opacity: 0.7; } .data-point { display: flex; align-items: center; margin-right: 1rem; } .data-color { width: 8px; height: 8px; margin-right: 4px; border-radius: 50%; } .data-label { white-space: nowrap; } .data-current .data-color { background-color: var(--neon-blue); } .data-predicted .data-color { background-color: var(--neon-purple); } .glow { position: absolute; width: 200px; height: 200px; border-radius: 50%; background: radial-gradient(circle, var(--neon-blue) 0%, transparent 70%); opacity: 0.1; z-index: -1; filter: blur(30px); } .glow-1 { top: 20%; left: -100px; } .glow-2 { bottom: 30%; right: -100px; background: radial-gradient(circle, var(--neon-purple) 0%, transparent 70%); } .digital-dots { position: absolute; top: 0; left: 0; width: 100%; height: 100%; background-image: radial-gradient(rgba(255, 255, 255, 0.1) 1px, transparent 1px); background-size: 20px 20px; z-index: -1; opacity: 0.2; } .trend-indicator { font-size: 0.8rem; display: flex; align-items: center; margin-top: 0.5rem; } .trend-indicator.up { color: var(--neon-green); } .trend-indicator.down { color: #ff4d4d; } .trend-value { margin-left: 5px; font-weight: 500; } .cta-button { font-family: 'Orbitron', sans-serif; background: linear-gradient(to right, var(--neon-blue), var(--neon-purple)); color: white; border: none; padding: 0.8rem 1.5rem; border-radius: 6px; font-size: 0.9rem; cursor: pointer; margin-top: 2rem; text-transform: uppercase; letter-spacing: 1px; transition: all 0.3s ease; display: block; width: 100%; position: relative; overflow: hidden; } .cta-button:hover { transform: translateY(-2px); box-shadow: 0 5px 15px rgba(0, 240, 255, 0.4); } .cta-button::before { content: ''; position: absolute; top: 0; left: -100%; width: 100%; height: 100%; background: linear-gradient(to right, transparent, rgba(255, 255, 255, 0.3), transparent); transition: all 0.5s ease; } .cta-button:hover::before { left: 100%; } @media (min-width: 550px) { .grid { grid-template-columns: repeat(2, 1fr); } .card-growth { grid-column: 1 / -1; } h1 { font-size: 2.5rem; } .metric-value { font-size: 3.5rem; } } /* Terminal blinking cursor effect */ .cursor::after { content: '|'; animation: blink 1s step-end infinite; margin-left: 2px; opacity: 0.7; } @keyframes blink { 0%, 100% { opacity: 0; } 50% { opacity: 1; } } /* Data loading animation */ .loading-bar { height: 2px; width: 100%; background-color: rgba(255,255,255,0.1); position: relative; margin-top: 8px; overflow: hidden; } .loading-progress { position: absolute; top: 0; left: 0; height: 100%; width: 30%; background: linear-gradient(to right, var(--neon-blue), var(--neon-purple)); animation: loading 2s infinite; } @keyframes loading { 0% { left: -30%; } 100% { left: 100%; } } .noise { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 200 200' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noiseFilter'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.65' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noiseFilter)'/%3E%3C/svg%3E"); opacity: 0.03; z-index: -1; pointer-events: none; } </style> </head> <body> <div class="noise"></div> <div class="digital-dots"></div> <div class="glow glow-1"></div> <div class="glow glow-2"></div> <div class="container"> <header> <h1>Quantum<span class="cursor"></span></h1> <p class="tagline">Real-time analytics powering next-gen startups. Monitor your growth with precision.</p> <div class="loading-bar"> <div class="loading-progress"></div> </div> </header> <div class="grid"> <div class="metric-card card-users"> <div class="metric-title"> <span class="metric-icon">⚡</span> Active Users </div> <div class="metric-value"> <span class="counter" data-target="142897">0</span> </div> <div class="trend-indicator up"> <span>↑</span> <span class="trend-value">24.8% last 30 days</span> </div> <div class="metric-desc">New sign-ups accelerating with 4,200+ daily activations. Peak hours at 2-4pm EST.</div> <div class="graph"> <div class="graph-grid"></div> <div class="graph-line"></div> </div> <div class="data-points"> <div class="data-point data-current"> <div class="data-color"></div> <div class="data-label">Current</div> </div> <div class="data-point data-predicted"> <div class="data-color"></div> <div class="data-label">Predicted Q4</div> </div> </div> </div> <div class="metric-card card-revenue"> <div class="metric-title"> <span class="metric-icon">💰</span> Revenue </div> <div class="metric-value"> <span class="prefix">$</span> <span class="counter" data-target="3724501">0</span> <span class="suffix">ARR</span> </div> <div class="trend-indicator up"> <span>↑</span> <span class="trend-value">32.1% last 30 days</span> </div> <div class="metric-desc">$22.8K MRR added last week. Enterprise tier conversion rate increased by 18%.</div> <div class="graph"> <div class="graph-grid"></div> <div class="graph-line"></div> </div> <div class="data-points"> <div class="data-point data-current"> <div class="data-color"></div> <div class="data-label">Current</div> </div> <div class="data-point data-predicted"> <div class="data-color"></div> <div class="data-label">Projected Q4</div> </div> </div> </div> <div class="metric-card card-growth"> <div class="metric-title"> <span class="metric-icon">📈</span> Growth Velocity </div> <div class="metric-value"> <span class="counter" data-target="47">0</span> <span class="suffix">%</span> </div> <div class="trend-indicator up"> <span>↑</span> <span class="trend-value">12.3% over industry average</span> </div> <div class="metric-desc">Achieving 3.2x faster growth than competitors. Cohort retention 89% after 6 months.</div> <div class="graph"> <div class="graph-grid"></div> <div class="graph-line"></div> </div> <div class="data-points"> <div class="data-point data-current"> <div class="data-color"></div> <div class="data-label">Your Growth</div> </div> <div class="data-point data-predicted"> <div class="data-color"></div> <div class="data-label">Industry Benchmark</div> </div> </div> </div> </div> <button class="cta-button">Schedule Analytics Demo</button> </div> <script> // Intersection Observer for scroll animations const observer = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { entry.target.classList.add('visible'); // Start counter animation only when card is visible if (entry.target.querySelector('.counter')) { const counter = entry.target.querySelector('.counter'); const target = parseInt(counter.getAttribute('data-target')); animateCounter(counter, target); } } }); }, { root: null, threshold: 0.3, rootMargin: '0px' }); // Observe all metric cards document.querySelectorAll('.metric-card').forEach(card => { observer.observe(card); }); // Counter animation function animateCounter(counterElement, target) { const duration = 2000; // 2 seconds const startTime = performance.now(); const formatNumber = num => { return new Intl.NumberFormat().format(Math.floor(num)); }; // Special handling for smaller numbers (less than 100) const increment = target <= 100 ? 1 : Math.ceil(target / 100); let current = 0; function updateCounter(currentTime) { const elapsedTime = currentTime - startTime; const progress = Math.min(elapsedTime / duration, 1); // Use easeOutExpo for smoother ending const easeOutExpo = progress === 1 ? 1 : 1 - Math.pow(2, -10 * progress); current = Math.floor(easeOutExpo * target); counterElement.textContent = formatNumber(current); if (progress < 1) { requestAnimationFrame(updateCounter); } else { counterElement.textContent = formatNumber(target); } } requestAnimationFrame(updateCounter); } // Button click effect (no actual submission) document.querySelector('.cta-button').addEventListener('click', function(e) { e.preventDefault(); this.textContent = "Request Submitted!"; setTimeout(() => { this.textContent = "Schedule Analytics Demo"; }, 2000); }); // Trigger animations on page load for initial visibility setTimeout(() => { document.querySelectorAll('.metric-card').forEach((card, index) => { setTimeout(() => { card.classList.add('visible'); if (card.querySelector('.counter')) { const counter = card.querySelector('.counter'); const target = parseInt(counter.getAttribute('data-target')); animateCounter(counter, target); } }, index * 300); // Staggered animation }); }, 500); </script> </body> </html>
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>TechCon 2024 Countdown</title> <style> @import url('https://fonts.googleapis.com/css2?family=Poppins:wght@400;600;700;800&family=Outfit:wght@300;400;600;800&display=swap'); :root { --primary: #FF3366; --secondary: #5B4CFF; --tertiary: #00C2A8; --dark: #1A1A2E; --light: #FFFFFF; --accent: #FFD166; } * { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: 'Outfit', sans-serif; background: linear-gradient(135deg, var(--dark), #121224); color: var(--light); display: flex; justify-content: center; align-items: center; min-height: 700px; overflow: hidden; position: relative; } .container { width: 100%; max-width: 680px; padding: 20px; position: relative; z-index: 10; } /* Confetti background */ .confetti { position: absolute; width: 10px; height: 10px; opacity: 0; animation: fall linear forwards; } @keyframes fall { 0% { transform: translateY(-100px) rotate(0deg); opacity: 1; } 100% { transform: translateY(700px) rotate(360deg); opacity: 0; } } .header { text-align: center; margin-bottom: 30px; position: relative; } .event-name { font-family: 'Poppins', sans-serif; font-weight: 800; font-size: 42px; background: linear-gradient(90deg, var(--primary), var(--secondary), var(--tertiary)); -webkit-background-clip: text; background-clip: text; color: transparent; margin-bottom: 5px; letter-spacing: -0.5px; transform: translateY(-50px); opacity: 0; animation: slideDown 0.8s cubic-bezier(0.175, 0.885, 0.32, 1.275) forwards; } .tagline { font-size: 16px; color: rgba(255, 255, 255, 0.8); margin-bottom: 5px; transform: translateY(-30px); opacity: 0; animation: slideDown 0.8s 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275) forwards; } .date-location { font-size: 18px; color: var(--accent); font-weight: 600; transform: translateY(-20px); opacity: 0; animation: slideDown 0.8s 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275) forwards; margin-bottom: 10px; } @keyframes slideDown { 0% { transform: translateY(-30px); opacity: 0; } 100% { transform: translateY(0); opacity: 1; } } .countdown-container { display: flex; justify-content: center; gap: 15px; margin-bottom: 30px; } .countdown-box { background: rgba(255, 255, 255, 0.1); backdrop-filter: blur(10px); border-radius: 10px; padding: 15px 5px; width: 80px; text-align: center; box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1); border: 1px solid rgba(255, 255, 255, 0.1); transform: translateY(50px); opacity: 0; animation: slideUp 0.8s cubic-bezier(0.175, 0.885, 0.32, 1.275) forwards; } .countdown-box:nth-child(1) { animation-delay: 0.4s; } .countdown-box:nth-child(2) { animation-delay: 0.5s; } .countdown-box:nth-child(3) { animation-delay: 0.6s; } .countdown-box:nth-child(4) { animation-delay: 0.7s; } @keyframes slideUp { 0% { transform: translateY(50px); opacity: 0; } 100% { transform: translateY(0); opacity: 1; } } .countdown-box .number { font-size: 32px; font-weight: 700; color: var(--light); margin-bottom: 5px; } .countdown-box .text { font-size: 14px; text-transform: uppercase; letter-spacing: 1px; color: rgba(255, 255, 255, 0.7); } .stats-container { display: flex; justify-content: space-between; margin-bottom: 40px; } .stat-box { flex: 1; text-align: center; padding: 20px; background: linear-gradient(135deg, rgba(91, 76, 255, 0.2), rgba(255, 51, 102, 0.2)); border-radius: 10px; margin: 0 8px; position: relative; overflow: hidden; transform: translateX(-50px); opacity: 0; animation: slideRight 0.8s cubic-bezier(0.175, 0.885, 0.32, 1.275) forwards; } .stat-box:nth-child(1) { animation-delay: 0.8s; } .stat-box:nth-child(2) { animation-delay: 0.9s; } .stat-box:nth-child(3) { animation-delay: 1s; } @keyframes slideRight { 0% { transform: translateX(-50px); opacity: 0; } 100% { transform: translateX(0); opacity: 1; } } .stat-box::before { content: ''; position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: linear-gradient(45deg, transparent, rgba(255, 255, 255, 0.1), transparent); transform: translateX(-100%); transition: transform 0.6s; } .stat-box:hover::before { transform: translateX(100%); } .stat-number { font-size: 28px; font-weight: 700; color: var(--light); margin-bottom: 5px; position: relative; } .stat-label { font-size: 14px; color: rgba(255, 255, 255, 0.7); } .milestone-alert { position: fixed; top: 20px; left: 50%; transform: translateX(-50%) translateY(-100px); background: var(--accent); color: var(--dark); padding: 12px 25px; border-radius: 30px; font-weight: 600; box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2); opacity: 0; transition: transform 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275), opacity 0.5s; z-index: 100; } .milestone-alert.show { transform: translateX(-50%) translateY(0); opacity: 1; } .cta-container { text-align: center; margin-top: 20px; transform: translateY(30px); opacity: 0; animation: slideUp 0.8s 1.1s cubic-bezier(0.175, 0.885, 0.32, 1.275) forwards; } .register-btn { background: linear-gradient(90deg, var(--primary), var(--secondary)); color: var(--light); border: none; padding: 15px 35px; font-size: 18px; font-weight: 600; border-radius: 30px; cursor: pointer; transition: transform 0.3s, box-shadow 0.3s; position: relative; overflow: hidden; box-shadow: 0 5px 15px rgba(91, 76, 255, 0.3); } .register-btn:hover { transform: translateY(-3px); box-shadow: 0 8px 25px rgba(91, 76, 255, 0.5); } .register-btn::after { content: ''; position: absolute; top: 50%; left: 50%; width: 5px; height: 5px; background: rgba(255, 255, 255, 0.7); border-radius: 50%; opacity: 0; transform: scale(1); } .register-btn:active::after { animation: ripple 0.6s ease-out; } @keyframes ripple { 0% { transform: scale(0); opacity: 1; } 100% { transform: scale(40); opacity: 0; } } .spots-left { font-size: 14px; color: var(--accent); margin-top: 15px; font-weight: 600; } .registration-form { background: rgba(255, 255, 255, 0.05); backdrop-filter: blur(10px); border-radius: 15px; padding: 25px; margin-top: 20px; border: 1px solid rgba(255, 255, 255, 0.1); transform: translateY(50px); opacity: 0; animation: slideUp 0.8s 1.2s cubic-bezier(0.175, 0.885, 0.32, 1.275) forwards; } .form-title { font-size: 18px; margin-bottom: 15px; color: var(--light); text-align: center; } .input-group { margin-bottom: 15px; } .input-group label { display: block; margin-bottom: 5px; font-size: 14px; color: rgba(255, 255, 255, 0.7); } .input-group input, .input-group select { width: 100%; padding: 12px 15px; background: rgba(255, 255, 255, 0.1); border: 1px solid rgba(255, 255, 255, 0.2); border-radius: 8px; color: var(--light); font-family: 'Outfit', sans-serif; transition: border-color 0.3s; } .input-group input:focus, .input-group select:focus { outline: none; border-color: var(--secondary); } .submit-btn { width: 100%; background: linear-gradient(90deg, var(--tertiary), var(--secondary)); color: var(--light); border: none; padding: 12px; border-radius: 8px; font-weight: 600; cursor: pointer; transition: transform 0.3s, box-shadow 0.3s; font-family: 'Outfit', sans-serif; font-size: 16px; margin-top: 5px; } .submit-btn:hover { transform: translateY(-2px); box-shadow: 0 5px 15px rgba(0, 194, 168, 0.3); } @media (max-width: 600px) { .event-name { font-size: 32px; } .countdown-container { gap: 10px; } .countdown-box { width: 65px; padding: 10px 5px; } .countdown-box .number { font-size: 26px; } .countdown-box .text { font-size: 12px; } .stats-container { flex-direction: column; gap: 10px; } .stat-box { margin: 5px 0; } .register-btn { padding: 12px 25px; font-size: 16px; } } /* Open/Close Form Animation */ .registration-form { max-height: 0; overflow: hidden; padding-top: 0; padding-bottom: 0; margin-top: 0; transition: max-height 0.6s cubic-bezier(0.175, 0.885, 0.32, 1.275), padding 0.6s cubic-bezier(0.175, 0.885, 0.32, 1.275), margin 0.6s cubic-bezier(0.175, 0.885, 0.32, 1.275); } .registration-form.active { max-height: 600px; padding: 25px; margin-top: 20px; } /* Pulse animation for low spots */ @keyframes pulse { 0% { transform: scale(1); } 50% { transform: scale(1.05); } 100% { transform: scale(1); } } .pulse { animation: pulse 1s infinite; color: var(--primary); } </style> </head> <body> <div class="milestone-alert" id="milestoneAlert">🎉 Milestone reached: 500 registrations!</div> <div class="container"> <div class="header"> <h1 class="event-name">TechCon 2024</h1> <p class="tagline">The ultimate tech conference for developers, designers & innovators</p> <p class="date-location">September 15-17, 2024 • San Francisco, CA</p> </div> <div class="countdown-container" id="countdown"> <div class="countdown-box"> <div class="number" id="days">00</div> <div class="text">Days</div> </div> <div class="countdown-box"> <div class="number" id="hours">00</div> <div class="text">Hours</div> </div> <div class="countdown-box"> <div class="number" id="minutes">00</div> <div class="text">Minutes</div> </div> <div class="countdown-box"> <div class="number" id="seconds">00</div> <div class="text">Seconds</div> </div> </div> <div class="stats-container"> <div class="stat-box"> <div class="stat-number" id="registrations">0</div> <div class="stat-label">Registrations</div> </div> <div class="stat-box"> <div class="stat-number" id="countries">0</div> <div class="stat-label">Countries</div> </div> <div class="stat-box"> <div class="stat-number" id="speakers">0</div> <div class="stat-label">Speakers</div> </div> </div> <div class="cta-container"> <button class="register-btn" id="registerBtn">Register Now</button> <p class="spots-left" id="spotsLeft">Limited spots remaining!</p> </div> <div class="registration-form" id="registrationForm"> <h3 class="form-title">Quick Registration</h3> <div class="input-group"> <label for="name">Full Name</label> <input type="text" id="name" placeholder="Your name"> </div> <div class="input-group"> <label for="email">Email Address</label> <input type="email" id="email" placeholder="[email protected]"> </div> <div class="input-group"> <label for="role">Your Role</label> <select id="role"> <option value="">Select your role</option> <option value="developer">Developer</option> <option value="designer">Designer</option> <option value="product">Product Manager</option> <option value="marketing">Marketing</option> <option value="other">Other</option> </select> </div> <button class="submit-btn" id="submitBtn">Secure Your Spot</button> </div> </div> <script> document.addEventListener('DOMContentLoaded', function() { // Create confetti background createConfetti(); // Set the event date - September 15, 2024 const eventDate = new Date('September 15, 2024 09:00:00').getTime(); // Stats counting animation animateStats('registrations', 0, 487, 2000); animateStats('countries', 0, 32, 1500); animateStats('speakers', 0, 45, 1800); // Update countdown timer function updateCountdown() { const now = new Date().getTime(); const distance = eventDate - now; // Calculate time units const days = Math.floor(distance / (1000 * 60 * 60 * 24)); const hours = Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)); const minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60)); const seconds = Math.floor((distance % (1000 * 60)) / 1000); // Update the countdown display document.getElementById('days').innerText = formatTime(days); document.getElementById('hours').innerText = formatTime(hours); document.getElementById('minutes').innerText = formatTime(minutes); document.getElementById('seconds').innerText = formatTime(seconds); // If the countdown is over if (distance < 0) { clearInterval(countdownInterval); document.getElementById('countdown').innerHTML = '<h2>The Event Has Started!</h2>'; } } // Add leading zero if needed function formatTime(time) { return time < 10 ? `0${time}` : time; } // Animate stats counting up function animateStats(id, start, end, duration) { let startTimestamp = null; const element = document.getElementById(id); const step = (timestamp) => { if (!startTimestamp) startTimestamp = timestamp; const progress = Math.min((timestamp - startTimestamp) / duration, 1); const value = Math.floor(progress * (end - start) + start); element.innerText = value; // Check for milestones if (id === 'registrations' && value === 450) { showMilestoneAlert('Almost there! Only 50 spots left!'); } if (progress < 1) { window.requestAnimationFrame(step); } else { // After stats animation completes, start updating them randomly if (id === 'registrations') { setTimeout(startRandomRegistrations, 3000); } } }; window.requestAnimationFrame(step); } // Update registrations randomly to simulate live updates function startRandomRegistrations() { const registrationsElement = document.getElementById('registrations'); let currentRegistrations = parseInt(registrationsElement.innerText); setInterval(() => { // Random increase between 1-3 registrations const increase = Math.floor(Math.random() * 3) + 1; currentRegistrations += increase; // Add bounce effect with class registrationsElement.classList.add('bounce'); setTimeout(() => { registrationsElement.classList.remove('bounce'); }, 300); registrationsElement.innerText = currentRegistrations; // Update spots left const spotsLeft = 600 - currentRegistrations; const spotsLeftElement = document.getElementById('spotsLeft'); if (spotsLeft <= 50) { spotsLeftElement.innerHTML = `<span class="pulse">Only ${spotsLeft} spots remaining!</span>`; } else { spotsLeftElement.innerText = `${spotsLeft} spots remaining!`; } // Check for milestones checkMilestones(currentRegistrations); }, 5000 + Math.random() * 10000); // Random interval between 5-15 seconds } // Check for registration milestones function checkMilestones(registrations) { if (registrations === 500) { showMilestoneAlert('🎉 Milestone reached: 500 registrations!'); createConfetti(50); } else if (registrations === 550) { showMilestoneAlert('🔥 We\'re on fire! 550 tech enthusiasts registered!'); createConfetti(30); } } // Show milestone alert function showMilestoneAlert(message) { const alertElement = document.getElementById('milestoneAlert'); alertElement.innerText = message; alertElement.classList.add('show'); setTimeout(() => { alertElement.classList.remove('show'); }, 4000); } // Toggle registration form document.getElementById('registerBtn').addEventListener('click', function() { const form = document.getElementById('registrationForm'); form.classList.toggle('active'); if (form.classList.contains('active')) { this.innerText = 'Hide Form'; } else { this.innerText = 'Register Now'; } }); // Handle form submission document.getElementById('submitBtn').addEventListener('click', function(e) { e.preventDefault(); const nameField = document.getElementById('name'); const emailField = document.getElementById('email'); const roleField = document.getElementById('role'); // Simple validation if (nameField.value && emailField.value && roleField.value) { // Update registrations count const registrationsElement = document.getElementById('registrations'); let currentRegistrations = parseInt(registrationsElement.innerText); currentRegistrations++; registrationsElement.innerText = currentRegistrations; // Animation for successful registration createConfetti(30); // Show success message showMilestoneAlert('🎉 Registration successful! Check your email for details.'); // Reset form and hide it nameField.value = ''; emailField.value = ''; roleField.value = ''; document.getElementById('registrationForm').classList.remove('active'); document.getElementById('registerBtn').innerText = 'Register Now'; } else { showMilestoneAlert('Please fill in all fields'); } }); // Create confetti elements function createConfetti(count = 20) { const colors = ['#FF3366', '#5B4CFF', '#00C2A8', '#FFD166']; for (let i = 0; i < count; i++) { const confetti = document.createElement('div'); confetti.className = 'confetti'; confetti.style.left = Math.random() * 100 + '%'; confetti.style.backgroundColor = colors[Math.floor(Math.random() * colors.length)]; confetti.style.width = Math.random() * 10 + 5 + 'px'; confetti.style.height = Math.random() * 10 + 5 + 'px'; confetti.style.animationDuration = Math.random() * 3 + 2 + 's'; document.body.appendChild(confetti); // Remove confetti after animation completes setTimeout(() => { confetti.remove(); }, 5000); } } // Add CSS bounce animation const style = document.createElement('style'); style.textContent = ` @keyframes bounce { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.1); } } .bounce { animation: bounce 0.3s ease; } `; document.head.appendChild(style); // Initialize countdown updateCountdown(); // Update countdown every second const countdownInterval = setInterval(updateCountdown, 1000); }); </script> </body> </html>
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Social Media Engagement Counters</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Nunito', sans-serif; } body { background: #f0f2f5; height: 100vh; display: flex; align-items: center; justify-content: center; overflow: hidden; } .container { width: 100%; max-width: 680px; padding: 20px; } .app-frame { background: white; border-radius: 24px; padding: 30px; box-shadow: 0 10px 30px rgba(0, 0, 0, 0.08); position: relative; overflow: hidden; } .app-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 25px; } .app-title { font-size: 28px; font-weight: 800; color: #333; } .post { background: #fff; border-radius: 18px; margin-bottom: 20px; padding: 20px; box-shadow: 0 4px 15px rgba(0, 0, 0, 0.05); position: relative; transition: transform 0.3s ease; } .post:hover { transform: translateY(-3px); } .post-header { display: flex; align-items: center; margin-bottom: 15px; } .avatar { width: 48px; height: 48px; border-radius: 50%; margin-right: 12px; background: linear-gradient(45deg, #ff7eb3, #ff758c); display: flex; align-items: center; justify-content: center; color: white; font-weight: bold; font-size: 18px; } .user-info { flex-grow: 1; } .username { font-weight: 700; font-size: 16px; color: #333; } .timestamp { font-size: 13px; color: #888; } .post-content { margin-bottom: 20px; font-size: 16px; line-height: 1.5; color: #444; } .post-image { width: 100%; height: 200px; border-radius: 16px; margin-bottom: 20px; object-fit: cover; } .engagement-bar { display: flex; align-items: center; justify-content: space-between; padding: 10px 0; } .counter-group { display: flex; align-items: center; cursor: pointer; position: relative; padding: 8px 16px; border-radius: 40px; transition: background 0.3s ease; } .counter-group:hover { background: rgba(0, 0, 0, 0.05); } .counter-group:active .counter-value { transform: scale(1.2); } .counter-icon { width: 28px; height: 28px; display: flex; align-items: center; justify-content: center; border-radius: 50%; margin-right: 8px; font-size: 15px; } .counter-value { font-weight: 700; font-size: 18px; transition: transform 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275); } .likes .counter-icon { background: #FF7EB3; color: white; } .likes .counter-value { color: #FF7EB3; } .comments .counter-icon { background: #7E9EFF; color: white; } .comments .counter-value { color: #7E9EFF; } .shares .counter-icon { background: #66E0C2; color: white; } .shares .counter-value { color: #66E0C2; } .ripple { position: absolute; border-radius: 50%; transform: scale(0); animation: ripple 0.6s linear; background-color: rgba(255, 255, 255, 0.7); } .is-pulsing { animation: pulse 0.5s cubic-bezier(0.4, 0, 0.6, 1); } .is-bouncing { animation: bounce 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275); } .floating-button { position: absolute; bottom: 20px; right: 20px; width: 60px; height: 60px; border-radius: 50%; background: linear-gradient(135deg, #FF7EB3, #FF758C); color: white; display: flex; align-items: center; justify-content: center; box-shadow: 0 4px 15px rgba(255, 126, 179, 0.4); cursor: pointer; z-index: 10; transition: transform 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275), box-shadow 0.3s ease; } .floating-button:hover { transform: scale(1.1); box-shadow: 0 6px 20px rgba(255, 126, 179, 0.5); } .floating-button:active { transform: scale(0.95); } .float-icon { font-size: 24px; } .floating-menu { position: absolute; bottom: 90px; right: 20px; background: white; border-radius: 20px; padding: 15px; box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1); transform: scale(0); transform-origin: bottom right; transition: transform 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275); z-index: 5; } .floating-menu.active { transform: scale(1); } .menu-item { display: flex; align-items: center; padding: 10px 15px; border-radius: 12px; margin-bottom: 8px; cursor: pointer; transition: background 0.3s ease; } .menu-item:last-child { margin-bottom: 0; } .menu-item:hover { background: #f7f8fa; } .menu-icon { width: 36px; height: 36px; border-radius: 10px; display: flex; align-items: center; justify-content: center; margin-right: 12px; color: white; font-size: 16px; } .menu-text { font-weight: 600; color: #333; } .menu-item:nth-child(1) .menu-icon { background: #FF7EB3; } .menu-item:nth-child(2) .menu-icon { background: #7E9EFF; } .menu-item:nth-child(3) .menu-icon { background: #66E0C2; } .confetti { position: absolute; width: 10px; height: 10px; border-radius: 2px; opacity: 0; pointer-events: none; } @keyframes ripple { to { transform: scale(4); opacity: 0; } } @keyframes pulse { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.1); } } @keyframes bounce { 0% { transform: scale(1); } 50% { transform: scale(1.2); } 100% { transform: scale(1); } } @keyframes confetti-fall { 0% { transform: translateY(0) rotate(0deg); opacity: 1; } 100% { transform: translateY(100px) rotate(720deg); opacity: 0; } } /* Pattern elements */ .pattern-circles { position: absolute; width: 100%; height: 100%; top: 0; left: 0; pointer-events: none; opacity: 0.5; z-index: -1; } .circle { position: absolute; border-radius: 50%; opacity: 0.1; } .c1 { width: 150px; height: 150px; background: #FF7EB3; top: -20px; left: -20px; } .c2 { width: 100px; height: 100px; background: #7E9EFF; bottom: 50px; right: -30px; } .c3 { width: 70px; height: 70px; background: #66E0C2; top: 70%; left: 10%; } /* Responsive styles */ @media (max-width: 600px) { .app-frame { padding: 20px; border-radius: 16px; } .app-title { font-size: 22px; } .post { padding: 15px; } .post-image { height: 150px; } .counter-group { padding: 6px 12px; } .counter-value { font-size: 16px; } .floating-button { width: 50px; height: 50px; } } </style> </head> <body> <div class="container"> <div class="app-frame"> <div class="pattern-circles"> <div class="circle c1"></div> <div class="circle c2"></div> <div class="circle c3"></div> </div> <div class="app-header"> <h1 class="app-title">Feed</h1> </div> <div class="post"> <div class="post-header"> <div class="avatar">JK</div> <div class="user-info"> <div class="username">Jamie Kim</div> <div class="timestamp">Just now</div> </div> </div> <div class="post-content"> Just launched a new design system for our mobile app! So excited to share this with you all. What do you think? 🚀 </div> <img src="https://images.unsplash.com/photo-1481487196290-c152efe083f5?ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=80" alt="Design system" class="post-image"> <div class="engagement-bar"> <div class="counter-group likes" data-count="124"> <div class="counter-icon">❤️</div> <div class="counter-value">124</div> </div> <div class="counter-group comments" data-count="43"> <div class="counter-icon">💬</div> <div class="counter-value">43</div> </div> <div class="counter-group shares" data-count="18"> <div class="counter-icon">🔄</div> <div class="counter-value">18</div> </div> </div> </div> <div class="post"> <div class="post-header"> <div class="avatar">AT</div> <div class="user-info"> <div class="username">Alex Torres</div> <div class="timestamp">3 min ago</div> </div> </div> <div class="post-content"> Working on micro-interactions for our app. Small details make a big difference in user experience! #UXDesign #Animation </div> <img src="https://images.unsplash.com/photo-1498050108023-c5249f4df085?ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=80" alt="Coding" class="post-image"> <div class="engagement-bar"> <div class="counter-group likes" data-count="89"> <div class="counter-icon">❤️</div> <div class="counter-value">89</div> </div> <div class="counter-group comments" data-count="24"> <div class="counter-icon">💬</div> <div class="counter-value">24</div> </div> <div class="counter-group shares" data-count="7"> <div class="counter-icon">🔄</div> <div class="counter-value">7</div> </div> </div> </div> <div class="floating-button"> <div class="float-icon">+</div> </div> <div class="floating-menu"> <div class="menu-item" data-action="like"> <div class="menu-icon">❤️</div> <div class="menu-text">Add Like</div> </div> <div class="menu-item" data-action="comment"> <div class="menu-icon">💬</div> <div class="menu-text">Add Comment</div> </div> <div class="menu-item" data-action="share"> <div class="menu-icon">🔄</div> <div class="menu-text">Add Share</div> </div> </div> </div> </div> <script> document.addEventListener('DOMContentLoaded', function() { const counterGroups = document.querySelectorAll('.counter-group'); const floatingButton = document.querySelector('.floating-button'); const floatingMenu = document.querySelector('.floating-menu'); const menuItems = document.querySelectorAll('.menu-item'); // Add ripple effect to counter groups counterGroups.forEach(group => { group.addEventListener('click', function(e) { const ripple = document.createElement('span'); ripple.classList.add('ripple'); this.appendChild(ripple); const rect = this.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`; // Increment counter const valueEl = this.querySelector('.counter-value'); let count = parseInt(this.dataset.count); count++; this.dataset.count = count; // Animate counter valueEl.classList.add('is-bouncing'); // Create confetti effect createConfetti(this); // Update counter value with animation setTimeout(() => { valueEl.textContent = count; }, 150); setTimeout(() => { ripple.remove(); valueEl.classList.remove('is-bouncing'); }, 500); }); }); // Floating button and menu floatingButton.addEventListener('click', function() { this.classList.toggle('is-pulsing'); floatingMenu.classList.toggle('active'); setTimeout(() => { this.classList.remove('is-pulsing'); }, 500); }); // Menu items menuItems.forEach(item => { item.addEventListener('click', function() { const action = this.dataset.action; let selector; switch(action) { case 'like': selector = '.likes'; break; case 'comment': selector = '.comments'; break; case 'share': selector = '.shares'; break; } // Target first post's counter const targetCounter = document.querySelector('.post:first-child ' + selector); // Simulate click on the counter if (targetCounter) { const event = new MouseEvent('click', { bubbles: true, cancelable: true, clientX: targetCounter.getBoundingClientRect().left + 20, clientY: targetCounter.getBoundingClientRect().top + 20 }); targetCounter.dispatchEvent(event); } // Close menu floatingMenu.classList.remove('active'); }); }); // Create confetti effect function createConfetti(element) { const colors = ['#FF7EB3', '#7E9EFF', '#66E0C2', '#FFEB3B']; const rect = element.getBoundingClientRect(); for (let i = 0; i < 20; i++) { const confetti = document.createElement('div'); confetti.classList.add('confetti'); const x = Math.random() * rect.width; const color = colors[Math.floor(Math.random() * colors.length)]; confetti.style.left = `${x}px`; confetti.style.top = `${rect.height / 2}px`; confetti.style.background = color; confetti.style.transform = `rotate(${Math.random() * 360}deg)`; confetti.style.animation = `confetti-fall ${0.5 + Math.random()}s forwards`; element.appendChild(confetti); setTimeout(() => { confetti.remove(); }, 1500); } } // Dynamic counter simulation setInterval(() => { const randomIndex = Math.floor(Math.random() * counterGroups.length); const randomCounter = counterGroups[randomIndex]; const shouldIncrement = Math.random() > 0.7; // 30% chance to increment if (shouldIncrement) { const valueEl = randomCounter.querySelector('.counter-value'); let count = parseInt(randomCounter.dataset.count); count++; randomCounter.dataset.count = count; valueEl.classList.add('is-pulsing'); valueEl.textContent = count; setTimeout(() => { valueEl.classList.remove('is-pulsing'); }, 500); } }, 5000); // Every 5 seconds }); </script> </body> </html>
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>QuantEdge Financial Dashboard</title> <style> @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap'); :root { --primary-blue: #0a2540; --accent-blue: #1a67d2; --light-blue: #ccd7e6; --primary-green: #00a86b; --secondary-green: #7ae2ad; --light-green: #e6f7ef; --red: #e63946; --chart-gray: #f5f7fa; --text-dark: #1a1a2e; --text-muted: #64748b; --white: #ffffff; --shadow: 0 4px 20px rgba(0, 0, 0, 0.08); --transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); } * { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif; background-color: var(--white); color: var(--text-dark); padding: 20px; max-width: 700px; margin: 0 auto; height: 100vh; display: flex; flex-direction: column; } .dashboard { display: grid; grid-template-columns: 1fr; grid-gap: 20px; flex: 1; } header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; } .logo { display: flex; align-items: center; gap: 10px; } .logo svg { width: 32px; height: 32px; } .logo h1 { font-size: 1.25rem; font-weight: 600; color: var(--primary-blue); } .time-indicator { display: flex; align-items: center; font-size: 0.85rem; color: var(--text-muted); background-color: var(--light-blue); padding: 6px 12px; border-radius: 20px; gap: 6px; } .time-indicator .pulse { width: 8px; height: 8px; background-color: var(--primary-green); border-radius: 50%; animation: pulse 2s infinite; } @keyframes pulse { 0% { transform: scale(0.95); box-shadow: 0 0 0 0 rgba(0, 168, 107, 0.7); } 70% { transform: scale(1); box-shadow: 0 0 0 6px rgba(0, 168, 107, 0); } 100% { transform: scale(0.95); box-shadow: 0 0 0 0 rgba(0, 168, 107, 0); } } .metrics-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 20px; margin-bottom: 20px; } .metric-card { background: var(--white); border-radius: 12px; padding: 20px; box-shadow: var(--shadow); position: relative; overflow: hidden; transition: var(--transition); } .metric-card:hover { transform: translateY(-4px); box-shadow: 0 8px 30px rgba(0, 0, 0, 0.12); } .metric-card::before { content: ''; position: absolute; top: 0; left: 0; width: 4px; height: 100%; background: linear-gradient(to bottom, var(--accent-blue), var(--primary-blue)); } .metric-card.gain::before { background: linear-gradient(to bottom, var(--secondary-green), var(--primary-green)); } .metric-card.loss::before { background: linear-gradient(to bottom, #ff9b9b, var(--red)); } .metric-label { font-size: 0.85rem; color: var(--text-muted); margin-bottom: 10px; display: flex; align-items: center; gap: 8px; } .metric-label svg { width: 16px; height: 16px; } .counter-value { font-size: 1.75rem; font-weight: 600; color: var(--primary-blue); display: flex; align-items: baseline; gap: 4px; } .counter-value .currency { font-size: 1rem; color: var(--text-muted); font-weight: 400; } .counter-value .unit { font-size: 0.85rem; color: var(--text-muted); font-weight: 400; margin-left: 4px; } .trend { display: flex; align-items: center; font-size: 0.85rem; margin-top: 10px; gap: 5px; } .trend.up { color: var(--primary-green); } .trend.down { color: var(--red); } .chart-container { background: var(--white); border-radius: 12px; padding: 20px; box-shadow: var(--shadow); margin-bottom: 20px; position: relative; overflow: hidden; } .chart-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 15px; } .chart-title { font-size: 1rem; font-weight: 600; color: var(--primary-blue); } .time-selector { display: flex; gap: 8px; } .time-option { font-size: 0.8rem; padding: 4px 10px; border-radius: 16px; cursor: pointer; background-color: var(--chart-gray); transition: var(--transition); } .time-option.active { background-color: var(--primary-blue); color: var(--white); } .chart { height: 200px; width: 100%; margin-top: 10px; position: relative; } .chart-line { position: absolute; bottom: 0; left: 0; width: 100%; height: 100%; fill: none; stroke: var(--accent-blue); stroke-width: 2; stroke-linecap: round; } .chart-area { position: absolute; bottom: 0; left: 0; width: 100%; height: 100%; fill: url(#gradient); opacity: 0.2; } .tooltip { position: absolute; background: var(--primary-blue); color: var(--white); padding: 8px 12px; border-radius: 6px; font-size: 0.8rem; pointer-events: none; opacity: 0; transition: opacity 0.3s; z-index: 10; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); } .tooltip:after { content: ''; position: absolute; bottom: -6px; left: 50%; transform: translateX(-50%); width: 0; height: 0; border-left: 6px solid transparent; border-right: 6px solid transparent; border-top: 6px solid var(--primary-blue); } .price-points { position: absolute; width: 100%; height: 100%; pointer-events: none; } .point { position: absolute; width: 6px; height: 6px; border-radius: 50%; background: var(--white); border: 2px solid var(--accent-blue); transform: translate(-50%, -50%); opacity: 0; transition: opacity 0.3s; } .chart-container:hover .point { opacity: 1; } .market-summary { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 15px; } .market-card { background: var(--white); border-radius: 12px; padding: 15px; box-shadow: var(--shadow); transition: var(--transition); cursor: pointer; } .market-card:hover { transform: translateY(-4px); box-shadow: 0 8px 30px rgba(0, 0, 0, 0.12); } .stock-name { font-size: 0.9rem; font-weight: 600; margin-bottom: 5px; display: flex; justify-content: space-between; } .stock-symbol { color: var(--text-muted); font-weight: normal; } .stock-price { font-size: 1.1rem; font-weight: 600; margin-bottom: 5px; } .stock-change { font-size: 0.8rem; font-weight: 500; padding: 3px 8px; border-radius: 12px; display: inline-block; } .stock-change.up { background-color: var(--light-green); color: var(--primary-green); } .stock-change.down { background-color: #fbe9e9; color: var(--red); } .mini-chart { height: 40px; width: 100%; margin-top: 10px; } .mini-line { fill: none; stroke-width: 1.5; stroke-linecap: round; } .mini-line.up { stroke: var(--primary-green); } .mini-line.down { stroke: var(--red); } .loading-bar { height: 3px; width: 100%; background-color: var(--light-blue); position: relative; overflow: hidden; border-radius: 3px; margin-bottom: 5px; } .loading-progress { height: 100%; width: 30%; background-color: var(--accent-blue); position: absolute; border-radius: 3px; animation: loading 2s infinite; } @keyframes loading { 0% { left: -30%; } 100% { left: 100%; } } .data-refresh { font-size: 0.75rem; color: var(--text-muted); text-align: center; margin-top: 5px; } @media (max-width: 600px) { .metrics-row { grid-template-columns: 1fr; } .market-summary { grid-template-columns: 1fr 1fr; } .logo h1 { font-size: 1rem; } } /* Animated counter effect */ @keyframes countUp { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } } .counter-animate { animation: countUp 0.5s ease forwards; } /* Data refresh flash effect */ @keyframes flash { 0% { color: var(--text-muted); } 50% { color: var(--primary-green); } 100% { color: var(--text-muted); } } .flash { animation: flash 1s ease-out; } </style> </head> <body> <header> <div class="logo"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="#0a2540" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <path d="M2 12h5l3-9 3 9h9"></path> <path d="M19 12l-7 7-7-7"></path> </svg> <h1>QuantEdge Analytics</h1> </div> <div class="time-indicator"> <div class="pulse"></div> <span id="live-time">Live Data</span> </div> </header> <div class="dashboard"> <div class="loading-bar"> <div class="loading-progress"></div> </div> <div class="metrics-row"> <div class="metric-card"> <div class="metric-label"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="#64748b" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <path d="M12 2v20M17 5H9.5a3.5 3.5 0 0 0 0 7h5a3.5 3.5 0 0 1 0 7H6"></path> </svg> Trading Volume </div> <div class="counter-value"> <span id="volume-counter">0</span> <span class="unit">M</span> </div> <div class="trend up"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <polyline points="18 15 12 9 6 15"></polyline> </svg> +18.7% vs yesterday </div> </div> <div class="metric-card gain"> <div class="metric-label"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="#64748b" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path> <polyline points="17 8 12 3 7 8"></polyline> <line x1="12" y1="3" x2="12" y2="15"></line> </svg> Market Value </div> <div class="counter-value"> <span class="currency">$</span> <span id="market-counter">0</span> <span class="unit">B</span> </div> <div class="trend up"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <polyline points="18 15 12 9 6 15"></polyline> </svg> +3.2% since opening </div> </div> <div class="metric-card loss"> <div class="metric-label"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="#64748b" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <circle cx="12" cy="8" r="7"></circle> <polyline points="8.21 13.89 7 23 12 20 17 23 15.79 13.88"></polyline> </svg> Market Cap </div> <div class="counter-value"> <span class="currency">$</span> <span id="cap-counter">0</span> <span class="unit">T</span> </div> <div class="trend down"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <polyline points="6 9 12 15 18 9"></polyline> </svg> -1.4% this week </div> </div> </div> <div class="chart-container"> <div class="chart-header"> <div class="chart-title">NASDAQ Composite Index</div> <div class="time-selector"> <div class="time-option">1H</div> <div class="time-option active">1D</div> <div class="time-option">1W</div> <div class="time-option">1M</div> </div> </div> <div class="chart"> <svg width="100%" height="100%" viewBox="0 0 800 200"> <defs> <linearGradient id="gradient" x1="0%" y1="0%" x2="0%" y2="100%"> <stop offset="0%" stop-color="#1a67d2" stop-opacity="0.7"/> <stop offset="100%" stop-color="#1a67d2" stop-opacity="0"/> </linearGradient> </defs> <path class="chart-line" d="M0,100 C100,80 150,130 200,110 S300,60 400,90 S550,140 650,60 S750,110 800,90"></path> <path class="chart-area" d="M0,100 C100,80 150,130 200,110 S300,60 400,90 S550,140 650,60 S750,110 800,90 V200 H0 Z"></path> </svg> <div class="price-points" id="price-points"></div> <div class="tooltip" id="tooltip"></div> </div> </div> <div class="market-summary"> <div class="market-card"> <div class="stock-name"> AAPL <span class="stock-symbol">Apple</span> </div> <div class="stock-price">$<span id="aapl-price">189.84</span></div> <div class="stock-change up">+1.79%</div> <svg class="mini-chart" viewBox="0 0 100 30"> <path class="mini-line up" d="M0,15 C10,13 20,18 30,12 C40,6 50,22 60,15 C70,8 80,17 90,10 C95,7 100,5 100,5"></path> </svg> </div> <div class="market-card"> <div class="stock-name"> MSFT <span class="stock-symbol">Microsoft</span> </div> <div class="stock-price">$<span id="msft-price">410.34</span></div> <div class="stock-change up">+2.03%</div> <svg class="mini-chart" viewBox="0 0 100 30"> <path class="mini-line up" d="M0,20 C10,18 20,15 30,10 C40,5 50,15 60,8 C70,5 80,12 90,7 C95,5 100,3 100,3"></path> </svg> </div> <div class="market-card"> <div class="stock-name"> GOOGL <span class="stock-symbol">Alphabet</span> </div> <div class="stock-price">$<span id="googl-price">147.21</span></div> <div class="stock-change down">-0.52%</div> <svg class="mini-chart" viewBox="0 0 100 30"> <path class="mini-line down" d="M0,10 C10,12 20,15 30,20 C40,22 50,18 60,25 C70,28 80,23 90,28 C95,29 100,30 100,30"></path> </svg> </div> <div class="market-card"> <div class="stock-name"> AMZN <span class="stock-symbol">Amazon</span> </div> <div class="stock-price">$<span id="amzn-price">178.75</span></div> <div class="stock-change up">+0.86%</div> <svg class="mini-chart" viewBox="0 0 100 30"> <path class="mini-line up" d="M0,15 C10,17 20,10 30,12 C40,14 50,8 60,5 C70,3 80,10 90,7 C95,6 100,5 100,5"></path> </svg> </div> </div> <div class="data-refresh" id="refresh-text"> Last update: <span id="update-time">Just now</span> </div> </div> <script> document.addEventListener('DOMContentLoaded', function() { // Counter animation function function animateCounter(elementId, targetValue, duration, prefix = '', suffix = '') { const counterElement = document.getElementById(elementId); const startValue = parseFloat(counterElement.textContent); const increment = (targetValue - startValue) / (duration / 16); let currentValue = startValue; const counterInterval = setInterval(() => { currentValue += increment; if ((increment > 0 && currentValue >= targetValue) || (increment < 0 && currentValue <= targetValue)) { clearInterval(counterInterval); currentValue = targetValue; } counterElement.textContent = currentValue.toFixed(2); counterElement.classList.add('counter-animate'); }, 16); } // Initialize counters animateCounter('volume-counter', 648.73, 1500); animateCounter('market-counter', 42.89, 1500); animateCounter('cap-counter', 2.47, 1500); // Update time function updateTime() { const now = new Date(); const hours = now.getHours().toString().padStart(2, '0'); const minutes = now.getMinutes().toString().padStart(2, '0'); const seconds = now.getSeconds().toString().padStart(2, '0'); document.getElementById('live-time').textContent = `Live Data (${hours}:${minutes}:${seconds})`; } setInterval(updateTime, 1000); updateTime(); // Create price points on chart const pricePoints = document.getElementById('price-points'); const tooltip = document.getElementById('tooltip'); const chartContainer = document.querySelector('.chart'); const points = [ { x: '9:30 AM', y: 15755.34, xPos: '5%', yPos: '40%' }, { x: '11:00 AM', y: 15812.56, xPos: '20%', yPos: '55%' }, { x: '12:30 PM', y: 15788.92, xPos: '35%', yPos: '45%' }, { x: '2:00 PM', y: 15843.12, xPos: '50%', yPos: '35%' }, { x: '3:30 PM', y: 15795.60, xPos: '65%', yPos: '60%' }, { x: '4:00 PM', y: 15832.80, xPos: '80%', yPos: '30%' }, { x: '4:30 PM', y: 15847.21, xPos: '95%', yPos: '35%' } ]; points.forEach(point => { const pointElement = document.createElement('div'); pointElement.classList.add('point'); pointElement.style.left = point.xPos; pointElement.style.top = point.yPos; pointElement.addEventListener('mouseenter', (e) => { tooltip.style.opacity = '1'; tooltip.style.left = `calc(${point.xPos} - 60px)`; tooltip.style.top = `calc(${point.yPos} - 40px)`; tooltip.textContent = `${point.x}: $${point.y.toLocaleString()}`; }); pointElement.addEventListener('mouseleave', () => { tooltip.style.opacity = '0'; }); pricePoints.appendChild(pointElement); }); // Time selector functionality const timeOptions = document.querySelectorAll('.time-option'); timeOptions.forEach(option => { option.addEventListener('click', () => { timeOptions.forEach(o => o.classList.remove('active')); option.classList.add('active'); // Simulate chart data change const chartLine = document.querySelector('.chart-line'); const chartArea = document.querySelector('.chart-area'); // Different paths for different time periods let newPath; if (option.textContent === '1H') { newPath = 'M0,100 C50,90 100,110 150,105 S250,115 300,100 S400,80 500,90 S650,105 800,90'; } else if (option.textContent === '1D') { newPath = 'M0,100 C100,80 150,130 200,110 S300,60 400,90 S550,140 650,60 S750,110 800,90'; } else if (option.textContent === '1W') { newPath = 'M0,120 C100,115 150,95 200,100 S300,80 400,70 S550,40 650,60 S750,70 800,50'; } else { newPath = 'M0,150 C100,130 150,120 200,100 S300,60 400,50 S550,70 650,30 S750,50 800,20'; } chartLine.setAttribute('d', newPath); chartArea.setAttribute('d', newPath + ' V200 H0 Z'); // Update counters with new values when time range changes if (option.textContent === '1H') { animateCounter('volume-counter', 187.42, 800); animateCounter('market-counter', 41.75, 800); } else if (option.textContent === '1D') { animateCounter('volume-counter', 648.73, 800); animateCounter('market-counter', 42.89, 800); } else if (option.textContent === '1W') { animateCounter('volume-counter', 3254.18, 800); animateCounter('market-counter', 43.21, 800); } else { animateCounter('volume-counter', 12847.37, 800); animateCounter('market-counter', 45.63, 800); } }); }); // Simulate real-time updates function simulateDataUpdates() { // Update stock prices const aaplPrice = document.getElementById('aapl-price'); const msftPrice = document.getElementById('msft-price'); const googlPrice = document.getElementById('googl-price'); const amznPrice = document.getElementById('amzn-price'); // Random fluctuations function updatePrice(element, baseValue, volatility) { const currentValue = parseFloat(element.textContent); const change = (Math.random() - 0.5) * volatility; const newValue = currentValue + change; element.textContent = newValue.toFixed(2); // Flash effect on update element.classList.add('flash'); setTimeout(() => { element.classList.remove('flash'); }, 1000); } updatePrice(aaplPrice, 189.84, 0.5); updatePrice(msftPrice, 410.34, 0.7); updatePrice(googlPrice, 147.21, 0.4); updatePrice(amznPrice, 178.75, 0.6); // Update market metrics slightly const volumeCounter = document.getElementById('volume-counter'); const marketCounter = document.getElementById('market-counter'); const capCounter = document.getElementById('cap-counter'); const volumeChange = (Math.random() - 0.4) * 2; const marketChange = (Math.random() - 0.45) * 0.1; const capChange = (Math.random() - 0.5) * 0.02; const newVolume = parseFloat(volumeCounter.textContent) + volumeChange; const newMarket = parseFloat(marketCounter.textContent) + marketChange; const newCap = parseFloat(capCounter.textContent) + capChange; volumeCounter.textContent = newVolume.toFixed(2); marketCounter.textContent = newMarket.toFixed(2); capCounter.textContent = newCap.toFixed(2); // Update last refresh time const now = new Date(); const hours = now.getHours().toString().padStart(2, '0'); const minutes = now.getMinutes().toString().padStart(2, '0'); const seconds = now.getSeconds().toString().padStart(2, '0'); document.getElementById('update-time').textContent = `${hours}:${minutes}:${seconds}`; // Flash update text const refreshText = document.getElementById('refresh-text'); refreshText.classList.add('flash'); setTimeout(() => { refreshText.classList.remove('flash'); }, 1000); } // Update data every 5 seconds setInterval(simulateDataUpdates, 5000); // First update after 2 seconds setTimeout(simulateDataUpdates, 2000); }); </script> </body> </html>
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Academia Progress Dashboard</title> <style> @import url('https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&family=Playfair+Display:wght@400;700&display=swap'); * { margin: 0; padding: 0; box-sizing: border-box; } :root { --blue-pastel: #BFDBFE; --lavender-pastel: #E9D5FF; --mint-pastel: #A7F3D0; --peach-pastel: #FECACA; --primary-text: #334155; --secondary-text: #64748B; --light-bg: #F8FAFC; } body { font-family: 'Poppins', sans-serif; background-color: var(--light-bg); color: var(--primary-text); min-height: 700px; display: flex; justify-content: center; align-items: center; overflow-x: hidden; width: 100%; padding: 20px; } .dashboard-container { width: 100%; max-width: 680px; background: white; border-radius: 16px; padding: 2rem; box-shadow: 0 10px 25px rgba(0,0,0,0.05); position: relative; overflow: hidden; } .dashboard-container::before { content: ""; position: absolute; top: 0; left: 0; width: 100%; height: 6px; background: linear-gradient(90deg, var(--blue-pastel), var(--lavender-pastel), var(--mint-pastel), var(--peach-pastel)); } .dashboard-header { margin-bottom: 2rem; opacity: 0; transform: translateY(20px); animation: fadeInUp 0.8s ease forwards; } .dashboard-title { font-family: 'Playfair Display', serif; font-size: 1.8rem; font-weight: 700; margin-bottom: 0.5rem; color: var(--primary-text); } .dashboard-subtitle { font-size: 0.95rem; color: var(--secondary-text); line-height: 1.5; } .counter-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 1.5rem; margin-bottom: 2rem; } .counter-card { background: white; border-radius: 12px; padding: 1.5rem; text-align: center; box-shadow: 0 4px 15px rgba(0,0,0,0.03); transition: transform 0.3s ease, box-shadow 0.3s ease; opacity: 0; transform: translateY(20px); position: relative; overflow: hidden; } .counter-card::after { content: ""; position: absolute; bottom: 0; left: 0; width: 100%; height: 4px; transform: scaleX(0); transform-origin: left; transition: transform 0.5s ease; } .counter-card:hover { transform: translateY(-5px); box-shadow: 0 8px 20px rgba(0,0,0,0.08); } .counter-card:hover::after { transform: scaleX(1); } .counter-card:nth-child(1)::after { background: var(--blue-pastel); } .counter-card:nth-child(2)::after { background: var(--lavender-pastel); } .counter-card:nth-child(3)::after { background: var(--mint-pastel); } .counter-card:nth-child(4)::after { background: var(--peach-pastel); } .counter-card:nth-child(1) { animation: fadeInUp 0.8s ease forwards 0.2s; background-color: rgba(191, 219, 254, 0.1); } .counter-card:nth-child(2) { animation: fadeInUp 0.8s ease forwards 0.4s; background-color: rgba(233, 213, 255, 0.1); } .counter-card:nth-child(3) { animation: fadeInUp 0.8s ease forwards 0.6s; background-color: rgba(167, 243, 208, 0.1); } .counter-card:nth-child(4) { animation: fadeInUp 0.8s ease forwards 0.8s; background-color: rgba(254, 202, 202, 0.1); } .counter-value { font-size: 2.5rem; font-weight: 600; margin-bottom: 0.5rem; display: flex; align-items: center; justify-content: center; height: 60px; } .counter-label { font-size: 0.9rem; color: var(--secondary-text); font-weight: 500; } .counter-icon { width: 40px; height: 40px; margin: 0 auto 1rem; display: flex; align-items: center; justify-content: center; border-radius: 8px; } .counter-card:nth-child(1) .counter-icon { background-color: var(--blue-pastel); } .counter-card:nth-child(2) .counter-icon { background-color: var(--lavender-pastel); } .counter-card:nth-child(3) .counter-icon { background-color: var(--mint-pastel); } .counter-card:nth-child(4) .counter-icon { background-color: var(--peach-pastel); } .progress-section { opacity: 0; transform: translateY(20px); animation: fadeInUp 0.8s ease forwards 1s; } .progress-title { font-size: 1.1rem; font-weight: 600; margin-bottom: 1rem; display: flex; align-items: center; } .progress-title svg { margin-right: 8px; } .progress-bars { display: flex; flex-direction: column; gap: 1rem; } .progress-item { margin-bottom: 1rem; } .progress-header { display: flex; justify-content: space-between; margin-bottom: 0.5rem; } .progress-name { font-size: 0.9rem; font-weight: 500; } .progress-percentage { font-size: 0.9rem; font-weight: 600; } .progress-bar { height: 8px; background-color: #EEF2F6; border-radius: 4px; overflow: hidden; } .progress-fill { height: 100%; width: 0; border-radius: 4px; transition: width 1.5s ease; } .progress-fill-1 { background: linear-gradient(90deg, var(--blue-pastel), var(--lavender-pastel)); } .progress-fill-2 { background: linear-gradient(90deg, var(--mint-pastel), var(--peach-pastel)); } .dashboard-footer { margin-top: 2rem; text-align: center; font-size: 0.85rem; color: var(--secondary-text); opacity: 0; animation: fadeInUp 0.8s ease forwards 1.2s; } @keyframes fadeInUp { from { opacity: 0; transform: translateY(20px); } to { opacity: 1; transform: translateY(0); } } .dot-pattern { position: absolute; width: 160px; height: 160px; z-index: -1; opacity: 0.5; } .dot-pattern-1 { top: -50px; right: -50px; background-image: radial-gradient(var(--blue-pastel) 2px, transparent 2px); background-size: 15px 15px; } .dot-pattern-2 { bottom: -50px; left: -50px; background-image: radial-gradient(var(--lavender-pastel) 2px, transparent 2px); background-size: 15px 15px; } @media (max-width: 600px) { .counter-grid { grid-template-columns: 1fr; gap: 1rem; } .dashboard-container { padding: 1.5rem; } .dashboard-title { font-size: 1.5rem; } .counter-value { font-size: 2rem; height: 50px; } } </style> </head> <body> <div class="dashboard-container"> <div class="dot-pattern dot-pattern-1"></div> <div class="dot-pattern dot-pattern-2"></div> <div class="dashboard-header"> <h1 class="dashboard-title">Learning Progress Dashboard</h1> <p class="dashboard-subtitle">Track your educational journey with real-time statistics and analytics to celebrate your academic achievements.</p> </div> <div class="counter-grid"> <div class="counter-card"> <div class="counter-icon"> <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M12 6.25278V19.2528M12 6.25278C10.8321 5.47686 9.24649 5 7.5 5C5.75351 5 4.16789 5.47686 3 6.25278V19.2528C4.16789 18.4769 5.75351 18 7.5 18C9.24649 18 10.8321 18.4769 12 19.2528M12 6.25278C13.1679 5.47686 14.7535 5 16.5 5C18.2465 5 19.8321 5.47686 21 6.25278V19.2528C19.8321 18.4769 18.2465 18 16.5 18C14.7535 18 13.1679 18.4769 12 19.2528" stroke="#334155" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> </svg> </div> <div class="counter-value" id="counter1">0</div> <div class="counter-label">Courses Completed</div> </div> <div class="counter-card"> <div class="counter-icon"> <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M15.75 6a3.75 3.75 0 11-7.5 0 3.75 3.75 0 017.5 0zM4.501 20.118a7.5 7.5 0 0114.998 0A17.933 17.933 0 0112 21.75c-2.676 0-5.216-.584-7.499-1.632z" stroke="#334155" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> </svg> </div> <div class="counter-value" id="counter2">0</div> <div class="counter-label">Active Learners</div> </div> <div class="counter-card"> <div class="counter-icon"> <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M12 6v6h4.5m4.5 0a9 9 0 11-18 0 9 9 0 0118 0z" stroke="#334155" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> </svg> </div> <div class="counter-value" id="counter3">0</div> <div class="counter-label">Learning Hours</div> </div> <div class="counter-card"> <div class="counter-icon"> <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M16.5 18.75h-9m9 0a3 3 0 013 3v-13.5a3 3 0 00-3-3h-9a3 3 0 00-3 3v13.5a3 3 0 003 3h9m0-18c-1.583 0-3.58-1.031-4.5-2.25m4.5 2.25c1.583 0 3.58-1.031 4.5-2.25" stroke="#334155" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> </svg> </div> <div class="counter-value" id="counter4">0</div> <div class="counter-label">Certificates Earned</div> </div> </div> <div class="progress-section"> <h2 class="progress-title"> <svg width="20" height="20" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M3.75 3v11.25A2.25 2.25 0 006 16.5h2.25M3.75 3h-1.5m1.5 0h16.5m0 0h1.5m-1.5 0v11.25A2.25 2.25 0 0118 16.5h-2.25m-7.5 0h7.5m-7.5 0L18 9m-6.75 7.5L3.75 9" stroke="#334155" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> </svg> Current Progress </h2> <div class="progress-bars"> <div class="progress-item"> <div class="progress-header"> <span class="progress-name">Course Completion Rate</span> <span class="progress-percentage" id="percentage1">0%</span> </div> <div class="progress-bar"> <div class="progress-fill progress-fill-1" id="progressBar1"></div> </div> </div> <div class="progress-item"> <div class="progress-header"> <span class="progress-name">Engagement Score</span> <span class="progress-percentage" id="percentage2">0%</span> </div> <div class="progress-bar"> <div class="progress-fill progress-fill-2" id="progressBar2"></div> </div> </div> </div> </div> <div class="dashboard-footer"> Updated just now • Real-time learning statistics </div> </div> <script> document.addEventListener('DOMContentLoaded', function() { // Counter animation function function animateCounter(element, target, duration, delay = 0) { setTimeout(() => { const startTime = performance.now(); const startValue = 0; function updateCounter(currentTime) { const elapsedTime = currentTime - startTime; const progress = Math.min(elapsedTime / duration, 1); // Easing function for smooth counter animation const easeOutQuart = 1 - Math.pow(1 - progress, 4); const currentValue = Math.floor(startValue + (target - startValue) * easeOutQuart); element.textContent = currentValue.toLocaleString(); if (progress < 1) { requestAnimationFrame(updateCounter); } } requestAnimationFrame(updateCounter); }, delay); } // Progress bar animation function function animateProgressBar(element, percentage, delay = 0) { setTimeout(() => { element.style.width = `${percentage}%`; }, delay); } // Initialize counters with animation animateCounter(document.getElementById('counter1'), 243, 2000, 500); animateCounter(document.getElementById('counter2'), 12879, 2500, 700); animateCounter(document.getElementById('counter3'), 52640, 3000, 900); animateCounter(document.getElementById('counter4'), 192, 2200, 1100); // Initialize progress bars const percentage1 = 78; const percentage2 = 92; setTimeout(() => { document.getElementById('percentage1').textContent = `${percentage1}%`; document.getElementById('percentage2').textContent = `${percentage2}%`; animateProgressBar(document.getElementById('progressBar1'), percentage1, 200); animateProgressBar(document.getElementById('progressBar2'), percentage2, 400); }, 1200); // Add scroll reveal effect for cards const observer = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { entry.target.style.opacity = 1; entry.target.style.transform = 'translateY(0)'; observer.unobserve(entry.target); } }); }, { threshold: 0.1 }); document.querySelectorAll('.counter-card').forEach(card => { observer.observe(card); }); }); </script> </body> </html>