45 lines
1.5 KiB
TypeScript
45 lines
1.5 KiB
TypeScript
import { ContentEditable } from "@common/components/ContentEditable";
|
|
import { highlight } from "@common/highlight";
|
|
import { useInputCallback } from "@common/hooks/useInputCallback";
|
|
import { useMemo } from "preact/hooks";
|
|
import styles from "../../assets/editor.module.css";
|
|
import { useAppState } from "../../contexts/state";
|
|
|
|
export const StoryEditor = ({ visible }: { visible: boolean }) => {
|
|
const { currentWorld, currentStory, dispatch } = useAppState();
|
|
|
|
const handleInput = useInputCallback((text: string) => {
|
|
if (!currentStory || !currentWorld) return;
|
|
dispatch({
|
|
type: 'EDIT_STORY',
|
|
worldId: currentWorld.id,
|
|
id: currentStory.id,
|
|
text,
|
|
});
|
|
}, [currentStory?.id, currentWorld?.id]);
|
|
|
|
const value = useMemo(() => {
|
|
if (!currentStory) return '';
|
|
const { text, lastEditedText } = currentStory;
|
|
if (!lastEditedText) return highlight(text);
|
|
const idx = text.lastIndexOf(lastEditedText);
|
|
if (idx === -1) return highlight(text);
|
|
const marked = text.slice(0, idx) + '<mark>' + lastEditedText + '</mark>' + text.slice(idx + lastEditedText.length);
|
|
return highlight(marked);
|
|
}, [currentStory?.text, currentStory?.lastEditedText]);
|
|
|
|
|
|
if (!currentWorld || !currentStory || !visible) {
|
|
return null;
|
|
}
|
|
|
|
return (
|
|
<ContentEditable
|
|
class={styles.editable}
|
|
value={value}
|
|
onInput={handleInput}
|
|
placeholder="Start writing your story..."
|
|
/>
|
|
);
|
|
};
|