Notebook: write your own note (alongside captured lines)
The field notebook gets a handwriting input to add a custom note manually; it posts to the same notebook store and can be torn to the board like a captured one. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+12
-1
@@ -112,6 +112,7 @@ export function Inventory({ onClose, session, onTearToBoard }: { onClose?: () =>
|
|||||||
// onto the board as a note (when a board tear handler is available).
|
// onto the board as a note (when a board tear handler is available).
|
||||||
function NotebookTool({ playthroughId, onTear }: { playthroughId?: string; onTear?: (text: string) => void }) {
|
function NotebookTool({ playthroughId, onTear }: { playthroughId?: string; onTear?: (text: string) => void }) {
|
||||||
const [pages, setPages] = useState<{ id: string; text: string }[]>([])
|
const [pages, setPages] = useState<{ id: string; text: string }[]>([])
|
||||||
|
const [draft, setDraft] = useState('')
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!playthroughId) return
|
if (!playthroughId) return
|
||||||
fetch(`/api/playthroughs/${playthroughId}/notebook`).then(r => r.ok ? r.json() : []).then(setPages).catch(() => {})
|
fetch(`/api/playthroughs/${playthroughId}/notebook`).then(r => r.ok ? r.json() : []).then(setPages).catch(() => {})
|
||||||
@@ -121,10 +122,20 @@ function NotebookTool({ playthroughId, onTear }: { playthroughId?: string; onTea
|
|||||||
setPages(list => list.filter(page => page.id !== id))
|
setPages(list => list.filter(page => page.id !== id))
|
||||||
}
|
}
|
||||||
const tear = (page: { id: string; text: string }) => { onTear?.(page.text); void remove(page.id) }
|
const tear = (page: { id: string; text: string }) => { onTear?.(page.text); void remove(page.id) }
|
||||||
|
const add = async () => {
|
||||||
|
const text = draft.trim()
|
||||||
|
if (!text || !playthroughId) return
|
||||||
|
const res = await fetch(`/api/playthroughs/${playthroughId}/notebook`, { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ text }) })
|
||||||
|
if (res.ok) { const page = await res.json(); setPages(list => [...list, { id: page.id, text: page.text }]); setDraft('') }
|
||||||
|
}
|
||||||
return <div className="notebook">
|
return <div className="notebook">
|
||||||
<div className="notebook-page">
|
<div className="notebook-page">
|
||||||
<div className="notebook-head">FIELD NOTEBOOK</div>
|
<div className="notebook-head">FIELD NOTEBOOK</div>
|
||||||
{!pages.length && <p className="notebook-empty">Nothing noted yet. During a conversation, use “✎ Note this” to jot down what someone says.</p>}
|
{playthroughId && <div className="notebook-add">
|
||||||
|
<textarea value={draft} onChange={event => setDraft(event.target.value)} placeholder="Write your own note…" spellCheck={false} rows={2} />
|
||||||
|
<button disabled={!draft.trim()} onClick={add}>+ Add</button>
|
||||||
|
</div>}
|
||||||
|
{!pages.length && <p className="notebook-empty">Nothing noted yet. Write one above, or during a conversation use “✎ Note this”.</p>}
|
||||||
{pages.map(page => <div key={page.id} className="notebook-note">
|
{pages.map(page => <div key={page.id} className="notebook-note">
|
||||||
<p>{page.text}</p>
|
<p>{page.text}</p>
|
||||||
<div className="notebook-note-actions">
|
<div className="notebook-note-actions">
|
||||||
|
|||||||
@@ -790,6 +790,11 @@ button:focus-visible { outline: 2px solid #e99a44; outline-offset: 2px; }
|
|||||||
.notebook-page { width: min(560px, 88vw); height: min(72vh, 720px); background: repeating-linear-gradient(#f4ecd6 0 30px, #e3d8b8 30px 31px); box-shadow: 0 20px 60px #0009; padding: 26px 30px; display: flex; flex-direction: column; gap: 12px; overflow-y: auto; }
|
.notebook-page { width: min(560px, 88vw); height: min(72vh, 720px); background: repeating-linear-gradient(#f4ecd6 0 30px, #e3d8b8 30px 31px); box-shadow: 0 20px 60px #0009; padding: 26px 30px; display: flex; flex-direction: column; gap: 12px; overflow-y: auto; }
|
||||||
.notebook-head { font: 700 13px IBM Plex Mono, monospace; letter-spacing: 3px; color: #6a5a3a; }
|
.notebook-head { font: 700 13px IBM Plex Mono, monospace; letter-spacing: 3px; color: #6a5a3a; }
|
||||||
.notebook-empty { font: 22px/1.3 "Reenie Beanie", cursive; color: #8a7a52; }
|
.notebook-empty { font: 22px/1.3 "Reenie Beanie", cursive; color: #8a7a52; }
|
||||||
|
.notebook-add { display: flex; gap: 8px; align-items: flex-end; border-bottom: 1px dashed #c8b98f; padding-bottom: 10px; }
|
||||||
|
.notebook-add textarea { flex: 1; background: transparent; border: none; outline: none; resize: none; font: 24px/26px "Reenie Beanie", cursive; color: #26356b; }
|
||||||
|
.notebook-add button { font: 11px IBM Plex Mono, monospace; letter-spacing: 1px; background: #e8dcbc; border: 1px solid #c0ad7f; color: #5a4a2a; padding: 4px 10px; cursor: pointer; white-space: nowrap; }
|
||||||
|
.notebook-add button:disabled { opacity: .45; cursor: default; }
|
||||||
|
.notebook-add button:not(:disabled):hover { border-color: #6a5a3a; }
|
||||||
.notebook-note { border-bottom: 1px dashed #c8b98f; padding-bottom: 8px; }
|
.notebook-note { border-bottom: 1px dashed #c8b98f; padding-bottom: 8px; }
|
||||||
.notebook-note p { margin: 0 0 6px; font: 27px/30px "Reenie Beanie", cursive; color: #26356b; }
|
.notebook-note p { margin: 0 0 6px; font: 27px/30px "Reenie Beanie", cursive; color: #26356b; }
|
||||||
.notebook-note-actions { display: flex; gap: 8px; }
|
.notebook-note-actions { display: flex; gap: 8px; }
|
||||||
|
|||||||
Reference in New Issue
Block a user