- Add generous padding and spacing throughout (p-10, p-12) - Constrain content width with max-w-4xl and max-w-5xl - Increase font sizes for better hierarchy (text-3xl, text-lg) - Add gradient backgrounds to cards and elements - Implement smooth transitions and hover states - Create professional progress stepper with labels - Add shadow effects with color-matched glows - Increase button padding and font sizes - Add gradient borders on hover - Implement proper visual breathing room - Create polished, premium aesthetic - Add smooth cubic-bezier transitions - Improve form input styling with focus rings - Create professional card hover effects
95 lines
3.0 KiB
TypeScript
95 lines
3.0 KiB
TypeScript
import { useState } from 'react';
|
||
|
||
interface TextInputSectionProps {
|
||
text: string;
|
||
onChange: (text: string) => void;
|
||
onNext: () => void;
|
||
isLoading: boolean;
|
||
disabled: boolean;
|
||
}
|
||
|
||
export default function TextInputSection({
|
||
text,
|
||
onChange,
|
||
onNext,
|
||
isLoading,
|
||
disabled
|
||
}: TextInputSectionProps) {
|
||
const [showValidation, setShowValidation] = useState(false);
|
||
|
||
const handleNext = () => {
|
||
if (text.trim() === '') {
|
||
setShowValidation(true);
|
||
return;
|
||
}
|
||
setShowValidation(false);
|
||
onNext();
|
||
};
|
||
|
||
const handleTextChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
|
||
onChange(e.target.value);
|
||
if (e.target.value.trim() !== '') {
|
||
setShowValidation(false);
|
||
}
|
||
};
|
||
|
||
const isButtonDisabled = disabled || isLoading || text.trim() === '';
|
||
|
||
return (
|
||
<div className="max-w-4xl mx-auto">
|
||
<div className="card-modern p-10 sm:p-12">
|
||
<div className="mb-10">
|
||
<h2 className="text-3xl font-bold text-gray-900 mb-3">Enter Your Text</h2>
|
||
<p className="text-lg text-gray-600">Paste or type your story below. Use patterns like "Name:" to mark different speakers.</p>
|
||
</div>
|
||
|
||
<div className="mb-8 relative">
|
||
<textarea
|
||
value={text}
|
||
onChange={handleTextChange}
|
||
placeholder="Example:
|
||
|
||
Sarah: Hello! How are you today?
|
||
John: I'm doing great, thanks for asking!
|
||
Sarah: That's wonderful to hear."
|
||
className="w-full h-96 p-6 border-2 border-gray-200 rounded-2xl focus:border-indigo-500 focus:ring-4 focus:ring-indigo-100 focus:outline-none resize-y text-base leading-relaxed transition-all duration-200 bg-gray-50 focus:bg-white"
|
||
disabled={disabled || isLoading}
|
||
/>
|
||
<div className="absolute bottom-5 right-5 text-sm text-gray-500 bg-white px-4 py-2 rounded-xl border border-gray-200 shadow-sm font-medium">
|
||
{text.length} characters
|
||
</div>
|
||
</div>
|
||
|
||
{showValidation && text.trim() === '' && (
|
||
<div className="mb-8 p-5 bg-red-50 border-2 border-red-200 text-red-700 rounded-2xl">
|
||
<div className="flex items-center gap-3">
|
||
<span className="text-xl">⚠️</span>
|
||
<p className="font-semibold">Please enter some text before proceeding.</p>
|
||
</div>
|
||
</div>
|
||
)}
|
||
|
||
<div className="flex justify-end">
|
||
<button
|
||
onClick={handleNext}
|
||
disabled={isButtonDisabled}
|
||
className="btn-primary"
|
||
>
|
||
{isLoading ? (
|
||
<span className="flex items-center gap-3">
|
||
<div className="animate-spin rounded-full h-5 w-5 border-2 border-white border-t-transparent"></div>
|
||
Processing...
|
||
</span>
|
||
) : (
|
||
<span className="flex items-center gap-3">
|
||
Continue
|
||
<span className="text-lg">→</span>
|
||
</span>
|
||
)}
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
);
|
||
}
|