.progress-container {
max-width: 1000px;
margin: 0 auto;
padding: 32px 24px;
font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
background: #f8fafc;
min-height: 100vh;
}
.progress-header {
text-align: center;
margin-bottom: 40px;
}
.progress-title {
font-size: 36px;
font-weight: 700;
color: #1a202c;
margin: 0 0 12px 0;
background: linear-gradient(135deg, #667eea, #764ba2);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.progress-subtitle {
font-size: 16px;
color: #6b7280;
margin: 0;
}
.progress-content {
display: flex;
flex-direction: column;
gap: 32px;
}
/* Overall Progress */
.overall-progress {
background: white;
border-radius: 16px;
padding: 32px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05);
}
.progress-info {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 24px;
}
.progress-info h2 {
font-size: 24px;
font-weight: 600;
color: #1a202c;
margin: 0;
}
.progress-percentage {
font-size: 32px;
font-weight: 700;
color: #667eea;
}
.progress-bar-container {
margin-bottom: 24px;
}
.progress-bar {
width: 100%;
height: 12px;
background: #e5e7eb;
border-radius: 6px;
overflow: hidden;
position: relative;
}
.progress-fill {
height: 100%;
background: linear-gradient(90deg, #667eea, #764ba2);
border-radius: 6px;
transition: width 0.8s ease;
position: relative;
}
.progress-fill::after {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: linear-gradient(90deg, transparent, rgba(255,255,255,0.3), transparent);
animation: shimmer 2s infinite;
}
@keyframes shimmer {
0% { transform: translateX(-100%); }
100% { transform: translateX(100%); }
}
.progress-stats {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 24px;
}
.stat-item {
text-align: center;
padding: 16px;
background: #f8fafc;
border-radius: 12px;
}
.stat-number {
display: block;
font-size: 28px;
font-weight: 700;
color: #1a202c;
margin-bottom: 4px;
}
.stat-label {
font-size: 14px;
color: #6b7280;
font-weight: 500;
}
/* Step Progress */
.step-progress {
background: white;
border-radius: 16px;
padding: 32px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05);
}
.step-progress h2 {
font-size: 24px;
font-weight: 600;
color: #1a202c;
margin: 0 0 32px 0;
}
.steps-container {
display: flex;
flex-direction: column;
gap: 24px;
}
.step {
display: flex;
align-items: flex-start;
gap: 20px;
padding: 24px;
border-radius: 12px;
transition: all 0.3s ease;
position: relative;
}
.step::before {
content: '';
position: absolute;
left: 31px;
top: 80px;
width: 2px;
height: calc(100% + 24px);
background: #e5e7eb;
z-index: 1;
}
.step:last-child::before {
display: none;
}
.step.completed {
background: #f0fdf4;
border: 1px solid #bbf7d0;
}
.step.completed::before {
background: #22c55e;
}
.step.active {
background: #eff6ff;
border: 1px solid #bfdbfe;
}
.step.active::before {
background: linear-gradient(to bottom, #3b82f6, #e5e7eb);
}
.step.pending {
background: #f9fafb;
border: 1px solid #e5e7eb;
}
.step-indicator {
width: 48px;
height: 48px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
position: relative;
z-index: 2;
font-weight: 600;
font-size: 18px;
}
.step.completed .step-indicator {
background: #22c55e;
color: white;
}
.step.active .step-indicator {
background: #3b82f6;
color: white;
}
.step.pending .step-indicator {
background: #e5e7eb;
color: #6b7280;
}
.step-icon {
width: 24px;
height: 24px;
}
.step-content {
flex: 1;
}
.step-title {
font-size: 18px;
font-weight: 600;
color: #1a202c;
margin: 0 0 8px 0;
}
.step-description {
font-size: 14px;
color: #6b7280;
margin: 0 0 16px 0;
line-height: 1.5;
}
.step-progress-bar {
width: 100%;
height: 6px;
background: #e5e7eb;
border-radius: 3px;
overflow: hidden;
margin-bottom: 12px;
}
.step-progress-fill {
height: 100%;
background: linear-gradient(90deg, #667eea, #764ba2);
border-radius: 3px;
transition: width 0.6s ease;
}
.step-status {
font-size: 12px;
font-weight: 500;
padding: 4px 8px;
border-radius: 4px;
display: inline-block;
}
.step.completed .step-status {
background: #dcfce7;
color: #166534;
}
.step.active .step-status {
background: #dbeafe;
color: #1e40af;
}
.step.pending .step-status {
background: #f3f4f6;
color: #6b7280;
}
/* Task List */
.task-list {
background: white;
border-radius: 16px;
padding: 32px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05);
}
.task-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 24px;
}
.task-header h2 {
font-size: 24px;
font-weight: 600;
color: #1a202c;
margin: 0;
}
.add-task-btn {
display: flex;
align-items: center;
gap: 8px;
padding: 8px 16px;
background: #667eea;
color: white;
border: none;
border-radius: 8px;
font-size: 14px;
font-weight: 500;
cursor: pointer;
transition: all 0.3s ease;
}
.add-task-btn:hover {
background: #5a67d8;
transform: translateY(-1px);
}
.add-task-btn svg {
width: 16px;
height: 16px;
}
.tasks-container {
display: flex;
flex-direction: column;
gap: 16px;
}
.task-item {
display: flex;
align-items: flex-start;
gap: 16px;
padding: 20px;
border-radius: 12px;
transition: all 0.3s ease;
cursor: pointer;
}
.task-item:hover {
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}
.task-item.completed {
background: #f0fdf4;
border: 1px solid #bbf7d0;
opacity: 0.8;
}
.task-item.active {
background: #eff6ff;
border: 1px solid #bfdbfe;
}
.task-item.pending {
background: #f9fafb;
border: 1px solid #e5e7eb;
}
.task-checkbox {
position: relative;
width: 20px;
height: 20px;
margin-top: 2px;
}
.task-checkbox input {
opacity: 0;
position: absolute;
width: 100%;
height: 100%;
cursor: pointer;
}
.checkmark {
position: absolute;
top: 0;
left: 0;
width: 20px;
height: 20px;
background: white;
border: 2px solid #d1d5db;
border-radius: 4px;
transition: all 0.3s ease;
}
.task-checkbox input:checked + .checkmark {
background: #22c55e;
border-color: #22c55e;
}
.task-checkbox input:checked + .checkmark::after {
content: '✓';
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
color: white;
font-size: 12px;
font-weight: bold;
}
.task-content {
flex: 1;
}
.task-title {
font-size: 16px;
font-weight: 600;
color: #1a202c;
margin: 0 0 8px 0;
}
.task-item.completed .task-title {
text-decoration: line-through;
color: #6b7280;
}
.task-description {
font-size: 14px;
color: #6b7280;
margin: 0 0 12px 0;
line-height: 1.5;
}
.task-meta {
display: flex;
align-items: center;
gap: 12px;
}
.task-priority {
font-size: 12px;
font-weight: 500;
padding: 4px 8px;
border-radius: 4px;
text-transform: uppercase;
}
.task-priority.high {
background: #fef2f2;
color: #dc2626;
}
.task-priority.medium {
background: #fef3c7;
color: #d97706;
}
.task-priority.low {
background: #f0fdf4;
color: #16a34a;
}
.task-date {
font-size: 12px;
color: #9ca3af;
}
/* Progress Actions */
.progress-actions {
display: flex;
justify-content: center;
gap: 16px;
margin-top: 16px;
}
.action-btn {
display: flex;
align-items: center;
gap: 8px;
padding: 12px 24px;
border: none;
border-radius: 8px;
font-size: 14px;
font-weight: 500;
cursor: pointer;
transition: all 0.3s ease;
}
.action-btn svg {
width: 18px;
height: 18px;
}
.action-btn.primary {
background: #667eea;
color: white;
}
.action-btn.primary:hover {
background: #5a67d8;
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(102, 126, 234, 0.3);
}
.action-btn.secondary {
background: #f3f4f6;
color: #6b7280;
border: 1px solid #d1d5db;
}
.action-btn.secondary:hover {
background: #e5e7eb;
transform: translateY(-2px);
}
/* Responsive Design */
@media (max-width: 768px) {
.progress-container {
padding: 24px 16px;
}
.progress-title {
font-size: 28px;
}
.overall-progress,
.step-progress,
.task-list {
padding: 24px 16px;
}
.progress-stats {
grid-template-columns: 1fr;
gap: 16px;
}
.step {
flex-direction: column;
align-items: center;
text-align: center;
gap: 16px;
}
.step::before {
display: none;
}
.task-header {
flex-direction: column;
gap: 16px;
align-items: stretch;
}
.progress-actions {
flex-direction: column;
}
}
@media (max-width: 480px) {
.progress-info {
flex-direction: column;
gap: 16px;
text-align: center;
}
.task-item {
padding: 16px;
}
.task-meta {
flex-direction: column;
align-items: flex-start;
gap: 8px;
}
}
document.addEventListener('DOMContentLoaded', () => {
const overallProgressBar = document.getElementById('overallProgressBar');
const overallPercentage = document.getElementById('overallPercentage');
const completedTasks = document.getElementById('completedTasks');
const totalTasks = document.getElementById('totalTasks');
const remainingDays = document.getElementById('remainingDays');
const tasksContainer = document.getElementById('tasksContainer');
const addTaskBtn = document.getElementById('addTaskBtn');
const resetBtn = document.getElementById('resetBtn');
const updateBtn = document.getElementById('updateBtn');
let tasks = [
{
id: 1,
title: 'Set up development environment',
description: 'Configure tools and dependencies',
priority: 'high',
completed: true,
date: 'Completed 2 days ago'
},
{
id: 2,
title: 'Create database schema',
description: 'Design and implement data structure',
priority: 'medium',
completed: true,
date: 'Completed 1 day ago'
},
{
id: 3,
title: 'Implement user authentication',
description: 'Build login and registration system',
priority: 'high',
completed: false,
date: 'Due in 2 days'
},
{
id: 4,
title: 'Design user interface',
description: 'Create responsive UI components',
priority: 'medium',
completed: false,
date: 'Due in 5 days'
}
];
let steps = [
{ id: 1, title: 'Planning & Research', progress: 100, status: 'completed' },
{ id: 2, title: 'Design & Prototyping', progress: 100, status: 'completed' },
{ id: 3, title: 'Development', progress: 75, status: 'active' },
{ id: 4, title: 'Testing & QA', progress: 0, status: 'pending' },
{ id: 5, title: 'Deployment', progress: 0, status: 'pending' }
];
// Calculate overall progress
function calculateOverallProgress() {
const completedCount = tasks.filter(task => task.completed).length;
const totalCount = tasks.length;
const percentage = Math.round((completedCount / totalCount) * 100);
return {
percentage,
completed: completedCount,
total: totalCount,
remaining: Math.max(0, 10 - Math.floor(percentage / 10)) // Simulated days
};
}
// Update progress display
function updateProgressDisplay() {
const progress = calculateOverallProgress();
// Animate percentage
animateNumber(overallPercentage, parseInt(overallPercentage.textContent), progress.percentage, '%');
// Animate progress bar
const progressFill = overallProgressBar.querySelector('.progress-fill');
progressFill.style.width = progress.percentage + '%';
// Update stats
animateNumber(completedTasks, parseInt(completedTasks.textContent), progress.completed);
animateNumber(totalTasks, parseInt(totalTasks.textContent), progress.total);
animateNumber(remainingDays, parseInt(remainingDays.textContent), progress.remaining);
}
// Animate number changes
function animateNumber(element, start, end, suffix = '') {
const duration = 1000;
const startTime = performance.now();
function update(currentTime) {
const elapsed = currentTime - startTime;
const progress = Math.min(elapsed / duration, 1);
const current = Math.round(start + (end - start) * easeOutCubic(progress));
element.textContent = current + suffix;
if (progress < 1) {
requestAnimationFrame(update);
}
}
requestAnimationFrame(update);
}
function easeOutCubic(t) {
return 1 - Math.pow(1 - t, 3);
}
// Render tasks
function renderTasks() {
tasksContainer.innerHTML = '';
tasks.forEach(task => {
const taskElement = document.createElement('div');
taskElement.className = `task-item ${task.completed ? 'completed' : 'pending'}`;
taskElement.innerHTML = `
<div class="task-checkbox">
<input type="checkbox" ${task.completed ? 'checked' : ''} data-task-id="${task.id}">
<span class="checkmark"></span>
</div>
<div class="task-content">
<h4 class="task-title">${task.title}</h4>
<p class="task-description">${task.description}</p>
<div class="task-meta">
<span class="task-priority ${task.priority}">${task.priority}</span>
<span class="task-date">${task.date}</span>
</div>
</div>
`;
tasksContainer.appendChild(taskElement);
});
// Add event listeners to checkboxes
const checkboxes = tasksContainer.querySelectorAll('input[type="checkbox"]');
checkboxes.forEach(checkbox => {
checkbox.addEventListener('change', handleTaskToggle);
});
}
// Handle task completion toggle
function handleTaskToggle(e) {
const taskId = parseInt(e.target.dataset.taskId);
const task = tasks.find(t => t.id === taskId);
if (task) {
task.completed = e.target.checked;
// Update task date
if (task.completed) {
task.date = 'Completed just now';
} else {
task.date = 'Due in 3 days'; // Reset to pending
}
// Re-render tasks and update progress
renderTasks();
updateProgressDisplay();
// Add completion animation
if (task.completed) {
showCompletionAnimation(e.target.closest('.task-item'));
}
}
}
// Show completion animation
function showCompletionAnimation(taskElement) {
taskElement.style.transform = 'scale(1.02)';
taskElement.style.transition = 'transform 0.3s ease';
setTimeout(() => {
taskElement.style.transform = 'scale(1)';
}, 300);
}
// Add new task
function addNewTask() {
const taskTitles = [
'Write unit tests',
'Optimize database queries',
'Implement error handling',
'Create API documentation',
'Set up monitoring',
'Configure CI/CD pipeline',
'Perform security audit',
'Update dependencies'
];
const taskDescriptions = [
'Ensure code quality and reliability',
'Improve application performance',
'Handle edge cases gracefully',
'Document API endpoints and usage',
'Set up logging and alerts',
'Automate deployment process',
'Check for security vulnerabilities',
'Keep packages up to date'
];
const priorities = ['high', 'medium', 'low'];
const randomIndex = Math.floor(Math.random() * taskTitles.length);
const newTask = {
id: Date.now(),
title: taskTitles[randomIndex],
description: taskDescriptions[randomIndex],
priority: priorities[Math.floor(Math.random() * priorities.length)],
completed: false,
date: `Due in ${Math.floor(Math.random() * 7) + 1} days`
};
tasks.push(newTask);
renderTasks();
updateProgressDisplay();
// Scroll to new task
setTimeout(() => {
const newTaskElement = tasksContainer.lastElementChild;
newTaskElement.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
newTaskElement.style.transform = 'scale(1.05)';
setTimeout(() => {
newTaskElement.style.transform = 'scale(1)';
}, 300);
}, 100);
}
// Reset progress
function resetProgress() {
if (confirm('Are you sure you want to reset all progress? This action cannot be undone.')) {
tasks.forEach(task => {
task.completed = false;
task.date = `Due in ${Math.floor(Math.random() * 7) + 1} days`;
});
steps.forEach(step => {
if (step.id > 2) {
step.progress = 0;
step.status = 'pending';
}
});
renderTasks();
updateProgressDisplay();
updateStepProgress();
showNotification('Progress has been reset', 'info');
}
}
// Update step progress
function updateStepProgress() {
const stepElements = document.querySelectorAll('.step');
stepElements.forEach((element, index) => {
const step = steps[index];
const progressFill = element.querySelector('.step-progress-fill');
const statusElement = element.querySelector('.step-status');
progressFill.style.width = step.progress + '%';
if (step.status === 'completed') {
statusElement.textContent = 'Completed';
} else if (step.status === 'active') {
statusElement.textContent = `In Progress (${step.progress}%)`;
} else {
statusElement.textContent = 'Pending';
}
});
}
// Simulate progress update
function simulateProgressUpdate() {
const activeStep = steps.find(step => step.status === 'active');
if (activeStep && activeStep.progress < 100) {
activeStep.progress = Math.min(100, activeStep.progress + Math.floor(Math.random() * 20) + 5);
if (activeStep.progress >= 100) {
activeStep.status = 'completed';
// Move to next step
const nextStepIndex = steps.findIndex(step => step.id === activeStep.id) + 1;
if (nextStepIndex < steps.length) {
steps[nextStepIndex].status = 'active';
steps[nextStepIndex].progress = Math.floor(Math.random() * 30) + 10;
}
}
updateStepProgress();
updateProgressDisplay();
showNotification('Progress updated successfully!', 'success');
} else {
showNotification('No active tasks to update', 'info');
}
}
// Show notification
function showNotification(message, type = 'info') {
const notification = document.createElement('div');
notification.className = `notification ${type}`;
notification.textContent = message;
notification.style.cssText = `
position: fixed;
top: 20px;
right: 20px;
padding: 12px 20px;
border-radius: 8px;
color: white;
font-weight: 500;
z-index: 1000;
transform: translateX(100%);
transition: transform 0.3s ease;
`;
if (type === 'success') {
notification.style.background = '#22c55e';
} else if (type === 'info') {
notification.style.background = '#3b82f6';
} else if (type === 'warning') {
notification.style.background = '#f59e0b';
}
document.body.appendChild(notification);
// Animate in
setTimeout(() => {
notification.style.transform = 'translateX(0)';
}, 100);
// Animate out and remove
setTimeout(() => {
notification.style.transform = 'translateX(100%)';
setTimeout(() => {
document.body.removeChild(notification);
}, 300);
}, 3000);
}
// Event listeners
addTaskBtn.addEventListener('click', addNewTask);
resetBtn.addEventListener('click', resetProgress);
updateBtn.addEventListener('click', simulateProgressUpdate);
// Initialize
renderTasks();
updateProgressDisplay();
updateStepProgress();
// Auto-update simulation (optional)
setInterval(() => {
if (Math.random() < 0.1) { // 10% chance every 5 seconds
simulateProgressUpdate();
}
}, 5000);
});