anvilsign in

collin/strudel-claude

1import { Box, Text } from 'ink';
2import { memo } from 'react';
3import type { ReactElement } from 'react';
4import { html } from './html.ts';
5import type { SessionMeta } from '../sessions.ts';
6
7export interface SessionListProps {
8 sessions: readonly SessionMeta[];
9 /** Index of the highlighted row, or -1 for none. */
10 selected: number;
11 /** The session currently open in the editor. */
12 current: string | null;
13 /** Whether this panel has keyboard focus. */
14 focused: boolean;
15 height: number;
16 /** First visible row — computed by the caller so clicks map to the same row. */
17 scrollTop: number;
18}
19
20export const SessionList = memo(function SessionList({
21 sessions, selected, current, focused, height, scrollTop,
22}: SessionListProps): ReactElement {
23 if (sessions.length === 0) {
24 return html`
25 <${Box} flexDirection="column">
26 <${Text} dimColor>no sessions yet<//>
27 <${Text} dimColor>^S to save<//>
28 <//>
29 `;
30 }
31
32 const top = scrollTop;
33 const shown = sessions.slice(top, top + height);
34
35 return html`
36 <${Box} flexDirection="column">
37 ${shown.map((session, i) => {
38 const index = top + i;
39 const isSelected = index === selected;
40 const isCurrent = session.name === current;
41 return html`
42 <${Text}
43 key=${session.file}
44 wrap="truncate-end"
45 inverse=${isSelected && focused}
46 bold=${isCurrent}
47 color=${isCurrent ? 'magenta' : undefined}
48 dimColor=${!isCurrent && !isSelected}
49 >${isCurrent ? '▸ ' : ' '}${session.name}${session.hasHistory ? '' : ' ·'}<//>
50 `;
51 })}
52 <//>
53 `;
54});