69 lines
3.1 KiB
TypeScript
69 lines
3.1 KiB
TypeScript
import { ContentEditable } from "@common/components/ContentEditable";
|
|
import { highlight } from "@common/highlight";
|
|
import { useMemo } from "preact/hooks";
|
|
import styles from "../../assets/chapters-editor.module.css";
|
|
import { useAppState } from "../../contexts/state";
|
|
import Chapters from "../../utils/chapters";
|
|
|
|
export const ChaptersEditor = () => {
|
|
const { currentWorld, currentStory, dispatch } = useAppState();
|
|
|
|
if (!currentStory) return null;
|
|
|
|
const parsed = useMemo(
|
|
() => Chapters.parseText(currentStory.text),
|
|
[currentStory.text]
|
|
);
|
|
|
|
if (parsed.length === 0) {
|
|
return (
|
|
<div class={styles.chaptersEditor}>
|
|
<p class={styles.empty}>No chapters yet. Use <code># Chapter Title</code> headers in your story to create chapters.</p>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<div class={styles.chaptersEditor}>
|
|
{parsed.map((parsedChapter) => {
|
|
const chunks = Chapters.splitIntoChunks(parsedChapter.body);
|
|
const cachedChapter = (currentStory.chapters ?? []).find(c => c.header === parsedChapter.header)
|
|
?? Chapters.emptyChapter(parsedChapter.header);
|
|
|
|
return (
|
|
<div class={styles.chapterCard} key={parsedChapter.header || '__preamble__'}>
|
|
<div class={styles.chapterTitle}>
|
|
{parsedChapter.header ? parsedChapter.header.replace(/^# /, '') : '(Preamble)'}
|
|
</div>
|
|
{chunks.map((body, i) => {
|
|
const { hash, summary } = Chapters.lookupSummary(cachedChapter, body);
|
|
return (
|
|
<div class={styles.chunk} key={i}>
|
|
{chunks.length > 1 && (
|
|
<div class={styles.chunkHeader}>Part {i + 1}</div>
|
|
)}
|
|
<div class={styles.chunkPreview}>{body}</div>
|
|
<ContentEditable
|
|
autoLines
|
|
class={styles.summaryEditable}
|
|
value={highlight(summary ?? '')}
|
|
placeholder="Not summarized yet..."
|
|
onInput={(e) => dispatch({
|
|
type: 'STORE_CHAPTER_SUMMARY',
|
|
worldId: currentWorld!.id,
|
|
storyId: currentStory.id,
|
|
header: parsedChapter.header,
|
|
hash,
|
|
summary: (e.target as HTMLDivElement).textContent || '',
|
|
})}
|
|
/>
|
|
</div>
|
|
);
|
|
})}
|
|
</div>
|
|
);
|
|
})}
|
|
</div>
|
|
);
|
|
};
|