diff --git a/CHANGELOG.md b/CHANGELOG.md index 41a7927..c1f7cdb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -54,3 +54,21 @@ e este projeto adere ao [Semantic Versioning](https://semver.org/lang/pt-BR/). ### Removido - N/A (primeira versão) + +## [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 + +### 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 +- 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 diff --git a/src/pages/student-dashboard/CreateStoryPage.tsx b/src/pages/student-dashboard/CreateStoryPage.tsx index f81fd43..4c592d1 100644 --- a/src/pages/student-dashboard/CreateStoryPage.tsx +++ b/src/pages/student-dashboard/CreateStoryPage.tsx @@ -3,12 +3,17 @@ import { ArrowLeft, Sparkles } from 'lucide-react'; import { useNavigate } from 'react-router-dom'; import { StoryGenerator } from '../../components/story/StoryGenerator'; import { useSession } from '../../hooks/useSession'; +import { TextCaseToggle } from '../../components/ui/text-case-toggle'; +import { AdaptiveTitle, AdaptiveParagraph, AdaptiveText } from '../../components/ui/adaptive-text'; +import { useUppercasePreference } from '../../hooks/useUppercasePreference'; export function CreateStoryPage() { const navigate = useNavigate(); const { session } = useSession(); const [error, setError] = React.useState(null); + const { isUpperCase, toggleUppercase, isLoading } = useUppercasePreference(session?.user?.id); + if (!session) { return (
@@ -39,11 +44,23 @@ export function CreateStoryPage() {
-

Criar Nova História

-

- Vamos criar uma história personalizada baseada nos seus interesses -

+ +
+ {error && ( @@ -59,10 +76,19 @@ export function CreateStoryPage() { Como funciona?
    -
  1. 1. Conte-nos sobre seus interesses e preferências
  2. -
  3. 2. Escolha personagens e cenários para sua história
  4. -
  5. 3. Nossa IA criará uma história única e personalizada
  6. -
  7. 4. Você poderá ler e praticar com sua nova história
  8. + {[ + 'Conte-nos sobre seus interesses e preferências', + 'Escolha personagens e cenários para sua história', + 'Nossa IA criará uma história única e personalizada', + 'Você poderá ler e praticar com sua nova história' + ].map((text, index) => ( + + ))}
diff --git a/src/pages/student-dashboard/ExercisePage.tsx b/src/pages/student-dashboard/ExercisePage.tsx index a219f34..94a9e74 100644 --- a/src/pages/student-dashboard/ExercisePage.tsx +++ b/src/pages/student-dashboard/ExercisePage.tsx @@ -5,6 +5,10 @@ import { WordFormation } from '../../components/exercises/WordFormation'; import { SentenceCompletion } from '../../components/exercises/SentenceCompletion'; import { PronunciationPractice } from '../../components/exercises/PronunciationPractice'; import { ArrowLeft } from 'lucide-react'; +import { TextCaseToggle } from '../../components/ui/text-case-toggle'; +import { AdaptiveText, AdaptiveTitle, AdaptiveParagraph } from '../../components/ui/adaptive-text'; +import { useUppercasePreference } from '../../hooks/useUppercasePreference'; +import { useSession } from '../../hooks/useSession'; interface ExerciseWord { word: string; @@ -31,6 +35,8 @@ export function ExercisePage() { const [exerciseData, setExerciseData] = React.useState(null); const [exerciseWords, setExerciseWords] = React.useState([]); const [error, setError] = React.useState(null); + const { session } = useSession(); + const { isUpperCase, toggleUppercase, isLoading } = useUppercasePreference(session?.user?.id); React.useEffect(() => { const loadExerciseData = async () => { @@ -136,7 +142,9 @@ export function ExercisePage() { case 'word-formation': return ( w.word)} + words={exerciseWords.map(w => + isUpperCase ? w.word.toUpperCase() : w.word + )} storyId={storyId as string} studentId={exerciseData.story.student_id} /> @@ -170,8 +178,24 @@ export function ExercisePage() { className="flex items-center gap-2 text-gray-600 hover:text-gray-900 mb-4" > - Voltar para história + + +
+ + +
{/* Exercício */} diff --git a/src/pages/student-dashboard/StoryPage.tsx b/src/pages/student-dashboard/StoryPage.tsx index 3917d87..a8bcb73 100644 --- a/src/pages/student-dashboard/StoryPage.tsx +++ b/src/pages/student-dashboard/StoryPage.tsx @@ -8,6 +8,10 @@ import { StoryMetrics } from '../../components/story/StoryMetrics'; import { convertWebmToMp3 } from '../../utils/audioConverter'; import * as Dialog from '@radix-ui/react-dialog'; import { ExerciseSuggestions } from '../../components/learning/ExerciseSuggestions'; +import { TextCaseToggle } from '../../components/ui/text-case-toggle'; +import { AdaptiveText, AdaptiveTitle, AdaptiveParagraph } from '../../components/ui/adaptive-text'; +import { useUppercasePreference } from '../../hooks/useUppercasePreference'; +import { useSession } from '../../hooks/useSession'; interface StoryRecording { id: string; @@ -385,6 +389,8 @@ export function StoryPage() { const [loadingRecordings, setLoadingRecordings] = React.useState(true); const [showDeleteModal, setShowDeleteModal] = useState(false); const [isDeleting, setIsDeleting] = useState(false); + const { session } = useSession(); + const { isUpperCase, toggleUppercase, isLoading } = useUppercasePreference(session?.user?.id); React.useEffect(() => { const fetchStory = async () => { @@ -602,10 +608,15 @@ export function StoryPage() { className="flex items-center gap-2 text-gray-600 hover:text-gray-900" > - Voltar para histórias +
+