Vault/VAULT/task-manager.html

741 lines
No EOL
23 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ADHS-Friendly Task List</title>
<style>
:root {
--lavender: #B8A9C9;
--lavender-dark: #9788AD;
--blue: #A8D8EA;
--blue-dark: #7CB8D0;
--yellow: #FFEAA7;
--yellow-dark: #FDD835;
--purple: #D4A5FF;
--purple-dark: #B57EDC;
--orange: #FFB4A2;
--orange-dark: #E8967E;
--white: #FAFAFA;
--beige: #F5F0E8;
--text-dark: #2D2D2D;
--text-light: #F5F5F5;
--card-bg: #FFFFFF;
--shadow: rgba(0, 0, 0, 0.1);
--progress-bg: #E8E8E8;
}
[data-theme="dark"] {
--white: #1A1A2E;
--beige: #16213E;
--text-dark: #F5F5F5;
--card-bg: #1F1F3A;
--shadow: rgba(0, 0, 0, 0.3);
--progress-bg: #2A2A4A;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background-color: var(--beige);
color: var(--text-dark);
line-height: 1.6;
transition: all 0.3s ease;
}
.container {
max-width: 900px;
margin: 0 auto;
padding: 20px;
}
.header {
text-align: center;
margin-bottom: 30px;
padding: 20px;
background: linear-gradient(135deg, var(--lavender), var(--purple));
border-radius: 20px;
color: white;
}
.header h1 {
font-size: 2em;
margin-bottom: 10px;
}
.dark-mode-toggle {
background: rgba(255, 255, 255, 0.2);
border: none;
color: white;
padding: 10px 20px;
border-radius: 25px;
cursor: pointer;
font-size: 14px;
transition: background 0.3s;
}
.dark-mode-toggle:hover {
background: rgba(255, 255, 255, 0.3);
}
.progress-section {
background: var(--card-bg);
padding: 20px;
border-radius: 15px;
margin-bottom: 20px;
box-shadow: 0 4px 15px var(--shadow);
}
.progress-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 15px;
}
.progress-bar {
height: 20px;
background-color: var(--progress-bg);
border-radius: 10px;
overflow: hidden;
position: relative;
}
.progress-fill {
height: 100%;
background: linear-gradient(90deg, var(--blue), var(--lavender));
border-radius: 10px;
transition: width 0.5s ease;
position: relative;
}
.progress-text {
position: absolute;
right: 10px;
top: 50%;
transform: translateY(-50%);
font-size: 12px;
color: var(--text-dark);
}
.stats {
display: flex;
justify-content: space-around;
margin-top: 15px;
flex-wrap: wrap;
gap: 10px;
}
.stat-item {
text-align: center;
padding: 10px;
background: var(--beige);
border-radius: 10px;
min-width: 80px;
}
.stat-number {
font-size: 1.5em;
font-weight: bold;
color: var(--lavender-dark);
}
.stat-label {
font-size: 0.8em;
opacity: 0.8;
}
.add-task-form {
background: var(--card-bg);
padding: 20px;
border-radius: 15px;
margin-bottom: 20px;
box-shadow: 0 4px 15px var(--shadow);
}
.form-group {
margin-bottom: 15px;
}
.form-group label {
display: block;
margin-bottom: 5px;
font-weight: 600;
}
.form-group input,
.form-group textarea,
.form-group select {
width: 100%;
padding: 12px;
border: 2px solid var(--beige);
border-radius: 10px;
font-size: 14px;
background: var(--white);
color: var(--text-dark);
transition: border-color 0.3s;
}
.form-group input:focus,
.form-group textarea:focus,
.form-group select:focus {
outline: none;
border-color: var(--lavender);
}
.add-button {
background: linear-gradient(135deg, var(--lavender), var(--purple));
color: white;
border: none;
padding: 12px 25px;
border-radius: 25px;
cursor: pointer;
font-size: 16px;
font-weight: 600;
transition: transform 0.2s, box-shadow 0.2s;
width: 100%;
}
.add-button:hover {
transform: translateY(-2px);
box-shadow: 0 5px 20px var(--shadow);
}
.task-list {
display: flex;
flex-direction: column;
gap: 15px;
}
.task-card {
background: var(--card-bg);
border-radius: 15px;
padding: 20px;
box-shadow: 0 4px 15px var(--shadow);
transition: all 0.3s ease;
border-left: 5px solid var(--lavender);
}
.task-card[data-status="todo"] {
border-left-color: var(--orange);
}
.task-card[data-status="in-progress"] {
border-left-color: var(--purple);
}
.task-card[data-status="done"] {
border-left-color: var(--blue);
}
.task-card:hover {
transform: translateY(-3px);
box-shadow: 0 6px 20px var(--shadow);
}
.task-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10px;
}
.task-title {
font-size: 1.2em;
font-weight: 600;
}
.task-priority {
padding: 5px 12px;
border-radius: 15px;
font-size: 12px;
font-weight: 600;
}
.priority-high {
background: var(--yellow);
color: var(--text-dark);
}
.priority-medium {
background: var(--orange);
color: white;
}
.priority-low {
background: var(--blue);
color: white;
}
.task-description {
color: var(--text-dark);
opacity: 0.8;
margin-bottom: 15px;
}
.task-actions {
display: flex;
gap: 10px;
flex-wrap: wrap;
align-items: center;
}
.task-action-button {
padding: 8px 15px;
border: none;
border-radius: 20px;
cursor: pointer;
font-size: 13px;
transition: all 0.2s;
}
.status-button {
background: var(--beige);
color: var(--text-dark);
}
.status-button:hover {
background: var(--lavender);
color: white;
}
.delete-button {
background: var(--orange);
color: white;
}
.delete-button:hover {
background: var(--orange-dark);
}
.timer-display {
background: var(--yellow);
color: var(--text-dark);
font-weight: 600;
padding: 8px 15px;
border-radius: 20px;
font-family: monospace;
font-size: 14px;
}
.set-timer-button {
background: var(--purple);
color: white;
}
.set-timer-button:hover {
background: var(--purple-dark);
}
.timer-input {
display: none;
margin-left: 10px;
}
.timer-input input {
padding: 8px;
border: 2px solid var(--beige);
border-radius: 10px;
width: 60px;
text-align: center;
}
.timer-input.active {
display: flex;
align-items: center;
}
.empty-state {
text-align: center;
padding: 40px;
color: var(--text-dark);
opacity: 0.6;
}
.empty-state-icon {
font-size: 4em;
margin-bottom: 20px;
}
@media (max-width: 768px) {
.container {
padding: 10px;
}
.header h1 {
font-size: 1.5em;
}
.task-actions {
flex-direction: column;
align-items: stretch;
}
.task-action-button {
width: 100%;
}
.stats {
flex-direction: column;
}
}
.fade-in {
animation: fadeIn 0.5s ease-in;
}
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.completed {
opacity: 0.7;
}
.completed .task-title {
text-decoration: line-through;
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>📋 Meine Aufgaben</h1>
<button class="dark-mode-toggle" onclick="toggleDarkMode()">🌙 Dark Mode</button>
</div>
<div class="progress-section">
<div class="progress-header">
<h3>Fortschritt</h3>
<span id="progress-percentage">0%</span>
</div>
<div class="progress-bar">
<div class="progress-fill" id="progress-fill" style="width: 0%">
<span class="progress-text">0%</span>
</div>
</div>
<div class="stats">
<div class="stat-item">
<div class="stat-number" id="total-count">0</div>
<div class="stat-label">Gesamt</div>
</div>
<div class="stat-item">
<div class="stat-number" id="todo-count">0</div>
<div class="stat-label">Zu tun</div>
</div>
<div class="stat-item">
<div class="stat-number" id="in-progress-count">0</div>
<div class="stat-label">In Arbeit</div>
</div>
<div class="stat-item">
<div class="stat-number" id="done-count">0</div>
<div class="stat-label">Erledigt</div>
</div>
</div>
</div>
<div class="add-task-form">
<h3>Neue Aufgabe hinzufügen</h3>
<div class="form-group">
<label for="task-title">Titel</label>
<input type="text" id="task-title" placeholder="Was muss erledigt werden?">
</div>
<div class="form-group">
<label for="task-description">Beschreibung</label>
<textarea id="task-description" rows="3" placeholder="Optionale Beschreibung..."></textarea>
</div>
<div class="form-group">
<label for="task-priority">Priorität</label>
<select id="task-priority">
<option value="high">🔴 Hoch (Dringend)</option>
<option value="medium" selected>🟡 Mittel</option>
<option value="low">🔵 Niedrig</option>
</select>
</div>
<button class="add-button" onclick="addTask()"> Aufgabe hinzufügen</button>
</div>
<div class="task-list" id="task-list">
<div class="empty-state">
<div class="empty-state-icon">📝</div>
<p>Noch keine Aufgaben vorhanden</p>
<p>Füge deine erste Aufgabe hinzu!</p>
</div>
</div>
</div>
<script>
let tasks = [];
let timers = {};
function generateId() {
return Date.now().toString(36) + Math.random().toString(36).substr(2);
}
function addTask() {
const title = document.getElementById('task-title').value.trim();
const description = document.getElementById('task-description').value.trim();
const priority = document.getElementById('task-priority').value;
if (!title) {
alert('Bitte gib einen Titel ein!');
return;
}
const task = {
id: generateId(),
title: title,
description: description,
priority: priority,
status: 'todo',
createdAt: new Date().toISOString(),
timerSeconds: 0
};
tasks.push(task);
saveTasks();
renderTasks();
clearForm();
}
function clearForm() {
document.getElementById('task-title').value = '';
document.getElementById('task-description').value = '';
document.getElementById('task-priority').value = 'medium';
}
function deleteTask(id) {
if (confirm('Möchtest du diese Aufgabe wirklich löschen?')) {
tasks = tasks.filter(task => task.id !== id);
if (timers[id]) {
clearInterval(timers[id]);
delete timers[id];
}
saveTasks();
renderTasks();
}
}
function changeStatus(id) {
const task = tasks.find(t => t.id === id);
if (!task) return;
const statusOrder = ['todo', 'in-progress', 'done'];
const currentIndex = statusOrder.indexOf(task.status);
task.status = statusOrder[(currentIndex + 1) % statusOrder.length];
saveTasks();
renderTasks();
}
function setTimer(id) {
const timerInput = document.querySelector(`#timer-${id}`);
const minutes = parseInt(timerInput.querySelector('input').value);
if (minutes > 0) {
task = tasks.find(t => t.id === id);
task.timerSeconds = minutes * 60;
if (timers[id]) {
clearInterval(timers[id]);
}
timers[id] = setInterval(() => {
if (task.timerSeconds > 0) {
task.timerSeconds--;
updateTimerDisplay(id);
} else {
clearInterval(timers[id]);
alert('⏰ Zeit abgelaufen!');
}
saveTasks();
}, 1000);
}
timerInput.classList.remove('active');
renderTasks();
}
function updateTimerDisplay(id) {
const task = tasks.find(t => t.id === id);
if (!task) return;
const hours = Math.floor(task.timerSeconds / 3600);
const minutes = Math.floor((task.timerSeconds % 3600) / 60);
const seconds = task.timerSeconds % 60;
const timerDisplay = document.querySelector(`#timer-display-${id}`);
if (timerDisplay) {
timerDisplay.textContent = `${String(hours).padStart(2, '0')}:${String(minutes).padStart(2, '0')}:${String(seconds).padStart(2, '0')}`;
}
}
function renderTasks() {
const taskList = document.getElementById('task-list');
if (tasks.length === 0) {
taskList.innerHTML = `
<div class="empty-state">
<div class="empty-state-icon">📝</div>
<p>Noch keine Aufgaben vorhanden</p>
<p>Füge deine erste Aufgabe hinzu!</p>
</div>
`;
updateStats();
return;
}
taskList.innerHTML = tasks.map(task => {
const statusEmoji = {
'todo': '⚪',
'in-progress': '🟣',
'done': '✅'
};
const statusLabel = {
'todo': 'Zu tun',
'in-progress': 'In Arbeit',
'done': 'Erledigt'
};
const priorityLabel = {
'high': 'Dringend',
'medium': 'Mittel',
'low': 'Niedrig'
};
const hours = Math.floor(task.timerSeconds / 3600);
const minutes = Math.floor((task.timerSeconds % 3600) / 60);
const seconds = task.timerSeconds % 60;
return `
<div class="task-card fade-in ${task.status === 'done' ? 'completed' : ''}" data-status="${task.status}">
<div class="task-header">
<span class="task-title">${statusEmoji[task.status]} ${task.title}</span>
<span class="task-priority priority-${task.priority}">${priorityLabel[task.priority]}</span>
</div>
${task.description ? `<div class="task-description">${task.description}</div>` : ''}
<div class="task-actions">
<button class="task-action-button status-button" onclick="changeStatus('${task.id}')">
${statusEmoji[task.status]} ${statusLabel[task.status]}
</button>
<button class="task-action-button set-timer-button" onclick="toggleTimerInput('${task.id}')">
⏰ Timer setzen
</button>
<div class="timer-input" id="timer-${task.id}">
<input type="number" placeholder="Min" min="1" max="180">
<button class="task-action-button" onclick="setTimer('${task.id}')">OK</button>
</div>
<span class="timer-display" id="timer-display-${task.id}">
${task.timerSeconds > 0 ? `${String(hours).padStart(2, '0')}:${String(minutes).padStart(2, '0')}:${String(seconds).padStart(2, '0')}` : '00:00:00'}
</span>
<button class="task-action-button delete-button" onclick="deleteTask('${task.id}')">
🗑️ Löschen
</button>
</div>
</div>
`;
}).join('');
updateStats();
}
function toggleTimerInput(id) {
const timerInput = document.getElementById(`timer-${id}`);
timerInput.classList.toggle('active');
}
function updateStats() {
const totalCount = tasks.length;
const todoCount = tasks.filter(t => t.status === 'todo').length;
const inProgressCount = tasks.filter(t => t.status === 'in-progress').length;
const doneCount = tasks.filter(t => t.status === 'done').length;
const progressPercent = totalCount > 0 ? Math.round((doneCount / totalCount) * 100) : 0;
document.getElementById('total-count').textContent = totalCount;
document.getElementById('todo-count').textContent = todoCount;
document.getElementById('in-progress-count').textContent = inProgressCount;
document.getElementById('done-count').textContent = doneCount;
document.getElementById('progress-percentage').textContent = `${progressPercent}%`;
document.getElementById('progress-fill').style.width = `${progressPercent}%`;
document.querySelector('.progress-fill .progress-text').textContent = `${progressPercent}%`;
}
function toggleDarkMode() {
const html = document.documentElement;
const isDark = html.getAttribute('data-theme') === 'dark';
html.setAttribute('data-theme', isDark ? 'light' : 'dark');
localStorage.setItem('darkMode', isDark ? 'false' : 'true');
}
function saveTasks() {
localStorage.setItem('adhs-tasks', JSON.stringify(tasks));
}
function loadTasks() {
const saved = localStorage.getItem('adhs-tasks');
if (saved) {
tasks = JSON.parse(saved);
}
}
function loadDarkMode() {
const isDark = localStorage.getItem('darkMode') === 'true';
if (isDark) {
document.documentElement.setAttribute('data-theme', 'dark');
}
}
// Initialize
loadTasks();
loadDarkMode();
renderTasks();
// Add some sample tasks if empty
if (tasks.length === 0) {
tasks = [
{
id: generateId(),
title: 'Projektplan erstellen',
description: 'Entwickle einen detaillierten Fahrplan für das neue Projekt',
priority: 'high',
status: 'in-progress',
createdAt: new Date().toISOString(),
timerSeconds: 0
},
{
id: generateId(),
title: 'E-Mails beantworten',
description: 'Überprüfe deinen Posteingang und beantworte wichtige Nachrichten',
priority: 'medium',
status: 'todo',
createdAt: new Date().toISOString(),
timerSeconds: 0
},
{
id: generateId(),
title: 'Mittagessen vorbereiten',
description: 'Gesundes Mittagessen für den Tag zubereiten',
priority: 'low',
status: 'done',
createdAt: new Date().toISOString(),
timerSeconds: 0
}
];
saveTasks();
renderTasks();
}
</script>
</body>
</html>