relay-companion 0.1.87 → 0.1.89
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/overlay/inbox.html +70 -10
- package/package.json +1 -1
- package/src/install.js +8 -0
package/overlay/inbox.html
CHANGED
|
@@ -504,7 +504,30 @@
|
|
|
504
504
|
.cv-chev { flex:0 0 auto; display:flex; align-items:center; }
|
|
505
505
|
.cv-empty { padding:34px 16px; text-align:center; color:var(--muted-2); font-size:12.5px; line-height:1.5; }
|
|
506
506
|
/* ---- contact groups (rosters) ---- */
|
|
507
|
-
|
|
507
|
+
/* Groups sits ABOVE the people list: a long contact list used to bury it
|
|
508
|
+
entirely (you had to scroll past every contact to discover groups exist).
|
|
509
|
+
Small set first, long list second. */
|
|
510
|
+
.cvg { padding-bottom:6px; }
|
|
511
|
+
/* Segmented island: an inset track with the selected segment lifted out of it —
|
|
512
|
+
depth from light, not borders, matching the open-actions menu. */
|
|
513
|
+
.cv-seg {
|
|
514
|
+
display:inline-flex; gap:2px; padding:2px; border-radius:9px;
|
|
515
|
+
background:rgba(31,26,23,.045);
|
|
516
|
+
}
|
|
517
|
+
.cv-seg-btn {
|
|
518
|
+
appearance:none; border:0; background:transparent; cursor:pointer;
|
|
519
|
+
font-family:var(--sans); font-size:11px; font-weight:500; letter-spacing:-0.01em;
|
|
520
|
+
color:var(--muted-2); height:22px; padding:0 9px; border-radius:7px;
|
|
521
|
+
display:inline-flex; align-items:center; gap:5px;
|
|
522
|
+
transition:background-color .15s var(--settle), color .15s var(--settle), box-shadow .15s var(--settle);
|
|
523
|
+
}
|
|
524
|
+
.cv-seg-btn:hover { color:var(--ink-2); }
|
|
525
|
+
.cv-seg-btn.active {
|
|
526
|
+
background:#fff; color:var(--ink); font-weight:600;
|
|
527
|
+
box-shadow:0 1px 2px rgba(31,26,23,.09), 0 0 0 0.5px rgba(31,26,23,.05);
|
|
528
|
+
}
|
|
529
|
+
.cv-seg-n { font-size:9.5px; font-variant-numeric:tabular-nums; opacity:.55; }
|
|
530
|
+
.cv-seg-btn.active .cv-seg-n { opacity:.65; }
|
|
508
531
|
.cvg-head { display:flex; align-items:center; justify-content:space-between; padding:12px 16px 6px; }
|
|
509
532
|
.cvg-newform { display:flex; gap:7px; padding:6px 16px 10px; align-items:center; }
|
|
510
533
|
.cvg-newform.hidden { display:none; }
|
|
@@ -824,8 +847,16 @@
|
|
|
824
847
|
<!-- Contacts view -->
|
|
825
848
|
<section class="view hidden" id="contactsView">
|
|
826
849
|
<div class="cv-head">
|
|
827
|
-
|
|
850
|
+
<!-- One island, two lists. Groups used to sit below every contact, so a
|
|
851
|
+
long book hid them completely; stacking them the other way would just
|
|
852
|
+
bury people instead. A segment switches the pane and keeps both a
|
|
853
|
+
single tap away, with counts so neither looks empty when it isn't. -->
|
|
854
|
+
<div class="cv-seg" role="tablist" aria-label="Contacts and groups">
|
|
855
|
+
<button class="cv-seg-btn active" type="button" role="tab" data-pane="people" id="cvSegPeople">People <span class="cv-seg-n" id="cvSegPeopleN"></span></button>
|
|
856
|
+
<button class="cv-seg-btn" type="button" role="tab" data-pane="groups" id="cvSegGroups">Groups <span class="cv-seg-n" id="cvSegGroupsN"></span></button>
|
|
857
|
+
</div>
|
|
828
858
|
<button class="cv-add" type="button" id="cvAdd">+ Add</button>
|
|
859
|
+
<button class="cv-add gone" type="button" id="cvgNew">+ New</button>
|
|
829
860
|
</div>
|
|
830
861
|
<form class="cv-form hidden" id="cvForm">
|
|
831
862
|
<div class="cv-row2">
|
|
@@ -848,16 +879,9 @@
|
|
|
848
879
|
<button class="cv-save" type="submit" id="cvSave">Save</button>
|
|
849
880
|
</div>
|
|
850
881
|
</form>
|
|
851
|
-
<div class="cv-list" id="cvList"></div>
|
|
852
|
-
<div id="contactsEmpty" class="cv-empty gone">No contacts yet.<br>Add someone, or your agent saves them as you relay.</div>
|
|
853
|
-
|
|
854
882
|
<!-- Contact groups: saved rosters. A relay to a group fans out to every
|
|
855
883
|
member under ONE shared thread; replies reach everyone. -->
|
|
856
884
|
<div class="cvg" id="cvGroups">
|
|
857
|
-
<div class="cvg-head">
|
|
858
|
-
<span class="cv-title">Groups</span>
|
|
859
|
-
<button class="cv-add" type="button" id="cvgNew">+ New group</button>
|
|
860
|
-
</div>
|
|
861
885
|
<form class="cvg-newform hidden" id="cvgNewForm">
|
|
862
886
|
<input class="cv-input" id="cvgNewName" placeholder="Group name" autocomplete="off" spellcheck="false" />
|
|
863
887
|
<button class="cv-save" type="submit">Create</button>
|
|
@@ -867,6 +891,9 @@
|
|
|
867
891
|
<div id="cvgList"></div>
|
|
868
892
|
<div class="cv-empty" id="cvgEmpty">No groups yet. A group relays to everyone in it as one conversation.</div>
|
|
869
893
|
</div>
|
|
894
|
+
<div class="cv-list" id="cvList"></div>
|
|
895
|
+
<div id="contactsEmpty" class="cv-empty gone">No contacts yet.<br>Add someone, or your agent saves them as you relay.</div>
|
|
896
|
+
|
|
870
897
|
</section>
|
|
871
898
|
|
|
872
899
|
<!-- Settings view (account card + sign-out / switch-account; rendered by JS) -->
|
|
@@ -2440,7 +2467,8 @@
|
|
|
2440
2467
|
}
|
|
2441
2468
|
function contactKey(c) { return c.id || (contactEmails(c)[0] || "") || c.name; }
|
|
2442
2469
|
function renderContacts() {
|
|
2443
|
-
contactsEmptyEl.classList.toggle("gone", contactsList.length > 0);
|
|
2470
|
+
contactsEmptyEl.classList.toggle("gone", contactsPane !== "people" || contactsList.length > 0);
|
|
2471
|
+
refreshPaneCounts();
|
|
2444
2472
|
cvListEl.innerHTML = contactsList.map((c) => {
|
|
2445
2473
|
const emails = contactEmails(c);
|
|
2446
2474
|
const primary = emails[0] || "";
|
|
@@ -2475,6 +2503,35 @@
|
|
|
2475
2503
|
const cvgNewFormEl = document.getElementById("cvgNewForm");
|
|
2476
2504
|
const cvgNewNameEl = document.getElementById("cvgNewName");
|
|
2477
2505
|
const cvgNewCancelEl = document.getElementById("cvgNewCancel");
|
|
2506
|
+
// ---- contacts / groups pane (the segmented island in the head) ----
|
|
2507
|
+
const cvSegPeopleEl = document.getElementById("cvSegPeople");
|
|
2508
|
+
const cvSegGroupsEl = document.getElementById("cvSegGroups");
|
|
2509
|
+
const cvSegPeopleNEl = document.getElementById("cvSegPeopleN");
|
|
2510
|
+
const cvSegGroupsNEl = document.getElementById("cvSegGroupsN");
|
|
2511
|
+
const cvGroupsEl = document.getElementById("cvGroups");
|
|
2512
|
+
let contactsPane = "people";
|
|
2513
|
+
function applyContactsPane() {
|
|
2514
|
+
const people = contactsPane === "people";
|
|
2515
|
+
cvSegPeopleEl.classList.toggle("active", people);
|
|
2516
|
+
cvSegGroupsEl.classList.toggle("active", !people);
|
|
2517
|
+
cvSegPeopleEl.setAttribute("aria-selected", String(people));
|
|
2518
|
+
cvSegGroupsEl.setAttribute("aria-selected", String(!people));
|
|
2519
|
+
cvListEl.classList.toggle("gone", !people);
|
|
2520
|
+
contactsEmptyEl.classList.toggle("gone", !people || contactsList.length > 0);
|
|
2521
|
+
cvGroupsEl.classList.toggle("gone", people);
|
|
2522
|
+
// The add button follows the pane it belongs to.
|
|
2523
|
+
cvAddEl.classList.toggle("gone", !people);
|
|
2524
|
+
cvgNewEl.classList.toggle("gone", people);
|
|
2525
|
+
if (people) cvgNewFormEl.classList.add("hidden");
|
|
2526
|
+
else cvFormEl.classList.add("hidden");
|
|
2527
|
+
}
|
|
2528
|
+
function refreshPaneCounts() {
|
|
2529
|
+
cvSegPeopleNEl.textContent = contactsList.length ? String(contactsList.length) : "";
|
|
2530
|
+
cvSegGroupsNEl.textContent = groupsList.length ? String(groupsList.length) : "";
|
|
2531
|
+
}
|
|
2532
|
+
cvSegPeopleEl.addEventListener("click", () => { contactsPane = "people"; applyContactsPane(); });
|
|
2533
|
+
cvSegGroupsEl.addEventListener("click", () => { contactsPane = "groups"; applyContactsPane(); loadGroups(); });
|
|
2534
|
+
|
|
2478
2535
|
const cvgListEl = document.getElementById("cvgList");
|
|
2479
2536
|
const cvgEmptyEl = document.getElementById("cvgEmpty");
|
|
2480
2537
|
const cvgErrorEl = document.getElementById("cvgError");
|
|
@@ -2515,6 +2572,7 @@
|
|
|
2515
2572
|
}
|
|
2516
2573
|
function renderGroups() {
|
|
2517
2574
|
cvgEmptyEl.classList.toggle("gone", groupsList.length > 0);
|
|
2575
|
+
refreshPaneCounts();
|
|
2518
2576
|
cvgListEl.innerHTML = groupsList.map((g) => {
|
|
2519
2577
|
const open = g.id === cvgExpandedId;
|
|
2520
2578
|
const count = Number(g.memberCount ?? (g.members || []).length) || 0;
|
|
@@ -3195,7 +3253,9 @@
|
|
|
3195
3253
|
taskDetailTimer = null;
|
|
3196
3254
|
}
|
|
3197
3255
|
if (activeView === "contacts") {
|
|
3256
|
+
applyContactsPane();
|
|
3198
3257
|
loadContacts();
|
|
3258
|
+
loadGroups(); // counts on the segment must be right before it is tapped
|
|
3199
3259
|
} else {
|
|
3200
3260
|
cvFormEl.classList.add("hidden");
|
|
3201
3261
|
if (window.relay.setFocusable) window.relay.setFocusable(false);
|
package/package.json
CHANGED
package/src/install.js
CHANGED
|
@@ -943,6 +943,14 @@ ${pillArgs.map((argument) => ` <string>${plistEscape(argument)}</string>`).jo
|
|
|
943
943
|
</array>
|
|
944
944
|
<key>RunAtLoad</key><true/>
|
|
945
945
|
<key>KeepAlive</key><true/>
|
|
946
|
+
<!-- The pill draws a window the user clicks, so it must be scheduled like an
|
|
947
|
+
app, not like batch work. Without ProcessType, launchd treats an agent as
|
|
948
|
+
ordinary background work: under load macOS starves it, and the field
|
|
949
|
+
symptom is a visible pill whose clicks and animation freeze for seconds
|
|
950
|
+
while it burns no CPU and runs no JavaScript. Interactive opts out of that
|
|
951
|
+
throttling; LowPriorityIO off keeps its disk reads from being deferred. -->
|
|
952
|
+
<key>ProcessType</key><string>Interactive</string>
|
|
953
|
+
<key>LowPriorityIO</key><false/>
|
|
946
954
|
<key>StandardOutPath</key><string>${plistEscape(logPath)}</string>
|
|
947
955
|
<key>StandardErrorPath</key><string>${plistEscape(logPath)}</string>
|
|
948
956
|
<key>EnvironmentVariables</key>
|