Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Workout Analytics Dashboard</title> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| <script src="https://cdn.jsdelivr.net/npm/chart.js"></script> | |
| <script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-annotation@1.0.2"></script> | |
| <script src="https://kit.fontawesome.com/a076d05399.js" crossorigin="anonymous"></script> | |
| <style> | |
| .custom-scrollbar::-webkit-scrollbar { | |
| width: 6px; | |
| height: 6px; | |
| } | |
| .custom-scrollbar::-webkit-scrollbar-track { | |
| background: #f1f1f1; | |
| border-radius: 10px; | |
| } | |
| .custom-scrollbar::-webkit-scrollbar-thumb { | |
| background: #888; | |
| border-radius: 10px; | |
| } | |
| .custom-scrollbar::-webkit-scrollbar-thumb:hover { | |
| background: #555; | |
| } | |
| .chart-container { | |
| position: relative; | |
| height: 100%; | |
| width: 100%; | |
| } | |
| .progress-ring__circle { | |
| transition: stroke-dashoffset 0.5s; | |
| transform: rotate(-90deg); | |
| transform-origin: 50% 50%; | |
| } | |
| .blink { | |
| animation: blink-animation 1.5s steps(5, start) infinite; | |
| } | |
| @keyframes blink-animation { | |
| to { | |
| visibility: hidden; | |
| } | |
| } | |
| </style> | |
| </head> | |
| <body class="bg-gray-100 font-sans"> | |
| <div class="container mx-auto px-4 py-8"> | |
| <div class="flex justify-between items-center mb-8"> | |
| <h1 class="text-3xl font-bold text-gray-800">Workout Performance Analytics</h1> | |
| <div class="flex space-x-4"> | |
| <div class="relative"> | |
| <select class="appearance-none bg-white border border-gray-300 rounded-md py-2 pl-3 pr-8 text-gray-700 focus:outline-none focus:ring-2 focus:ring-blue-500"> | |
| <option>Last 7 Days</option> | |
| <option selected>Last 30 Days</option> | |
| <option>Last 90 Days</option> | |
| <option>Custom Range</option> | |
| </select> | |
| <div class="pointer-events-none absolute inset-y-0 right-0 flex items-center px-2 text-gray-700"> | |
| <i class="fas fa-chevron-down"></i> | |
| </div> | |
| </div> | |
| <button class="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-md flex items-center"> | |
| <i class="fas fa-download mr-2"></i> Export | |
| </button> | |
| </div> | |
| </div> | |
| <!-- Summary Cards --> | |
| <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 mb-8"> | |
| <div class="bg-white rounded-xl shadow-md p-6 flex items-center"> | |
| <div class="p-3 rounded-full bg-blue-100 text-blue-600 mr-4"> | |
| <i class="fas fa-dumbbell text-xl"></i> | |
| </div> | |
| <div> | |
| <p class="text-gray-500 text-sm">Total Volume</p> | |
| <h3 class="text-2xl font-bold">12,450 kg</h3> | |
| <p class="text-green-500 text-sm flex items-center"> | |
| <i class="fas fa-arrow-up mr-1"></i> 8.2% from last month | |
| </p> | |
| </div> | |
| </div> | |
| <div class="bg-white rounded-xl shadow-md p-6 flex items-center"> | |
| <div class="p-3 rounded-full bg-purple-100 text-purple-600 mr-4"> | |
| <i class="fas fa-clock text-xl"></i> | |
| </div> | |
| <div> | |
| <p class="text-gray-500 text-sm">Avg Rest Time</p> | |
| <h3 class="text-2xl font-bold">72s</h3> | |
| <p class="text-red-500 text-sm flex items-center"> | |
| <i class="fas fa-arrow-down mr-1"></i> 5.3% from last month | |
| </p> | |
| </div> | |
| </div> | |
| <div class="bg-white rounded-xl shadow-md p-6 flex items-center"> | |
| <div class="p-3 rounded-full bg-green-100 text-green-600 mr-4"> | |
| <i class="fas fa-fire text-xl"></i> | |
| </div> | |
| <div> | |
| <p class="text-gray-500 text-sm">Workout Intensity</p> | |
| <h3 class="text-2xl font-bold">78%</h3> | |
| <p class="text-green-500 text-sm flex items-center"> | |
| <i class="fas fa-arrow-up mr-1"></i> 12.1% from last month | |
| </p> | |
| </div> | |
| </div> | |
| <div class="bg-white rounded-xl shadow-md p-6 flex items-center"> | |
| <div class="p-3 rounded-full bg-orange-100 text-orange-600 mr-4"> | |
| <i class="fas fa-heartbeat text-xl"></i> | |
| </div> | |
| <div> | |
| <p class="text-gray-500 text-sm">Avg Heart Rate</p> | |
| <h3 class="text-2xl font-bold">142 bpm</h3> | |
| <p class="text-green-500 text-sm flex items-center"> | |
| <i class="fas fa-arrow-up mr-1"></i> 3.7% from last month | |
| </p> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Main Charts --> | |
| <div class="grid grid-cols-1 lg:grid-cols-2 gap-8 mb-8"> | |
| <!-- Workout Volume & Intensity Chart --> | |
| <div class="bg-white rounded-xl shadow-md p-6"> | |
| <div class="flex justify-between items-center mb-4"> | |
| <h2 class="text-xl font-semibold text-gray-800">Workout Volume & Intensity</h2> | |
| <div class="flex space-x-2"> | |
| <button class="px-3 py-1 text-sm bg-blue-100 text-blue-600 rounded-md">Volume</button> | |
| <button class="px-3 py-1 text-sm bg-gray-100 text-gray-600 rounded-md">Intensity</button> | |
| <button class="px-3 py-1 text-sm bg-gray-100 text-gray-600 rounded-md">Both</button> | |
| </div> | |
| </div> | |
| <div class="chart-container"> | |
| <canvas id="volumeIntensityChart"></canvas> | |
| </div> | |
| </div> | |
| <!-- Rest Periods & Recovery Chart --> | |
| <div class="bg-white rounded-xl shadow-md p-6"> | |
| <div class="flex justify-between items-center mb-4"> | |
| <h2 class="text-xl font-semibold text-gray-800">Rest Periods & Recovery</h2> | |
| <div class="flex items-center text-sm text-gray-500"> | |
| <i class="fas fa-info-circle mr-1"></i> Optimal range: 60-90s | |
| </div> | |
| </div> | |
| <div class="chart-container"> | |
| <canvas id="restRecoveryChart"></canvas> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Secondary Charts --> | |
| <div class="grid grid-cols-1 lg:grid-cols-3 gap-8 mb-8"> | |
| <!-- Muscle Group Distribution --> | |
| <div class="bg-white rounded-xl shadow-md p-6"> | |
| <h2 class="text-xl font-semibold text-gray-800 mb-4">Muscle Group Distribution</h2> | |
| <div class="chart-container"> | |
| <canvas id="muscleGroupChart"></canvas> | |
| </div> | |
| </div> | |
| <!-- Weight Progression --> | |
| <div class="bg-white rounded-xl shadow-md p-6"> | |
| <h2 class="text-xl font-semibold text-gray-800 mb-4">Weight Progression</h2> | |
| <div class="chart-container"> | |
| <canvas id="weightProgressionChart"></canvas> | |
| </div> | |
| </div> | |
| <!-- Workout Consistency --> | |
| <div class="bg-white rounded-xl shadow-md p-6"> | |
| <h2 class="text-xl font-semibold text-gray-800 mb-4">Workout Consistency</h2> | |
| <div class="flex items-center justify-center h-48"> | |
| <svg class="w-40 h-40"> | |
| <circle | |
| class="text-gray-200" | |
| stroke-width="10" | |
| stroke="currentColor" | |
| fill="transparent" | |
| r="60" | |
| cx="80" | |
| cy="80" | |
| /> | |
| <circle | |
| class="progress-ring__circle text-blue-600" | |
| stroke-width="10" | |
| stroke-linecap="round" | |
| stroke="currentColor" | |
| fill="transparent" | |
| r="60" | |
| cx="80" | |
| cy="80" | |
| stroke-dasharray="377" | |
| stroke-dashoffset="75.4" | |
| /> | |
| </svg> | |
| <div class="absolute text-center"> | |
| <span class="text-3xl font-bold">80%</span> | |
| <p class="text-gray-500 text-sm">Completion Rate</p> | |
| </div> | |
| </div> | |
| <div class="mt-4 text-center"> | |
| <p class="text-gray-600">You've completed 16 of 20 planned workouts this month</p> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Detailed Metrics Table --> | |
| <div class="bg-white rounded-xl shadow-md overflow-hidden mb-8"> | |
| <div class="px-6 py-4 border-b border-gray-200 flex justify-between items-center"> | |
| <h2 class="text-xl font-semibold text-gray-800">Workout Session Details</h2> | |
| <div class="relative"> | |
| <input type="text" placeholder="Search workouts..." class="pl-8 pr-4 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"> | |
| <i class="fas fa-search absolute left-3 top-3 text-gray-400"></i> | |
| </div> | |
| </div> | |
| <div class="overflow-x-auto custom-scrollbar"> | |
| <table class="min-w-full divide-y divide-gray-200"> | |
| <thead class="bg-gray-50"> | |
| <tr> | |
| <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Date</th> | |
| <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Workout</th> | |
| <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Volume (kg)</th> | |
| <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Avg Rest</th> | |
| <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Intensity</th> | |
| <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">HR Max</th> | |
| <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Recovery</th> | |
| </tr> | |
| </thead> | |
| <tbody class="bg-white divide-y divide-gray-200"> | |
| <tr class="hover:bg-gray-50"> | |
| <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">Jun 12, 2023</td> | |
| <td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-blue-600">Upper Body</td> | |
| <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">2,450</td> | |
| <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">68s</td> | |
| <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900"> | |
| <div class="flex items-center"> | |
| <div class="h-2 w-16 bg-gray-200 rounded-full mr-2"> | |
| <div class="h-2 bg-green-500 rounded-full" style="width: 75%"></div> | |
| </div> | |
| <span>75%</span> | |
| </div> | |
| </td> | |
| <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">158 bpm</td> | |
| <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900"> | |
| <span class="px-2 py-1 text-xs rounded-full bg-green-100 text-green-800">Excellent</span> | |
| </td> | |
| </tr> | |
| <tr class="hover:bg-gray-50"> | |
| <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">Jun 10, 2023</td> | |
| <td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-blue-600">Leg Day</td> | |
| <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">3,120</td> | |
| <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">82s</td> | |
| <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900"> | |
| <div class="flex items-center"> | |
| <div class="h-2 w-16 bg-gray-200 rounded-full mr-2"> | |
| <div class="h-2 bg-yellow-500 rounded-full" style="width: 65%"></div> | |
| </div> | |
| <span>65%</span> | |
| </div> | |
| </td> | |
| <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">162 bpm</td> | |
| <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900"> | |
| <span class="px-2 py-1 text-xs rounded-full bg-yellow-100 text-yellow-800">Good</span> | |
| </td> | |
| </tr> | |
| <tr class="hover:bg-gray-50"> | |
| <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">Jun 8, 2023</td> | |
| <td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-blue-600">Full Body</td> | |
| <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">2,780</td> | |
| <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">71s</td> | |
| <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900"> | |
| <div class="flex items-center"> | |
| <div class="h-2 w-16 bg-gray-200 rounded-full mr-2"> | |
| <div class="h-2 bg-green-500 rounded-full" style="width: 80%"></div> | |
| </div> | |
| <span>80%</span> | |
| </div> | |
| </td> | |
| <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">155 bpm</td> | |
| <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900"> | |
| <span class="px-2 py-1 text-xs rounded-full bg-green-100 text-green-800">Excellent</span> | |
| </td> | |
| </tr> | |
| <tr class="hover:bg-gray-50"> | |
| <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">Jun 5, 2023</td> | |
| <td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-blue-600">Upper Body</td> | |
| <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">2,310</td> | |
| <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">65s</td> | |
| <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900"> | |
| <div class="flex items-center"> | |
| <div class="h-2 w-16 bg-gray-200 rounded-full mr-2"> | |
| <div class="h-2 bg-red-500 rounded-full" style="width: 45%"></div> | |
| </div> | |
| <span>45%</span> | |
| </div> | |
| </td> | |
| <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">148 bpm</td> | |
| <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900"> | |
| <span class="px-2 py-1 text-xs rounded-full bg-red-100 text-red-800">Poor</span> | |
| </td> | |
| </tr> | |
| </tbody> | |
| </table> | |
| </div> | |
| <div class="px-6 py-4 border-t border-gray-200 flex items-center justify-between"> | |
| <div class="text-sm text-gray-500"> | |
| Showing <span class="font-medium">1</span> to <span class="font-medium">4</span> of <span class="font-medium">16</span> workouts | |
| </div> | |
| <div class="flex space-x-2"> | |
| <button class="px-3 py-1 border border-gray-300 rounded-md text-sm bg-white text-gray-700 hover:bg-gray-50">Previous</button> | |
| <button class="px-3 py-1 border border-gray-300 rounded-md text-sm bg-blue-600 text-white hover:bg-blue-700">1</button> | |
| <button class="px-3 py-1 border border-gray-300 rounded-md text-sm bg-white text-gray-700 hover:bg-gray-50">2</button> | |
| <button class="px-3 py-1 border border-gray-300 rounded-md text-sm bg-white text-gray-700 hover:bg-gray-50">3</button> | |
| <button class="px-3 py-1 border border-gray-300 rounded-md text-sm bg-white text-gray-700 hover:bg-gray-50">Next</button> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Insights Section --> | |
| <div class="bg-white rounded-xl shadow-md p-6 mb-8"> | |
| <h2 class="text-xl font-semibold text-gray-800 mb-4">Performance Insights</h2> | |
| <div class="grid grid-cols-1 md:grid-cols-2 gap-6"> | |
| <div class="border-l-4 border-blue-500 pl-4"> | |
| <h3 class="text-lg font-medium text-gray-800 mb-2">Positive Trend</h3> | |
| <p class="text-gray-600">Your workout volume has increased by 8.2% compared to last month, indicating progressive overload which is essential for muscle growth.</p> | |
| </div> | |
| <div class="border-l-4 border-yellow-500 pl-4"> | |
| <h3 class="text-lg font-medium text-gray-800 mb-2">Attention Needed</h3> | |
| <p class="text-gray-600">Your average rest periods have decreased by 5.3%. While this may increase workout density, ensure you're getting adequate recovery between sets.</p> | |
| </div> | |
| <div class="border-l-4 border-green-500 pl-4"> | |
| <h3 class="text-lg font-medium text-gray-800 mb-2">Excellent Progress</h3> | |
| <p class="text-gray-600">Your workout intensity has improved significantly (+12.1%), showing you're pushing yourself appropriately during sessions.</p> | |
| </div> | |
| <div class="border-l-4 border-purple-500 pl-4"> | |
| <h3 class="text-lg font-medium text-gray-800 mb-2">Recommendation</h3> | |
| <p class="text-gray-600">Consider adding 1-2 additional lower body sessions per week to balance your muscle group distribution (currently 65% upper body focus).</p> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <script> | |
| // Volume & Intensity Chart | |
| const volumeIntensityCtx = document.getElementById('volumeIntensityChart').getContext('2d'); | |
| const volumeIntensityChart = new Chart(volumeIntensityCtx, { | |
| type: 'line', | |
| data: { | |
| labels: ['Week 1', 'Week 2', 'Week 3', 'Week 4', 'Week 5', 'Week 6'], | |
| datasets: [ | |
| { | |
| label: 'Workout Volume (kg)', | |
| data: [8500, 9200, 8800, 10200, 11000, 12450], | |
| borderColor: 'rgba(59, 130, 246, 1)', | |
| backgroundColor: 'rgba(59, 130, 246, 0.05)', | |
| borderWidth: 2, | |
| fill: true, | |
| tension: 0.3, | |
| yAxisID: 'y' | |
| }, | |
| { | |
| label: 'Workout Intensity (%)', | |
| data: [65, 68, 70, 72, 75, 78], | |
| borderColor: 'rgba(16, 185, 129, 1)', | |
| backgroundColor: 'rgba(16, 185, 129, 0.05)', | |
| borderWidth: 2, | |
| borderDash: [5, 5], | |
| tension: 0.3, | |
| yAxisID: 'y1' | |
| } | |
| ] | |
| }, | |
| options: { | |
| responsive: true, | |
| interaction: { | |
| mode: 'index', | |
| intersect: false, | |
| }, | |
| plugins: { | |
| tooltip: { | |
| callbacks: { | |
| label: function(context) { | |
| let label = context.dataset.label || ''; | |
| if (label) { | |
| label += ': '; | |
| } | |
| if (context.datasetIndex === 0) { | |
| label += context.parsed.y.toLocaleString() + ' kg'; | |
| } else { | |
| label += context.parsed.y + '%'; | |
| } | |
| return label; | |
| } | |
| } | |
| }, | |
| legend: { | |
| position: 'top', | |
| }, | |
| annotation: { | |
| annotations: { | |
| line1: { | |
| type: 'line', | |
| yMin: 70, | |
| yMax: 70, | |
| borderColor: 'rgba(16, 185, 129, 0.5)', | |
| borderWidth: 1, | |
| borderDash: [6, 6], | |
| label: { | |
| content: 'Target Intensity', | |
| enabled: true, | |
| position: 'right' | |
| } | |
| } | |
| } | |
| } | |
| }, | |
| scales: { | |
| y: { | |
| type: 'linear', | |
| display: true, | |
| position: 'left', | |
| title: { | |
| display: true, | |
| text: 'Volume (kg)' | |
| }, | |
| grid: { | |
| drawOnChartArea: false | |
| } | |
| }, | |
| y1: { | |
| type: 'linear', | |
| display: true, | |
| position: 'right', | |
| title: { | |
| display: true, | |
| text: 'Intensity (%)' | |
| }, | |
| min: 50, | |
| max: 100, | |
| grid: { | |
| drawOnChartArea: false | |
| } | |
| } | |
| } | |
| } | |
| }); | |
| // Rest & Recovery Chart | |
| const restRecoveryCtx = document.getElementById('restRecoveryChart').getContext('2d'); | |
| const restRecoveryChart = new Chart(restRecoveryCtx, { | |
| type: 'bar', | |
| data: { | |
| labels: ['Jun 5', 'Jun 8', 'Jun 10', 'Jun 12', 'Jun 15', 'Jun 18', 'Jun 22', 'Jun 25', 'Jun 28'], | |
| datasets: [ | |
| { | |
| label: 'Rest Period (s)', | |
| data: [65, 71, 82, 68, 75, 70, 67, 73, 69], | |
| backgroundColor: 'rgba(124, 58, 237, 0.7)', | |
| borderColor: 'rgba(124, 58, 237, 1)', | |
| borderWidth: 1, | |
| yAxisID: 'y' | |
| }, | |
| { | |
| label: 'Recovery Score', | |
| data: [62, 85, 72, 88, 78, 82, 75, 80, 84], | |
| type: 'line', | |
| borderColor: 'rgba(245, 158, 11, 1)', | |
| backgroundColor: 'rgba(245, 158, 11, 0.1)', | |
| borderWidth: 2, | |
| pointRadius: 4, | |
| pointBackgroundColor: 'rgba(245, 158, 11, 1)', | |
| tension: 0.3, | |
| yAxisID: 'y1' | |
| } | |
| ] | |
| }, | |
| options: { | |
| responsive: true, | |
| plugins: { | |
| tooltip: { | |
| callbacks: { | |
| label: function(context) { | |
| let label = context.dataset.label || ''; | |
| if (label) { | |
| label += ': '; | |
| } | |
| if (context.datasetIndex === 0) { | |
| label += context.parsed.y + 's'; | |
| } else { | |
| label += context.parsed.y + '/100'; | |
| } | |
| return label; | |
| } | |
| } | |
| }, | |
| legend: { | |
| position: 'top', | |
| }, | |
| annotation: { | |
| annotations: { | |
| box1: { | |
| type: 'box', | |
| yMin: 60, | |
| yMax: 90, | |
| backgroundColor: 'rgba(124, 58, 237, 0.05)', | |
| borderColor: 'rgba(124, 58, 237, 0.3)', | |
| borderWidth: 1, | |
| label: { | |
| content: 'Optimal Rest Range', | |
| enabled: true, | |
| position: 'top' | |
| } | |
| } | |
| } | |
| } | |
| }, | |
| scales: { | |
| y: { | |
| type: 'linear', | |
| display: true, | |
| position: 'left', | |
| title: { | |
| display: true, | |
| text: 'Rest Period (seconds)' | |
| }, | |
| min: 50, | |
| max: 100 | |
| }, | |
| y1: { | |
| type: 'linear', | |
| display: true, | |
| position: 'right', | |
| title: { | |
| display: true, | |
| text: 'Recovery Score' | |
| }, | |
| min: 50, | |
| max: 100, | |
| grid: { | |
| drawOnChartArea: false | |
| } | |
| } | |
| } | |
| } | |
| }); | |
| // Muscle Group Chart | |
| const muscleGroupCtx = document.getElementById('muscleGroupChart').getContext('2d'); | |
| const muscleGroupChart = new Chart(muscleGroupCtx, { | |
| type: 'doughnut', | |
| data: { | |
| labels: ['Chest', 'Back', 'Legs', 'Shoulders', 'Arms', 'Core'], | |
| datasets: [{ | |
| data: [25, 20, 15, 15, 15, 10], | |
| backgroundColor: [ | |
| 'rgba(59, 130, 246, 0.8)', | |
| 'rgba(16, 185, 129, 0.8)', | |
| 'rgba(245, 158, 11, 0.8)', | |
| 'rgba(124, 58, 237, 0.8)', | |
| 'rgba(239, 68, 68, 0.8)', | |
| 'rgba(14, 165, 233, 0.8)' | |
| ], | |
| borderColor: [ | |
| 'rgba(59, 130, 246, 1)', | |
| 'rgba(16, 185, 129, 1)', | |
| 'rgba(245, 158, 11, 1)', | |
| 'rgba(124, 58, 237, 1)', | |
| 'rgba(239, 68, 68, 1)', | |
| 'rgba(14, 165, 233, 1)' | |
| ], | |
| borderWidth: 1 | |
| }] | |
| }, | |
| options: { | |
| responsive: true, | |
| plugins: { | |
| legend: { | |
| position: 'right', | |
| }, | |
| tooltip: { | |
| callbacks: { | |
| label: function(context) { | |
| const label = context.label || ''; | |
| const value = context.raw || 0; | |
| const total = context.dataset.data.reduce((a, b) => a + b, 0); | |
| const percentage = Math.round((value / total) * 100); | |
| return `${label}: ${percentage}% (${value} sessions)`; | |
| } | |
| } | |
| } | |
| }, | |
| cutout: '65%' | |
| } | |
| }); | |
| // Weight Progression Chart | |
| const weightProgressionCtx = document.getElementById('weightProgressionChart').getContext('2d'); | |
| const weightProgressionChart = new Chart(weightProgressionCtx, { | |
| type: 'line', | |
| data: { | |
| labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun'], | |
| datasets: [ | |
| { | |
| label: 'Bench Press (kg)', | |
| data: [60, 62, 65, 67, 70, 72], | |
| borderColor: 'rgba(59, 130, 246, 1)', | |
| backgroundColor: 'rgba(59, 130, 246, 0.1)', | |
| borderWidth: 2, | |
| tension: 0.3, | |
| fill: true | |
| }, | |
| { | |
| label: 'Squat (kg)', | |
| data: [80, 82, 85, 87, 90, 95], | |
| borderColor: 'rgba(16, 185, 129, 1)', | |
| backgroundColor: 'rgba(16, 185, 129, 0.1)', | |
| borderWidth: 2, | |
| tension: 0.3, | |
| fill: true | |
| }, | |
| { | |
| label: 'Deadlift (kg)', | |
| data: [90, 92, 95, 100, 105, 110], | |
| borderColor: 'rgba(245, 158, 11, 1)', | |
| backgroundColor: 'rgba(245, 158, 11, 0.1)', | |
| borderWidth: 2, | |
| tension: 0.3, | |
| fill: true | |
| } | |
| ] | |
| }, | |
| options: { | |
| responsive: true, | |
| plugins: { | |
| legend: { | |
| position: 'top', | |
| }, | |
| tooltip: { | |
| callbacks: { | |
| label: function(context) { | |
| return context.dataset.label + ': ' + context.parsed.y + 'kg'; | |
| } | |
| } | |
| } | |
| }, | |
| scales: { | |
| y: { | |
| beginAtZero: false, | |
| min: 50, | |
| title: { | |
| display: true, | |
| text: 'Weight (kg)' | |
| } | |
| } | |
| } | |
| } | |
| }); | |
| // Animate progress ring | |
| document.addEventListener('DOMContentLoaded', function() { | |
| const circle = document.querySelector('.progress-ring__circle'); | |
| const radius = circle.r.baseVal.value; | |
| const circumference = 2 * Math.PI * radius; | |
| circle.style.strokeDasharray = circumference; | |
| circle.style.strokeDashoffset = circumference - (0.8 * circumference); | |
| }); | |
| </script> | |
| <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=PhoenixBomb/workout-board" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> | |
| </html> |