File size: 2,516 Bytes
5a0e691
 
2f67ecf
 
d54a751
5a0e691
76fb273
 
 
 
5a0e691
 
 
 
 
76fb273
 
 
 
 
 
 
 
 
5a0e691
 
 
 
 
 
9a28cd0
5a0e691
 
9a28cd0
5a0e691
 
 
 
 
 
d54a751
 
5a0e691
 
d54a751
5a0e691
 
d54a751
 
5a0e691
9a28cd0
d54a751
9a28cd0
5a0e691
 
76fb273
 
 
 
 
d54a751
76fb273
 
 
 
d54a751
5a0e691
 
 
d54a751
5a0e691
d54a751
 
 
5a0e691
d54a751
 
5a0e691
2f67ecf
5a0e691
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
'use client';

import { motion } from 'framer-motion';
import { fadeUp } from '@/lib/animations';
import { CriticalButton, FlatTextarea } from '@/components/ui';

const SAMPLES = [
  {
    label: 'p53 (human)',
    seq: `>sp|P04637|P53_HUMAN Cellular tumor antigen p53
MEEPQSDPSVEPPLSQETFSDLWKLLPENNVLSPLPSQAMDDLMLSPDDIEQWFTEDPGP
DEAPRMPEAAPPVAPAPAAPTPAAPAPAPSWPLSSSVPSQKTYPQGLNGTVNLPGRNSFEV
RVCACPHERCTEGRAVKLFSPKELNCEMAQDIINNKFNLNLLPETIPNTIICFVESQPPQGD
SVTTCFSWRGEGNEMYLHTEKEYKALKSTLSEKYMATCLLLSPKKKSLFPEALKLCNQKYS
EEFLLLDEALLSGCFAELACALHLAPAEGRYSGGFNHELYNMMTQQQQHQHHLQMQQHHQQ
HHQQHHQQHHQQQQQQQQQQQQQQQQQH`,
  },
  {
    label: 'Insulin (human)',
    seq: `>sp|P01308|INS_HUMAN Insulin
MALWMRLLPLLALLALWGPDPAAAFVNQHLCGSHLVEALYLVCGERGFFYTPKTRREAED
LQVGQVELGGGPGAGSLQPLALEGSLQKRGIVEQCCTSICSLYQLENYCN`,
  },
];

interface SequenceInputProps {
  value: string;
  onChange: (value: string) => void;
  onSubmit: () => void;
  loading: boolean;
  error?: string | null;
}

export function SequenceInput({ value, onChange, onSubmit, loading, error }: SequenceInputProps) {
  const aaCount = value
    .split('\n')
    .filter((l) => !l.startsWith('>'))
    .join('').length;

  return (
    <motion.div variants={fadeUp} className="data-card p-6">
      <label className="block text-sm font-medium text-text-secondary mb-2">
        Enter protein sequence (FASTA or plain)
      </label>
      <FlatTextarea
        value={value}
        onChange={(e) => onChange(e.target.value)}
        rows={10}
        placeholder={">sp|P04637|P53_HUMAN\nMEEPQSDPSVEPPLSQETFSDLWKLLPENNVLSPLPSQ..."}
      />
      {error && (
        <p className="mt-2 text-sm text-error">{error}</p>
      )}
      <div className="flex items-center justify-between mt-4">
        <div className="flex items-center gap-4">
          {SAMPLES.map((s) => (
            <button
              key={s.label}
              type="button"
              onClick={() => onChange(s.seq)}
              className="text-sm text-accent-cyan hover:underline underline-offset-2"
            >
              Load {s.label}
            </button>
          ))}
          <span className="text-xs text-text-muted">
            {value ? `${aaCount} aa` : '0 aa'}
          </span>
        </div>
        <CriticalButton
          onClick={onSubmit}
          disabled={!value.trim()}
          loading={loading}
          type="button"
        >
          {loading ? 'Running pipeline…' : 'Run Pipeline'}
        </CriticalButton>
      </div>
    </motion.div>
  );
}