117 lines
3.7 KiB
TypeScript
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>
|
|
),
|
|
},
|
|
]}
|
|
/>
|
|
);
|
|
}
|