From a4bc735bf0b5fe469d79edd1ce434d7ad3a6dea6 Mon Sep 17 00:00:00 2001 From: Ricardo Trapp Date: Thu, 24 Jul 2025 09:55:08 -0400 Subject: [PATCH] feat(frontend): implement CodeEditor and hook --- README.md | 24 +++--- src/frontend/package.json | 1 + src/frontend/src/app/page.tsx | 2 +- .../src/components/features/code-editor.tsx | 73 +++++++++++++++++++ src/frontend/src/hooks/use-code-editor.ts | 64 ++++++++++++++++ src/frontend/src/types/common.ts | 16 ++++ src/frontend/src/types/editor.ts | 15 ++++ 7 files changed, 185 insertions(+), 10 deletions(-) create mode 100644 src/frontend/src/components/features/code-editor.tsx create mode 100644 src/frontend/src/hooks/use-code-editor.ts create mode 100644 src/frontend/src/types/common.ts create mode 100644 src/frontend/src/types/editor.ts diff --git a/README.md b/README.md index aa999d4..5225cb9 100644 --- a/README.md +++ b/README.md @@ -66,6 +66,7 @@ QuickLintAI/ > 📥 **Para instalação detalhada**: Consulte o [**Guia Completo de Instalação**](docs/INSTALLATION.md) com instruções específicas para Linux, Windows e macOS. > ✅ **Story #000 Concluída**: O header com sistema de temas e layout base já estão implementados e funcionais! +> ✅ **Story #001 Concluída**: Editor de código com Monaco integrado e validação de caracteres. ### Pré-requisitos @@ -143,7 +144,12 @@ dotnet run - ⚡ **Base sólida** estabelecida para desenvolvimento das próximas features - 🚀 **Aplicação rodando** em http://localhost:3000 -**Próximo marco**: Story #001 - Monaco Editor Setup +### ✅ **Fevereiro 2025 - Story #001 Concluída** +- 📝 **CodeEditor** implementado com Monaco Editor +- 🔢 **Validação de 1024 caracteres** integrada +- 🌓 **Suporte a temas claro/escuro** + +**Próximo marco**: Story #002 - Seletor de Perfil ### 🧠 Perfis de Análise @@ -185,7 +191,7 @@ Acompanhe o desenvolvimento incremental do projeto através das stories: | Story | Título | Tipo | Prioridade | Status | Descrição | |-------|--------|------|------------|--------|-----------| | [#000](docs/stories/000-setup-inicial-header.md) | Setup Inicial e Header | Infraestrutura | Alta | ✅ Concluída | Header com nome do app e seleção de tema | -| [#001](docs/stories/001-monaco-editor-setup.md) | Editor de Código Monaco | Funcionalidade | Alta | 📋 Planejada | Editor com syntax highlighting e validação | +| [#001](docs/stories/001-monaco-editor-setup.md) | Editor de Código Monaco | Funcionalidade | Alta | ✅ Concluída | Editor com syntax highlighting e validação | | [#002](docs/stories/002-profile-selector.md) | Seletor de Perfil | Funcionalidade | Alta | 📋 Planejada | Escolha entre análise Rigorosa/Flexível | | [#003](docs/stories/003-backend-api-feedback.md) | API Backend Feedback | Funcionalidade | Alta | 📋 Planejada | Endpoint de análise com integração IA | | [#004](docs/stories/004-diff-viewer-component.md) | Visualizador de Diff | Funcionalidade | Alta | 📋 Planejada | Comparação lado a lado de código | @@ -197,16 +203,16 @@ Acompanhe o desenvolvimento incremental do projeto através das stories: | [#009](docs/stories/009-prompt-debugging-panel.md) | Painel de Debugging | Funcionalidade | Baixa | 📋 Planejada | Visualização de prompts enviados | ### 📊 Status das Stories -- 📋 **Planejada**: 9 stories -- 🔄 **Em Andamento**: 0 stories -- ✅ **Concluída**: 1 story +- 📋 **Planejada**: 8 stories +- 🔄 **Em Andamento**: 0 stories +- ✅ **Concluída**: 2 stories - ❌ **Cancelada**: 0 stories ### 🎯 Próximas Prioridades -1. **Story #001** - Implementar editor Monaco com syntax highlighting -2. **Story #002** - Adicionar seleção de perfil de análise -3. **Story #003** - Desenvolver API backend com IA -4. **Story #004** - Visualizador de diff lado a lado +1. **Story #002** - Adicionar seleção de perfil de análise +2. **Story #003** - Desenvolver API backend com IA +3. **Story #004** - Visualizador de diff lado a lado +4. **Story #005** - Integração completa > 💡 **Dica**: Cada story é independente e pode ser desenvolvida incrementalmente. Consulte os arquivos individuais para detalhes técnicos completos. diff --git a/src/frontend/package.json b/src/frontend/package.json index 598b2d1..3e0ef28 100644 --- a/src/frontend/package.json +++ b/src/frontend/package.json @@ -60,6 +60,7 @@ "devDependencies": { "@eslint/eslintrc": "^3", "@tailwindcss/postcss": "^4", + "@types/monaco-editor": "^0.44.16", "@types/node": "^20", "@types/react": "^19", "@types/react-dom": "^19", diff --git a/src/frontend/src/app/page.tsx b/src/frontend/src/app/page.tsx index efeafac..6bd4c57 100644 --- a/src/frontend/src/app/page.tsx +++ b/src/frontend/src/app/page.tsx @@ -79,7 +79,7 @@ export default function HomePage() { {/* Status Badge */}
- Em desenvolvimento - Story #000 concluída + Em desenvolvimento - Story #001 concluída
diff --git a/src/frontend/src/components/features/code-editor.tsx b/src/frontend/src/components/features/code-editor.tsx new file mode 100644 index 0000000..b4ffa29 --- /dev/null +++ b/src/frontend/src/components/features/code-editor.tsx @@ -0,0 +1,73 @@ +import { Editor } from '@monaco-editor/react' +import { useCallback } from 'react' +import { Badge } from '@/components/ui/badge' +import { Alert, AlertDescription } from '@/components/ui/alert' +import type { Language } from '@/types/editor' + +interface CodeEditorProps { + language: Language + value: string + onChange: (value: string) => void + maxLength?: number + placeholder?: string + theme?: 'light' | 'dark' +} + +export function CodeEditor({ + language, + value, + onChange, + maxLength = 1024, + placeholder = 'Cole seu código aqui...', + theme = 'light', +}: CodeEditorProps) { + const handleEditorChange = useCallback( + (val: string | undefined) => { + const newValue = val || '' + onChange(newValue) + }, + [onChange], + ) + + const isOverLimit = value.length > maxLength + const remainingChars = maxLength - value.length + + return ( +
+
+ +
+ +
+ + {value.length}/{maxLength} caracteres + + + {isOverLimit && ( + + + Limite excedido em {Math.abs(remainingChars)} caracteres + + + )} +
+
+ ) +} diff --git a/src/frontend/src/hooks/use-code-editor.ts b/src/frontend/src/hooks/use-code-editor.ts new file mode 100644 index 0000000..650735d --- /dev/null +++ b/src/frontend/src/hooks/use-code-editor.ts @@ -0,0 +1,64 @@ +import { useState, useCallback, useMemo } from 'react' +import type { Language, CodeEditorState } from '@/types/editor' + +interface UseCodeEditorProps { + initialValue?: string + initialLanguage?: Language + maxLength?: number +} + +export function useCodeEditor({ + initialValue = '', + initialLanguage = 'javascript', + maxLength = 1024, +}: UseCodeEditorProps = {}) { + const [state, setState] = useState({ + value: initialValue, + language: initialLanguage, + isValid: initialValue.length <= maxLength, + characterCount: initialValue.length, + }) + + const updateValue = useCallback( + (value: string) => { + setState(prev => ({ + ...prev, + value, + characterCount: value.length, + isValid: value.length <= maxLength, + })) + }, + [maxLength], + ) + + const updateLanguage = useCallback((language: Language) => { + setState(prev => ({ ...prev, language })) + }, []) + + const validation = useMemo( + () => ({ + isValid: state.isValid, + isOverLimit: state.characterCount > maxLength, + remainingChars: maxLength - state.characterCount, + errorMessage: + state.characterCount > maxLength + ? `Código excede o limite em ${state.characterCount - maxLength} caracteres` + : null, + }), + [state.isValid, state.characterCount, maxLength], + ) + + return { + ...state, + validation, + updateValue, + updateLanguage, + reset: () => + setState({ + value: '', + language: initialLanguage, + isValid: true, + characterCount: 0, + }), + } +} diff --git a/src/frontend/src/types/common.ts b/src/frontend/src/types/common.ts new file mode 100644 index 0000000..8744105 --- /dev/null +++ b/src/frontend/src/types/common.ts @@ -0,0 +1,16 @@ +export type Language = 'javascript' | 'typescript' | 'csharp' +export type FeedbackProfile = 'flexible' | 'rigorous' + +export interface EditorConfig { + language: Language + theme: 'vs-light' | 'vs-dark' + fontSize: number + maxLength: number +} + +export interface CodeEditorState { + value: string + language: Language + isValid: boolean + characterCount: number +} diff --git a/src/frontend/src/types/editor.ts b/src/frontend/src/types/editor.ts new file mode 100644 index 0000000..e4412b0 --- /dev/null +++ b/src/frontend/src/types/editor.ts @@ -0,0 +1,15 @@ +export type { Language, FeedbackProfile } from './common' + +export interface EditorConfig { + language: Language + theme: 'vs-light' | 'vs-dark' + fontSize: number + maxLength: number +} + +export interface CodeEditorState { + value: string + language: Language + isValid: boolean + characterCount: number +}