My little To-do list with HTML5/CSS3 and JavaScript

My little To-do list with HTML5/CSS3 and JavaScript

Beside the Linux stuff, I try to do something more easy, even on a static (no online) webpage. Only for me.

How it looks like

The code

HTML5

<!DOCTYPE html>
<html lang="de">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Meine ToDo-Liste</title>
  <link rel="stylesheet" href="CSS/aufgabenliste.css">
</head>
<body>

  <div id="myDIV" class="header">
    <h2>My To Do List</h2>
    <div class="input-group">
      <input type="text" id="myInput" placeholder='z. B. "Milch kaufen morgen" oder "Steuer bis 31.12."' autocomplete="off">
      <span onclick="newElement()" class="addBtn">Add</span>
    </div>
  </div>

  <ul id="myUL"></ul>

  <div id="counter">Wird geladen...</div>

  <div class="backup-buttons">
    <button onclick="exportBackup()" class="backup-btn">Backup erstellen</button>
    <button onclick="document.getElementById('importFile').click()" class="backup-btn">Backup laden</button>
    <input type="file" id="importFile" accept=".json" onchange="importBackup(event)">
  </div>

  <script src="javascript/aufgabenliste.js"></script>
</body>
</html>

CSS3

/* aufgabenliste.css – finale, saubere Version */

body {

margin: 0;

min-width: 250px;

font-family: system-ui, -apple-system, sans-serif;

background: #f5f7fa;

color: #333;

}

h2 {

color: white;

margin: 0 0 20px 0;

font-size: 2em;

}

/* Box-Modell */

* { box-sizing: border-box; }

/* Zähler */

#counter {

margin: 20px 0;

font-size: 17px;

color: #680895;

text-align: center;

font-weight: 500;

}

/* Liste */

ul {

margin: 0;

padding: 0;

list-style: none;

}

ul li {

cursor: pointer;

position: relative;

padding: 14px 8px 14px 50px;

background: white;

font-size: 18px;

transition: 0.3s;

border-bottom: 1px solid #eee;

user-select: none;

}

