Desenvolvimento de uma Aplicação de Tarefas com IA Assistida

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 ao Date.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.

Tags: javascript ES6 LocalStorage html5 CSS3

Publicado em 7-22 17:58