import { useMemo, useState } from "react"; import { useNotes } from "../../hooks/useNotes"; import { useNoteDraft } from "./useNoteDraft"; import NoteSwitcher from "./NoteSwitcher"; import SendToAgentButton from "./SendToAgentButton"; import Button from "../ui/Button"; import OverflowMenu from "../ui/OverflowMenu"; import SaveIndicator from "../ui/SaveIndicator"; interface Props { projectId: string; } /** * Notes at dock width. * * Deliberately not `NotesPanel` in a narrower box. The tab can afford a column * of titles beside the editor; the dock cannot, and shrinking that layout * spends its height on chrome — a title strip, a wrapped button row and a * paragraph of help — for a body that ends up a few words wide. * * So the dock shows exactly one note. The title row names it and switches to * another, the actions that are not writing live in the overflow menu, and * everything left over is the body. Roughly 240px of height comes back. * * What the two surfaces share is the part that must not drift: `useNotes` for * the cache and its write ordering, and `useNoteDraft` for when a keystroke * becomes a save. Only the layout is different. */ export default function NotesDockPanel({ projectId }: Props) { const { notes, loading, saveState, createNote, saveNote, deleteNote } = useNotes(projectId); const [selectedId, setSelectedId] = useState(null); const selected = useMemo( () => notes.find((n) => n.id === selectedId) ?? notes[0] ?? null, [notes, selectedId], ); const { title, body, setTitle, setBody, commit } = useNoteDraft( selected, saveNote, ); const onCreate = async () => { const note = await createNote(); if (note) setSelectedId(note.id); }; if (loading) { return (

Loading notes…

); } if (!selected) { return (

Keep reminders here, and send any of them straight to a running Claude session.

); } return (
{/* Renders nothing while idle, so it costs no width until it matters. */} void onCreate() }, { label: "Delete note", danger: true, onSelect: () => void deleteNote(selected.id), }, ]} />