@nanocollective/roster 0.1.0-alpha.47 → 0.1.0-alpha.48

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nanocollective/roster",
3
- "version": "0.1.0-alpha.47",
3
+ "version": "0.1.0-alpha.48",
4
4
  "description": "An agent-run org, powered by GitHub. Scaffold AI staff members whose brain is a repo.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -40,7 +40,7 @@
40
40
  }
41
41
 
42
42
  .homeworking{display:flex;flex-direction:column;padding:4px 16px}
43
- .homerun{display:grid;grid-template-columns:minmax(150px,220px) auto 1fr auto;align-items:center;
43
+ .homerun{display:grid;grid-template-columns:minmax(150px,220px) 84px 1fr auto;align-items:center;
44
44
  gap:12px;padding:12px 0;font-size:13.5px}
45
45
  .homerun + .homerun{border-top:1px solid var(--line)}
46
46
  .homewho2{display:inline-flex;align-items:center;gap:8px;min-width:0}
@@ -60,27 +60,16 @@
60
60
  .homerunwhat{grid-area:what}.homerunlog{grid-area:log}
61
61
  }
62
62
 
63
- .homerow{display:flex;align-items:baseline;gap:10px;flex-wrap:wrap;padding:8px 2px;
64
- border-bottom:1px solid var(--line);font-size:13px}
65
- .homerow .homeopen{font-weight:500;font-size:13.5px}
66
- .homelist{display:grid;grid-template-columns:auto 1fr;align-items:start;gap:4px 12px}
67
- .homelist > .chip{margin-top:2px}
68
- .homelist .meta{margin-top:3px}
69
- .homeclick{cursor:pointer;border-radius:8px;padding-left:8px;padding-right:8px;margin:0 -8px}
70
- .homeclick:hover{background:var(--hover)}
71
- .homeclick:focus-visible{outline:2px solid var(--accent);outline-offset:-2px}
72
- .homeclosed{display:grid;grid-template-columns:1fr auto;align-items:center;gap:4px 14px}
73
- .homeclosed .meta{margin-top:3px}
74
63
  .homerest{margin-top:26px}
