Spaces:
Sleeping
Sleeping
| "use client"; | |
| import TooltipItem from "../common/TooltipItem"; | |
| interface Props { | |
| predictionInput: any; | |
| setPredictionInput: (v: any) => void; | |
| filters: any; | |
| handlePredict: () => void; | |
| predicting: boolean; | |
| } | |
| export default function InputForm({ | |
| predictionInput, | |
| setPredictionInput, | |
| filters, | |
| handlePredict, | |
| predicting, | |
| }: Props) { | |
| const update = (key: string, value: string) => | |
| setPredictionInput({ ...predictionInput, [key]: value }); | |
| return ( | |
| <div className="bg-white rounded-xl border border-slate-200 shadow-sm overflow-hidden"> | |
| <div className="bg-slate-50 border-b border-slate-200 p-6"> | |
| <div className="flex items-center gap-2 mb-1 flex-wrap"> | |
| <h3 className="text-lg font-semibold text-slate-800">Target Finished Parameters</h3> | |
| <span className="rounded-full bg-amber-100 border border-amber-300 px-2 py-0.5 text-[10px] font-bold uppercase tracking-wide text-amber-800"> | |
| Prototype Input | |
| </span> | |
| </div> | |
| <p className="text-sm text-slate-500"> | |
| Enter finish specifications to explore greige construction options in this prototype. | |
| Results are for evaluation feedback — not final production issuance. | |
| </p> | |
| </div> | |
| <div className="p-6"> | |
| <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-5"> | |
| <SelectField | |
| label="Weave" | |
| value={predictionInput.weave} | |
| onChange={(v: string) => update("weave", v)} | |
| options={filters?.weaves || []} | |
| required | |
| tooltip="The interlacing pattern (Plain, Twill, Satin). Determines fabric texture." | |
| /> | |
| <SelectField | |
| label="Blend" | |
| value={predictionInput.blend} | |
| onChange={(v: string) => update("blend", v)} | |
| options={filters?.blends || []} | |
| required | |
| tooltip="Yarn composition. 100%CO = 100% Cotton." | |
| /> | |
| <SelectField | |
| label="Dataset" | |
| value={predictionInput.dataset} | |
| onChange={(v: string) => update("dataset", v)} | |
| options={["all", "working", "piece_dyed"]} | |
| tooltip="Working = general catalog. Piece Dyed = dyed after weaving." | |
| /> | |
| <InputField | |
| label="Warp Count" | |
| value={predictionInput.warp_count} | |
| onChange={(e: any) => update("warp_count", e.target.value)} | |
| placeholder="e.g. 40" | |
| tooltip="Yarn thickness (Ne). Raw value from swatch analysis." | |
| type="number" | |
| /> | |
| <InputField | |
| label="Weft Count" | |
| value={predictionInput.weft_count} | |
| onChange={(e: any) => update("weft_count", e.target.value)} | |
| placeholder="e.g. 40" | |
| tooltip="Weft yarn count (Ne). Used for GSM computation." | |
| type="number" | |
| /> | |
| <InputField | |
| label="Finish EPI" | |
| value={predictionInput.finish_epi} | |
| onChange={(e: any) => update("finish_epi", e.target.value)} | |
| placeholder="e.g. 120" | |
| tooltip="Ends per inch in finished fabric." | |
| type="number" | |
| /> | |
| <InputField | |
| label="Finish PPI" | |
| value={predictionInput.finish_ppi} | |
| onChange={(e: any) => update("finish_ppi", e.target.value)} | |
| placeholder="e.g. 90" | |
| tooltip="Picks per inch in finished fabric." | |
| type="number" | |
| /> | |
| <InputField | |
| label="Target GSM" | |
| value={predictionInput.target_gsm} | |
| onChange={(e: any) => update("target_gsm", e.target.value)} | |
| placeholder="e.g. 120" | |
| tooltip="Target fabric weight. Optional — GSM is also computed if counts + EPI/PPI provided." | |
| type="number" | |
| /> | |
| </div> | |
| <div className="mt-8 flex justify-end"> | |
| <button | |
| onClick={handlePredict} | |
| disabled={predicting || !predictionInput.weave || !predictionInput.blend || !predictionInput.finish_epi || !predictionInput.finish_ppi} | |
| className="bg-indigo-600 hover:bg-indigo-700 disabled:opacity-50 disabled:cursor-not-allowed text-white px-6 py-2.5 rounded-lg font-medium shadow-sm transition-colors flex items-center gap-2" | |
| > | |
| {predicting ? ( | |
| <> | |
| <svg className="animate-spin h-5 w-5" viewBox="0 0 24 24"> | |
| <circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4" fill="none" /> | |
| <path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z" /> | |
| </svg> | |
| Analyzing... | |
| </> | |
| ) : ( | |
| <> | |
| <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"> | |
| <rect width="7" height="7" x="14" y="3" rx="1"></rect> | |
| <path d="M10 21V8l-7 8"></path> | |
| <path d="M10 13h12"></path> | |
| </svg> | |
| Generate Construction | |
| </> | |
| )} | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| ); | |
| } | |
| function InputField({ label, type = "text", value, onChange, placeholder, tooltip }: any) { | |
| return ( | |
| <div className="flex flex-col space-y-1.5"> | |
| <div className="text-sm font-medium text-slate-700 flex items-center"> | |
| {label} | |
| {tooltip && <TooltipItem label={label} text={tooltip} />} | |
| </div> | |
| <input | |
| type={type} | |
| value={value} | |
| onChange={onChange} | |
| placeholder={placeholder} | |
| className="px-3 py-2 border border-slate-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-transparent text-sm bg-white text-slate-900" | |
| /> | |
| </div> | |
| ); | |
| } | |
| function SelectField({ label, value, onChange, options, required, tooltip }: any) { | |
| return ( | |
| <div className="flex flex-col space-y-1.5"> | |
| <div className="text-sm font-medium text-slate-700 flex items-center"> | |
| {label} {required && <span className="text-red-500 ml-1">*</span>} | |
| {tooltip && <TooltipItem label={label} text={tooltip} />} | |
| </div> | |
| <select | |
| value={value} | |
| onChange={(e) => onChange(e.target.value)} | |
| className="px-3 py-2 border border-slate-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-transparent text-sm bg-white text-slate-900" | |
| > | |
| <option value="">Select...</option> | |
| {options?.map((opt: string) => ( | |
| <option key={opt} value={opt}> | |
| {opt} | |
| </option> | |
| ))} | |
| </select> | |
| </div> | |
| ); | |
| } | |