Full document, spreadsheet, slideshow, and diagram tooling
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat: workspace archive — split active vs completed workspaces

Done workspaces (tagged forge-done) appear in a collapsed "Completed"
section below the active workspace grid. Done cards are visually muted.

Also adds archive CSS styling for the details/summary toggle.

+50 -13
+20
src/css/app.css
··· 1468 1468 1469 1469 /* ── Forge Note Button (in doc editor) ── */ 1470 1470 1471 + .forge-archive { 1472 + margin-top: var(--space-sm); 1473 + } 1474 + .forge-archive-summary { 1475 + font-size: 0.75rem; 1476 + color: var(--color-text-faint); 1477 + cursor: pointer; 1478 + padding: var(--space-xs) 0; 1479 + } 1480 + .forge-archive-summary:hover { 1481 + color: var(--color-text); 1482 + } 1483 + .forge-workspace-card--done { 1484 + opacity: 0.6; 1485 + border-color: var(--color-border); 1486 + } 1487 + .forge-workspace-card--done:hover { 1488 + opacity: 0.8; 1489 + } 1490 + 1471 1491 .forge-note-btn { 1472 1492 position: fixed; 1473 1493 bottom: var(--space-lg);
+30 -13
src/landing-render.ts
··· 216 216 return; 217 217 } 218 218 219 - // Find workspace-tagged docs (both forge-workspace and forge-report) 220 - const workspaceDocs = activeDocs.filter(d => { 219 + // Find workspace-tagged docs 220 + const allWsDocs = activeDocs.filter(d => { 221 221 const tags = parseTags(d.tags); 222 222 return tags.includes('forge-workspace') || tags.includes('forge-report'); 223 223 }).sort((a, b) => new Date(b.updated_at + 'Z').getTime() - new Date(a.updated_at + 'Z').getTime()); 224 224 225 - if (workspaceDocs.length === 0) { 225 + if (allWsDocs.length === 0) { 226 226 wsEl.innerHTML = ''; 227 227 return; 228 228 } 229 229 230 + // Split active vs archived (done) 231 + const activeDocs2 = allWsDocs.filter(d => !parseTags(d.tags).includes('forge-done')); 232 + const archivedDocs = allWsDocs.filter(d => parseTags(d.tags).includes('forge-done')); 233 + 230 234 let html = '<div class="forge-section">'; 231 - html += '<h3 class="forge-section-heading">\u2692 Forge Workspaces</h3>'; 232 - html += '<div class="forge-workspace-grid">'; 235 + 236 + if (activeDocs2.length > 0) { 237 + html += '<h3 class="forge-section-heading">\u2692 Forge Workspaces</h3>'; 238 + html += '<div class="forge-workspace-grid">'; 239 + html += activeDocs2.map(doc => renderWorkspaceCard(doc)).join(''); 240 + html += '</div>'; 241 + } 242 + 243 + if (archivedDocs.length > 0) { 244 + html += `<details class="forge-archive"><summary class="forge-archive-summary">Completed (${archivedDocs.length})</summary>`; 245 + html += '<div class="forge-workspace-grid">'; 246 + html += archivedDocs.map(doc => renderWorkspaceCard(doc)).join(''); 247 + html += '</div></details>'; 248 + } 249 + 250 + html += '</div>'; 251 + wsEl.innerHTML = html; 233 252 234 - for (const doc of workspaceDocs) { 253 + function renderWorkspaceCard(doc: DocumentMeta): string { 235 254 const name = doc._decryptedName || 'Forge Workspace'; 236 255 const keyStr = doc._keyStr; 237 256 const href = keyStr ? `docs/${doc.id}#${keyStr}` : '#'; 238 257 const time = relativeTime(doc.updated_at); 239 258 const tags = parseTags(doc.tags); 240 259 const isWorkspace = tags.includes('forge-workspace'); 260 + const isDone = tags.includes('forge-done'); 241 261 242 - html += ` 243 - <a class="forge-workspace-card" href="${href}" data-doc-id="${doc.id}"> 262 + return ` 263 + <a class="forge-workspace-card${isDone ? ' forge-workspace-card--done' : ''}" href="${href}" data-doc-id="${doc.id}"> 244 264 <div class="forge-workspace-card-header"> 245 - <span class="forge-workspace-card-type">${isWorkspace ? 'workspace' : 'report'}</span> 265 + <span class="forge-workspace-card-type">${isDone ? 'done' : isWorkspace ? 'workspace' : 'report'}</span> 246 266 <span class="forge-workspace-card-time">${time}</span> 247 267 </div> 248 268 <span class="forge-workspace-card-name">${escapeHtml(name)}</span> ··· 250 270 </a>`; 251 271 } 252 272 253 - html += '</div></div>'; 254 - wsEl.innerHTML = html; 255 - 256 273 // Async: fetch version counts for each workspace doc 257 - for (const doc of workspaceDocs) { 274 + for (const doc of allWsDocs) { 258 275 fetch(`/api/documents/${doc.id}/versions`) 259 276 .then(r => r.json()) 260 277 .then((versions: Array<{ metadata?: string | null }>) => {