@bobfrankston/rmfmail 1.1.110 → 1.1.112

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/client/app.js CHANGED
@@ -6,7 +6,7 @@ import { initFolderTree, refreshFolderTree, updateFolderCounts, setFolderSynced,
6
6
  import { initMessageList, loadMessages, loadUnifiedInbox, loadSearchResults, reloadCurrentFolder, clearSearchMode, getSelectedMessages, markBodiesCached, getCurrentFocused, releaseFocus, removeMessagesAndReconcile, setRowFlagged, scrollFocusedIntoView, refreshPriorityIndex } from "./components/message-list.js";
7
7
  import { seenOf, flaggedOf, draftOf, setSeen, setFlagged } from "@bobfrankston/mailx-types";
8
8
  import { initTabs, setActiveView as setActiveTabView, openTab } from "./components/tabs.js";
9
- import { getCurrentMessage, initViewer, popOutCurrentMessage, toggleFullscreenPreview, showPreviewBodyMenu, wrapHtmlBody } from "./components/message-viewer.js";
9
+ import { getCurrentMessage, initViewer, popOutCurrentMessage, printCurrentMessage, toggleFullscreenPreview, showPreviewBodyMenu, wrapHtmlBody } from "./components/message-viewer.js";
10
10
  import { connectWebSocket, onWsEvent, triggerSync, syncAccount, reauthenticate, getAccounts, getFolders, deleteMessage, deleteMessages, undeleteMessage, restartServer, getSyncPending, getVersion, getSettings, saveSettings, getAutocompleteSettings, saveAutocompleteSettings, repairAccounts, updateFlags, markAsSpamMessages, logClientEvent, sendMessage as apiSendMessage, subscribeStore, cancelServerSearch } from "./lib/api-client.js";
11
11
  import * as messageState from "./lib/message-state.js";
12
12
  // ── New message badge (favicon + title) ──
@@ -994,7 +994,7 @@ function showComposeOverlay(title = "Compose") {
994
994
  // Full-screen on small/short screens, floating on larger
995
995
  const isSmall = window.innerWidth <= 768 || window.innerHeight <= 600;
996
996
  if (isSmall) {
997
- wrapper.style.cssText = "position:fixed;inset:0;z-index:1000;display:flex;flex-direction:column;background:#fff;";
997
+ wrapper.style.cssText = "position:fixed;inset:0;z-index:1600;display:flex;flex-direction:column;background:#fff;";
998
998
  }
999
999
  else {
1000
1000
  // CSS `resize:both` only gives a single lower-right grip. To allow
@@ -1003,7 +1003,7 @@ function showComposeOverlay(title = "Compose") {
1003
1003
  // Open horizontally centred, near the top — not docked to the
1004
1004
  // lower-right corner (Bob 2026-05-18). The title bar still drags it
1005
1005
  // anywhere; this is just the initial placement.
1006
- wrapper.style.cssText = "position:fixed;top:48px;left:calc((100vw - min(900px,55vw)) / 2);width:min(900px,55vw);height:min(700px,70vh);z-index:1000;border-radius:8px;box-shadow:0 4px 24px rgba(0,0,0,0.3);display:flex;flex-direction:column;overflow:hidden;";
1006
+ wrapper.style.cssText = "position:fixed;top:48px;left:calc((100vw - min(900px,55vw)) / 2);width:min(900px,55vw);height:min(700px,70vh);z-index:1600;border-radius:8px;box-shadow:0 4px 24px rgba(0,0,0,0.3);display:flex;flex-direction:column;overflow:hidden;";
1007
1007
  }
1008
1008
  // Title bar — drag to move; right-side cluster holds discard, popout, close.
1009
1009
  const titleBar = document.createElement("div");
@@ -1049,7 +1049,7 @@ function showComposeOverlay(title = "Compose") {
1049
1049
  popoutBtn.addEventListener("click", () => {
1050
1050
  if (!maximized) {
1051
1051
  savedCss = wrapper.style.cssText;
1052
- wrapper.style.cssText = "position:fixed;inset:0;z-index:1000;display:flex;flex-direction:column;background:#fff;overflow:hidden;";
1052
+ wrapper.style.cssText = "position:fixed;inset:0;z-index:1600;display:flex;flex-direction:column;background:#fff;overflow:hidden;";
1053
1053
  popoutBtn.innerHTML = RESTORE_SVG;
1054
1054
  popoutBtn.title = "Restore";
1055
1055
  maximized = true;
@@ -3025,6 +3025,16 @@ document.addEventListener("keydown", (e) => {
3025
3025
  e.preventDefault();
3026
3026
  openCompose("new");
3027
3027
  }
3028
+ // Ctrl+P = Print the focused message. preventDefault stops the host
3029
+ // browser from printing the whole app window instead of the letter.
3030
+ if (e.ctrlKey && (e.key === "p" || e.key === "P") && !e.shiftKey && !e.altKey) {
3031
+ const t = e.target;
3032
+ const inText = t && (t.tagName === "INPUT" || t.tagName === "TEXTAREA" || t.isContentEditable);
3033
+ if (!inText) {
3034
+ e.preventDefault();
3035
+ printCurrentMessage();
3036
+ }
3037
+ }
3028
3038
  // Ctrl+T = new view tab. The strip is hidden with a single tab (no wasted
3029
3039
  // band), so this is how the second tab gets opened; once 2+ exist the
3030
3040
  // strip's "+" is also available.