89 lines
2.9 KiB
TypeScript
89 lines
2.9 KiB
TypeScript
import { ContentEditable } from "@common/components/ContentEditable";
|
|
import { highlight } from "@common/highlight";
|
|
import { useAppState, type Tab } from "../contexts/state";
|
|
import styles from '../assets/editor.module.css';
|
|
import { useMemo } from "preact/hooks";
|
|
import clsx from "clsx";
|
|
import { CharacterEditor } from "./character-editor";
|
|
import { LocationEditor } from "./location-editor";
|
|
import { ChaptersEditor } from "./chapters-editor";
|
|
import { LoreEditor } from "./lore-editor";
|
|
import { useInputCallback } from "@common/hooks/useInputCallback";
|
|
|
|
const TABS: { id: Tab; label: string }[] = [
|
|
{ id: "story", label: "Story" },
|
|
{ id: "chapters", label: "Chapters" },
|
|
{ id: "lore", label: "Lore" },
|
|
{ id: "characters", label: "Characters" },
|
|
{ id: "locations", label: "Locations" },
|
|
];
|
|
|
|
export const Editor = () => {
|
|
const { currentStory, dispatch } = useAppState();
|
|
|
|
const handleInput = useInputCallback((text: string) => {
|
|
if (!currentStory) return;
|
|
dispatch({
|
|
type: 'EDIT_STORY',
|
|
id: currentStory.id,
|
|
text,
|
|
});
|
|
}, [currentStory?.id]);
|
|
|
|
const handleTabChange = (tab: Tab) => {
|
|
if (!currentStory) return;
|
|
dispatch({
|
|
type: 'SET_CURRENT_TAB',
|
|
id: currentStory.id,
|
|
tab,
|
|
});
|
|
};
|
|
|
|
const storyValue = useMemo(() => currentStory ? highlight(currentStory.text) : '', [currentStory?.text]);
|
|
|
|
if (!currentStory) {
|
|
return <div class={styles.editor} />;
|
|
}
|
|
|
|
return (
|
|
<div class={styles.editor}>
|
|
<div class={styles.title}>
|
|
{currentStory.title}
|
|
</div>
|
|
<div class={styles.content}>
|
|
{currentStory.currentTab === "story" && (
|
|
<ContentEditable
|
|
class={styles.editable}
|
|
value={storyValue}
|
|
onInput={handleInput}
|
|
placeholder="Start writing your story..."
|
|
/>
|
|
)}
|
|
{currentStory.currentTab === "lore" && (
|
|
<LoreEditor />
|
|
)}
|
|
{currentStory.currentTab === "characters" && (
|
|
<CharacterEditor />
|
|
)}
|
|
{currentStory.currentTab === "locations" && (
|
|
<LocationEditor />
|
|
)}
|
|
{currentStory.currentTab === "chapters" && (
|
|
<ChaptersEditor />
|
|
)}
|
|
</div>
|
|
<div class={styles.tabs}>
|
|
{TABS.map((tab) => (
|
|
<button
|
|
key={tab.id}
|
|
class={clsx(styles.tab, currentStory.currentTab === tab.id && styles.active)}
|
|
onClick={() => handleTabChange(tab.id)}
|
|
>
|
|
{tab.label}
|
|
</button>
|
|
))}
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|