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; gap: 2px;
} }
.itemWrapper {
display: flex;
align-items: center;
gap: 4px;
padding: 2px 0;
&.active {
background: var(--bg-active);
border-radius: 4px;
}
}
.item { .item {
width: 100%; flex: 1;
padding: 6px 8px; padding: 6px 8px;
text-align: left; text-align: left;
font-size: 13px; font-size: 13px;
white-space: nowrap; white-space: nowrap;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
} background: transparent;
border: none;
.active { outline: none;
color: var(--text); cursor: pointer;
background: var(--bg-active); color: inherit;
&:hover { &: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 { useAppState } from "../contexts/state";
import type { Story } from "../contexts/state"; import type { Story } from "../contexts/state";
import styles from '../assets/menu-sidebar.module.css'; import styles from '../assets/menu-sidebar.module.css';
import { useState } from "preact/hooks";
// ─── Story Item ─────────────────────────────────────────────────────────────── // ─── Story Item ───────────────────────────────────────────────────────────────
@ -10,16 +11,68 @@ interface StoryItemProps {
story: Story; story: Story;
active: boolean; active: boolean;
onSelect: () => void; onSelect: () => void;
onRename: (newTitle: string) => void;
onDelete: () => void;
} }
const StoryItem = ({ story, active, onSelect }: StoryItemProps) => ( 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 <button
class={clsx(styles.item, active && styles.active)} class={clsx(styles.item, active && styles.active)}
onClick={onSelect} onClick={onSelect}
> >
{story.title} {story.title}
</button> </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 ───────────────────────────────────────────────────────────── // ─── Menu Sidebar ─────────────────────────────────────────────────────────────
@ -34,6 +87,18 @@ export const MenuSidebar = () => {
dispatch({ type: 'SELECT_STORY', id }); 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 ( return (
<Sidebar side="left"> <Sidebar side="left">
<div class={styles.menu}> <div class={styles.menu}>
@ -47,6 +112,8 @@ export const MenuSidebar = () => {
story={story} story={story}
active={story.id === currentStory?.id} active={story.id === currentStory?.id}
onSelect={() => handleSelect(story.id)} onSelect={() => handleSelect(story.id)}
onRename={(newTitle) => handleRename(story.id, newTitle)}
onDelete={() => handleDelete(story.id)}
/> />
))} ))}
</div> </div>