sdl3/examples/todo_app.php
2025-11-13 22:33:48 +01:00

151 lines
4.9 KiB
PHP

<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use PHPNative\Framework\Application;
use PHPNative\Ui\Widget\Button;
use PHPNative\Ui\Widget\Container;
use PHPNative\Ui\Widget\Label;
use PHPNative\Ui\Widget\TextInput;
use PHPNative\Ui\Window;
$storagePath = __DIR__ . '/todo_data.json';
$loadTasks = static function (string $path): array {
if (!is_file($path)) {
return [];
}
$raw = file_get_contents($path);
$data = json_decode($raw ?: '[]', true);
if (!is_array($data)) {
return [];
}
// Normalize task structure
return array_values(array_map(static function ($task) {
return [
'id' => $task['id'] ?? uniqid('task_', true),
'title' => trim((string) ($task['title'] ?? '')),
'done' => (bool) ($task['done'] ?? false),
];
}, $data));
};
$saveTasks = static function (string $path, array $tasks): void {
file_put_contents(
$path,
json_encode($tasks, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE),
LOCK_EX,
);
};
$tasks = $loadTasks($storagePath);
$app = new Application();
$window = new Window('Todo Beispiel', 520, 720);
$statusLabel = new Label('Bereit.', 'text-sm text-gray-600');
$main = new Container('flex flex-col bg-gray-100 gap-4 p-4 h-full w-full');
$title = new Label('Todo Liste', 'text-2xl font-bold text-black');
$main->addComponent($title);
$input = new TextInput('Neue Aufgabe hinzufügen …', 'flex-1 border border-gray-300 rounded px-3 py-2 bg-white text-black');
$addButton = new Button('Hinzufügen', 'px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700');
$inputRow = new Container('flex flex-row gap-3 w-full');
$inputRow->addComponent($input);
$inputRow->addComponent($addButton);
$main->addComponent($inputRow);
$listWrapper = new Container('flex-1 w-full overflow-auto bg-white rounded border border-gray-300 p-2');
$listContainer = new Container('flex flex-col gap-2 w-full');
$listWrapper->addComponent($listContainer);
$main->addComponent($listWrapper);
$main->addComponent($statusLabel);
$renderTasks = null;
$renderTasks = function () use (&$tasks, $listContainer, $statusLabel, $storagePath, $saveTasks, &$renderTasks) {
$listContainer->clearChildren();
if (empty($tasks)) {
$emptyLabel = new Label('Keine Aufgaben vorhanden. Erstelle die erste oben im Feld.', 'text-sm text-gray-500');
$listContainer->addComponent($emptyLabel);
return;
}
foreach ($tasks as $index => $task) {
$row = new Container('flex flex-row items-center gap-3 w-full border border-gray-200 rounded px-3 py-2 bg-white shadow-sm');
$taskLabelStyles = $task['done']
? 'flex-1 text-gray-500 line-through'
: 'flex-1 text-black';
$taskLabel = new Label($task['title'], $taskLabelStyles);
$row->addComponent($taskLabel);
$toggleButton = new Button(
$task['done'] ? 'Reaktivieren' : 'Erledigt',
$task['done']
? 'px-3 py-1 text-sm bg-amber-500 text-white rounded hover:bg-amber-600'
: 'px-3 py-1 text-sm bg-emerald-500 text-white rounded hover:bg-emerald-600',
);
$toggleButton->setOnClick(function () use (&$tasks, $task, $storagePath, $saveTasks, $statusLabel, $renderTasks) {
foreach ($tasks as &$entry) {
if ($entry['id'] === $task['id']) {
$entry['done'] = !$entry['done'];
break;
}
}
$saveTasks($storagePath, $tasks);
$statusLabel->setText(($task['done'] ? 'Aufgabe reaktiviert: ' : 'Aufgabe erledigt: ') . $task['title']);
$renderTasks();
});
$deleteButton = new Button(
'Löschen',
'px-3 py-1 text-sm bg-red-500 text-white rounded hover:bg-red-600',
);
$deleteButton->setOnClick(function () use (&$tasks, $index, $task, $storagePath, $saveTasks, $statusLabel, $renderTasks) {
array_splice($tasks, $index, 1);
$saveTasks($storagePath, $tasks);
$statusLabel->setText('Aufgabe entfernt: ' . $task['title']);
$renderTasks();
});
$row->addComponent($toggleButton);
$row->addComponent($deleteButton);
$listContainer->addComponent($row);
}
};
$renderTasks();
$addButton->setOnClick(function () use (&$tasks, $input, $saveTasks, $storagePath, $statusLabel, $renderTasks) {
$title = trim($input->getValue());
if ($title === '') {
$statusLabel->setText('Bitte zuerst einen Aufgabentext eingeben.');
return;
}
$tasks[] = [
'id' => uniqid('task_', true),
'title' => $title,
'done' => false,
];
$saveTasks($storagePath, $tasks);
$input->setValue('');
$statusLabel->setText('Aufgabe hinzugefügt: ' . $title);
$renderTasks();
});
$window->setRoot($main);
$app->addWindow($window);
$app->run();