Este guia prático demonstra a criação de uma aplicação web completa de lista de tarefas (To-Do List) utilizando a plataforma de programação assistida por IA Trae CN. O projeto ilustra como ferramentas de IA podem acelerar o desenvolvimento frontend enquanto se dominam os fundamentos do HTML, CSS e JavaScript.
Ferramentas e Tecnologias do Projeto
- Plataforma de Desenvolvimento: Trae CN
- Lingugaens: HTML5, CSS3, JavaScript (ES6+)
- Persistência de Dados: API localStorage do navegador
- Princípios de Design: Interface com gradientes, layout responsivo
Preparando o Ambiente de Trabalho
Para iniciar, baixe e instale o software Trae CN a partir do site oficial. Após a instalação, crie uma conta e efetue o login para acessar o painel de geração de código.
Elaborando a Solicitação para a IA
A precisão no prompt é crucial para obter resultados desejados. A instrução fronecida ao Trae CN detalhava:
Criar uma aplicação de lista de tarefas com as seguintes funcionalidades:
- Adicionar novas tarefas via campo de entrada e botão, ou pressionando Enter.
- Listar todas as tarefas, riscando o texto das concluídas.
- Marcar/desmarcar tarefas como concluídas com uma caixa de seleção.
- Editar o texto de uma tarefa existente.
- Excluir tarefas após confirmação.
- Persistir os dados localmente no navegador.
- Design moderno com fundo em gradiente, responsivo para mobile.
Requisitos técnicos:
- Utilizar sintaxe moderna do JavaScript (ES6+).
- Estruturar o código orientado a objetos.
- Garantir responsividade.
- Incluir transições e animações.
Estrutura dos Arquivos Gerados
Após a execução do prompt, o Trae CN produz a estrutura de arquivos fundamental para a aplicação.
1. Arquivo Estrutural HTML (index.html)
Define a esqueleto da página, com os containers para a entrada de tarefas e a lista dinâmica.
<html lang="pt-BR">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Gerenciador de Afazeres</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<main class="app-container">
<header class="app-header">
<h1>Meus Afazeres</h1>
</header>
<section class="input-area">
<input type="text" id="newItemField" placeholder="Descreva a nova tarefa..." aria-label="Nova tarefa">
<button id="addItemBtn" aria-label="Adicionar tarefa">Adicionar</button>
</section>
<section class="items-display">
<ul id="itemList" class="items-list"></ul>
</section>
</main>
<script src="app.js"></script>
</body>
</html>
2. Arquivo de Estilos (styles.css)
Contém toda a estilização, desde o fundo gradiente e o layout de cartão centralizado até as regras de responsividade e as classes para o estado "concluído" das tarefas.
3. Arquivo de Lógica Principal (app.js)
A lógica é encapsulada em uma classe, garantindo organização e separação de preocupações. A implementação a seguir representa uma versão com estrutura e nomenclatura revisadas.
class TaskManager {
#tasks = [];
#storageKey = 'app_task_data';
constructor() {
this.#loadFromStorage();
this.#setupUIReferences();
this.#attachEventListeners();
this.#refreshView();
}
#setupUIReferences() {
this.inputField = document.getElementById('newItemField');
this.addButton = document.getElementById('addItemBtn');
this.listContainer = document.getElementById('itemList');
}
#attachEventListeners() {
this.addButton.addEventListener('click', () => this.#createTask());
this.inputField.addEventListener('keydown', (event) => {
if (event.code === 'Enter') this.#createTask();
});
// Delegação de eventos para botões dinâmicos
this.listContainer.addEventListener('click', (event) => {
const target = event.target;
const taskElement = target.closest('.task-entry');
if (!taskElement) return;
const taskId = Number(taskElement.dataset.identifier);
if (target.classList.contains('completion-toggle')) {
this.#alterTaskStatus(taskId);
} else if (target.classList.contains('edit-action')) {
this.#initiateEdit(taskId);
} else if (target.classList.contains('removal-action')) {
this.#removeTask(taskId);
}
});
}
#loadFromStorage() {
const storedData = localStorage.getItem(this.#storageKey);
if (storedData) {
try {
this.#tasks = JSON.parse(storedData);
} catch (e) {
this.#tasks = [];
}
}
}
#saveToStorage() {
localStorage.setItem(this.#storageKey, JSON.stringify(this.#tasks));
}
#createTask() {
const description = this.inputField.value.trim();
if (!description) return;
const newTask = {
id: performance.now(), // ID único baseado no tempo de carregamento
description: description,
isComplete: false,
createdAt: new Date().toISOString()
};
this.#tasks.unshift(newTask); // Adiciona no início da lista
this.#saveToStorage();
this.#refreshView();
this.inputField.value = '';
this.inputField.focus();
}
#alterTaskStatus(taskId) {
const task = this.#tasks.find(t => t.id === taskId);
if (task) {
task.isComplete = !task.isComplete;
this.#saveToStorage();
this.#refreshView();
}
}
#initiateEdit(taskId) {
const task = this.#tasks.find(t => t.id === taskId);
if (!task) return;
const taskElement = this.listContainer.querySelector(`[data-identifier="${taskId}"]`);
const descSpan = taskElement.querySelector('.task-description');
const currentText = descSpan.textContent;
// Transforma o span em um input editável
const editInput = document.createElement('input');
editInput.type = 'text';
editInput.className = 'edit-field';
editInput.value = currentText;
descSpan.replaceWith(editInput);
editInput.focus();
const confirmEdit = () => {
const newText = editInput.value.trim();
if (newText && newText !== currentText) {
task.description = newText;
this.#saveToStorage();
}
this.#refreshView();
};
editInput.addEventListener('blur', confirmEdit);
editInput.addEventListener('keydown', (e) => {
if (e.key === 'Enter') confirmEdit();
if (e.key === 'Escape') this.#refreshView();
});
}
#removeTask(taskId) {
if (!window.confirm('Tem certeza que deseja excluir esta tarefa?')) return;
this.#tasks = this.#tasks.filter(t => t.id !== taskId);
this.#saveToStorage();
this.#refreshView();
}
#refreshView() {
this.listContainer.innerHTML = '';
if (this.#tasks.length === 0) {
const emptyNotice = document.createElement('li');
emptyNotice.className = 'empty-notice';
emptyNotice.textContent = 'Nenhuma tarefa encontrada. Comece adicionando uma!';
this.listContainer.appendChild(emptyNotice);
return;
}
this.#tasks.forEach(task => {
const taskNode = document.createElement('li');
taskNode.className = `task-entry ${task.isComplete ? 'finished' : ''}`;
taskNode.dataset.identifier = task.id;
taskNode.innerHTML = `
<input type="checkbox" class="completion-toggle" ${task.isComplete ? 'checked' : ''}>
<span class="task-description">${task.description}</span>
<div class="task-actions">
<button class="action-btn edit-action" title="Editar">✏️</button>
<button class="action-btn removal-action" title="Excluir">🗑️</button>
</div>
`;
this.listContainer.appendChild(taskNode);
});
}
}
// Inicializa a aplicação quando o DOM estiver carregado
window.addEventListener('DOMContentLoaded', () => {
new TaskManager();
});
Executando e Validando a Aplicação
Abra o arquivo index.html diretamente no navegador. Teste as funcionalidades core: adicionar uma tarefa, marcá-la como concluída, editá-la inline e excluí-la. A validação crucial é atualizar a página (F5) para confirmar que os dados foram salvos pelo localStorage.
Teste a adaptabilidade redimensionando a janela do navegador ou acessando pelo celular. A interface deve se reorganizar mantendo a usabilidade.
Diferenciais da Implementação
O código revisado apresenta algumas escolhas técnicas particulares:
- Uso de Campos Privados (#): Propriedades e métodos internos da classe são marcados como privados, reforçando o encapsulamento.
- Delegação de Eventos: Um único listener na lista-mãe gerencia cliques em todos os botões de ação, sendo mais eficiente que múltiplos listeners.
- Edição Inline com Fallback: Ao editar, o texto é substituído por um campo input. A edição é confirmada com Enter ou ao perder o foco, e cancelada com Escape.
- ID Dinâmico: Utiliza
performance.now()para gerar IDs únicos durante a sessão, uma alternativa aoDate.now().
Possibilidades de Expansão
A base sólida permite adicionar inúmeras funcionalidades:
- Sistema de categorias ou etiquetas para as tarefas.
- Priorização das tarefas (urgente, importante).
- Campo de pesquisa e filtros por status.
- Funções para importar e exportar dados em JSON.
- Alternância entre tema claro e escuro.
- Sincronização com uma API backend para acesso em múltiplos dispositivos.