75
- .homecard.gone,.homerow.gone{opacity:0;transform:translateX(12px);
64
+ .homecard.gone,.homerun.gone{opacity:0;transform:translateX(12px);
76
65
  transition:opacity .2s var(--ease),transform .2s var(--ease)}
77
66
 
78
67
  /* Activity you have not seen, as Trackers marks it: a blue edge and a bold title. Opening the
79
68
  thread marks it read, here and on GitHub. */
80
69
  .homecard.unread{box-shadow:inset 3px 0 0 var(--blue)}
81
- .homerow.unread{box-shadow:inset 3px 0 0 var(--blue);background:color-mix(in srgb,var(--blue) 6%,transparent)}
82
- .unread .homeopen{font-weight:700}
83
- .unread .homeopen::before{content:"";display:inline-block;width:7px;height:7px;border-radius:50%;
70
+ .homerun.unread{box-shadow:inset 3px 0 0 var(--blue);margin:0 -16px;padding-left:13px;padding-right:16px}
71
+ .unread .homeopen,.unread .homerowtitle{font-weight:700}
72
+ .unread .homeopen::before,.unread .homerowtitle::before{content:"";display:inline-block;width:7px;height:7px;border-radius:50%;
84
73
  background:var(--blue);margin:0 7px 1px 0;vertical-align:middle}
85
74
 
86
75
  .homereports{display:flex;flex-direction:column;gap:14px;padding:14px 16px}
@@ -93,3 +82,9 @@
93
82
  @media (max-width:640px){
94
83
  .homehead{flex-wrap:wrap}
95
84
  }
85
+
86
+ /* Rows in the Working now card that open a thread. */
87
+ .homerun.homeclick{cursor:pointer}
88
+ .homerun.homeclick:hover .homerowtitle{color:var(--accent)}
89
+ .homerun.homeclick:focus-visible{outline:2px solid var(--accent);outline-offset:2px;border-radius:6px}
90
+ .homerowtitle{font-weight:600;color:var(--ink)}
@@ -75,7 +75,7 @@ export function viewHome(m) {
75
75
 
76
76
  if (h.unread.length) {
77
77
  page.append(section("Unread", h.unread.length));
78
- for (const e of h.unread) page.append(unreadRow(e));
78
+ page.append(listBox(h.unread.map(unreadRow)));
79
79
  }
80
80
 
81
81
  page.append(section("Working now"));
@@ -83,12 +83,12 @@ export function viewHome(m) {
83
83
 
84
84
  if (h.requests.length) {
85
85
  page.append(section("Your requests", h.requests.length));
86
- for (const e of h.requests) page.append(requestRow(e));
86
+ page.append(listBox(h.requests.map(requestRow)));
87
87
  }
88
88
 
89
89
  if (h.closedToday.length) {
90
90
  page.append(section("Closed today", h.closedToday.length));
91
- for (const e of h.closedToday) page.append(closedRow(e));
91
+ page.append(listBox(h.closedToday.map(closedRow)));
92
92
  }
93
93
 
94
94
  page.append(rest(h));
@@ -247,7 +247,7 @@ async function act(note, actions, payload, ok) {
247
247
  await post(payload);
248
248
  note.textContent = ok;
249
249
  // Done is done: the card goes now, rather than when GitHub next answers.
250
- const card = actions.closest?.(".homecard, .homerow");
250
+ const card = actions.closest?.(".homecard, .homerun");
251
251
  if (card) {
252
252
  card.classList.add("gone");
253
253
  setTimeout(() => card.remove(), 220);
@@ -373,7 +373,44 @@ function poll() {
373
373
 
374
374
  /* ------------------------------ your requests ---------------------------- */
375
375
 
376
- const STATUS = { waiting: "Waiting", working: "Being worked on", answered: "Answered" };
376
+ /** A card of rows, laid out like Working now. */
377
+ function listBox(rows) {
378
+ return el("div", { className: "card homeworking" }, rows);
379
+ }
380
+
381
+ /**
382
+ * One row in the shape Working now uses: who, a status chip, the title with one line under it,
383
+ * and a button on the right. The whole row opens the thread, except the button.
384
+ */
385
+ function listRow(e, { chip, tone = "", sub, action = null }) {
386
+ const s = e.staff;
387
+ const row = el(
388
+ "div",
389
+ { className: "homerun homeclick" + (e.item.unread ? " unread" : ""), tabIndex: 0, role: "button" },
390
+ [
391
+ el("span", { className: "homewho2" }, [
392
+ icon(s ? staffIcon(s) : "issue-open", "ic"),
393
+ el("b", { textContent: s?.name ?? (e.item.repo.split("/")[1] ?? e.item.repo) }),
394
+ ]),
395
+ el("span", { className: "chip homestate " + tone, textContent: chip }),
396
+ el("div", { className: "homerunwhat" }, [
397
+ el("div", { className: "homerowtitle", textContent: e.item.title }),
398
+ el("div", { className: "homerunsub", textContent: sub }),
399
+ ]),
400
+ el("div", { className: "homerunlog" }, action ? [action] : []),
401
+ ],
402
+ );
403
+ row.onclick = (ev) => {
404
+ if (!ev.target.closest("button, a")) openThread(e.item);
405
+ };
406
+ row.onkeydown = (ev) => {
407
+ if (ev.target === row && (ev.key === "Enter" || ev.key === " ")) {
408
+ ev.preventDefault();
409
+ openThread(e.item);
410
+ }
411
+ };
412
+ return row;
413
+ }
377
414
 
378
415
  const WHY = {
379
416
  status: "Status",
@@ -386,58 +423,34 @@ const WHY = {
386
423
 
387
424
  /** Something on a staff member's tracker, or elsewhere, with activity you have not seen. */
388
425
  function unreadRow(e) {
389
- return clickable(e.item, "homerow homelist", [
390
- el("span", { className: "chip", textContent: WHY[e.why] ?? "Issue" }),
391
- el("div", {}, [
392
- openLink(e.item),
393
- el("div", { className: "meta", textContent: whereOf(e) + " · " + ago(e.item.updatedAt) }),
394
- ]),
395
- ]);
426
+ return listRow(e, {
427
+ chip: WHY[e.why] ?? "Issue",
428
+ tone: "cool",
429
+ sub: `#${e.item.number} · ${ago(e.item.updatedAt)}`,
430
+ });
396
431
  }
397
432
 
398
- function requestRow(e) {
399
- return clickable(e.item, "homerow homelist", [
400
- el("span", {
401
- className: "chip " + (e.status === "answered" ? "cool" : e.status === "working" ? "warm" : ""),
402
- textContent: STATUS[e.status],
403
- }),
404
- el("div", {}, [
405
- openLink(e.item),
406
- el("div", { className: "meta", textContent: whereOf(e) + " · " + ago(e.item.updatedAt) }),
407
- ]),
408
- ]);
409
- }
433
+ const STATUS = { waiting: "Waiting", working: "Working", answered: "Answered" };
410
434
 
411
- /** A row that opens its thread from anywhere on it, except a button inside it. */
412
- function clickable(item, className, kids) {
413
- const row = el(
414
- "div",
415
- { className: className + " homeclick" + (item.unread ? " unread" : ""), tabIndex: 0, role: "button" },
416
- kids,
417
- );
418
- row.onclick = (ev) => {
419
- if (!ev.target.closest("button, a")) openThread(item);
420
- };
421
- row.onkeydown = (ev) => {
422
- if (ev.target === row && (ev.key === "Enter" || ev.key === " ")) {
423
- ev.preventDefault();
424
- openThread(item);
425
- }
426
- };
427
- return row;
435
+ function requestRow(e) {
436
+ return listRow(e, {
437
+ chip: STATUS[e.status],
438
+ tone: e.status === "answered" ? "cool" : e.status === "working" ? "ok" : "",
439
+ sub: `#${e.item.number} · ${ago(e.item.updatedAt)}`,
440
+ });
428
441
  }
429
442
 
430
443
  function closedRow(e) {
431
444
  const note = el("span", { className: "meta" });
432
- const reopen = button("Reopen", false, () => act(note, row, { action: "reopen", repo: e.item.repo, number: e.item.number }, "Reopened."));
433
- const row = clickable(e.item, "homerow homeclosed", [
434
- el("div", {}, [
435
- openLink(e.item),
436
- el("div", { className: "meta", textContent: whereOf(e) + " · " + (e.reason || "No reason given.") }),
437
- ]),
438
- el("div", { className: "row" }, [note, reopen]),
439
- ]);
440
- return row;
445
+ const reopen = button("Reopen", false, () =>
446
+ act(note, holder, { action: "reopen", repo: e.item.repo, number: e.item.number }, "Reopened."),
447
+ );
448
+ const holder = el("div", { className: "row" }, [note, reopen]);
449
+ return listRow(e, {
450
+ chip: "Closed",
451
+ sub: `#${e.item.number} · ${e.reason || "No reason given."}`,
452
+ action: holder,
453
+ });
441
454
  }
442
455
 
443
456
  /* --------------------------------- rest --------------------------------- */