textmachine/frontend/src/showcase/Context.tsx

117 lines
3.7 KiB
TypeScript

import type { Bank as BankData, BookDetail, Chapter, NoteList } from '../api';
import { useText } from '../i18n/text';
import { Panel } from '../shell/Panel';
import { About } from './About';
import { Bank } from './Bank';
import { Loaded } from './Loaded';
import { Notes } from './Notes';
interface Props {
book: Parameters<typeof Loaded<BookDetail>>[0]['query'];
/** True when the library came back with nothing: "pick a book" would point at an empty list. */
libraryEmpty?: boolean;
chapters: Chapter[];
notes: Parameters<typeof Loaded<NoteList>>[0]['query'];
bank: Parameters<typeof Loaded<BankData>>[0]['query'];
/** The tab is raised onto the screen: the go-to palette leads HERE, to the term it found. */
tab: string;
onTabChange: (id: string) => void;
/** The palette's request to show a term. The search string is the bank's own to keep. */
request: { term: string; seq: number };
onOpenChapter: (chapterId: string) => void;
/** Opens the run form. Absent while there is no book to run one over. */
onStartRun?: () => void;
}
/**
* The panel of context for the book being read. The bank lives here rather than on the left
* (owner, 02.08): the reader's cycle is "read the translation → trip over a term → check it in the
* bank", and all three have to be visible at once — that is, in columns, not in rows.
*/
export function Context({
book,
libraryEmpty,
chapters,
notes,
bank,
tab,
onTabChange,
request,
onOpenChapter,
onStartRun,
}: Props) {
const text = useText();
// Telling the reader to pick a book from a panel that says "not a single book" is a screen
// arguing with itself; it was on the session's own first-run shot.
const idle = libraryEmpty
? { title: text('about.noBooksTitle'), description: text('about.noBooksDescription') }
: undefined;
return (
<Panel
label={text('about.panel')}
landmark="complementary"
selectedId={tab}
onSelect={onTabChange}
// The panels do not unmount: the bank's scroll over hundreds of terms survives a trip
// to "About the book" and back (Ф-19).
keepAlive
tabs={[
{
id: 'about',
label: text('about.tab'),
content: (
<Loaded query={book} waiting={text('about.tab')} idle={idle}>
{(detail) => <About detail={detail} onStartRun={onStartRun} />}
</Loaded>
),
},
{
id: 'notes',
label: text('notes.tab'),
content: (
<Loaded
query={notes}
waiting={text('notes.tab')}
idle={idle}
isEmpty={(data) => data.notes.length === 0}
empty={{
title: text('notes.emptyTitle'),
description: text('notes.emptyDescription'),
}}
>
{(data) => (
<Notes notes={data.notes} chapters={chapters} onOpenChapter={onOpenChapter} />
)}
</Loaded>
),
},
{
id: 'bank',
label: text('bank.tab'),
content: (
<Loaded
query={bank}
waiting={text('bank.waiting')}
idle={idle}
isEmpty={(data) => data.total === 0}
empty={{
title: text('bank.emptyTitle'),
description: text('bank.emptyDescription'),
}}
>
{(data) => (
<Bank
bank={data}
sourceLang={book.data?.book.source_lang}
awaitingSignature={book.data?.book.status === 'awaiting_bank'}
request={request}
/>
)}
</Loaded>
),
},
]}
/>
);
}