mirror of
https://github.com/lucasrcsantana/story-generator.git
synced 2025-12-17 05:47:52 +00:00
feat: Adicionando transformação de texto para maiúsculo
This commit is contained in:
parent
a0cfccc14d
commit
7880ce8dda
89
src/components/ui/adaptive-text.tsx
Normal file
89
src/components/ui/adaptive-text.tsx
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { cn } from '../../lib/utils';
|
||||||
|
|
||||||
|
interface AdaptiveTextProps extends React.HTMLAttributes<HTMLSpanElement> {
|
||||||
|
text: string;
|
||||||
|
isUpperCase: boolean;
|
||||||
|
as?: keyof JSX.IntrinsicElements;
|
||||||
|
preserveWhitespace?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const AdaptiveText = React.memo(({
|
||||||
|
text,
|
||||||
|
isUpperCase,
|
||||||
|
as: Component = 'span',
|
||||||
|
preserveWhitespace = false,
|
||||||
|
className,
|
||||||
|
...props
|
||||||
|
}: AdaptiveTextProps) => {
|
||||||
|
// Transformar o texto mantendo espaços em branco se necessário
|
||||||
|
const transformedText = React.useMemo(() => {
|
||||||
|
const transformed = isUpperCase ? text.toUpperCase() : text;
|
||||||
|
return preserveWhitespace ? transformed : transformed.trim();
|
||||||
|
}, [text, isUpperCase, preserveWhitespace]);
|
||||||
|
|
||||||
|
return React.createElement(
|
||||||
|
Component,
|
||||||
|
{
|
||||||
|
className: cn(
|
||||||
|
'transition-colors duration-200',
|
||||||
|
className
|
||||||
|
),
|
||||||
|
...props
|
||||||
|
},
|
||||||
|
transformedText
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
AdaptiveText.displayName = 'AdaptiveText';
|
||||||
|
|
||||||
|
// Variantes específicas para diferentes contextos
|
||||||
|
export const AdaptiveTitle = ({
|
||||||
|
className,
|
||||||
|
...props
|
||||||
|
}: AdaptiveTextProps) => (
|
||||||
|
<AdaptiveText
|
||||||
|
as="h1"
|
||||||
|
className={cn(
|
||||||
|
'text-2xl font-bold text-gray-900',
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
export const AdaptiveParagraph = ({
|
||||||
|
className,
|
||||||
|
...props
|
||||||
|
}: AdaptiveTextProps) => (
|
||||||
|
<AdaptiveText
|
||||||
|
as="p"
|
||||||
|
className={cn(
|
||||||
|
'text-base text-gray-700 leading-relaxed',
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
export const AdaptiveLabel = ({
|
||||||
|
className,
|
||||||
|
...props
|
||||||
|
}: AdaptiveTextProps) => (
|
||||||
|
<AdaptiveText
|
||||||
|
as="span"
|
||||||
|
className={cn(
|
||||||
|
'text-sm font-medium text-gray-600',
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
// Hook para memoização de textos longos
|
||||||
|
export function useAdaptiveText(text: string, isUpperCase: boolean) {
|
||||||
|
return React.useMemo(
|
||||||
|
() => isUpperCase ? text.toUpperCase() : text,
|
||||||
|
[text, isUpperCase]
|
||||||
|
);
|
||||||
|
}
|
||||||
40
src/components/ui/text-case-toggle.tsx
Normal file
40
src/components/ui/text-case-toggle.tsx
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { Loader2, Type } from 'lucide-react';
|
||||||
|
import { cn } from '../../lib/utils';
|
||||||
|
|
||||||
|
interface TextCaseToggleProps {
|
||||||
|
isUpperCase: boolean;
|
||||||
|
onToggle: () => void;
|
||||||
|
isLoading?: boolean;
|
||||||
|
className?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function TextCaseToggle({
|
||||||
|
isUpperCase,
|
||||||
|
onToggle,
|
||||||
|
isLoading = false,
|
||||||
|
className
|
||||||
|
}: TextCaseToggleProps) {
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
onClick={onToggle}
|
||||||
|
disabled={isLoading}
|
||||||
|
className={cn(
|
||||||
|
'flex items-center gap-2 px-3 py-1.5 rounded-lg transition-colors',
|
||||||
|
'text-gray-600 hover:text-gray-900 hover:bg-gray-100',
|
||||||
|
'border border-gray-200',
|
||||||
|
'disabled:opacity-50 disabled:cursor-not-allowed',
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
title={isUpperCase ? 'Mudar para minúsculas' : 'Mudar para maiúsculas'}
|
||||||
|
>
|
||||||
|
<Type className="h-4 w-4" />
|
||||||
|
<span className="text-sm font-medium select-none">
|
||||||
|
{isUpperCase ? 'Aa' : 'AA'}
|
||||||
|
</span>
|
||||||
|
{isLoading && (
|
||||||
|
<Loader2 className="h-4 w-4 animate-spin" />
|
||||||
|
)}
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
}
|
||||||
74
src/hooks/useUppercasePreference.ts
Normal file
74
src/hooks/useUppercasePreference.ts
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
import { useState, useEffect } from 'react';
|
||||||
|
import { supabase } from '../lib/supabase';
|
||||||
|
|
||||||
|
interface UseUppercasePreferenceReturn {
|
||||||
|
isUpperCase: boolean;
|
||||||
|
toggleUppercase: () => Promise<void>;
|
||||||
|
isLoading: boolean;
|
||||||
|
error: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useUppercasePreference(studentId?: string): UseUppercasePreferenceReturn {
|
||||||
|
const [isUpperCase, setIsUpperCase] = useState(false);
|
||||||
|
const [isLoading, setIsLoading] = useState(true);
|
||||||
|
const [error, setError] = useState<string | null>(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const loadPreference = async () => {
|
||||||
|
if (!studentId) {
|
||||||
|
setIsLoading(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const { data, error: fetchError } = await supabase
|
||||||
|
.from('students')
|
||||||
|
.select('uppercase_text_preferences')
|
||||||
|
.eq('id', studentId)
|
||||||
|
.single();
|
||||||
|
|
||||||
|
if (fetchError) throw fetchError;
|
||||||
|
|
||||||
|
setIsUpperCase(data?.uppercase_text_preferences ?? false);
|
||||||
|
setError(null);
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Erro ao carregar preferência de texto:', err);
|
||||||
|
setError('Não foi possível carregar sua preferência de texto');
|
||||||
|
} finally {
|
||||||
|
setIsLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
loadPreference();
|
||||||
|
}, [studentId]);
|
||||||
|
|
||||||
|
const toggleUppercase = async () => {
|
||||||
|
if (!studentId || isLoading) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
setIsLoading(true);
|
||||||
|
|
||||||
|
const { error: updateError } = await supabase
|
||||||
|
.from('students')
|
||||||
|
.update({ uppercase_text_preferences: !isUpperCase })
|
||||||
|
.eq('id', studentId);
|
||||||
|
|
||||||
|
if (updateError) throw updateError;
|
||||||
|
|
||||||
|
setIsUpperCase(!isUpperCase);
|
||||||
|
setError(null);
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Erro ao atualizar preferência de texto:', err);
|
||||||
|
setError('Não foi possível atualizar sua preferência de texto');
|
||||||
|
} finally {
|
||||||
|
setIsLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
isUpperCase,
|
||||||
|
toggleUppercase,
|
||||||
|
isLoading,
|
||||||
|
error
|
||||||
|
};
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user