|
24 | 24 | .sessundo .ut { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } |
25 | 25 | .sessundo .ub { flex: 0 0 auto; background: transparent; border: none; color: var(--cc-accent); font: inherit; font-size: 12.5px; font-weight: 600; cursor: pointer; padding: 2px 4px; border-radius: 4px; } |
26 | 26 | .sessundo .ub:hover { text-decoration: underline; } |
| 27 | + /* Memory tab (§M3): a second surface beside History for the recorded outcomes — edit or forget. */ |
| 28 | + .svtabs { display: flex; gap: 2px; padding: 6px 10px 0; flex: 0 0 auto; } |
| 29 | + .svtab { flex: 1; background: transparent; border: none; border-bottom: 2px solid transparent; color: var(--cc-text3); font: inherit; font-size: 12px; padding: 6px 4px 7px; cursor: pointer; } |
| 30 | + .svtab:hover { color: var(--cc-text); } |
| 31 | + .svtab.on { color: var(--cc-text); border-bottom-color: var(--cc-accent); } |
| 32 | + .svpane { flex: 1 1 auto; display: flex; flex-direction: column; min-height: 0; } |
| 33 | + .svpane[hidden] { display: none; } |
| 34 | + .svmemhead { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; padding: 10px 12px 4px; font-size: 11px; color: var(--cc-text3); } |
| 35 | + .svmemopen { background: transparent; border: none; color: var(--cc-accent); font: inherit; font-size: 11px; cursor: pointer; padding: 0; white-space: nowrap; } |
| 36 | + .svmemopen:hover { text-decoration: underline; } |
| 37 | + .memcard { position: relative; padding: 8px 8px 9px; margin-bottom: 1px; border-radius: 6px; cursor: pointer; } |
| 38 | + .memcard:hover { background: color-mix(in srgb, var(--cc-text3) 13%, transparent); } |
| 39 | + .memcard:focus-visible { background: color-mix(in srgb, var(--cc-accent) 15%, transparent); outline: none; } |
| 40 | + .memcard .memtext { font-size: 13px; line-height: 1.45; color: var(--cc-text); } |
| 41 | + .memcard .memline2 { display: flex; align-items: center; min-height: 22px; margin-top: 3px; } |
| 42 | + .memcard .memmeta { flex: 1 1 auto; min-width: 0; font-size: 11.5px; color: var(--cc-text3); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } |
| 43 | + .memcard .memacts { display: none; align-items: center; gap: 4px; flex: 0 0 auto; } |
| 44 | + .memcard:hover .memmeta, .memcard:focus-within .memmeta { display: none; } |
| 45 | + .memcard:hover .memacts, .memcard:focus-within .memacts { display: flex; } |
| 46 | + .memcard .memact { background: transparent; border: none; color: var(--cc-text2); border-radius: 4px; padding: 2px 8px; font: inherit; font-size: 11px; cursor: pointer; white-space: nowrap; } |
| 47 | + .memcard .memact:hover { background: color-mix(in srgb, var(--cc-text3) 20%, transparent); color: var(--cc-text); } |
| 48 | + .memcard .memact[data-act="forget"]:hover { background: color-mix(in srgb, var(--cc-danger) 18%, transparent); color: var(--cc-danger); } |
27 | 49 | .sesslist { flex: 1 1 auto; overflow-y: auto; padding: 0 10px 12px; } |
28 | 50 | .sessbucket { display: flex; justify-content: space-between; align-items: baseline; font-family: var(--vscode-editor-font-family, ui-monospace, monospace); font-size: 10px; letter-spacing: .1em; text-transform: uppercase; color: var(--cc-text3); margin: 12px 4px 7px; } |
29 | 51 | .sessbucket .cnt { letter-spacing: 0; } |
|
56 | 78 | </head> |
57 | 79 | <body> |
58 | 80 | <div class="sessview"> |
59 | | - <button id="svNew" class="sessnew" type="button">New Session</button> |
60 | | - <div class="sesslist" id="svList"></div> |
| 81 | + <div class="svtabs"> |
| 82 | + <button class="svtab on" data-tab="history" type="button">History</button> |
| 83 | + <button class="svtab" data-tab="memory" type="button">Memory</button> |
| 84 | + </div> |
| 85 | + <div class="svpane" id="paneHistory"> |
| 86 | + <button id="svNew" class="sessnew" type="button">New Session</button> |
| 87 | + <div class="sesslist" id="svList"></div> |
| 88 | + </div> |
| 89 | + <div class="svpane" id="paneMemory" hidden> |
| 90 | + <div class="svmemhead"><span>What this project remembers</span><button class="svmemopen" id="svMemOpen" type="button">open file ↗</button></div> |
| 91 | + <div class="sesslist" id="svMemList"></div> |
| 92 | + </div> |
61 | 93 | <div class="sessundo" id="svUndo" hidden></div> |
62 | 94 | </div> |
63 | 95 | <script nonce="__NONCE__"> |
|
154 | 186 | const id = card.getAttribute('data-id'); const btn = e.target.closest('[data-act]'); |
155 | 187 | vscode.postMessage({ type: 'sessionAction', action: btn ? btn.getAttribute('data-act') : 'resume', id: id }); |
156 | 188 | }); |
| 189 | + // ── Memory tab (§M3): the recorded outcomes, each with Edit / Forget; click the card to resume it ── |
| 190 | + function memCardHtml(e){ |
| 191 | + const files = Array.isArray(e.files) ? e.files : []; |
| 192 | + const when = e.at ? new Date(e.at).toLocaleDateString(undefined, { month: 'short', day: 'numeric' }) : ''; |
| 193 | + const meta = (files.length ? esc(files[0]) + (files.length > 1 ? ' +' + (files.length - 1) : '') + ' · ' : '') + esc(when); |
| 194 | + return '<div class="memcard" data-id="' + escAttr(e.id || '') + '" tabindex="0" role="button" title="' + escAttr(e.summary || '') + '">' |
| 195 | + + '<div class="memtext">' + esc(e.summary || e.title || 'a session') + '</div>' |
| 196 | + + '<div class="memline2"><span class="memmeta">' + meta + '</span>' |
| 197 | + + '<span class="memacts"><button type="button" class="memact" data-act="edit" title="Edit this memory">Edit</button>' |
| 198 | + + '<button type="button" class="memact" data-act="forget" title="Forget this session">Forget</button></span></div>' |
| 199 | + + '</div>'; |
| 200 | + } |
| 201 | + function renderMemory(items){ |
| 202 | + const list = document.getElementById('svMemList'); if (!list) { return; } |
| 203 | + const arr = Array.isArray(items) ? items : []; |
| 204 | + if (!arr.length){ list.innerHTML = '<div class="sessempty">Nothing remembered yet. As sessions finish, what they achieved appears here — plain text you can edit or forget.</div>'; return; } |
| 205 | + list.innerHTML = arr.map(memCardHtml).join(''); |
| 206 | + } |
| 207 | + document.getElementById('svMemList').addEventListener('click', (e) => { |
| 208 | + const card = e.target.closest && e.target.closest('.memcard'); if (!card) { return; } |
| 209 | + const id = card.getAttribute('data-id'); const btn = e.target.closest('[data-act]'); |
| 210 | + vscode.postMessage({ type: 'memoryAction', action: btn ? btn.getAttribute('data-act') : 'resume', id: id }); |
| 211 | + }); |
| 212 | + document.getElementById('svMemOpen').addEventListener('click', () => vscode.postMessage({ type: 'openMemory' })); |
| 213 | + function showTab(tab){ |
| 214 | + const hist = tab === 'history'; |
| 215 | + document.getElementById('paneHistory').hidden = !hist; |
| 216 | + document.getElementById('paneMemory').hidden = hist; |
| 217 | + document.querySelectorAll('.svtab').forEach((b) => b.classList.toggle('on', b.getAttribute('data-tab') === tab)); |
| 218 | + if (!hist) { vscode.postMessage({ type: 'listMemory' }); } |
| 219 | + } |
| 220 | + document.querySelectorAll('.svtab').forEach((b) => b.addEventListener('click', () => showTab(b.getAttribute('data-tab')))); |
157 | 221 | // The Undo toast for Done/Delete — a quick, recoverable safety net. Auto-hides after a few seconds. |
158 | 222 | let sessUndoTimer = null; |
159 | 223 | function showUndo(m){ |
|
168 | 232 | vscode.postMessage({ type: 'sessionAction', action: 'restore', id: b.getAttribute('data-id') }); |
169 | 233 | document.getElementById('svUndo').hidden = true; clearTimeout(sessUndoTimer); |
170 | 234 | }); |
171 | | - window.addEventListener('message', (ev) => { const m = ev.data; if (m && m.type === 'sessions'){ sessData = Array.isArray(m.entries) ? m.entries : []; renderSessions(); } else if (m && m.type === 'sessionUndo'){ showUndo(m); } }); |
| 235 | + window.addEventListener('message', (ev) => { const m = ev.data; if (m && m.type === 'sessions'){ sessData = Array.isArray(m.entries) ? m.entries : []; renderSessions(); } else if (m && m.type === 'memoryList'){ renderMemory(m.items); } else if (m && m.type === 'sessionUndo'){ showUndo(m); } }); |
172 | 236 | renderSessions(); |
173 | 237 | vscode.postMessage({ type: 'listSessions' }); |
174 | 238 | </script> |
|
0 commit comments