@bobfrankston/mailx 1.0.9 → 1.0.13

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.
Files changed (246) hide show
  1. package/bin/mailx.js +47 -29
  2. package/bin/postinstall.js +41 -0
  3. package/client/app.js +93 -13
  4. package/client/components/folder-tree.js +84 -3
  5. package/client/components/message-list.js +134 -8
  6. package/client/components/message-viewer.js +130 -13
  7. package/client/compose/compose.html +4 -4
  8. package/client/compose/compose.js +53 -34
  9. package/client/index.html +33 -9
  10. package/client/lib/api-client.js +102 -30
  11. package/client/lib/mailxapi.js +123 -0
  12. package/client/package.json +5 -1
  13. package/client/styles/components.css +188 -15
  14. package/client/styles/layout.css +2 -1
  15. package/killmail.cmd +6 -0
  16. package/launch.ps1 +48 -3
  17. package/launcher/bin/mailx-app.exe +0 -0
  18. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Breadcrumbs +0 -0
  19. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Crashpad/metadata +0 -0
  20. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Crashpad/settings.dat +0 -0
  21. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Crashpad/throttle_store.dat +1 -0
  22. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/CrashpadMetrics-active.pma +0 -0
  23. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/BrowsingTopicsSiteData +0 -0
  24. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/Cache/No_Vary_Search/journal.baj +1 -0
  25. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/DIPS +0 -0
  26. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/DashTrackerDatabase +0 -0
  27. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/EdgeJourneys/EdgeJourneys.db +0 -0
  28. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/Extension Rules/LOCK +0 -0
  29. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/Extension Rules/LOG +3 -0
  30. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/Extension Rules/MANIFEST-000001 +0 -0
  31. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/Extension Scripts/LOCK +0 -0
  32. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/Extension Scripts/LOG +3 -0
  33. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/Extension Scripts/MANIFEST-000001 +0 -0
  34. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/Extension State/LOCK +0 -0
  35. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/Extension State/LOG +3 -0
  36. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/Extension State/MANIFEST-000001 +0 -0
  37. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/ExtensionActivityComp +0 -0
  38. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/ExtensionActivityEdge +0 -0
  39. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/Favicons +0 -0
  40. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/History +0 -0
  41. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/History-journal +0 -0
  42. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/IndexedDB/devtools_devtools_0.indexeddb.leveldb/LOCK +0 -0
  43. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/IndexedDB/devtools_devtools_0.indexeddb.leveldb/LOG +3 -0
  44. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/IndexedDB/devtools_devtools_0.indexeddb.leveldb/MANIFEST-000001 +0 -0
  45. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/Local Storage/leveldb/LOCK +0 -0
  46. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/Local Storage/leveldb/LOG +3 -0
  47. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/Local Storage/leveldb/MANIFEST-000001 +0 -0
  48. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/Login Data +0 -0
  49. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/Login Data For Account +0 -0
  50. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/Network/Cookies +0 -0
  51. NEL +0 -0
  52. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/Network/Trust Tokens +0 -0
  53. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/Network Action Predictor +0 -0
  54. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/Preferences +1 -0
  55. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/Safe Browsing Network/Safe Browsing Cookies +0 -0
  56. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/ServerCertificate +0 -0
  57. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/Session Storage/LOCK +0 -0
  58. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/Session Storage/LOG +3 -0
  59. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/Session Storage/MANIFEST-000001 +0 -0
  60. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/Shared Dictionary/db +0 -0
  61. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/SharedStorage +0 -0
  62. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/Shortcuts +0 -0
  63. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/Site Characteristics Database/LOCK +0 -0
  64. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/Site Characteristics Database/LOG +3 -0
  65. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/Site Characteristics Database/MANIFEST-000001 +0 -0
  66. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/Sync Data/LevelDB/LOCK +0 -0
  67. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/Sync Data/LevelDB/LOG +3 -0
  68. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/Sync Data/LevelDB/MANIFEST-000001 +0 -0
  69. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/Top Sites +0 -0
  70. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/Vpn Tokens +0 -0
  71. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/Web Data +0 -0
  72. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/Web Data-journal +0 -0
  73. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/WebStorage/QuotaManager +0 -0
  74. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/WebStorage/QuotaManager-journal +0 -0
  75. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/heavy_ad_intervention_opt_out.db +0 -0
  76. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/shared_proto_db/LOCK +0 -0
  77. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/shared_proto_db/LOG +3 -0
  78. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/shared_proto_db/MANIFEST-000001 +0 -0
  79. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/shared_proto_db/metadata/LOCK +0 -0
  80. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/shared_proto_db/metadata/LOG +3 -0
  81. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/shared_proto_db/metadata/MANIFEST-000001 +0 -0
  82. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/DeferredBrowserMetrics/BrowserMetrics-69CAD063-BE24.pma +0 -0
  83. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Local State +1 -0
  84. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Variations +1 -0
  85. package/launcher/bin/mailx-app.old.exe +0 -0
  86. package/launcher/mailx.ico +0 -0
  87. package/npmg.bat +6 -0
  88. package/package.json +9 -3
  89. package/packages/mailx-api/index.js +79 -26
  90. package/packages/mailx-api/package.json +5 -1
  91. package/packages/mailx-compose/package.json +5 -1
  92. package/packages/mailx-core/index.d.ts +129 -0
  93. package/packages/mailx-core/index.js +323 -0
  94. package/packages/mailx-core/ipc.d.ts +13 -0
  95. package/packages/mailx-core/ipc.js +56 -0
  96. package/packages/mailx-core/package.json +18 -0
  97. package/packages/mailx-imap/index.d.ts +5 -1
  98. package/packages/mailx-imap/index.js +76 -14
  99. package/packages/mailx-imap/package.json +5 -1
  100. package/packages/mailx-send/package.json +12 -2
  101. package/packages/mailx-server/index.js +42 -31
  102. package/packages/mailx-server/package.json +5 -2
  103. package/packages/mailx-settings/index.d.ts +1 -1
  104. package/packages/mailx-settings/index.js +21 -12
  105. package/packages/mailx-settings/package.json +5 -1
  106. package/packages/mailx-store/db.d.ts +5 -1
  107. package/packages/mailx-store/db.js +64 -12
  108. package/packages/mailx-store/file-store.d.ts +2 -8
  109. package/packages/mailx-store/file-store.js +7 -31
  110. package/packages/mailx-store/package.json +5 -1
  111. package/packages/mailx-types/index.d.ts +3 -1
  112. package/packages/mailx-types/package.json +6 -2
  113. package/.tswalk.json +0 -3366
  114. package/mailx.json +0 -9
  115. package/packages/mailx-api/node_modules/nodemailer/.ncurc.js +0 -9
  116. package/packages/mailx-api/node_modules/nodemailer/.prettierignore +0 -8
  117. package/packages/mailx-api/node_modules/nodemailer/.prettierrc +0 -12
  118. package/packages/mailx-api/node_modules/nodemailer/.prettierrc.js +0 -10
  119. package/packages/mailx-api/node_modules/nodemailer/.release-please-config.json +0 -9
  120. package/packages/mailx-api/node_modules/nodemailer/LICENSE +0 -16
  121. package/packages/mailx-api/node_modules/nodemailer/README.md +0 -86
  122. package/packages/mailx-api/node_modules/nodemailer/SECURITY.txt +0 -22
  123. package/packages/mailx-api/node_modules/nodemailer/eslint.config.js +0 -88
  124. package/packages/mailx-api/node_modules/nodemailer/lib/addressparser/index.js +0 -383
  125. package/packages/mailx-api/node_modules/nodemailer/lib/base64/index.js +0 -139
  126. package/packages/mailx-api/node_modules/nodemailer/lib/dkim/index.js +0 -253
  127. package/packages/mailx-api/node_modules/nodemailer/lib/dkim/message-parser.js +0 -155
  128. package/packages/mailx-api/node_modules/nodemailer/lib/dkim/relaxed-body.js +0 -154
  129. package/packages/mailx-api/node_modules/nodemailer/lib/dkim/sign.js +0 -117
  130. package/packages/mailx-api/node_modules/nodemailer/lib/fetch/cookies.js +0 -281
  131. package/packages/mailx-api/node_modules/nodemailer/lib/fetch/index.js +0 -280
  132. package/packages/mailx-api/node_modules/nodemailer/lib/json-transport/index.js +0 -82
  133. package/packages/mailx-api/node_modules/nodemailer/lib/mail-composer/index.js +0 -629
  134. package/packages/mailx-api/node_modules/nodemailer/lib/mailer/index.js +0 -441
  135. package/packages/mailx-api/node_modules/nodemailer/lib/mailer/mail-message.js +0 -316
  136. package/packages/mailx-api/node_modules/nodemailer/lib/mime-funcs/index.js +0 -625
  137. package/packages/mailx-api/node_modules/nodemailer/lib/mime-funcs/mime-types.js +0 -2113
  138. package/packages/mailx-api/node_modules/nodemailer/lib/mime-node/index.js +0 -1316
  139. package/packages/mailx-api/node_modules/nodemailer/lib/mime-node/last-newline.js +0 -33
  140. package/packages/mailx-api/node_modules/nodemailer/lib/mime-node/le-unix.js +0 -43
  141. package/packages/mailx-api/node_modules/nodemailer/lib/mime-node/le-windows.js +0 -52
  142. package/packages/mailx-api/node_modules/nodemailer/lib/nodemailer.js +0 -157
  143. package/packages/mailx-api/node_modules/nodemailer/lib/punycode/index.js +0 -460
  144. package/packages/mailx-api/node_modules/nodemailer/lib/qp/index.js +0 -227
  145. package/packages/mailx-api/node_modules/nodemailer/lib/sendmail-transport/index.js +0 -210
  146. package/packages/mailx-api/node_modules/nodemailer/lib/ses-transport/index.js +0 -234
  147. package/packages/mailx-api/node_modules/nodemailer/lib/shared/index.js +0 -754
  148. package/packages/mailx-api/node_modules/nodemailer/lib/smtp-connection/data-stream.js +0 -108
  149. package/packages/mailx-api/node_modules/nodemailer/lib/smtp-connection/http-proxy-client.js +0 -143
  150. package/packages/mailx-api/node_modules/nodemailer/lib/smtp-connection/index.js +0 -1870
  151. package/packages/mailx-api/node_modules/nodemailer/lib/smtp-pool/index.js +0 -652
  152. package/packages/mailx-api/node_modules/nodemailer/lib/smtp-pool/pool-resource.js +0 -259
  153. package/packages/mailx-api/node_modules/nodemailer/lib/smtp-transport/index.js +0 -421
  154. package/packages/mailx-api/node_modules/nodemailer/lib/stream-transport/index.js +0 -135
  155. package/packages/mailx-api/node_modules/nodemailer/lib/well-known/index.js +0 -47
  156. package/packages/mailx-api/node_modules/nodemailer/lib/well-known/services.json +0 -611
  157. package/packages/mailx-api/node_modules/nodemailer/lib/xoauth2/index.js +0 -427
  158. package/packages/mailx-api/node_modules/nodemailer/package.json +0 -47
  159. package/packages/mailx-imap/node_modules/nodemailer/.ncurc.js +0 -9
  160. package/packages/mailx-imap/node_modules/nodemailer/.prettierignore +0 -8
  161. package/packages/mailx-imap/node_modules/nodemailer/.prettierrc +0 -12
  162. package/packages/mailx-imap/node_modules/nodemailer/.prettierrc.js +0 -10
  163. package/packages/mailx-imap/node_modules/nodemailer/.release-please-config.json +0 -9
  164. package/packages/mailx-imap/node_modules/nodemailer/LICENSE +0 -16
  165. package/packages/mailx-imap/node_modules/nodemailer/README.md +0 -86
  166. package/packages/mailx-imap/node_modules/nodemailer/SECURITY.txt +0 -22
  167. package/packages/mailx-imap/node_modules/nodemailer/eslint.config.js +0 -88
  168. package/packages/mailx-imap/node_modules/nodemailer/lib/addressparser/index.js +0 -383
  169. package/packages/mailx-imap/node_modules/nodemailer/lib/base64/index.js +0 -139
  170. package/packages/mailx-imap/node_modules/nodemailer/lib/dkim/index.js +0 -253
  171. package/packages/mailx-imap/node_modules/nodemailer/lib/dkim/message-parser.js +0 -155
  172. package/packages/mailx-imap/node_modules/nodemailer/lib/dkim/relaxed-body.js +0 -154
  173. package/packages/mailx-imap/node_modules/nodemailer/lib/dkim/sign.js +0 -117
  174. package/packages/mailx-imap/node_modules/nodemailer/lib/fetch/cookies.js +0 -281
  175. package/packages/mailx-imap/node_modules/nodemailer/lib/fetch/index.js +0 -280
  176. package/packages/mailx-imap/node_modules/nodemailer/lib/json-transport/index.js +0 -82
  177. package/packages/mailx-imap/node_modules/nodemailer/lib/mail-composer/index.js +0 -629
  178. package/packages/mailx-imap/node_modules/nodemailer/lib/mailer/index.js +0 -441
  179. package/packages/mailx-imap/node_modules/nodemailer/lib/mailer/mail-message.js +0 -316
  180. package/packages/mailx-imap/node_modules/nodemailer/lib/mime-funcs/index.js +0 -625
  181. package/packages/mailx-imap/node_modules/nodemailer/lib/mime-funcs/mime-types.js +0 -2113
  182. package/packages/mailx-imap/node_modules/nodemailer/lib/mime-node/index.js +0 -1316
  183. package/packages/mailx-imap/node_modules/nodemailer/lib/mime-node/last-newline.js +0 -33
  184. package/packages/mailx-imap/node_modules/nodemailer/lib/mime-node/le-unix.js +0 -43
  185. package/packages/mailx-imap/node_modules/nodemailer/lib/mime-node/le-windows.js +0 -52
  186. package/packages/mailx-imap/node_modules/nodemailer/lib/nodemailer.js +0 -157
  187. package/packages/mailx-imap/node_modules/nodemailer/lib/punycode/index.js +0 -460
  188. package/packages/mailx-imap/node_modules/nodemailer/lib/qp/index.js +0 -227
  189. package/packages/mailx-imap/node_modules/nodemailer/lib/sendmail-transport/index.js +0 -210
  190. package/packages/mailx-imap/node_modules/nodemailer/lib/ses-transport/index.js +0 -234
  191. package/packages/mailx-imap/node_modules/nodemailer/lib/shared/index.js +0 -754
  192. package/packages/mailx-imap/node_modules/nodemailer/lib/smtp-connection/data-stream.js +0 -108
  193. package/packages/mailx-imap/node_modules/nodemailer/lib/smtp-connection/http-proxy-client.js +0 -143
  194. package/packages/mailx-imap/node_modules/nodemailer/lib/smtp-connection/index.js +0 -1870
  195. package/packages/mailx-imap/node_modules/nodemailer/lib/smtp-pool/index.js +0 -652
  196. package/packages/mailx-imap/node_modules/nodemailer/lib/smtp-pool/pool-resource.js +0 -259
  197. package/packages/mailx-imap/node_modules/nodemailer/lib/smtp-transport/index.js +0 -421
  198. package/packages/mailx-imap/node_modules/nodemailer/lib/stream-transport/index.js +0 -135
  199. package/packages/mailx-imap/node_modules/nodemailer/lib/well-known/index.js +0 -47
  200. package/packages/mailx-imap/node_modules/nodemailer/lib/well-known/services.json +0 -611
  201. package/packages/mailx-imap/node_modules/nodemailer/lib/xoauth2/index.js +0 -427
  202. package/packages/mailx-imap/node_modules/nodemailer/package.json +0 -47
  203. package/packages/mailx-send/node_modules/nodemailer/.ncurc.js +0 -9
  204. package/packages/mailx-send/node_modules/nodemailer/.prettierignore +0 -8
  205. package/packages/mailx-send/node_modules/nodemailer/.prettierrc +0 -12
  206. package/packages/mailx-send/node_modules/nodemailer/.prettierrc.js +0 -10
  207. package/packages/mailx-send/node_modules/nodemailer/.release-please-config.json +0 -9
  208. package/packages/mailx-send/node_modules/nodemailer/LICENSE +0 -16
  209. package/packages/mailx-send/node_modules/nodemailer/README.md +0 -86
  210. package/packages/mailx-send/node_modules/nodemailer/SECURITY.txt +0 -22
  211. package/packages/mailx-send/node_modules/nodemailer/eslint.config.js +0 -88
  212. package/packages/mailx-send/node_modules/nodemailer/lib/addressparser/index.js +0 -383
  213. package/packages/mailx-send/node_modules/nodemailer/lib/base64/index.js +0 -139
  214. package/packages/mailx-send/node_modules/nodemailer/lib/dkim/index.js +0 -253
  215. package/packages/mailx-send/node_modules/nodemailer/lib/dkim/message-parser.js +0 -155
  216. package/packages/mailx-send/node_modules/nodemailer/lib/dkim/relaxed-body.js +0 -154
  217. package/packages/mailx-send/node_modules/nodemailer/lib/dkim/sign.js +0 -117
  218. package/packages/mailx-send/node_modules/nodemailer/lib/fetch/cookies.js +0 -281
  219. package/packages/mailx-send/node_modules/nodemailer/lib/fetch/index.js +0 -280
  220. package/packages/mailx-send/node_modules/nodemailer/lib/json-transport/index.js +0 -82
  221. package/packages/mailx-send/node_modules/nodemailer/lib/mail-composer/index.js +0 -629
  222. package/packages/mailx-send/node_modules/nodemailer/lib/mailer/index.js +0 -441
  223. package/packages/mailx-send/node_modules/nodemailer/lib/mailer/mail-message.js +0 -316
  224. package/packages/mailx-send/node_modules/nodemailer/lib/mime-funcs/index.js +0 -625
  225. package/packages/mailx-send/node_modules/nodemailer/lib/mime-funcs/mime-types.js +0 -2113
  226. package/packages/mailx-send/node_modules/nodemailer/lib/mime-node/index.js +0 -1316
  227. package/packages/mailx-send/node_modules/nodemailer/lib/mime-node/last-newline.js +0 -33
  228. package/packages/mailx-send/node_modules/nodemailer/lib/mime-node/le-unix.js +0 -43
  229. package/packages/mailx-send/node_modules/nodemailer/lib/mime-node/le-windows.js +0 -52
  230. package/packages/mailx-send/node_modules/nodemailer/lib/nodemailer.js +0 -157
  231. package/packages/mailx-send/node_modules/nodemailer/lib/punycode/index.js +0 -460
  232. package/packages/mailx-send/node_modules/nodemailer/lib/qp/index.js +0 -227
  233. package/packages/mailx-send/node_modules/nodemailer/lib/sendmail-transport/index.js +0 -210
  234. package/packages/mailx-send/node_modules/nodemailer/lib/ses-transport/index.js +0 -234
  235. package/packages/mailx-send/node_modules/nodemailer/lib/shared/index.js +0 -754
  236. package/packages/mailx-send/node_modules/nodemailer/lib/smtp-connection/data-stream.js +0 -108
  237. package/packages/mailx-send/node_modules/nodemailer/lib/smtp-connection/http-proxy-client.js +0 -143
  238. package/packages/mailx-send/node_modules/nodemailer/lib/smtp-connection/index.js +0 -1870
  239. package/packages/mailx-send/node_modules/nodemailer/lib/smtp-pool/index.js +0 -652
  240. package/packages/mailx-send/node_modules/nodemailer/lib/smtp-pool/pool-resource.js +0 -259
  241. package/packages/mailx-send/node_modules/nodemailer/lib/smtp-transport/index.js +0 -421
  242. package/packages/mailx-send/node_modules/nodemailer/lib/stream-transport/index.js +0 -135
  243. package/packages/mailx-send/node_modules/nodemailer/lib/well-known/index.js +0 -47
  244. package/packages/mailx-send/node_modules/nodemailer/lib/well-known/services.json +0 -611
  245. package/packages/mailx-send/node_modules/nodemailer/lib/xoauth2/index.js +0 -427
  246. package/packages/mailx-send/node_modules/nodemailer/package.json +0 -47
