Spaces:
Running
Running
| import { useMemo } from 'react' | |
| import FileDropZone from './FileDropZone' | |
| import { parseSequences } from '../lib/parseSequences' | |
| interface SequenceInputProps { | |
| value: string | |
| onChange: (v: string) => void | |
| label: string | |
| placeholder?: string | |
| onLoadExample?: () => void | |
| } | |
| export default function SequenceInput({ | |
| value, | |
| onChange, | |
| label, | |
| placeholder, | |
| onLoadExample, | |
| }: SequenceInputProps) { | |
| const parsed = useMemo(() => parseSequences(value), [value]) | |
| return ( | |
| <div className="field"> | |
| <div | |
| className="field-label" | |
| style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }} | |
| > | |
| <span>{label}</span> | |
| {onLoadExample && ( | |
| <button | |
| type="button" | |
| className="btn btn-ghost btn-sm" | |
| onClick={onLoadExample} | |
| > | |
| Load example | |
| </button> | |
| )} | |
| </div> | |
| <FileDropZone onFile={(text) => onChange(text)} /> | |
| <div style={{ margin: '10px 0 6px', fontSize: 'var(--text-sm)' }} className="muted"> | |
| …or paste sequences (FASTA, one-per-line, or comma-separated): | |
| </div> | |
| <textarea | |
| value={value} | |
| placeholder={ | |
| placeholder ?? | |
| '>protein_1\nMAKLVFSLCFLL...\n\nor: PEPTIDE, PEPTIDE, ...' | |
| } | |
| onChange={(e) => onChange(e.target.value)} | |
| /> | |
| <div | |
| style={{ marginTop: 8, display: 'flex', gap: 8, alignItems: 'center' }} | |
| > | |
| <span className={'badge' + (parsed.length ? ' badge-accent' : '')}> | |
| {parsed.length} sequence{parsed.length === 1 ? '' : 's'} parsed | |
| </span> | |
| {value && ( | |
| <button | |
| type="button" | |
| className="btn btn-ghost btn-sm" | |
| onClick={() => onChange('')} | |
| > | |
| Clear | |
| </button> | |
| )} | |
| </div> | |
| </div> | |
| ) | |
| } | |