textmachine/frontend/src/showcase/Document.tsx

57 lines
2.3 KiB
TypeScript

import { useQuery } from '@tanstack/react-query';
import { FileClock } from 'lucide-react';
import { unitsQuery } from '../api';
import { useText } from '../i18n/text';
import { icon } from '../ui/icon';
import { Reader } from './Reader';
import styles from './Document.module.css';
interface Props {
bookId: string;
chapterId: string;
sourceLang?: string;
targetLang?: string;
/** The run over the book has not brought it to ready yet — the text may be regenerated. */
draft: boolean;
/** A meaningful interaction with the content pins the tab (the VS Code model). */
onEngage: () => void;
}
/**
* An open chapter as a document tab. The query lives HERE, not on the screen: tabs are not
* unmounted when switching (keep-alive, Ф-19), and one shared query would hand every open tab the
* text of the active chapter.
*/
export function Document({ bookId, chapterId, sourceLang, targetLang, draft, onEngage }: Props) {
const text = useText();
// There are no tabs without a book, but the query is switched off explicitly: an address built
// from an empty id would go out to the network and come back a refusal, which the screen would
// show as a breakage.
const units = useQuery({ ...unitsQuery(bookId, chapterId), enabled: bookId !== '' });
return (
<div
className={styles.document}
onMouseUp={(event) => {
// Selecting text is that very "meaningful interaction": the reader compared or copied a
// piece, which means the chapter is needed further on. Plain scrolling does not pin.
//
// We ask about exactly THIS chapter and exactly the left button: a right click and a
// selection in a neighbouring panel arrive here too, and a non-empty global selection was
// enough for them to pin a tab nobody touched.
const selection = document.getSelection();
if (event.button !== 0 || selection === null || selection.isCollapsed) return;
if (event.currentTarget.contains(selection.anchorNode)) onEngage();
}}
>
{draft && (
<p className={styles.draft} title={text('document.draftTooltip')}>
<FileClock {...icon} className={styles.draftMark} />
{text('document.draftNote')}
</p>
)}
<Reader sourceLang={sourceLang} targetLang={targetLang} units={units} />
</div>
);
}