package/client/index.html CHANGED
@@ -48,21 +48,29 @@
48
48
  <search>
49
49
  <input type="search" id="search-input" placeholder="Search..." autocomplete="off">
50
50
  </search>
51
- <button class="tb-btn" id="btn-sync" title="Sync">
52
- <span class="tb-icon">&#x21BB;</span>
51
+ <button class="tb-btn" id="btn-sync" title="Sync all folders (F5)">
52
+ <span class="tb-icon">&#x21BB;</span> Sync
53
53
  </button>
54
- <button class="tb-btn" id="btn-restart" title="Restart server + reload">
55
- <span class="tb-icon">&#x26A1;</span>
54
+ <button class="tb-btn" id="btn-restart" title="Restart server and reload page">
55
+ <span class="tb-icon">&#x26A1;</span> Restart
56
56
  </button>
57
57
  </div>
58
58
  </header>
59
59
 
60
- <nav class="folder-tree" id="folder-tree">
61
- <div class="folder-loading">Loading accounts...</div>
62
- </nav>
60
+ <div class="folder-panel">
61
+ <div class="ft-filter">
62
+ <input type="text" id="ft-filter-input" placeholder="Find folder..." autocomplete="off">
63
+ </div>
64
+ <nav class="folder-tree" id="folder-tree">
65
+ <div class="folder-loading">Loading accounts...</div>
66
+ </nav>
67
+ </div>
63
68
 
