sdl3/examples/todo_app.php
2025-10-26 13:39:25 +01:00

130 lines
3.8 KiB
PHP

<?php
require_once __DIR__ . '/../vendor/autoload.php';
use PHPNative\Framework\Application;
use PHPNative\Ui\Widget\Button;
use PHPNative\Ui\Widget\Checkbox;
use PHPNative\Ui\Widget\Container;
use PHPNative\Ui\Widget\Label;
use PHPNative\Ui\Widget\TextInput;
use PHPNative\Ui\Window;
$app = new Application();
$window = new Window('Todo App', 600, 500);
// Main container
$mainContainer = new Container('flex flex-col p-4 bg-gray-50');
// Title
$title = new Label('My Todo List', 'text-2xl font-bold mb-4 text-gray-800');
$mainContainer->addComponent($title);
// Input section
$inputContainer = new Container('flex flex-row mb-4');
$input = new TextInput(
placeholder: 'What needs to be done?',
style: 'flex-1 p-2 border border-gray-300 rounded mr-2',
);
$addButton = new Button('Add', 'bg-blue-500 text-white p-2 rounded-lg hover:bg-blue-600');
$inputContainer->addComponent($input);
$inputContainer->addComponent($addButton);
$mainContainer->addComponent($inputContainer);
// Todo list container
$todoListContainer = new Container('flex flex-col');
$mainContainer->addComponent($todoListContainer);
// Stats
$statsLabel = new Label('0 items', 'mt-4 text-gray-600 text-sm h-10');
$mainContainer->addComponent($statsLabel);
// Todos array
$todos = [];
// Function to update stats
$updateStats = function () use (&$todos, $statsLabel) {
$total = count($todos);
$completed = count(array_filter($todos, fn($t) => $t['completed']));
$statsLabel->setText("{$total} items ({$completed} completed)");
};
// Function to render todos - use a reference so it can be used in closures
$renderTodos = null;
$renderTodos = function () use (&$todos, $todoListContainer, $updateStats, &$renderTodos, $window) {
// Clear existing todos
$todoListContainer->clearChildren();
foreach ($todos as $index => $todo) {
$todoItem = new Container('flex flex-row items-center p-2 mb-2 bg-white border border-gray-200 rounded h-12');
// Checkbox
$checkbox = new Checkbox(
label: '',
checked: $todo['completed'],
style: 'mr-2 w-6 h-6',
);
$checkbox->setOnChange(function ($checked) use (&$todos, $index, &$renderTodos, $updateStats) {
$todos[$index]['completed'] = $checked;
$updateStats();
});
// Text
$textStyle = $todo['completed'] ? 'flex-1 text-gray-400 line-through' : 'flex-1 text-gray-800';
$todoText = new Label($todo['text'], $textStyle);
// Delete button
$deleteButton = new Button('Delete', 'bg-red-500 text-white px-2 py-1 rounded text-sm hover:bg-red-600');
$deleteButton->setOnClick(function () use (&$todos, $index, &$renderTodos, $updateStats) {
array_splice($todos, $index, 1);
$renderTodos();
$updateStats();
});
$todoItem->addComponent($checkbox);
$todoItem->addComponent($todoText);
$todoItem->addComponent($deleteButton);
$todoListContainer->addComponent($todoItem);
}
$updateStats();
// Trigger re-layout after adding new components
$window->setShouldBeReLayouted(true);
};
// Add button click handler
$addButton->setOnClick(function () use ($input, &$todos, &$renderTodos) {
$text = trim($input->getValue());
if (!empty($text)) {
$todos[] = [
'text' => $text,
'completed' => false,
];
$input->setValue(''); // Clear input
$renderTodos();
}
});
// Handle Enter key in input
$input->setOnChange(function ($value) {
// Could add live validation here
});
$window->setRoot($mainContainer);
$app->addWindow($window);
echo "Todo App started!\n";
echo "- Type in the input field and click 'Add' or press Enter\n";
echo "- Click checkboxes to mark todos as complete\n";
echo "- Click 'Delete' to remove a todo\n\n";
$app->run();