741 lines
No EOL
23 KiB
HTML
741 lines
No EOL
23 KiB
HTML
<!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> |