ul li:nth-child(odd) { background: #fbfbff; }

ul li:hover { background: #f0f0ff; }

ul li.checked {

background: #680895;

color: white;

text-decoration: line-through;

}

ul li.checked::before {

content: “;

position: absolute;

border: 3px solid white;

border-width: 0 3px 3px 0;

top: 16px;

left: 18px;

transform: rotate(45deg);

height: 18px;

width: 9px;

}

/* Close-Button */

.close {

position: absolute;

right: 0;

top: 0;

padding: 14px 20px;

font-weight: bold;

font-size: 24px;

}

.close:hover {

background-color: #c20c45;

color: white;

}

/* Header */

.header {

background: linear-gradient(135deg, #07cfee, #0099cc);

padding: 40px 20px;

color: white;

text-align: center;

box-shadow: 0 4px 10px rgba(0,0,0,0.1);

}

.header:after { content: „“; display: table; clear: both; }

/* Eingabe */

.input-group {

display: flex;

gap: 10px;

flex-wrap: wrap;

align-items: center;

margin: 20px auto;

max-width: 600px;

}

#myInput {

flex: 1;

min-width: 250px;

padding: 14px;

border: none;

border-radius: 8px;

font-size: 17px;

box-shadow: 0 2px 8px rgba(0,0,0,0.1);

}

.addBtn {

padding: 14px 28px;

background: #680895;

color: white;

font-size: 17px;

border: none;

border-radius: 8px;

cursor: pointer;

transition: 0.3s;

font-weight: bold;

}

.addBtn:hover {

background: #520b77;

transform: translateY(-2px);

}

/* Fälligkeitsdatum-Anzeige */

.due-date {

margin-left: 12px;

font-size: 0.9em;

color: #555;

font-weight: 500;

}

/* Überfällig / Heute */

.li-overdue {

border-left: 6px solid #e74c3c !important;

background-color: #ffeaea !important;

font-weight: bold;

}

.li-due-today {

border-left: 6px solid #f39c12;

background-color: #fff8e1;

}

/* Backup-Buttons */

.backup-buttons {

margin: 30px 0;

text-align: center;

}

.backup-btn {

margin: 0 10px;

padding: 12px 20px;

background: white;

border: 2px solid #680895;

color: #680895;

border-radius: 8px;

cursor: pointer;

font-size: 15px;

font-weight: bold;

transition: all 0.3s ease;

}

.backup-btn:hover {

background: #680895;

color: white;

transform: translateY(-3px);

box-shadow: 0 6px 12px rgba(104, 8, 149, 0.3);

}

#importFile {

display: none;

}

JavaScript

const STORAGE_KEY = ‚todoListItems‘;

// ==================== DATUM FORMATIEREN ====================

function formatDate(dateString) {

if (!dateString) return „“;

const date = new Date(dateString);

const options = { weekday: ’short‘, day: ’numeric‘, month: ’short‘ };

return `Fällig: ${date.toLocaleDateString(‚de-DE‘, options)}`;

}

// ==================== SPEICHERN ====================

function saveTasks() {

const listItems = document.querySelectorAll(‚#myUL li‘);

const tasks = [];

listItems.forEach(item => {

tasks.push({

text: item.firstChild.textContent.trim(),

checked: item.classList.contains(‚checked‘),

dueDate: item.dataset.dueDate || null

});

});

localStorage.setItem(STORAGE_KEY, JSON.stringify(tasks));

updateCounter();

}

// ==================== LADEN ====================

function loadTasks() {

const storedTasks = localStorage.getItem(STORAGE_KEY);

if (storedTasks) {

const tasks = JSON.parse(storedTasks);

tasks.forEach(task => {

createListItem(task.text, task.checked, task.dueDate, false);

});

} else {

createListItem(„Milch kaufen morgen“, false, null, true);

createListItem(„Steuererklärung bis 31.12.“, true, null, true);

createListItem(„Eltern anrufen Freitag“, false, null, true);

}

updateCounter();

}

// ==================== NEUE AUFGABE ERSTELLEN ====================

function createListItem(text, isChecked = false, dueDate = null, shouldSave = true) {

const li = document.createElement(„li“);

li.appendChild(document.createTextNode(text));

if (isChecked) li.classList.add(‚checked‘);

if (dueDate) li.dataset.dueDate = dueDate;

if (dueDate) {

const dateSpan = document.createElement(„SPAN“);

dateSpan.className = „due-date“;

dateSpan.textContent = “ “ + formatDate(dueDate);

dateSpan.style.cssText = „margin-left: 12px; font-size: 0.9em; color: #555;“;

li.appendChild(dateSpan);

const today = new Date();

today.setHours(0, 0, 0, 0);

const due = new Date(dueDate);

due.setHours(0, 0, 0, 0);

if (due < today) li.classList.add(„li-overdue“);

else if (due.getTime() === today.getTime()) li.classList.add(„li-due-today“);

}

const span = document.createElement(„SPAN“);

span.className = „close“;

span.appendChild(document.createTextNode(„ד));

span.onclick = () => { li.remove(); saveTasks(); };

li.appendChild(span);

document.getElementById(„myUL“).appendChild(li);

if (shouldSave) saveTasks();

return li;

}

// ==================== INTELLIGENTE EINGABE ====================

function newElement() {

const input = document.getElementById(„myInput“);

const rawText = input.value.trim();

if (!rawText) { alert(„Bitte eine Aufgabe eingeben!“); return; }

let taskText = rawText;

let dueDate = null;

const heute = new Date(); heute.setHours(0,0,0,0);

const lower = rawText.toLowerCase();

// 1. Datum: 25.12. / 25.12 / 25/12 / 25-12

const dateMatch = rawText.match(/(?:\s|^)(\d{1,2})[.\-\/](\d{1,2})(?:[.\-\/](\d{2,4}))?(?=\s|$)/);

if (dateMatch) {

let day = parseInt(dateMatch[1], 10);

let month = parseInt(dateMatch[2], 10) – 1;

let year = dateMatch[3] ? parseInt(dateMatch[3], 10) : heute.getFullYear();

if (year < 100) year += 2000;

const d = new Date(year, month, day);

if (!isNaN(d.getTime())) {

dueDate = d.toISOString().split(‚T‘)[0];

taskText = rawText.replace(dateMatch[0], „“).trim();

}

}

// 2. morgen / übermorgen / Wochentage

else if (lower.includes(„morgen“)) {

const d = new Date(heute); d.setDate(d.getDate() + 1);

dueDate = d.toISOString().split(‚T‘)[0];

taskText = rawText.replace(/morgen/gi, „“).trim();

}

else if (lower.includes(„übermorgen“)) {

const d = new Date(heute); d.setDate(d.getDate() + 2);

dueDate = d.toISOString().split(‚T‘)[0];

taskText = rawText.replace(/übermorgen/gi, „“).trim();

}

else {

const days = [„sonntag“,“montag“,“dienstag“,“mittwoch“,“donnerstag“,“freitag“,“samstag“];

for (let i = 0; i < days.length; i++) {

if (lower.includes(days[i])) {

const diff = (i – heute.getDay() + 7) % 7 || 7;

const d = new Date(heute); d.setDate(d.getDate() + diff);

dueDate = d.toISOString().split(‚T‘)[0];

taskText = rawText.replace(new RegExp(days[i], „gi“), „“).trim();

break;

}

}

}

if (!taskText) taskText = rawText;

createListItem(taskText, false, dueDate);

input.value = „“; input.focus();

}

// ==================== ENTER-TASTE ====================

document.getElementById(„myInput“).addEventListener(„keydown“, e => {

if (e.key === „Enter“) { e.preventDefault(); newElement(); }

});

// ==================== ABHAKEN ====================

document.querySelector(‚ul‘).addEventListener(‚click‘, e => {

if (e.target.tagName === ‚LI‘) {

e.target.classList.toggle(‚checked‘);

saveTasks();

}

}, false);

// ==================== ZÄHLER ====================

function updateCounter() {

const total = document.querySelectorAll(‚#myUL li‘).length;

const done = document.querySelectorAll(‚#myUL li.checked‘).length;

const pending = total – done;

const el = document.getElementById(„counter“);

if (el) el.textContent = `${pending} offen • ${done} erledigt • ${total} insgesamt`;

}

// ==================== BACKUP ERSTELLEN ====================

function exportBackup() {

const data = localStorage.getItem(STORAGE_KEY);

if (!data || JSON.parse(data).length === 0) {

alert(„Keine Aufgaben zum Sichern!“);

return;

}

const date = new Date().toISOString().slice(0,10);

const blob = new Blob([data], { type: ‚application/json‘ });

const url = URL.createObjectURL(blob);

const a = document.createElement(‚a‘);

a.href = url;

a.download = `todolist-backup-${date}.json`;

a.click();

URL.revokeObjectURL(url);

alert(`Backup gespeichert: todolist-backup-${date}.json`);

}

// ==================== BACKUP WIEDERHERSTELLEN ====================

function importBackup(event) {

const file = event.target.files[0];

if (!file || !file.name.endsWith(‚.json‘)) {

alert(„Bitte eine gültige .json-Datei auswählen!“);

return;

}

const reader = new FileReader();

reader.onload = function(e) {

try {

const content = e.target.result;

JSON.parse(content); // Gültigkeit prüfen

localStorage.setItem(STORAGE_KEY, content);

document.getElementById(„myUL“).innerHTML = „“;

loadTasks();

alert(„Backup erfolgreich wiederhergestellt!“);

} catch (err) {

alert(„Fehler: Ungültige oder beschädigte Datei!“);

}

};

reader.readAsText(file);

}

// ==================== AUTOMATISCHES LOGGING (kann später erweitert werden) ====================

setInterval(() => {

if (document.querySelectorAll(‚#myUL li‘).length > 0) {

console.log(„Automatisches Backup aktiv – alles ist sicher in localStorage gespeichert“);

}

}, 5 * 60 * 1000);

// ==================== START ====================

loadTasks();

updateCounter();

Die Kommentare sind geschlossen.