import clsx from "clsx";
import { ConnectionSettingsModal } from "./connection-settings-modal";
import { SettingsModal } from "./settings-modal";
import { useAppState } from "../contexts/state";
import { useBool } from "@common/hooks/useBool";
import { useInputState } from "@common/hooks/useInputState";
import type { World, Story } from "../contexts/state";
import styles from '../assets/menu.module.css';
import { Pencil, X, Plus, Plug, Settings, Copy, ChevronRight, ChevronDown, Globe } from "lucide-preact";
// ─── Inline Rename Input ──────────────────────────────────────────────────────
interface RenameInputProps {
value: string;
onSubmit: (title: string) => void;
onCancel: () => void;
className?: string;
}
const RenameInput = ({ value, onSubmit, onCancel, className }: RenameInputProps) => {
const [editTitle, setEditTitle] = useInputState(value);
const handleSubmit = () => {
if (editTitle.trim()) onSubmit(editTitle.trim());
else onCancel();
};
const handleKeyDown = (e: KeyboardEvent) => {
if (e.key === 'Enter') handleSubmit();
else if (e.key === 'Escape') onCancel();
};
return (
);
};
// ─── Story Item ───────────────────────────────────────────────────────────────
interface StoryItemProps {
story: Story;
active: boolean;
onSelect: () => void;
onRename: (newTitle: string) => void;
onDelete: () => void;
onDuplicate: () => void;
}
const StoryItem = ({ story, active, onSelect, onRename, onDelete, onDuplicate }: StoryItemProps) => {
const isEditing = useBool(false);
if (isEditing.value) {
return (
{ onRename(t); isEditing.setFalse(); }}
onCancel={isEditing.setFalse}
/>
);
}
return (
);
};
// ─── World Item ───────────────────────────────────────────────────────────────
interface WorldItemProps {
world: World;
activeWorldId: string | null;
activeStoryId: string | null;
onSelectWorld: () => void;
onRenameWorld: (title: string) => void;
onDeleteWorld: () => void;
onCreateStory: () => void;
onSelectStory: (storyId: string) => void;
onRenameStory: (storyId: string, title: string) => void;
onDeleteStory: (storyId: string) => void;
onDuplicateStory: (storyId: string) => void;
}
const WorldItem = ({
world, activeWorldId, activeStoryId,
onSelectWorld, onRenameWorld, onDeleteWorld, onCreateStory,
onSelectStory, onRenameStory, onDeleteStory, onDuplicateStory,
}: WorldItemProps) => {
const isRenaming = useBool(false);
const isExpanded = useBool(activeWorldId === world.id);
const isWorldActive = activeWorldId === world.id && !activeStoryId;
const toggleExpand = (e: MouseEvent) => {
e.stopPropagation();
isExpanded.toggle();
};
return (
{isRenaming.value ? (
{ onRenameWorld(t); isRenaming.setFalse(); }}
onCancel={isRenaming.setFalse}
/>
) : (
)}
{isExpanded.value && (
{world.stories.map(story => (
onSelectStory(story.id)}
onRename={(title) => onRenameStory(story.id, title)}
onDelete={() => onDeleteStory(story.id)}
onDuplicate={() => onDuplicateStory(story.id)}
/>
))}
{world.stories.length === 0 && (
No stories yet
)}
)}
);
};
// ─── Menu Sidebar ─────────────────────────────────────────────────────────────
export const Menu = () => {
const { worlds, currentWorld, currentStory, dispatch } = useAppState();
const isConnectionSettingsOpen = useBool(false);
const isSettingsOpen = useBool(false);
const handleCreateWorld = () => {
dispatch({ type: 'CREATE_WORLD', title: 'New World' });
};
const handleSelectWorld = (worldId: string) => {
dispatch({ type: 'SELECT_WORLD', worldId });
};
const handleRenameWorld = (worldId: string, title: string) => {
dispatch({ type: 'RENAME_WORLD', worldId, title });
};
const handleDeleteWorld = (worldId: string) => {
const world = worlds.find(w => w.id === worldId);
if (!world) return;
if (confirm(`Delete world "${world.title}" and all its stories?`)) {
dispatch({ type: 'DELETE_WORLD', worldId });
}
};
const handleCreateStory = (worldId: string) => {
dispatch({ type: 'CREATE_STORY', worldId, title: 'New Story' });
};
const handleSelectStory = (worldId: string, storyId: string) => {
dispatch({ type: 'SELECT_STORY', worldId, id: storyId });
};
const handleRenameStory = (worldId: string, storyId: string, title: string) => {
dispatch({ type: 'RENAME_STORY', worldId, id: storyId, title });
};
const handleDeleteStory = (worldId: string, storyId: string) => {
const world = worlds.find(w => w.id === worldId);
const story = world?.stories.find(s => s.id === storyId);
if (!story) return;
if (confirm(`Delete "${story.title}"?`)) {
dispatch({ type: 'DELETE_STORY', worldId, id: storyId });
}
};
const handleDuplicateStory = (worldId: string, storyId: string) => {
dispatch({ type: 'DUPLICATE_STORY', worldId, id: storyId });
};
return (
);
};