shepherd-onboard 0.1.13 → 0.1.14

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.
@@ -1333,18 +1333,19 @@ function renderMessagesSelectorPage(chats, token, error = "") {
1333
1333
  .join(" ")
1334
1334
  .toLowerCase();
1335
1335
 
1336
+ const kindKey = chat.kind === "group" ? "group" : chat.kind === "dm" ? "dm" : "other";
1337
+ const kindLabel = kindKey === "group" ? "Group" : kindKey === "dm" ? "Contact" : "Chat";
1336
1338
  return `
1337
1339
  <label class="chat-row" data-index="${index}" data-search="${htmlAttr(searchText)}">
1338
1340
  <input type="checkbox" name="chatId" value="${htmlAttr(chat.chatId)}">
1339
1341
  <span class="box" aria-hidden="true"></span>
1340
- <span class="chat-main">
1341
- <span class="chat-top">
1342
- <span class="chat-name">${html(chat.label)}</span>
1343
- <span class="chat-kind">${html(chat.kind === "group" ? "Group" : chat.kind === "dm" ? "Contact" : "Chat")}</span>
1344
- </span>
1342
+ <span class="avatar" aria-hidden="true">${html(chatInitials(chat.label))}</span>
1343
+ <span class="chat-name-block">
1344
+ <span class="chat-name">${html(chat.label)}</span>
1345
1345
  ${people ? `<span class="chat-people">${html(people)}</span>` : ""}
1346
- ${when ? `<span class="chat-meta">${html(when)}</span>` : ""}
1347
1346
  </span>
1347
+ <span class="chat-kind chat-kind--${kindKey}">${html(kindLabel)}</span>
1348
+ <span class="chat-meta">${when ? html(when) : "—"}</span>
1348
1349
  </label>`;
1349
1350
  }).join("");
1350
1351
 
