| import { MAX_TEXT_LENGTH, OPTIMAL_WORDS } from '../constants' | |
| interface Props { | |
| value: string | |
| onChange: (v: string) => void | |
| disabled?: boolean | |
| } | |
| export const TextInput = ({ value, onChange, disabled }: Props) => { | |
| const over = value.length > MAX_TEXT_LENGTH | |
| const wordCount = value.trim() ? value.trim().split(/\s+/).length : 0 | |
| const overOptimal = wordCount > OPTIMAL_WORDS | |
| return ( | |
| <div className="flex flex-col gap-1"> | |
| <label className="text-sm font-medium text-gray-700"> | |
| Text to speak | |
| </label> | |
| <textarea | |
| value={value} | |
| onChange={e => onChange(e.target.value)} | |
| disabled={disabled} | |
| rows={5} | |
| placeholder="Type Gujarati text here..." | |
| className={`w-full rounded-md border px-3 py-2 text-sm resize-none focus:outline-none focus:ring-2 focus:ring-blue-500 disabled:opacity-50 ${ | |
| over ? "border-red-400" : "border-gray-300" | |
| }`} | |
| /> | |
| <div className="flex justify-between text-xs"> | |
| <span className={overOptimal ? "text-amber-600" : "text-gray-400"}> | |
| {wordCount} {wordCount === 1 ? "word" : "words"} | |
| {overOptimal && " — will be split into chunks"} | |
| </span> | |
| <span className={over ? "text-red-600 font-medium" : "text-gray-500"}> | |
| {value.length}/{MAX_TEXT_LENGTH} | |
| </span> | |
| </div> | |
| </div> | |
| ) | |
| } | |