64
69
  <main class="main-area">
65
70
  <section class="message-list" id="message-list">
71
+ <div class="ml-filter">
72
+ <input type="text" id="ml-filter-input" placeholder="Filter..." autocomplete="off">
73
+ </div>
66
74
  <div class="ml-header">
67
75
  <span class="ml-col ml-col-flag"></span>
68
76
  <span class="ml-col ml-col-from" data-sort="from">From</span>
@@ -78,8 +86,17 @@
78
86
 
79
87
  <section class="message-viewer" id="message-viewer">
80
88
  <div class="mv-header" id="mv-header" hidden>
81
- <div class="mv-from"></div>
82
- <div class="mv-to"></div>
89
+ <div class="mv-header-top">
90
+ <div class="mv-header-info">
91
+ <div class="mv-from"></div>
92
+ <div class="mv-to"></div>
93
+ </div>
94
+ <div class="mv-header-actions">
95
+ <button class="mv-action mv-action-primary" id="mv-edit-draft" hidden>Edit &amp; Send</button>
96
+ <a class="mv-unsubscribe" id="mv-unsubscribe" hidden>Unsubscribe</a>
97
+ <button class="mv-action" id="mv-view-source" title="View source (.eml)" hidden>Source</button>
98
+ </div>
99
+ </div>
83
100
  <div class="mv-subject"></div>
