()
| 242 | } |
| 243 | |
| 244 | function handleIndex(): Response { |
| 245 | const sorted = [...boards.values()].sort((a, b) => b.publishedAt - a.publishedAt); |
| 246 | const rows = sorted |
| 247 | .map((b) => { |
| 248 | const ts = new Date(b.publishedAt).toISOString(); |
| 249 | const titleSuffix = b.title ? ` — ${escapeHtml(b.title)}` : ""; |
| 250 | return `<li><a href="/boards/${b.id}/">${b.id}</a> <span class="state state-${b.state}">${b.state}</span> <time>${ts}</time>${titleSuffix}</li>`; |
| 251 | }) |
| 252 | .join("\n"); |
| 253 | const empty = `<p class="empty">No boards yet. Run <code>$D compare --serve</code> to publish one.</p>`; |
| 254 | const list = sorted.length === 0 ? empty : `<ul>\n${rows}\n</ul>`; |
| 255 | const html = `<!DOCTYPE html><html lang="en"><head> |
| 256 | <meta charset="utf-8"><title>gstack design boards</title><style> |
| 257 | body{font:14px/1.5 -apple-system,system-ui,sans-serif;max-width:720px;margin:32px auto;padding:0 16px;color:#1a1a1a} |
| 258 | h1{font-size:20px;margin-bottom:4px} |
| 259 | .meta{color:#666;margin-bottom:24px;font-size:13px} |
| 260 | ul{padding:0;list-style:none} |
| 261 | li{padding:10px 0;border-bottom:1px solid #eee;display:flex;align-items:center;gap:12px;flex-wrap:wrap} |
| 262 | a{color:#0070f3;text-decoration:none;font-family:ui-monospace,monospace} |
| 263 | a:hover{text-decoration:underline} |
| 264 | .state{font-size:11px;padding:2px 8px;border-radius:10px;background:#eef;color:#335} |
| 265 | .state-done{background:#efe;color:#353} |
| 266 | .state-regenerating{background:#ffe;color:#553} |
| 267 | time{color:#888;font-size:12px} |
| 268 | .empty{color:#888;font-style:italic} |
| 269 | code{font-family:ui-monospace,monospace;background:#f5f5f5;padding:2px 6px;border-radius:3px} |
| 270 | </style></head><body> |
| 271 | <h1>gstack design boards</h1> |
| 272 | <p class="meta">daemon up ${Math.floor((Date.now() - startTime) / 1000)}s · ${boards.size} board(s) · ${nonDoneCount()} active</p> |
| 273 | ${list} |
| 274 | </body></html>`; |
| 275 | return new Response(html, { headers: { "Content-Type": "text/html; charset=utf-8" } }); |
| 276 | } |
| 277 | |
| 278 | async function handlePublish(req: Request, origin: string): Promise<Response> { |
| 279 | let body: any; |
no test coverage detected