File size: 2,319 Bytes
c3633b1
0ed8124
 
6c62075
0ed8124
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6c62075
0ed8124
 
 
 
 
 
6c62075
0ed8124
 
6c62075
 
0ed8124
 
 
 
6c62075
0ed8124
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21ad36a
 
0ed8124
 
 
 
 
 
 
 
 
 
 
6c62075
0ed8124
 
 
 
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
import type { ModelId, ModelOption } from '../../lib/contracts';

interface ModelRailProps {
  hidden?: boolean;
  models: ModelOption[];
  activeModelId: ModelId;
  busy: boolean;
  onModelSelect: (modelId: ModelId) => void;
}

const availabilityLabels: Record<ModelOption['availability'], string> = {
  loaded: 'loaded',
  cached: 'cached',
  remote: 'remote',
  limited: 'limited',
  loading: 'loading',
};

export function ModelRail({
  hidden = false,
  models,
  activeModelId,
  busy,
  onModelSelect,
}: ModelRailProps) {
  return (
    <aside className="model-rail" aria-labelledby="model-rail-title" hidden={hidden}>
      <div className="rail-heading">
        <div>
          <h2 id="model-rail-title">Models</h2>
          <p>Choose what runs in this browser.</p>
        </div>
      </div>

      <div className="model-list" role="list" aria-label="Available Bonsai models">
        {models.map((model) => {
          const active = model.id === activeModelId;
          return (
            <article className={`model-card${active ? ' is-active' : ''}`} key={model.id} role="listitem">
              <button
                className="model-select"
                type="button"
                disabled={busy}
                onClick={() => onModelSelect(model.id)}
                aria-pressed={active}
              >
                <span className="model-copy">
                  <span className="model-title-line">
                    <strong>{model.parameters}</strong>
                    <small className={`availability availability-${model.availability}`}>
                      {availabilityLabels[model.availability]}
                    </small>
                  </span>
                  <span className="model-architecture">{model.architectureLabel}</span>
                  <span>{model.runtimeLabel}</span>
                </span>
                <span className="model-footprint">{model.footprint}</span>
              </button>
              {model.availability === 'limited' && <small className="model-limit-reason">{model.limitReason ?? 'Device gate unavailable'}</small>}
            </article>
          );
        })}
      </div>

      <footer className="rail-footnote">
        <span>GGUF · Q1_0</span>
        <span>Commit pinned</span>
      </footer>
    </aside>
  );
}