File size: 3,652 Bytes
dd079af
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
import { useNavigate } from 'react-router-dom';
import type { SequenceSummary } from '../lib/api';
import { cleanFunction, fmtInt, methodShort, sequencePath, year } from '../lib/format';
import { MiniSplit } from './charts';

export type SortKey = 'sequence' | 'length' | 'observations' | 'states' | 'entries' | 'released';

function Th({
  k,
  label,
  sort,
  order,
  onSort,
  num,
}: {
  k: SortKey;
  label: string;
  sort?: SortKey;
  order?: 'asc' | 'desc';
  onSort?: (k: SortKey) => void;
  num?: boolean;
}) {
  const active = sort === k;
  if (!onSort) return <th className={num ? 'num' : ''}>{label}</th>;
  return (
    <th className={num ? 'num' : ''} aria-sort={active ? (order === 'asc' ? 'ascending' : 'descending') : 'none'}>
      <button type="button" className={`th-sort ${active ? 'is-active' : ''}`} onClick={() => onSort(k)}>
        {label}
        <span className="th-sort__arrow" aria-hidden>
          {active ? (order === 'asc' ? '↑' : '↓') : '↕'}
        </span>
      </button>
    </th>
  );
}

export function SequenceTable({
  items,
  sort,
  order,
  onSort,
}: {
  items: SequenceSummary[];
  sort?: SortKey;
  order?: 'asc' | 'desc';
  onSort?: (k: SortKey) => void;
}) {
  const navigate = useNavigate();
  const p = { sort, order, onSort };
  return (
    <div className="table-wrap">
      <table className="table table--rows">
        <thead>
          <tr>
            <Th k="sequence" label="Sequence" {...p} />
            <th>Function</th>
            <Th k="length" label="Length" num {...p} />
            <Th k="observations" label="Obs." num {...p} />
            <Th k="states" label="States" num {...p} />
            <Th k="entries" label="Entries" num {...p} />
            <th>Apo / holo</th>
            <th>Methods</th>
            <Th k="released" label="Latest" num {...p} />
          </tr>
        </thead>
        <tbody>
          {items.map((s) => (
            <tr
              key={s.sequence_id}
              className="is-clickable"
              onClick={(e) => {
                if ((e.target as HTMLElement).closest('a')) return;
                navigate(sequencePath(s.sequence_id));
              }}
            >
              <td>
                <a
                  href={sequencePath(s.sequence_id)}
                  className="mono strong"
                  onClick={(e) => {
                    e.preventDefault();
                    navigate(sequencePath(s.sequence_id));
                  }}
                >
                  {s.sequence_id}
                </a>
                <div className="sub mono">{s.uniprot_id ?? 'no UniProt'}</div>
              </td>
              <td className="fn-cell">
                <span title={s.top_function ?? undefined}>{s.top_function ? cleanFunction(s.top_function) : '—'}</span>
              </td>
              <td className="num tabular">{fmtInt(s.length)}</td>
              <td className="num tabular">{fmtInt(s.n_obs)}</td>
              <td className="num tabular strong">{fmtInt(s.n_states)}</td>
              <td className="num tabular">{fmtInt(s.n_entries)}</td>
              <td>
                <MiniSplit
                  a={s.n_apo}
                  b={s.n_holo}
                  colorA="var(--apo)"
                  colorB="var(--holo)"
                  title={`${s.n_apo} apo · ${s.n_holo} holo`}
                />
              </td>
              <td className="methods-cell">{s.methods.slice(0, 2).map(methodShort).join(', ')}</td>
              <td className="num tabular">{year(s.last_release)}</td>
            </tr>
          ))}
        </tbody>
      </table>
    </div>
  );
}