@@ -1356,125 +1357,131 @@ function renderMessagesSelectorPage(chats, token, error = "") {
1356
1357
  <title>Select Messages Chats</title>
1357
1358
  <style>
1358
1359
  :root {
1359
- color-scheme: light dark;
1360
- --bg: #FCFCFC;
1361
- --fg: #111111;
1362
- --muted: #6D726D;
1363
- --line: #E8ECE8;
1360
+ --hero-top: #136033;
1361
+ --hero-bottom: #0c3f22;
1364
1362
  --panel: #FFFFFF;
1365
- --button: #136033;
1366
- --button-text: #FFFFFF;
1367
- --link: #136033;
1368
- --radius: 10px;
1369
- }
1370
- @media (prefers-color-scheme: dark) {
1371
- :root {
1372
- --bg: #000000;
1373
- --fg: #F8F8F8;
1374
- --muted: #A2A8A2;
1375
- --line: #202520;
1376
- --panel: #070907;
1377
- --button: #FFFFFF;
1378
- --button-text: #000000;
1379
- --link: #136033;
1380
- }
1363
+ --fg: #15201a;
1364
+ --muted: #6B736D;
1365
+ --faint: #8A938C;
1366
+ --line: #EEF1EE;
1367
+ --green: #136033;
1368
+ --green-soft: #E7F3EC;
1369
+ --green-text: #1F7A43;
1370
+ --neutral-soft: #F0F1EF;
1371
+ --button: #1F6E3C;
1372
+ --button-hover: #237b44;
1373
+ --radius: 12px;
1374
+ --grid: 20px 36px minmax(0, 1fr) 92px 124px;
1381
1375
  }
1382
1376
  * { box-sizing: border-box; }
1383
1377
  body {
1384
1378
  margin: 0;
1385
- background: var(--bg);
1379
+ min-height: 100vh;
1380
+ background: linear-gradient(180deg, var(--hero-top) 0%, var(--hero-top) 150px, var(--hero-bottom) 520px, var(--hero-bottom) 100%);
1386
1381
  color: var(--fg);
1387
1382
  font-family: Geist, "Geist Sans", ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
1388
1383
  letter-spacing: 0;
1384
+ -webkit-font-smoothing: antialiased;
1389
1385
  }
1390
1386
  main {
1391
- width: min(700px, calc(100vw - 32px));
1392
- margin: 36px auto;
1393
- }
1394
- header {
1395
- display: flex;
1396
- justify-content: space-between;
1397
- gap: 16px;
1398
- align-items: center;
1399
- padding-bottom: 18px;
1400
- border-bottom: 1px solid var(--line);
1387
+ width: min(760px, calc(100vw - 32px));
1388
+ margin: 0 auto;
1389
+ padding: 48px 0 40px;
1401
1390
  }
1402
- .brand {
1391
+ .hero {
1403
1392
  display: flex;
1404
- gap: 10px;
1393
+ gap: 22px;
1405
1394
  align-items: center;
1406
- min-width: 0;
1395
+ padding: 0 6px 34px;
1396
+ color: #FFFFFF;
1407
1397
  }
1408
- .logo {
1409
- width: 30px;
1410
- height: 30px;
1411
- border-radius: 8px;
1398
+ .hero .logo {
1399
+ width: 96px;
1400
+ height: 96px;
1412
1401
  object-fit: contain;
1413
1402
  flex: none;
1414
1403
  }
1415
- .logo-fallback {
1416
- width: 30px;
1417
- height: 30px;
1418
- border-radius: 8px;
1404
+ .hero .logo-fallback {
1405
+ width: 88px;
1406
+ height: 88px;
1407
+ border-radius: 20px;
1419
1408
  display: grid;
1420
1409
  place-items: center;
1421
1410
  color: #FFFFFF;
1422
- background: #136033;
1411
+ border: 2px solid rgba(255, 255, 255, 0.35);
1412
+ font-size: 34px;
1423
1413
  font-weight: 700;
1424
1414
  flex: none;
1425
1415
  }
1426
1416
  h1 {
1427
1417
  margin: 0;
1428
- font-size: 22px;
1429
- line-height: 1.1;
1430
- font-weight: 650;
1418
+ font-size: clamp(30px, 4.6vw, 44px);
1419
+ line-height: 1.05;
1420
+ font-weight: 700;
1421
+ letter-spacing: -0.02em;
1431
1422
  }
1432
- form {
1433
- margin-top: 18px;
1423
+ .subtitle {
1424
+ margin: 12px 0 0;
1425
+ font-size: 16px;
1426
+ line-height: 1.45;
1427
+ color: rgba(231, 243, 235, 0.72);
1428
+ }
1429
+ .panel {
1430
+ background: var(--panel);
1431
+ border-radius: 22px;
1432
+ box-shadow: 0 18px 50px rgba(0, 0, 0, 0.22);
1433
+ padding: 8px 0 0;
1434
+ overflow: hidden;
1435
+ }
1436
+ .panel-head {
1437
+ padding: 18px 24px 14px;
1434
1438
  }
1435
1439
  .search {
1436
1440
  width: 100%;
1437
- margin: 0 0 12px;
1438
- border: 1px solid var(--line);
1439
- border-radius: var(--radius);
1440
- background: var(--panel);
1441
+ border: 1px solid #E6EAE6;
1442
+ border-radius: 10px;
1443
+ background: #F6F8F6;
1441
1444
  color: var(--fg);
1442
- padding: 11px 12px;
1445
+ padding: 11px 13px;
1443
1446
  font: inherit;
1444
1447
  font-size: 14px;
1445
1448
  outline: none;
1446
1449
  }
1447
1450
  .search:focus {
1448
- border-color: #136033;
1449
- box-shadow: 0 0 0 3px color-mix(in srgb, #136033 16%, transparent);
1450
- }
1451
- .search::placeholder {
1452
- color: var(--muted);
1451
+ border-color: var(--green);
1452
+ background: #FFFFFF;
1453
+ box-shadow: 0 0 0 3px color-mix(in srgb, var(--green) 16%, transparent);
1453
1454
  }
1455
+ .search::placeholder { color: var(--faint); }
1454
1456
  .error {
1455
- margin: 0 0 12px;
1457
+ margin: 12px 24px 0;
1456
1458
  color: #9B1C1C;
1457
1459
  font-size: 14px;
1458
1460
  }
1459
- .chat-list {
1461
+ .list-head {
1460
1462
  display: grid;
1461
- gap: 8px;
1462
- margin: 0 0 18px;
1463
+ grid-template-columns: var(--grid);
1464
+ gap: 14px;
1465
+ align-items: center;
1466
+ padding: 6px 24px 12px;
1467
+ border-bottom: 1px solid var(--line);
1468
+ color: var(--faint);
1469
+ font-size: 13px;
1470
+ font-weight: 500;
1463
1471
  }
1472
+ .list-head .right { text-align: left; }
1473
+ .chat-list { display: block; }
1464
1474
  .chat-row {
1465
1475
  display: grid;
1466
- grid-template-columns: 24px 1fr;
1467
- gap: 12px;
1468
- align-items: start;
1469
- padding: 13px 14px;
1470
- background: var(--panel);
1471
- border: 1px solid var(--line);
1472
- border-radius: var(--radius);
1476
+ grid-template-columns: var(--grid);
1477
+ gap: 14px;
1478
+ align-items: center;
1479
+ padding: 13px 24px;
1480
+ border-bottom: 1px solid var(--line);
1473
1481
  cursor: pointer;
1482
+ transition: background 120ms ease;
1474
1483
  }
1475
- .chat-row:hover {
1476
- border-color: color-mix(in srgb, var(--link) 45%, var(--line));
1477
- }
1484
+ .chat-row:hover { background: #F7FAF8; }
1478
1485
  input[type="checkbox"] {
1479
1486
  position: absolute;
1480
1487
  opacity: 0;
@@ -1483,34 +1490,41 @@ function renderMessagesSelectorPage(chats, token, error = "") {
1483
1490
  .box {
1484
1491
  width: 18px;
1485
1492
  height: 18px;
1486
- margin-top: 2px;
1487
- border: 1.5px solid var(--muted);
1493
+ border: 1.5px solid #C7CDC8;
1488
1494
  border-radius: 5px;
1489
1495
  display: inline-grid;
1490
1496
  place-items: center;
1497
+ transition: background 120ms ease, border-color 120ms ease;
1491
1498
  }
1499
+ .chat-row:hover .box { border-color: var(--green); }
1492
1500
  input[type="checkbox"]:checked + .box {
1493
- background: var(--button);
1494
- border-color: var(--button);
1501
+ background: var(--green);
1502
+ border-color: var(--green);
1495
1503
  }
1496
1504
  input[type="checkbox"]:checked + .box::after {
1497
1505
  content: "";
1498
1506
  width: 7px;
1499
1507
  height: 4px;
1500
- border-left: 2px solid var(--button-text);
1501
- border-bottom: 2px solid var(--button-text);
1508
+ border-left: 2px solid #FFFFFF;
1509
+ border-bottom: 2px solid #FFFFFF;
1502
1510
  transform: rotate(-45deg) translateY(-1px);
1503
1511
  }
1504
- .chat-main {
1505
- min-width: 0;
1512
+ .avatar {
1513
+ width: 36px;
1514
+ height: 36px;
1515
+ border-radius: 50%;
1516
+ background: var(--green);
1517
+ color: #FFFFFF;
1506
1518
  display: grid;
1507
- gap: 4px;
1519
+ place-items: center;
1520
+ font-size: 13px;
1521
+ font-weight: 650;
1522
+ letter-spacing: 0.02em;
1508
1523
  }
1509
- .chat-top {
1510
- display: flex;
1511
- gap: 10px;
1512
- align-items: center;
1524
+ .chat-name-block {
1513
1525
  min-width: 0;
1526
+ display: grid;
1527
+ gap: 2px;
1514
1528
  }
1515
1529
  .chat-name {
1516
1530
  overflow: hidden;
@@ -1519,23 +1533,33 @@ function renderMessagesSelectorPage(chats, token, error = "") {
1519
1533
  font-size: 15px;
1520
1534
  font-weight: 600;
1521
1535
  }
1536
+ .chat-people {
1537
+ color: var(--muted);
1538
+ font-size: 13px;
1539
+ line-height: 1.3;
1540
+ overflow: hidden;
1541
+ text-overflow: ellipsis;
1542
+ white-space: nowrap;
1543
+ }
1522
1544
  .chat-kind {
1523
- color: var(--link);
1524
- font-size: 12px;
1525
- flex: none;
1545
+ justify-self: start;
1546
+ padding: 3px 11px;
1547
+ border-radius: 999px;
1548
+ font-size: 12.5px;
1549
+ font-weight: 500;
1526
1550
  }
1527
- .chat-people,
1551
+ .chat-kind--group { background: var(--green-soft); color: var(--green-text); }
1552
+ .chat-kind--dm,
1553
+ .chat-kind--other { background: var(--neutral-soft); color: var(--muted); }
1528
1554
  .chat-meta {
1529
1555
  color: var(--muted);
1530
- font-size: 13px;
1531
- line-height: 1.35;
1556
+ font-size: 13.5px;
1532
1557
  overflow-wrap: anywhere;
1533
1558
  }
1534
- [hidden] {
1535
- display: none !important;
1536
- }
1559
+ [hidden] { display: none !important; }
1537
1560
  .empty {
1538
- margin: 18px 0 28px;
1561
+ margin: 0;
1562
+ padding: 28px 24px 32px;
1539
1563
  color: var(--muted);
1540
1564
  font-size: 14px;
1541
1565
  text-align: center;
@@ -1547,44 +1571,73 @@ function renderMessagesSelectorPage(chats, token, error = "") {
1547
1571
  gap: 12px;
1548
1572
  position: sticky;
1549
1573
  bottom: 0;
1550
- padding: 14px 0 0;
1551
- background: linear-gradient(to top, var(--bg) 70%, transparent);
1574
+ margin-top: 22px;
1575
+ padding: 16px 6px 4px;
1552
1576
  }
1553
1577
  .selection-count {
1554
- color: var(--muted);
1555
- font-size: 13px;
1578
+ color: rgba(231, 243, 235, 0.82);
1579
+ font-size: 14.5px;
1580
+ font-weight: 500;
1556
1581
  }
1557
1582
  button {
1558
1583
  appearance: none;
1559
1584
  border: 0;
1560
- border-radius: var(--radius);
1585
+ border-radius: 14px;
1561
1586
  background: var(--button);
1562
- color: var(--button-text);
1563
- padding: 10px 14px;
1587
+ color: #FFFFFF;
1588
+ padding: 14px 24px;
1564
1589
  font: inherit;
1565
- font-weight: 620;
1590
+ font-size: 15px;
1591
+ font-weight: 600;
1566
1592
  cursor: pointer;
1593
+ display: inline-flex;
1594
+ align-items: center;
1595
+ gap: 10px;
1596
+ box-shadow: 0 10px 24px rgba(0, 0, 0, 0.28);
1597
+ transition: background 120ms ease, transform 120ms ease;
1598
+ }
1599
+ button:hover { background: var(--button-hover); }
1600
+ button:active { transform: scale(0.985); }
1601
+ button svg { width: 18px; height: 18px; }
1602
+ @media (max-width: 560px) {
1603
+ :root { --grid: 18px 32px minmax(0, 1fr) auto; }
1604
+ .list-head span:last-child,
1605
+ .chat-meta { display: none; }
1567
1606
  }
1568
- a { color: var(--link); }
1569
1607
  </style>
1570
1608
  </head>
1571
1609
  <body>
1572
1610
  <main>
1573
- <header>
1574
- <div class="brand">
1575
- ${logo ? `<img class="logo" src="${htmlAttr(logo)}" alt="">` : `<span class="logo-fallback" aria-hidden="true">G</span>`}
1576
- <h1>Select chats</h1>
1611
+ <header class="hero">
1612
+ ${logo ? `<img class="logo" src="${htmlAttr(logo)}" alt="">` : `<span class="logo-fallback" aria-hidden="true">S</span>`}
1613
+ <div>
1614
+ <h1>Select Your Recent Chats</h1>
1615
+ <p class="subtitle">Choose the chats Shepherd should sync. Search if you do not see one.</p>
1577
1616
  </div>
1578
1617
  </header>
1579
1618
  <form method="post" action="/select">
1580
1619
  <input type="hidden" name="token" value="${htmlAttr(token)}">
1581
- <input class="search" id="search" type="search" placeholder="Search contacts or groups" autocomplete="off">
1582
- ${error ? `<p class="error">${html(error)}</p>` : ""}
1583
- <div class="chat-list">${rows}</div>
1584
- <p class="empty" id="empty" hidden>No chats found.</p>
1620
+ <div class="panel">
1621
+ <div class="panel-head">
1622
+ <input class="search" id="search" type="search" placeholder="Search contacts or groups" autocomplete="off">
1623
+ </div>
1624
+ ${error ? `<p class="error">${html(error)}</p>` : ""}
1625
+ <div class="list-head">
1626
+ <span></span>
1627
+ <span></span>
1628
+ <span>Name</span>
1629
+ <span>Type</span>
1630
+ <span class="right">Last message</span>
1631
+ </div>
1632
+ <div class="chat-list">${rows}</div>
1633
+ <p class="empty" id="empty" hidden>No chats found.</p>
1634
+ </div>
1585
1635
  <div class="actions">
1586
- <span class="selection-count" id="selection-count">Select one or more</span>
1587
- <button type="submit">return</button>
1636
+ <span class="selection-count" id="selection-count">0 selected</span>
1637
+ <button type="submit">
1638
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M19 12H5"/><path d="m12 19-7-7 7-7"/></svg>
1639
+ Return
1640
+ </button>
1588
1641
  </div>
1589
1642
  </form>
1590
1643
  </main>
@@ -1611,7 +1664,7 @@ function renderMessagesSelectorPage(chats, token, error = "") {
1611
1664
 
1612
1665
  function updateSelected() {
1613
1666
  const count = checks.filter((check) => check.checked).length;
1614
- selected.textContent = count ? count + " selected" : "Select one or more";
1667
+ selected.textContent = count + " selected";
1615
1668
  }
1616
1669
 
1617
1670
  search.addEventListener("input", updateRows);
@@ -1656,6 +1709,13 @@ function renderChatPeople(chat) {
1656
1709
  return `<span class="chat-people">${html(people)}</span>`;
1657
1710
  }
1658
1711
 
1712
+ function chatInitials(label) {
1713
+ const words = String(label ?? "").trim().split(/\s+/).filter(Boolean);
1714
+ if (words.length === 0) return "?";
1715
+ if (words.length === 1) return words[0].slice(0, 2).toUpperCase();
1716
+ return (words[0][0] + words[words.length - 1][0]).toUpperCase();
1717
+ }
1718
+
1659
1719
  function chatPeopleLine(chat) {
1660
1720
  if (chat.kind !== "group") return "";
1661
1721
  const names = chat.participants?.map((participant) => participant.name ?? participant.handle).filter(Boolean) ?? [];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shepherd-onboard",
3
- "version": "0.1.13",
3
+ "version": "0.1.14",
4
4
  "description": "Customer-facing Shepherd raw sync onboarding CLI",
5
5
  "type": "module",
6
6
  "bin": {