1
0
Fork 0

Stories renaming

This commit is contained in:
Pabloader 2026-03-19 16:55:41 +00:00
parent 061f79c473
commit b274d0d018
2 changed files with 140 additions and 15 deletions

View File

@ -24,21 +24,79 @@
gap: 2px;
}
.itemWrapper {
display: flex;
align-items: center;
gap: 4px;
padding: 2px 0;
&.active {
background: var(--bg-active);
border-radius: 4px;
}
}
.item {
width: 100%;
flex: 1;
padding: 6px 8px;
text-align: left;
font-size: 13px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.active {
color: var(--text);
background: var(--bg-active);
background: transparent;
border: none;
outline: none;
cursor: pointer;
color: inherit;
&:hover {
background: var(--bg-active);
background: var(--bg-hover);
}
}
.active .item {
background: transparent;
&:hover {
background: var(--bg-hover);
}
}
.actions {
display: flex;
gap: 2px;
opacity: 0;
transition: opacity 0.1s;
.itemWrapper:hover & {
opacity: 1;
}
}
.actionButton {
padding: 4px 6px;
font-size: 12px;
background: transparent;
border: none;
outline: none;
cursor: pointer;
color: var(--text-muted);
border-radius: 2px;
&:hover {
background: var(--bg-hover);
color: var(--text);
}
}
.input {
flex: 1;
padding: 6px 8px;
font-size: 13px;
background: var(--bg-hover);
border: none;
outline: none;
color: var(--text);
border-radius: 4px;
}

View File

@ -3,6 +3,7 @@ import { Sidebar } from "./sidebar";
import { useAppState } from "../contexts/state";
import type { Story } from "../contexts/state";
import styles from '../assets/menu-sidebar.module.css';
import { useState } from "preact/hooks";
// ─── Story Item ───────────────────────────────────────────────────────────────
@ -10,16 +11,68 @@ interface StoryItemProps {
story: Story;
active: boolean;
onSelect: () => void;
onRename: (newTitle: string) => void;
onDelete: () => void;
}
const StoryItem = ({ story, active, onSelect }: StoryItemProps) => (
<button
class={clsx(styles.item, active && styles.active)}
onClick={onSelect}
>
{story.title}
</button>
);
const StoryItem = ({ story, active, onSelect, onRename, onDelete }: StoryItemProps) => {
const [isEditing, setIsEditing] = useState(false);
const [editTitle, setEditTitle] = useState(story.title);
const handleSubmit = () => {
if (editTitle.trim()) {
onRename(editTitle.trim());
}
setIsEditing(false);
};
const handleKeyDown = (e: KeyboardEvent) => {
if (e.key === 'Enter') {
handleSubmit();
} else if (e.key === 'Escape') {
setEditTitle(story.title);
setIsEditing(false);
}
};
const handleBlur = () => {
handleSubmit();
};
if (isEditing) {
return (
<div class={clsx(styles.itemWrapper, active && styles.active)}>
<input
class={styles.input}
value={editTitle}
onInput={(e) => setEditTitle((e.target as HTMLInputElement).value)}
onKeyDown={handleKeyDown}
onBlur={handleBlur}
autoFocus
/>
</div>
);
}
return (
<div class={clsx(styles.itemWrapper, active && styles.active)}>
<button
class={clsx(styles.item, active && styles.active)}
onClick={onSelect}
>
{story.title}
</button>
<div class={styles.actions}>
<button class={styles.actionButton} onClick={() => setIsEditing(true)} title="Rename">
</button>
<button class={styles.actionButton} onClick={onDelete} title="Delete">
×
</button>
</div>
</div>
);
};
// ─── Menu Sidebar ─────────────────────────────────────────────────────────────
@ -34,6 +87,18 @@ export const MenuSidebar = () => {
dispatch({ type: 'SELECT_STORY', id });
};
const handleRename = (id: string, newTitle: string) => {
dispatch({ type: 'RENAME_STORY', id, title: newTitle });
};
const handleDelete = (id: string) => {
const story = stories.find(s => s.id === id);
if (!story) return;
if (confirm(`Delete "${story.title}"?`)) {
dispatch({ type: 'DELETE_STORY', id });
}
};
return (
<Sidebar side="left">
<div class={styles.menu}>
@ -47,6 +112,8 @@ export const MenuSidebar = () => {
story={story}
active={story.id === currentStory?.id}
onSelect={() => handleSelect(story.id)}
onRename={(newTitle) => handleRename(story.id, newTitle)}
onDelete={() => handleDelete(story.id)}
/>
))}
</div>