@bobfrankston/rmfmail 1.0.666 → 1.0.667

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.
@@ -3426,7 +3426,8 @@ async function fetchUpcoming(from) {
3426
3426
  notes: r.notes,
3427
3427
  source: r.providerId ? "google" : "local",
3428
3428
  recurringEventId: r.recurringEventId,
3429
- htmlLink: r.htmlLink
3429
+ htmlLink: r.htmlLink,
3430
+ isHoliday: !!r.isHoliday
3430
3431
  }));
3431
3432
  }
3432
3433
  function formatDayHeader(d, today, tomorrow) {
@@ -3518,8 +3519,12 @@ function renderEvents(events) {
3518
3519
  }
3519
3520
  const recurMark = e.recurringEventId ? `<span class="cal-side-event-recur" title="Recurring event">\u21BB</span>` : "";
3520
3521
  const link = e.htmlLink || "";
3521
- html += `<div class="cal-side-event" data-id="${e.id}" data-link="${escapeHtml4(link)}" ${link ? 'title="Click to open in Google Calendar"' : ""}>
3522
- <span class="cal-side-event-dot ${e.source === "google" ? "g" : "l"}"></span>
3522
+ const holidayAttr = e.isHoliday ? ' data-holiday="1"' : "";
3523
+ const clickable = !e.isHoliday;
3524
+ const titleAttr = clickable && link ? 'title="Click to open in Google Calendar"' : "";
3525
+ const dataLink = clickable ? `data-link="${escapeHtml4(link)}"` : "";
3526
+ html += `<div class="cal-side-event" data-id="${e.id}"${holidayAttr} ${dataLink} ${titleAttr}>
3527
+ <span class="cal-side-event-dot ${e.isHoliday ? "h" : e.source === "google" ? "g" : "l"}"></span>
3523
3528
  <span class="cal-side-event-time">${escapeHtml4(formatTime(e))}</span>
3524
3529
  <span class="cal-side-event-title">${escapeHtml4(e.title)}${recurMark}</span>
3525
3530
  </div>`;
@@ -3908,6 +3913,24 @@ function initCalendarSidebar() {
3908
3913
  refresh();
3909
3914
  });
3910
3915
  }
3916
+ const holiCb = document.getElementById("cal-side-show-holidays");
3917
+ if (holiCb && !holiCb.__wired) {
3918
+ holiCb.__wired = true;
3919
+ getSettings().then((s) => {
3920
+ holiCb.checked = !!s?.calendar?.showHolidays;
3921
+ }).catch(() => {
3922
+ });
3923
+ holiCb.addEventListener("change", async () => {
3924
+ try {
3925
+ const s = await getSettings();
3926
+ s.calendar = { ...s.calendar || {}, showHolidays: holiCb.checked };
3927
+ await saveSettings(s);
3928
+ } catch (e) {
3929
+ console.error("[cal] showHolidays save failed:", e);
3930
+ }
3931
+ refresh();
3932
+ });
3933
+ }
3911
3934
  const horizonInput = document.getElementById("cal-side-horizon");
3912
3935
  if (horizonInput && !horizonInput.__wired) {
3913
3936
  horizonInput.__wired = true;
@@ -4346,21 +4369,45 @@ async function firePopupForItem(item) {
4346
4369
  if (openPopups.has(item.uuid))
4347
4370
  return;
4348
4371
  openPopups.add(item.uuid);
4372
+ const buttons = ["Snooze 15m", "Snooze 1h", "Dismiss"];
4373
+ if (item.htmlLink)
4374
+ buttons.push("Open");
4375
+ if (item.kind === "calendar")
4376
+ buttons.push("Delete");
4377
+ const icon = item.kind === "calendar" ? "\u{1F4C5}" : "\u2611";
4378
+ const kindLabel = item.kind === "calendar" ? "Calendar event" : "Task due";
4379
+ const buttonsHtml = buttons.map((b) => `<button type="button" data-btn="${escapeHtml6(b)}">${escapeHtml6(b)}</button>`).join("");
4349
4380
  const html = `<!DOCTYPE html>
4350
4381
  <html><head><meta charset="utf-8"><style>
4351
- body { font: 13px system-ui, sans-serif; margin: 0; padding: 16px 18px; background: #fff; color: #222; }
4352
- .icon { display: inline-block; width: 18px; text-align: center; margin-right: 4px; }
4353
- .title { font-size: 1.05em; font-weight: 600; margin-bottom: 6px; }
4354
- .when { color: #555; font-size: 0.95em; margin-bottom: 4px; }
4382
+ html, body { height: 100%; }
4383
+ body { font: 13px system-ui, sans-serif; margin: 0; padding: 16px 18px; background: #fff; color: #222; display:flex; flex-direction:column; box-sizing:border-box; }
4384
+ .icon { display: inline-block; width: 20px; text-align: center; margin-right: 4px; }
4385
+ .title { font-size: 1.1em; font-weight: 600; margin-bottom: 8px; }
4386
+ .when { color: #555; font-size: 0.95em; margin-bottom: 2px; }
4355
4387
  .kind { color: #888; font-size: 0.85em; }
4388
+ .spacer { flex: 1; }
4389
+ .buttons { display: flex; gap: 8px; justify-content: flex-end; margin-top: 12px; }
4390
+ .buttons button { padding: 6px 14px; border: none; border-radius: 4px; background: #0066cc; color: #fff; font: 13px system-ui, sans-serif; cursor: pointer; min-width: 70px; }
4391
+ .buttons button:hover { background: #0052a3; }
4356
4392
  </style></head><body>
4357
- <div class="title"><span class="icon">${item.kind === "calendar" ? "\u{1F4C5}" : "\u2611"}</span>${escapeHtml6(item.title)}</div>
4393
+ <div class="title"><span class="icon">${icon}</span>${escapeHtml6(item.title)}</div>
4358
4394
  <div class="when">${escapeHtml6(formatWhen(item.whenMs))}</div>
4359
- <div class="kind">${item.kind === "calendar" ? "Calendar event" : "Task due"}</div>
4395
+ <div class="kind">${kindLabel}</div>
4396
+ <div class="spacer"></div>
4397
+ <div class="buttons">${buttonsHtml}</div>
4398
+ <script>
4399
+ // Wire each button to fire window.ipc.postMessage({button: "..."}) so
4400
+ // msger's parent resolves the result promise. Same wire used by the
4401
+ // built-in template; works in rawHtml mode because window.ipc is a
4402
+ // wry-level bridge, not a msger-template construct.
4403
+ document.querySelectorAll("button[data-btn]").forEach(function(b) {
4404
+ b.addEventListener("click", function() {
4405
+ try { window.ipc.postMessage(JSON.stringify({ button: b.getAttribute("data-btn") })); }
4406
+ catch (e) { /* IPC unavailable \u2014 close, parent treats as dismissed */ try { window.close(); } catch (_) {} }
4407
+ });
4408
+ });
4409
+ <\/script>
4360
4410
  </body></html>`;
4361
- const buttons = ["Snooze 15m", "Snooze 1h", "Dismiss"];
4362
- if (item.htmlLink)
4363
- buttons.push("Open");
4364
4411
  const title = item.kind === "calendar" ? "Calendar reminder" : "Task reminder";
4365
4412
  const hasHost = !!window.mailxapi?.showReminderPopup;
4366
4413
  let r;
@@ -4411,6 +4458,15 @@ async function firePopupForItem(item) {
4411
4458
  saveDismissed(m);
4412
4459
  }
4413
4460
  break;
4461
+ case "Delete":
4462
+ {
4463
+ const m = loadDismissed();
4464
+ m[item.uuid] = true;
4465
+ saveDismissed(m);
4466
+ }
4467
+ firedThisSession.delete(item.uuid);
4468
+ deleteCalendarEvent(item.uuid).catch((e) => console.error(` [alarm] delete failed for ${item.uuid}: ${e?.message || e}`));
4469
+ break;
4414
4470
  default:
4415
4471
  snoozeItem(item, 15);
4416
4472
  break;