Files
audiobook/frontend/src/components/TextInputSection.tsx
Paul Bailey 4a53c897c5 feat: create professional, polished UI with perfect spacing
- 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
2025-12-09 13:29:48 +00:00

95 lines
3.0 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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>
);
}