~bigbes/lethe

ref: 859d3fd879fffd81f7f72b5511e9fec061e3288d lethe/docs/design_handoff_assistant_log/proto-atoms.jsx -rw-r--r-- 4.4 KiB
859d3fd8 — Eugene Blikh auth: lift oidc test stub into internal/testutil/oidcstub a month ago
                                                                                
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
115
116
117
118
119
120
121
122
123
124
125
126
// Atoms reused across screens

const Spark = ({ w = 60, h = 16, accent = false, seed = 1 }) => {
  const pts = [];
  let v = h * 0.5;
  for (let i = 0; i < 14; i++) {
    v += (Math.sin(seed * i * 1.7) + Math.cos(seed * i * 0.9)) * 2.5;
    v = Math.max(2, Math.min(h - 2, v));
    pts.push(`${(i / 13) * (typeof w === 'number' ? w : 100)},${v.toFixed(1)}`);
  }
  return (
    <svg width={w} height={h} viewBox={`0 0 ${typeof w === 'number' ? w : 100} ${h}`}
         preserveAspectRatio="none" style={{ display: 'block' }}>
      <polyline points={pts.join(' ')} className={'spark' + (accent ? ' accent' : '')} />
    </svg>
  );
};

const ToolDot = ({ tool }) => (
  <span className="tooldot" style={{ background: TOOL_COLORS[tool] || '#888' }} />
);

const ToolTag = ({ tool }) => (
  <span className="tag"><ToolDot tool={tool} /> {tool}</span>
);

const HostTag = ({ host }) => <span className="tag host">{host}</span>;

const StatusDot = ({ status }) => <span className={'statusdot ' + status} />;

// Filter chip popover
const FilterPopover = ({ dim, value, onPick, onClose, anchor }) => {
  const ref = React.useRef(null);
  React.useEffect(() => {
    const onDoc = (e) => { if (ref.current && !ref.current.contains(e.target)) onClose(); };
    setTimeout(() => document.addEventListener('mousedown', onDoc), 0);
    return () => document.removeEventListener('mousedown', onDoc);
  }, [onClose]);
  const opts = FILTER_DIMS[dim] || [];
  const top = (anchor?.top || 30) + 4;
  const left = anchor?.left || 14;
  return (
    <div ref={ref} className="popover" style={{ top, left }}>
      <div className="ph">{dim}</div>
      {opts.map(o => (
        <div key={o} className="pi" onClick={() => { onPick(o); onClose(); }}>
          <span style={{
            width: 10, height: 10, borderRadius: 99,
            border: '1px solid var(--ink-3)',
            background: o === value ? 'var(--accent)' : 'transparent',
            display: 'inline-block', flex: 'none'
          }} />
          <span className="mono">{o}</span>
        </div>
      ))}
    </div>
  );
};

// Removable filter chip with click-through to popover
const FilterChip = ({ dim, value, onChange, onRemove }) => {
  const [open, setOpen] = React.useState(false);
  const [anchor, setAnchor] = React.useState(null);
  const ref = React.useRef(null);
  return (
    <>
      <span ref={ref} className={'tag click' + (value !== 'any' ? ' accent' : '')}
        onClick={(e) => {
          const r = ref.current.getBoundingClientRect();
          const parent = ref.current.closest('.app').getBoundingClientRect();
          setAnchor({ top: r.bottom - parent.top, left: r.left - parent.left });
          setOpen(true);
        }}>
        {dim}: {value}
        {onRemove && (
          <span style={{ opacity: 0.6, marginLeft: 2 }}
            onClick={(e) => { e.stopPropagation(); onRemove(); }}>×</span>
        )}
      </span>
      {open && <FilterPopover dim={dim} value={value} anchor={anchor}
        onPick={onChange} onClose={() => setOpen(false)} />}
    </>
  );
};

// Add-filter dashed chip + popover for which dim
const AddFilterChip = ({ availableDims, onAdd }) => {
  const [open, setOpen] = React.useState(false);
  const [anchor, setAnchor] = React.useState(null);
  const ref = React.useRef(null);
  return (
    <>
      <span ref={ref} className="tag dashed"
        onClick={() => {
          const r = ref.current.getBoundingClientRect();
          const parent = ref.current.closest('.app').getBoundingClientRect();
          setAnchor({ top: r.bottom - parent.top, left: r.left - parent.left });
          setOpen(true);
        }}>+ filter</span>
      {open && (
        <div className="popover" style={{ top: anchor.top + 4, left: anchor.left }}
          onMouseLeave={() => setOpen(false)}>
          <div className="ph">add filter</div>
          {availableDims.map(d => (
            <div key={d} className="pi" onClick={() => { onAdd(d); setOpen(false); }}>
              <span className="mono">{d}</span>
            </div>
          ))}
        </div>
      )}
    </>
  );
};

const Empty = ({ glyph = '∅', title, hint }) => (
  <div className="empty">
    <div className="glyph">{glyph}</div>
    <div style={{ fontSize: 13, color: 'var(--ink-2)' }}>{title}</div>
    {hint && <div style={{ marginTop: 4 }} className="muted mono">{hint}</div>}
  </div>
);

Object.assign(window, {
  Spark, ToolDot, ToolTag, HostTag, StatusDot,
  FilterPopover, FilterChip, AddFilterChip, Empty,
});