From ea5c5e87f160b567c9a071e37ac29f79099072ba Mon Sep 17 00:00:00 2001 From: Lucas Santana Date: Thu, 23 Jan 2025 16:49:12 -0300 Subject: [PATCH] =?UTF-8?q?feat:=20Adicionando=20separa=C3=A7=C3=A3o=20de?= =?UTF-8?q?=20s=C3=ADlabas?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 20 +++++++------ docs/accessibility-features.md | 15 ++++++++++ src/components/phonics/ExercisePlayer.tsx | 9 ++++++ src/components/ui/adaptive-text.tsx | 7 ++++- .../components/SyllableHighlighter.tsx | 29 +++++++++++++++++++ src/features/syllables/hooks/useSyllables.ts | 10 +++++++ .../syllables/utils/syllableSplitter.test.ts | 7 +++++ .../syllables/utils/syllableSplitter.ts | 22 ++++++++++++++ .../student-dashboard/CreateStoryPage.tsx | 5 +++- src/pages/student-dashboard/ExercisePage.tsx | 6 +++- src/pages/student-dashboard/StoryPage.tsx | 22 +++++++++++--- .../StudentDashboardLayout.tsx | 7 ++++- 12 files changed, 142 insertions(+), 17 deletions(-) create mode 100644 docs/accessibility-features.md create mode 100644 src/features/syllables/components/SyllableHighlighter.tsx create mode 100644 src/features/syllables/hooks/useSyllables.ts create mode 100644 src/features/syllables/utils/syllableSplitter.test.ts create mode 100644 src/features/syllables/utils/syllableSplitter.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index c1f7cdb..89de2c2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -51,6 +51,9 @@ e este projeto adere ao [Semantic Versioning](https://semver.org/lang/pt-BR/). ### Modificado - N/A (primeira versão) +- Todas as páginas principais para usar texto adaptativo +- Componentes de exercícios para suportar transformação de texto +- Movido controle de sílabas para a página de histórias ### Removido - N/A (primeira versão) @@ -58,17 +61,16 @@ e este projeto adere ao [Semantic Versioning](https://semver.org/lang/pt-BR/). ## [1.1.0] - 2024-05-20 ### Adicionado -- Novo componente `TextCaseToggle` para alternar entre maiúsculas/minúsculas -- Componentes de texto adaptativo (`AdaptiveText`, `AdaptiveTitle`, `AdaptiveParagraph`) -- Hook `useUppercasePreference` para gerenciar preferência do usuário -- Suporte a texto em maiúsculas para crianças em fase de alfabetização +- Suporte a texto maiúsculo para alfabetização infantil +- Componente de alternância de caixa de texto +- Sistema de persistência de preferências +- Destaque silábico interativo para apoio à decodificação ### Modificado -- Páginas de histórias e exercícios para usar o novo sistema de texto -- Cabeçalho das páginas principal com controle de caixa de texto +- Todas as páginas principais para usar texto adaptativo - Componentes de exercícios para suportar transformação de texto ### Técnico -- Adicionada coluna `uppercase_text_preferences` na tabela students -- Sistema de persistência de preferências via Supabase -- Otimizações de performance com memoização de componentes +- Nova coluna na tabela students +- Hook para gerenciamento de estado +- Otimizações de performance diff --git a/docs/accessibility-features.md b/docs/accessibility-features.md new file mode 100644 index 0000000..86f41ab --- /dev/null +++ b/docs/accessibility-features.md @@ -0,0 +1,15 @@ +## Destaque Silábico + +**Objetivo:** +Facilitar a identificação das sílabas durante a leitura + +**Como usar:** +1. Clique no botão "Sílabas" ao lado do título da história +2. Todas as palavras serão divididas em sílabas +3. Sílabas destacadas em fundo amarelo +4. Clique novamente para desativar + +**Benefícios:** +- Auxilia na decodificação fonêmica +- Promove consciência silábica +- Facilita a leitura de palavras complexas \ No newline at end of file diff --git a/src/components/phonics/ExercisePlayer.tsx b/src/components/phonics/ExercisePlayer.tsx index 93fb04b..8640d83 100644 --- a/src/components/phonics/ExercisePlayer.tsx +++ b/src/components/phonics/ExercisePlayer.tsx @@ -7,6 +7,8 @@ import { ExerciseFactory } from "./exercises/ExerciseFactory"; import { Timer } from "lucide-react"; import type { PhonicsExercise, UpdateProgressParams } from "@/types/phonics"; import { cn } from "@/lib/utils"; +import { AdaptiveText } from '../ui/adaptive-text'; +import { useUppercasePreference } from '../../hooks/useUppercasePreference'; interface ExercisePlayerProps { exercise: PhonicsExercise; @@ -33,6 +35,7 @@ export function ExercisePlayer({ const [lastAnswerCorrect, setLastAnswerCorrect] = useState(null); const updateProgress = useUpdatePhonicsProgress(); + const { isUpperCase } = useUppercasePreference(); useEffect(() => { const timer = setInterval(() => { @@ -150,6 +153,12 @@ export function ExercisePlayer({ Exercício {currentStep + 1} de {correctWords.length} + + { text: string; isUpperCase: boolean; as?: keyof JSX.IntrinsicElements; preserveWhitespace?: boolean; + highlightSyllables?: boolean; } export const AdaptiveText = React.memo(({ @@ -13,6 +15,7 @@ export const AdaptiveText = React.memo(({ isUpperCase, as: Component = 'span', preserveWhitespace = false, + highlightSyllables = false, className, ...props }: AdaptiveTextProps) => { @@ -31,7 +34,9 @@ export const AdaptiveText = React.memo(({ ), ...props }, - transformedText + highlightSyllables ? ( + + ) : transformedText ); }); diff --git a/src/features/syllables/components/SyllableHighlighter.tsx b/src/features/syllables/components/SyllableHighlighter.tsx new file mode 100644 index 0000000..2a99152 --- /dev/null +++ b/src/features/syllables/components/SyllableHighlighter.tsx @@ -0,0 +1,29 @@ +import React from 'react'; +import { splitIntoSyllables } from '../utils/syllableSplitter'; + +interface SyllableHighlighterProps { + text: string; + highlightColor?: string; + className?: string; +} + +export function SyllableHighlighter({ + text, + highlightColor = 'bg-yellow-100', + className +}: SyllableHighlighterProps) { + const syllables = splitIntoSyllables(text); + + return ( +
+ {syllables.map((syllable, index) => ( + + {syllable} + + ))} +
+ ); +} \ No newline at end of file diff --git a/src/features/syllables/hooks/useSyllables.ts b/src/features/syllables/hooks/useSyllables.ts new file mode 100644 index 0000000..f6d65e8 --- /dev/null +++ b/src/features/syllables/hooks/useSyllables.ts @@ -0,0 +1,10 @@ +import { useState } from 'react'; + +export function useSyllables() { + const [isHighlighted, setIsHighlighted] = useState(false); + + return { + isHighlighted, + toggleHighlight: () => setIsHighlighted(!isHighlighted) + }; +} \ No newline at end of file diff --git a/src/features/syllables/utils/syllableSplitter.test.ts b/src/features/syllables/utils/syllableSplitter.test.ts new file mode 100644 index 0000000..c7ed7a4 --- /dev/null +++ b/src/features/syllables/utils/syllableSplitter.test.ts @@ -0,0 +1,7 @@ +import { splitIntoSyllables } from './syllableSplitter'; + +test('Separação silábica básica', () => { + expect(splitIntoSyllables('casa')).toEqual(['ca', 'sa']); + expect(splitIntoSyllables('banana')).toEqual(['ba', 'na', 'na']); + expect(splitIntoSyllables('computador')).toEqual(['com', 'pu', 'ta', 'dor']); +}); \ No newline at end of file diff --git a/src/features/syllables/utils/syllableSplitter.ts b/src/features/syllables/utils/syllableSplitter.ts new file mode 100644 index 0000000..ebc571f --- /dev/null +++ b/src/features/syllables/utils/syllableSplitter.ts @@ -0,0 +1,22 @@ +const VOWELS = new Set(['a', 'e', 'i', 'o', 'u', 'á', 'é', 'í', 'ó', 'ú', 'â', 'ê', 'ô', 'ã', 'õ']); + +export function splitIntoSyllables(word: string): string[] { + const syllables: string[] = []; + let currentSyllable = ''; + + for (let i = 0; i < word.length; i++) { + const char = word[i].toLowerCase(); + currentSyllable += word[i]; + + if (VOWELS.has(char)) { + if (i < word.length - 1 && !VOWELS.has(word[i+1].toLowerCase())) { + syllables.push(currentSyllable); + currentSyllable = ''; + } else if (i === word.length - 1) { + syllables.push(currentSyllable); + } + } + } + + return syllables.length > 0 ? syllables : [word]; +} \ No newline at end of file diff --git a/src/pages/student-dashboard/CreateStoryPage.tsx b/src/pages/student-dashboard/CreateStoryPage.tsx index 4c592d1..95a6fa7 100644 --- a/src/pages/student-dashboard/CreateStoryPage.tsx +++ b/src/pages/student-dashboard/CreateStoryPage.tsx @@ -65,7 +65,10 @@ export function CreateStoryPage() { {error && (
- {error} +
)} diff --git a/src/pages/student-dashboard/ExercisePage.tsx b/src/pages/student-dashboard/ExercisePage.tsx index 94a9e74..bc95694 100644 --- a/src/pages/student-dashboard/ExercisePage.tsx +++ b/src/pages/student-dashboard/ExercisePage.tsx @@ -110,7 +110,11 @@ export function ExercisePage() { return (
-

{error}

+