84
101
  <div class="mv-date"></div>
85
102
  </div>
@@ -96,5 +113,12 @@
96
113
  <span id="status-pending"></span>
97
114
  <span id="status-queue">Queue: empty</span>
98
115
  </footer>
116
+
117
+ <div id="startup-overlay" class="startup-overlay">
118
+ <div class="startup-content">
119
+ <div class="startup-spinner"></div>
120
+ <div id="startup-status">Connecting to server...</div>
121
+ </div>
122
+ </div>
99
123
  </body>
100
124
  </html>
@@ -1,8 +1,23 @@
1
1
  /**
2
- * REST + WebSocket client for communicating with mailx-server.
3
- * All server communication goes through here.
2
+ * API client auto-detects IPC (WebView) vs HTTP (browser).
3
+ * When mailxapi is available (injected by launcher), calls go directly via IPC.
4
+ * Otherwise falls back to REST/WebSocket.
4
5
  */
5
- /** Generic fetch wrapper */
6
+ const hasIPC = typeof mailxapi !== "undefined" && mailxapi?.isApp;
7
+ // ── HTTP fallback ──
8
+ // Abort controller for message-list requests — cancel stale fetches when folder changes
9
+ let messageListAbort = null;
10
+ export function abortMessageListRequests() {
11
+ if (messageListAbort) {
12
+ messageListAbort.abort();
13
+ messageListAbort = null;
14
+ }
15
+ }
16
+ function newMessageListSignal() {
17
+ abortMessageListRequests();
18
+ messageListAbort = new AbortController();
19
+ return messageListAbort.signal;
20
+ }
6
21
  async function api(path, options) {
7
22
  const res = await fetch(`/api${path}`, {
8
23
  headers: { "Content-Type": "application/json" },
@@ -14,54 +29,111 @@ async function api(path, options) {
14
29
  }
15
30
  return res.json();
16
31
  }
17
- // ── REST Methods ──
32
+ // ── API Methods (IPC or HTTP) ──
18
33
  export function getAccounts() {
34
+ if (hasIPC)
35
+ return mailxapi.getAccounts();
19
36
  return api("/accounts");
20
37
  }
21
38
  export function getFolders(accountId) {
39
+ if (hasIPC)
40
+ return mailxapi.getFolders(accountId);
22
41
  return api(`/folders/${accountId}`);
23
42
  }
24
43
  export function getMessages(accountId, folderId, page = 1, pageSize = 50) {
25
- return api(`/messages/${accountId}/${folderId}?page=${page}&pageSize=${pageSize}`);
44
+ if (hasIPC)
45
+ return mailxapi.getMessages(accountId, folderId, page, pageSize);
46
+ const signal = newMessageListSignal();
47
+ return api(`/messages/${accountId}/${folderId}?page=${page}&pageSize=${pageSize}`, { signal });
48
+ }
49
+ export function getUnifiedInbox(page = 1, pageSize = 50) {
50
+ if (hasIPC)
51
+ return mailxapi.getUnifiedInbox(page, pageSize);
52
+ const signal = newMessageListSignal();
53
+ return api(`/messages/unified/inbox?page=${page}&pageSize=${pageSize}`, { signal });
26
54
  }
27
55
  export function searchMessages(query, page = 1, pageSize = 50) {
56
+ if (hasIPC)
57
+ return mailxapi.searchMessages(query, page, pageSize);
28
58
  return api(`/search?q=${encodeURIComponent(query)}&page=${page}&pageSize=${pageSize}`);
29
59
  }
30
- export function getUnifiedInbox(page = 1, pageSize = 50) {
31
- return api(`/messages/unified/inbox?page=${page}&pageSize=${pageSize}`);
32
- }
33
- export function getMessage(accountId, uid, allowRemote = false) {
34
- const q = allowRemote ? "?allowRemote=true" : "";
60
+ export function getMessage(accountId, uid, allowRemote = false, folderId) {
61
+ if (hasIPC)
62
+ return mailxapi.getMessage(accountId, uid, allowRemote, folderId);
63
+ const params = new URLSearchParams();
64
+ if (allowRemote)
65
+ params.set("allowRemote", "true");
66
+ if (folderId != null)
67
+ params.set("folderId", String(folderId));
68
+ const q = params.toString() ? `?${params}` : "";
35
69
  return api(`/message/${accountId}/${uid}${q}`);
36
70
  }
37
71
  export function updateFlags(accountId, uid, flags) {
72
+ if (hasIPC)
73
+ return mailxapi.updateFlags(accountId, uid, flags);
38
74
  return api(`/message/${accountId}/${uid}/flags`, {
39
75
  method: "PATCH",
40
76
  body: JSON.stringify({ flags })
41
77
  });
42
78
  }
43
79
  export function triggerSync() {
80
+ if (hasIPC)
81
+ return mailxapi.syncAll();
44
82
  return api("/sync", { method: "POST" });
45
83
  }
46
- let ws;
47
- const handlers = [];
48
- export function connectWebSocket() {
49
- const protocol = location.protocol === "https:" ? "wss:" : "ws:";
50
- ws = new WebSocket(`${protocol}//${location.host}`);
51
- ws.onmessage = (ev) => {
52
- try {
53
- const event = JSON.parse(ev.data);
54
- for (const handler of handlers)
55
- handler(event);
56
- }
57
- catch { /* ignore parse errors */ }
58
- };
59
- ws.onclose = () => {
60
- // Reconnect after 3 seconds
61
- setTimeout(connectWebSocket, 3000);
62
- };
63
- }
64
- export function onWsEvent(handler) {
65
- handlers.push(handler);
84
+ export function getVersion() {
85
+ if (hasIPC)
86
+ return mailxapi.getVersion();
87
+ return api("/version");
88
+ }
89
+ export function getSyncPending() {
90
+ if (hasIPC)
91
+ return mailxapi.getSyncPending();
92
+ return api("/sync/pending");
93
+ }
94
+ export function searchContacts(query) {
95
+ if (hasIPC)
96
+ return mailxapi.searchContacts(query);
97
+ return api(`/contacts?q=${encodeURIComponent(query)}`);
98
+ }
99
+ export function allowRemoteContent(type, value) {
100
+ if (hasIPC)
101
+ return mailxapi.allowRemoteContent(type, value);
102
+ return api("/settings/allow-remote", {
103
+ method: "POST",
104
+ body: JSON.stringify({ type, value })
105
+ });
106
+ }
107
+ const eventHandlers = [];
108
+ export function onEvent(handler) {
109
+ eventHandlers.push(handler);
110
+ }
111
+ export function connectEvents() {
112
+ if (hasIPC) {
113
+ // IPC events come via mailxapi.onEvent
114
+ mailxapi.onEvent((event) => {
115
+ for (const h of eventHandlers)
116
+ h(event);
117
+ });
118
+ }
119
+ else {
120
+ // WebSocket for HTTP mode
121
+ const protocol = location.protocol === "https:" ? "wss:" : "ws:";
122
+ const ws = new WebSocket(`${protocol}//${location.host}`);
123
+ ws.onmessage = (ev) => {
124
+ try {
125
+ const event = JSON.parse(ev.data);
126
+ for (const h of eventHandlers)
127
+ h(event);
128
+ }
129
+ catch { /* ignore */ }
130
+ };
131
+ ws.onclose = () => {
132
+ setTimeout(connectEvents, 3000);
133
+ };
134
+ }
66
135
  }
136
+ // Legacy exports for backward compatibility
137
+ export const connectWebSocket = connectEvents;
138
+ export const onWsEvent = onEvent;
67
139
  //# sourceMappingURL=api-client.js.map
@@ -0,0 +1,123 @@
1
+ /**
2
+ * mailxapi — IPC bridge injected into WebView by the Rust launcher.
3
+ * Follows the msgapi pattern: callNode → Promise → _mailxapiResolve/Reject.
4
+ *
5
+ * When running in a browser (no IPC), this file is not loaded.
6
+ * api-client.ts auto-detects and falls back to HTTP fetch.
7
+ */
8
+
9
+ (function() {
10
+ "use strict";
11
+
12
+ var _callbacks = {};
13
+ var _callbackId = 0;
14
+ var _eventHandlers = [];
15
+
16
+ function callNode(action, params) {
17
+ var id = String(++_callbackId);
18
+ return new Promise(function(resolve, reject) {
19
+ var timer = setTimeout(function() {
20
+ delete _callbacks[id];
21
+ reject(new Error("mailxapi timeout: " + action));
22
+ }, 30000);
23
+ _callbacks[id] = { resolve: resolve, reject: reject, timer: timer };
24
+ var msg = Object.assign({ _action: action, _cbid: id }, params || {});
25
+ if (window.ipc && window.ipc.postMessage) {
26
+ window.ipc.postMessage(JSON.stringify(msg));
27
+ } else {
28
+ // Fallback: should not happen in WebView
29
+ clearTimeout(timer);
30
+ delete _callbacks[id];
31
+ reject(new Error("No IPC channel available"));
32
+ }
33
+ });
34
+ }
35
+
36
+ // Called by Rust to resolve promises
37
+ window._mailxapiResolve = function(id, value) {
38
+ var cb = _callbacks[id];
39
+ if (!cb) return;
40
+ delete _callbacks[id];
41
+ clearTimeout(cb.timer);
42
+ cb.resolve(value);
43
+ };
44
+
45
+ // Called by Rust to reject promises
46
+ window._mailxapiReject = function(id, error) {
47
+ var cb = _callbacks[id];
48
+ if (!cb) return;
49
+ delete _callbacks[id];
50
+ clearTimeout(cb.timer);
51
+ cb.reject(new Error(error));
52
+ };
53
+
54
+ // Called by Rust to push events (new mail, sync progress, etc.)
55
+ window._mailxapiEvent = function(event) {
56
+ for (var i = 0; i < _eventHandlers.length; i++) {
57
+ try { _eventHandlers[i](event); } catch(e) { /* ignore */ }
58
+ }
59
+ };
60
+
61
+ window.mailxapi = {
62
+ isApp: true,
63
+ platform: "webview2",
64
+
65
+ // Accounts
66
+ getAccounts: function() { return callNode("getAccounts"); },
67
+ getFolders: function(accountId) { return callNode("getFolders", { accountId: accountId }); },
68
+
69
+ // Messages
70
+ getMessages: function(accountId, folderId, page, pageSize) {
71
+ return callNode("getMessages", { accountId: accountId, folderId: folderId, page: page, pageSize: pageSize });
72
+ },
73
+ getUnifiedInbox: function(page, pageSize) {
74
+ return callNode("getUnifiedInbox", { page: page, pageSize: pageSize });
75
+ },
76
+ getMessage: function(accountId, uid, allowRemote) {
77
+ return callNode("getMessage", { accountId: accountId, uid: uid, allowRemote: allowRemote });
78
+ },
79
+
80
+ // Actions
81
+ updateFlags: function(accountId, uid, flags) {
82
+ return callNode("updateFlags", { accountId: accountId, uid: uid, flags: flags });
83
+ },
84
+ deleteMessage: function(accountId, uid) {
85
+ return callNode("deleteMessage", { accountId: accountId, uid: uid });
86
+ },
87
+ undeleteMessage: function(accountId, uid, folderId) {
88
+ return callNode("undeleteMessage", { accountId: accountId, uid: uid, folderId: folderId });
89
+ },
90
+
91
+ // Compose
92
+ sendMessage: function(msg) { return callNode("sendMessage", msg); },
93
+ saveDraft: function(params) { return callNode("saveDraft", params); },
94
+ deleteDraft: function(accountId, draftUid) {
95
+ return callNode("deleteDraft", { accountId: accountId, draftUid: draftUid });
96
+ },
97
+
98
+ // Search
99
+ searchMessages: function(query, page, pageSize) {
100
+ return callNode("searchMessages", { query: query, page: page, pageSize: pageSize });
101
+ },
102
+ searchContacts: function(query) {
103
+ return callNode("searchContacts", { query: query });
104
+ },
105
+
106
+ // Sync
107
+ syncAll: function() { return callNode("syncAll"); },
108
+ getSyncPending: function() { return callNode("getSyncPending"); },
109
+
110
+ // Settings
111
+ allowRemoteContent: function(type, value) {
112
+ return callNode("allowRemoteContent", { type: type, value: value });
113
+ },
114
+ getSettings: function() { return callNode("getSettings"); },
115
+ saveSettings: function(data) { return callNode("saveSettingsData", data); },
116
+ getVersion: function() { return callNode("getVersion"); },
117
+
118
+ // Events
119
+ onEvent: function(handler) { _eventHandlers.push(handler); },
120
+ };
121
+
122
+ window.dispatchEvent(new CustomEvent("mailxapiready"));
123
+ })();
@@ -1,9 +1,13 @@
1
1
  {
2
2
  "name": "@bobfrankston/mailx-client",
3
- "version": "1.0.1",
3
+ "version": "1.0.7",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "dependencies": {
7
7
  "quill": "^2.0.0"
8
+ },
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "https://github.com/BobFrankston/mailx-client.git"
8
12
  }
9
13
  }
@@ -7,7 +7,7 @@
7
7
  align-items: center;
8
8
  justify-content: space-between;
9
9
  padding: 0 var(--gap-sm);
10
- background: oklch(0.82 0.06 240); /* DEBUG: light blue toolbar */
10
+ background: var(--color-brand);
11
11
  border-bottom: 1px solid var(--color-border);
12
12
  gap: var(--gap-sm);
13
13
 
@@ -26,9 +26,9 @@
26
26
  border: none;
27
27
  border-radius: var(--radius-sm);
28
28
  background: transparent;
29
- color: var(--color-text);
29
+ color: var(--color-brand-dark);
30
30
  font-size: var(--font-size-sm);
31
- font-weight: 600;
31
+ font-weight: 700;
32
32
  cursor: pointer;
33
33
  white-space: nowrap;
34
34
 
@@ -99,9 +99,9 @@
99
99
  align-items: center;
100
100
  gap: var(--gap-xs);
101
101
  padding: var(--gap-xs) var(--gap-sm);
102
- font-weight: 600;
103
- font-size: var(--font-size-sm);
104
- color: var(--color-text-muted);
102
+ font-weight: 700;
103
+ font-size: var(--font-size-base);
104
+ color: var(--color-brand-dark);
105
105
  text-transform: uppercase;
106
106
  letter-spacing: 0.05em;
107
107
  cursor: pointer;
@@ -130,7 +130,8 @@
130
130
  padding: var(--gap-xs) var(--gap-sm) var(--gap-xs) var(--gap-lg);
131
131
  cursor: pointer;
132
132
  font-size: var(--font-size-base);
133
- color: var(--color-text);
133
+ font-weight: 600;
134
+ color: var(--color-brand-dark);
134
135
  border-radius: 0;
135
136
 
136
137
  &:hover { background: var(--color-bg-hover); }
@@ -150,18 +151,57 @@
150
151
  text-align: center;
151
152
  }
152
153
 
154
+ .ft-badge-outbox {
155
+ background: oklch(0.55 0.18 25);
156
+ }
157
+
158
+ .ft-filter {
159
+ padding: 2px var(--gap-xs);
160
+ border-bottom: 1px solid var(--color-border);
161
+ background: var(--color-bg-surface);
162
+ flex-shrink: 0;
163
+ }
164
+
165
+ .ft-filter input {
166
+ width: 100%;
167
+ padding: 2px var(--gap-sm);
168
+ border: 1px solid var(--color-border);
169
+ border-radius: var(--radius-sm);
170
+ background: var(--color-bg);
171
+ color: var(--color-text);
172
+ font-size: var(--font-size-sm);
173
+ outline: none;
174
+ }
175
+
176
+ .ft-filter input:focus { border-color: var(--color-accent); }
177
+
178
+ .ft-folder.ft-filter-hidden,
179
+ .ft-account.ft-filter-hidden,
180
+ .ft-account-header.ft-filter-hidden { display: none; }
181
+
153
182
  .folder-loading {
154
183
  padding: var(--gap-lg);
155
184
  color: var(--color-text-muted);
156
185
  font-size: var(--font-size-sm);
157
186
  }
158
187
 
188
+ .ft-folder.drop-target {
189
+ background: var(--color-accent);
190
+ color: white;
191
+ outline: 2px solid var(--color-brand-dark);
192
+ outline-offset: -2px;
193
+ }
194
+
195
+ .ml-row.dragging {
196
+ opacity: 0.5;
197
+ }
198
+
159
199
  /* ── Message List ── */
160
200
 
161
201
  .message-list {
162
202
  display: grid;
163
203
  grid-template-columns: 1.2em minmax(120px, 200px) auto 1fr;
164
- grid-template-rows: auto 1fr;
204
+ grid-template-rows: auto auto 1fr;
165
205
  column-gap: var(--gap-sm);
166
206
  overflow: hidden;
167
207
  border-right: 1px solid var(--color-border);
@@ -187,6 +227,30 @@
187
227
  font-size: var(--font-size-sm);
188
228
  }
189
229
 
230
+ .ml-filter {
231
+ grid-column: 1 / -1;
232
+ padding: 2px var(--gap-xs);
233
+ border-bottom: 1px solid var(--color-border);
234
+ background: var(--color-bg-surface);
235
+ }
236
+
237
+ .ml-filter input {
238
+ width: 100%;
239
+ padding: 2px var(--gap-sm);
240
+ border: 1px solid var(--color-border);
241
+ border-radius: var(--radius-sm);
242
+ background: var(--color-bg);
243
+ color: var(--color-text);
244
+ font-size: var(--font-size-sm);
245
+ outline: none;
246
+ }
247
+
248
+ .ml-filter input:focus {
249
+ border-color: var(--color-accent);
250
+ }
251
+
252
+ .ml-row.filter-hidden { display: none; }
253
+
190
254
  .ml-header {
191
255
  display: grid;
192
256
  grid-template-columns: subgrid;
@@ -195,8 +259,8 @@
195
259
  border-bottom: 1px solid var(--color-border);
196
260
  background: var(--color-bg-toolbar);
197
261
  font-size: var(--font-size-sm);
198
- font-weight: 600;
199
- color: var(--color-text-muted);
262
+ font-weight: 700;
263
+ color: var(--color-brand-dark);
200
264
  user-select: none;
201
265
 
202
266
  .ml-col { cursor: pointer; &:hover { color: var(--color-text); } }
@@ -219,10 +283,11 @@
219
283
  border-bottom: 1px solid color-mix(in oklch, var(--color-border) 50%, transparent);
220
284
  cursor: pointer;
221
285
  font-size: var(--font-size-base);
286
+ color: var(--color-text);
222
287
  align-items: baseline;
223
288
 
224
289
  &:hover { background: var(--color-bg-hover); }
225
- &.selected { background: var(--color-bg-selected); color: var(--color-unread); }
290
+ &.selected { background: var(--color-brand); color: var(--color-brand-dark); font-weight: 600; }
226
291
  &.unread {
227
292
  font-weight: 600;
228
293
  color: var(--color-unread);
@@ -282,21 +347,91 @@
282
347
  font-size: var(--font-size-sm);
283
348
  line-height: 1.5;
284
349
 
350
+ .mv-header-top { display: flex; justify-content: space-between; align-items: flex-start; gap: var(--gap-sm); }
351
+ .mv-header-info { flex: 1; min-width: 0; }
352
+ .mv-header-actions { display: flex; align-items: center; gap: var(--gap-xs); flex-shrink: 0; }
285
353
  .mv-from { font-weight: 600; }
286
354
  .mv-to { color: var(--color-text-muted); }
287
355
  .mv-subject { font-size: var(--font-size-lg); font-weight: 600; margin-top: var(--gap-xs); }
288
356
  .mv-date { color: var(--color-text-muted); font-size: var(--font-size-sm); }
357
+ .mv-unsubscribe {
358
+ font-size: var(--font-size-sm);
359
+ color: var(--color-danger);
360
+ cursor: pointer;
361
+ text-decoration: underline;
362
+ white-space: nowrap;
363
+ }
364
+ .mv-action {
365
+ font-size: var(--font-size-sm);
366
+ padding: 2px 6px;
367
+ border: 1px solid var(--color-border);
368
+ border-radius: var(--radius-sm);
369
+ background: transparent;
370
+ color: var(--color-text-muted);
371
+ cursor: pointer;
372
+ white-space: nowrap;
373
+ }
374
+ .mv-action:hover { background: var(--color-bg-hover); color: var(--color-text); }
375
+ .mv-action-primary {
376
+ background: var(--color-brand-dark) !important;
377
+ color: white !important;
378
+ border-color: var(--color-brand-dark) !important;
379
+ }
380
+ .mv-action-primary:hover { opacity: 0.85; }
289
381
  }
290
382
 
291
383
  .mv-remote-banner {
384
+ background: oklch(0.45 0.12 60);
385
+ color: white;
386
+ font-size: var(--font-size-sm);
387
+ font-weight: 600;
388
+ }
389
+
390
+ .mv-rb-summary {
292
391
  display: flex;
293
392
  align-items: center;
294
393
  gap: var(--gap-sm);
295
394
  padding: var(--gap-xs) var(--gap-md);
296
- background: oklch(0.45 0.12 60);
297
- color: white;
298
- font-size: var(--font-size-sm);
395
+ cursor: pointer;
396
+ flex-wrap: wrap;
397
+ }
398
+
399
+ .mv-rb-toggle {
400
+ font-size: 0.8em;
401
+ width: 1em;
402
+ display: inline-block;
403
+ flex-shrink: 0;
404
+ }
405
+
406
+ .mv-rb-buttons {
407
+ display: flex;
408
+ flex-wrap: wrap;
409
+ gap: var(--gap-xs);
410
+ margin-left: auto;
411
+ }
412
+
413
+ .mv-rb-details {
414
+ padding: var(--gap-xs) var(--gap-md) var(--gap-sm);
415
+ border-top: 1px solid rgba(255,255,255,0.2);
416
+ }
417
+
418
+ .mv-rb-info {
419
+ font-weight: 400;
420
+ line-height: 1.6;
421
+ margin-bottom: var(--gap-sm);
422
+ }
423
+
424
+ .mv-rb-actions {
425
+ display: flex;
426
+ flex-wrap: wrap;
427
+ gap: var(--gap-xs);
428
+ }
429
+
430
+ .mv-rb-label {
431
+ color: rgba(255,255,255,0.7);
299
432
  font-weight: 600;
433
+ display: inline-block;
434
+ min-width: 6em;
300
435
  }
301
436
 
302
437
  .mv-remote-banner button {
@@ -307,6 +442,7 @@
307
442
  color: white;
308
443
  font-size: var(--font-size-sm);
309
444
  cursor: pointer;
445
+ font-weight: 600;
310
446
  }
311
447
 
312
448
  .mv-remote-banner button:hover {
@@ -315,7 +451,7 @@
315
451
 
316
452
  .mv-body {
317
453
  flex: 1;
318
- overflow-y: auto;
454
+ overflow: hidden;
319
455
  background: var(--color-bg-surface);
320
456
 
321
457
  iframe {
@@ -359,3 +495,40 @@
359
495
  font-size: var(--font-size-sm);
360
496
  color: var(--color-text-muted);
361
497
  }
498
+
499
+ /* ── Startup Overlay ── */
500
+
501
+ .startup-overlay {
502
+ position: fixed;
503
+ inset: var(--toolbar-height) 0 var(--statusbar-height) 0;
504
+ display: flex;
505
+ align-items: center;
506
+ justify-content: center;
507
+ background: var(--color-bg);
508
+ z-index: 100;
509
+ transition: opacity 0.3s ease;
510
+ }
511
+
512
+ .startup-overlay.hidden {
513
+ opacity: 0;
514
+ pointer-events: none;
515
+ }
516
+
517
+ .startup-content {
518
+ text-align: center;
519
+ color: var(--color-text);
520
+ }
521
+
522
+ .startup-spinner {
523
+ width: 32px;
524
+ height: 32px;
525
+ margin: 0 auto var(--gap-md);
526
+ border: 3px solid var(--color-border);
527
+ border-top-color: var(--color-brand-dark);
528
+ border-radius: 50%;
529
+ animation: spin 1s linear infinite;
530
+ }
531
+
532
+ #startup-status {
533
+ font-size: var(--font-size-lg);
534
+ }
@@ -24,7 +24,8 @@ body {
24
24
  }
25
25
 
26
26
  .toolbar { grid-area: toolbar; }
27
- .folder-tree { grid-area: folders; }
27
+ .folder-panel { grid-area: folders; display: flex; flex-direction: column; overflow: hidden; }
28
+ .folder-tree { flex: 1; overflow-y: auto; }
28
29
  .main-area { grid-area: main; }
29
30
  .status-bar { grid-area: status; }
30
31