@rapidmx/web-client 0.14.1 → 0.16.0

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 (314) hide show
  1. package/README.md +373 -373
  2. package/apps/admin/branding/index.tsx +39 -39
  3. package/apps/admin/data-requests/index.tsx +482 -480
  4. package/apps/admin/domains/[uid].tsx +164 -163
  5. package/apps/admin/escrow-scopes/[uid].tsx +348 -348
  6. package/apps/admin/index.tsx +127 -124
  7. package/apps/admin/mailboxes/[uid].tsx +269 -224
  8. package/apps/admin/mailboxes/new/index.tsx +28 -28
  9. package/apps/admin/plugins/index.tsx +15 -15
  10. package/apps/admin/retention-policy/index.tsx +39 -39
  11. package/apps/admin/signing-certificates/index.tsx +343 -343
  12. package/apps/escrow/audit-log/index.tsx +196 -196
  13. package/apps/escrow/matters/[uid].tsx +621 -621
  14. package/apps/shared/appearance/AppearanceForm.tsx +9 -1
  15. package/apps/shared/auth/adminAccess.ts +99 -99
  16. package/apps/shared/calendar/bookingPlugin.ts +100 -0
  17. package/apps/shared/calendar/calendarLiveUpdates.ts +27 -0
  18. package/apps/shared/components/admin/layout/AdminShell.tsx +378 -346
  19. package/apps/shared/components/admin/mailboxes/EraseLeftoverDataDialog.tsx +238 -0
  20. package/apps/shared/components/admin/mailboxes/EscrowScopeCard.tsx +152 -152
  21. package/apps/shared/components/admin/mailboxes/LeftoverMailboxesSection.tsx +194 -0
  22. package/apps/shared/components/admin/settings/BrandingForm.tsx +423 -423
  23. package/apps/shared/components/admin/settings/EncryptionPolicyForm.tsx +119 -119
  24. package/apps/shared/components/admin/settings/MailboxCreateForm.tsx +53 -4
  25. package/apps/shared/components/admin/settings/MailboxPolicyForm.tsx +198 -198
  26. package/apps/shared/components/admin/settings/PluginsManager.tsx +64 -10
  27. package/apps/shared/components/admin/settings/RetentionPolicyForm.tsx +182 -182
  28. package/apps/shared/components/admin/setup/EscrowSetupStep.tsx +288 -288
  29. package/apps/shared/components/admin/setup/SetupWizard.tsx +444 -444
  30. package/apps/shared/components/admin/usePagedList.tsx +129 -129
  31. package/apps/shared/components/calendar/AppointmentQuickForm.tsx +327 -0
  32. package/apps/shared/components/calendar/DescriptionEditor.tsx +274 -0
  33. package/apps/shared/components/calendar/EventDescriptionView.tsx +70 -0
  34. package/apps/shared/components/calendar/EventDetails.tsx +401 -0
  35. package/apps/shared/components/calendar/EventEditor.tsx +635 -0
  36. package/apps/shared/components/calendar/EventExpandedForm.tsx +210 -0
  37. package/apps/shared/components/calendar/EventFormParts.tsx +591 -0
  38. package/apps/shared/components/calendar/EventModal.tsx +206 -946
  39. package/apps/shared/components/calendar/EventQuickForm.tsx +116 -0
  40. package/apps/shared/components/calendar/EventShell.tsx +202 -0
  41. package/apps/shared/components/calendar/FindATime.tsx +379 -0
  42. package/apps/shared/components/calendar/GuestInput.tsx +100 -0
  43. package/apps/shared/components/calendar/LazyDescriptionEditor.tsx +70 -0
  44. package/apps/shared/components/calendar/MonthView.tsx +185 -173
  45. package/apps/shared/components/calendar/QuickCreateFaces.tsx +87 -0
  46. package/apps/shared/components/calendar/QuickCreateTabs.tsx +81 -0
  47. package/apps/shared/components/calendar/QuickFaceFrame.tsx +81 -0
  48. package/apps/shared/components/calendar/RecurrenceEditor.tsx +227 -222
  49. package/apps/shared/components/calendar/RequestChangeForm.tsx +240 -0
  50. package/apps/shared/components/calendar/SplitDayView.tsx +144 -143
  51. package/apps/shared/components/calendar/TaskQuickForm.tsx +289 -0
  52. package/apps/shared/components/calendar/TimeGridView.tsx +246 -244
  53. package/apps/shared/components/calendar/allDay.ts +124 -124
  54. package/apps/shared/components/calendar/eventDialogFields.ts +86 -0
  55. package/apps/shared/components/calendar/eventForm.ts +108 -0
  56. package/apps/shared/components/calendar/eventFormat.ts +210 -0
  57. package/apps/shared/components/calendar/findTimeGrid.ts +90 -0
  58. package/apps/shared/components/calendar/layout/CalendarShell.tsx +201 -200
  59. package/apps/shared/components/calendar/swipeNavigation.ts +14 -0
  60. package/apps/shared/components/contacts/ContactForm.tsx +383 -383
  61. package/apps/shared/components/contacts/ContactsSidebar.tsx +1 -1
  62. package/apps/shared/components/contacts/ContactsToolbar.tsx +103 -98
  63. package/apps/shared/components/contacts/layout/ContactsShell.tsx +217 -216
  64. package/apps/shared/components/escrow/layout/EscrowShell.tsx +155 -155
  65. package/apps/shared/components/layout/AppShell.tsx +480 -480
  66. package/apps/shared/components/layout/FloatingActionButton.tsx +31 -0
  67. package/apps/shared/components/layout/KeyEnrollmentGate.tsx +398 -398
  68. package/apps/shared/components/layout/MailboxProvisioning.tsx +168 -168
  69. package/apps/shared/components/layout/ResponsiveToolbar.tsx +315 -315
  70. package/apps/shared/components/layout/ThemeSwitch.tsx +84 -84
  71. package/apps/shared/components/layout/UserMenu.tsx +439 -372
  72. package/apps/shared/components/mail/ConversationList.tsx +323 -271
  73. package/apps/shared/components/mail/ConversationThreadPane.tsx +130 -5
  74. package/apps/shared/components/mail/InviteCard.tsx +387 -0
  75. package/apps/shared/components/mail/MailSelectionBar.tsx +236 -227
  76. package/apps/shared/components/mail/MessageDetailPane.tsx +1559 -1537
  77. package/apps/shared/components/mail/SwipeRow.tsx +120 -0
  78. package/apps/shared/components/mail/compose/ComposeContext.tsx +312 -312
  79. package/apps/shared/components/mail/compose/ComposeToolbar.tsx +422 -422
  80. package/apps/shared/components/mail/compose/ComposeWindow.tsx +1681 -1673
  81. package/apps/shared/components/mail/compose/RecipientInput.tsx +54 -11
  82. package/apps/shared/components/mail/compose/RichTextEditor.tsx +147 -147
  83. package/apps/shared/components/mail/compose/composeFlushRegistry.ts +60 -60
  84. package/apps/shared/components/mail/compose/quotedBody.ts +161 -161
  85. package/apps/shared/components/mail/invite/InviteRowChip.tsx +104 -0
  86. package/apps/shared/components/mail/invite/InviteRsvpPopover.tsx +271 -0
  87. package/apps/shared/components/mail/invite/InviteTimeline.tsx +200 -0
  88. package/apps/shared/components/mail/invite/ProposeTimeForm.tsx +109 -0
  89. package/apps/shared/components/mail/invite/inviteFormat.ts +110 -0
  90. package/apps/shared/components/mail/invite/inviteStore.ts +114 -0
  91. package/apps/shared/components/mail/layout/FolderBadgeChip.tsx +21 -0
  92. package/apps/shared/components/mail/layout/MailShell.tsx +546 -490
  93. package/apps/shared/components/mail/layout/SidebarSection.tsx +66 -0
  94. package/apps/shared/components/mail/reading/PendingMessageCard.tsx +68 -0
  95. package/apps/shared/components/mail/verificationSeals.ts +125 -125
  96. package/apps/shared/components/rules/RuleBuilder.tsx +311 -311
  97. package/apps/shared/components/settings/SigningCertificateCard.tsx +344 -344
  98. package/apps/shared/components/settings/layout/SettingsShell.tsx +255 -253
  99. package/apps/shared/components/tasks/TasksSidebar.tsx +1 -1
  100. package/apps/shared/components/tasks/layout/TasksShell.tsx +218 -217
  101. package/apps/shared/gestures/useEnterSlide.ts +54 -0
  102. package/apps/shared/gestures/useSwipe.ts +114 -0
  103. package/apps/shared/gestures/useSwipeSlide.ts +113 -0
  104. package/apps/shared/gestures/useWheelPaging.ts +107 -0
  105. package/apps/shared/keyboard/GlobalShortcuts.tsx +51 -51
  106. package/apps/shared/keyboard/ShortcutProvider.tsx +62 -62
  107. package/apps/shared/keyboard/ShortcutsDialog.tsx +84 -84
  108. package/apps/shared/keyboard/dispatch.ts +124 -124
  109. package/apps/shared/keyboard/format.ts +89 -89
  110. package/apps/shared/keyboard/keymap.ts +114 -114
  111. package/apps/shared/keyboard/registry.ts +65 -65
  112. package/apps/shared/keyboard/targets.ts +79 -79
  113. package/apps/shared/mail/folderCounts.ts +17 -0
  114. package/apps/shared/mail/folderTree.ts +143 -143
  115. package/apps/shared/mail/listAllPages.ts +39 -39
  116. package/apps/shared/mail/newMailNotifications.ts +3 -15
  117. package/apps/shared/mail/outbox/outgoingReplies.ts +192 -0
  118. package/apps/shared/mail/outbox/sendJob.ts +19 -1
  119. package/apps/shared/mail/outbox/sendOutcomes.ts +13 -4
  120. package/apps/shared/mail/primaryMailbox.ts +71 -0
  121. package/apps/shared/mail/useCollapsedSections.ts +146 -0
  122. package/apps/shared/mail/useMailConnection.ts +205 -203
  123. package/apps/shared/mail/useMailLiveUpdates.ts +277 -277
  124. package/apps/shared/mail/useMarkMessageRead.ts +47 -47
  125. package/apps/shared/mail/useNewMailNotifications.ts +2 -2
  126. package/apps/shared/navigation/AppRouter.tsx +300 -300
  127. package/apps/shared/navigation/routerContext.tsx +83 -83
  128. package/apps/shared/notifications/preferences.ts +36 -0
  129. package/apps/shared/notifications/store.ts +9 -0
  130. package/apps/shared/search/LocalIndexLifecycle.tsx +114 -114
  131. package/apps/shared/search/crossMailboxSearch.ts +169 -0
  132. package/apps/shared/search/localIndexBuilder.ts +481 -481
  133. package/apps/shared/signing/enrollmentStorage.ts +33 -33
  134. package/apps/shared/signing/enrollmentTracker.ts +385 -385
  135. package/apps/shared/signing/enrollmentView.ts +251 -251
  136. package/apps/shared/signing/useNow.ts +19 -19
  137. package/apps/shared/signing/useSigningEnrollmentWatcher.ts +90 -90
  138. package/apps/shared/styles/app.css +396 -386
  139. package/apps/www/_routes.ts +1 -0
  140. package/apps/www/calendar/index.tsx +578 -469
  141. package/apps/www/contacts/[uid].tsx +109 -109
  142. package/apps/www/contacts/index.tsx +6 -0
  143. package/apps/www/index.tsx +2847 -2332
  144. package/apps/www/messages/[uid].tsx +135 -108
  145. package/apps/www/settings/auto-reply/index.tsx +133 -133
  146. package/apps/www/settings/encryption/index.tsx +1287 -1287
  147. package/apps/www/settings/filters/[uid].tsx +176 -176
  148. package/apps/www/settings/filters/index.tsx +102 -102
  149. package/apps/www/settings/filters/new/index.tsx +140 -140
  150. package/apps/www/settings/labels/index.tsx +204 -204
  151. package/apps/www/settings/privacy/index.tsx +492 -492
  152. package/apps/www/settings/profile/index.tsx +248 -0
  153. package/apps/www/settings/read-receipts/index.tsx +147 -147
  154. package/apps/www/settings/sharing/index.tsx +256 -256
  155. package/apps/www/settings/signatures/[uid].tsx +172 -172
  156. package/apps/www/settings/signatures/index.tsx +88 -88
  157. package/apps/www/settings/signatures/new/index.tsx +135 -135
  158. package/apps/www/tasks/index.tsx +649 -649
  159. package/dist/apps/admin/data-requests/index.js +1 -1
  160. package/dist/apps/admin/domains/[uid].js +4 -2
  161. package/dist/apps/admin/index.js +2 -1
  162. package/dist/apps/admin/mailboxes/[uid].js +12 -2
  163. package/dist/apps/shared/appearance/AppearanceForm.js +9 -1
  164. package/dist/apps/shared/calendar/bookingPlugin.d.ts +50 -0
  165. package/dist/apps/shared/calendar/bookingPlugin.js +57 -0
  166. package/dist/apps/shared/calendar/calendarLiveUpdates.d.ts +11 -0
  167. package/dist/apps/shared/calendar/calendarLiveUpdates.js +23 -0
  168. package/dist/apps/shared/components/admin/layout/AdminShell.d.ts +1 -1
  169. package/dist/apps/shared/components/admin/layout/AdminShell.js +7 -3
  170. package/dist/apps/shared/components/admin/mailboxes/EraseLeftoverDataDialog.d.ts +35 -0
  171. package/dist/apps/shared/components/admin/mailboxes/EraseLeftoverDataDialog.js +115 -0
  172. package/dist/apps/shared/components/admin/mailboxes/LeftoverMailboxesSection.d.ts +16 -0
  173. package/dist/apps/shared/components/admin/mailboxes/LeftoverMailboxesSection.js +92 -0
  174. package/dist/apps/shared/components/admin/settings/BrandingForm.js +3 -3
  175. package/dist/apps/shared/components/admin/settings/MailboxCreateForm.js +28 -4
  176. package/dist/apps/shared/components/admin/settings/PluginsManager.js +40 -6
  177. package/dist/apps/shared/components/calendar/AppointmentQuickForm.d.ts +47 -0
  178. package/dist/apps/shared/components/calendar/AppointmentQuickForm.js +135 -0
  179. package/dist/apps/shared/components/calendar/DescriptionEditor.d.ts +26 -0
  180. package/dist/apps/shared/components/calendar/DescriptionEditor.js +192 -0
  181. package/dist/apps/shared/components/calendar/EventDescriptionView.d.ts +14 -0
  182. package/dist/apps/shared/components/calendar/EventDescriptionView.js +39 -0
  183. package/dist/apps/shared/components/calendar/EventDetails.d.ts +33 -0
  184. package/dist/apps/shared/components/calendar/EventDetails.js +137 -0
  185. package/dist/apps/shared/components/calendar/EventEditor.d.ts +59 -0
  186. package/dist/apps/shared/components/calendar/EventEditor.js +544 -0
  187. package/dist/apps/shared/components/calendar/EventExpandedForm.d.ts +14 -0
  188. package/dist/apps/shared/components/calendar/EventExpandedForm.js +44 -0
  189. package/dist/apps/shared/components/calendar/EventFormParts.d.ts +70 -0
  190. package/dist/apps/shared/components/calendar/EventFormParts.js +191 -0
  191. package/dist/apps/shared/components/calendar/EventModal.d.ts +26 -13
  192. package/dist/apps/shared/components/calendar/EventModal.js +57 -459
  193. package/dist/apps/shared/components/calendar/EventQuickForm.d.ts +18 -0
  194. package/dist/apps/shared/components/calendar/EventQuickForm.js +25 -0
  195. package/dist/apps/shared/components/calendar/EventShell.d.ts +64 -0
  196. package/dist/apps/shared/components/calendar/EventShell.js +134 -0
  197. package/dist/apps/shared/components/calendar/FindATime.d.ts +18 -0
  198. package/dist/apps/shared/components/calendar/FindATime.js +190 -0
  199. package/dist/apps/shared/components/calendar/GuestInput.d.ts +45 -0
  200. package/dist/apps/shared/components/calendar/GuestInput.js +30 -0
  201. package/dist/apps/shared/components/calendar/LazyDescriptionEditor.d.ts +8 -0
  202. package/dist/apps/shared/components/calendar/LazyDescriptionEditor.js +44 -0
  203. package/dist/apps/shared/components/calendar/MonthView.d.ts +5 -1
  204. package/dist/apps/shared/components/calendar/MonthView.js +11 -5
  205. package/dist/apps/shared/components/calendar/QuickCreateFaces.d.ts +30 -0
  206. package/dist/apps/shared/components/calendar/QuickCreateFaces.js +44 -0
  207. package/dist/apps/shared/components/calendar/QuickCreateTabs.d.ts +24 -0
  208. package/dist/apps/shared/components/calendar/QuickCreateTabs.js +46 -0
  209. package/dist/apps/shared/components/calendar/QuickFaceFrame.d.ts +25 -0
  210. package/dist/apps/shared/components/calendar/QuickFaceFrame.js +19 -0
  211. package/dist/apps/shared/components/calendar/RecurrenceEditor.d.ts +4 -1
  212. package/dist/apps/shared/components/calendar/RecurrenceEditor.js +2 -2
  213. package/dist/apps/shared/components/calendar/RequestChangeForm.d.ts +36 -0
  214. package/dist/apps/shared/components/calendar/RequestChangeForm.js +127 -0
  215. package/dist/apps/shared/components/calendar/SplitDayView.d.ts +3 -2
  216. package/dist/apps/shared/components/calendar/SplitDayView.js +3 -2
  217. package/dist/apps/shared/components/calendar/TaskQuickForm.d.ts +40 -0
  218. package/dist/apps/shared/components/calendar/TaskQuickForm.js +101 -0
  219. package/dist/apps/shared/components/calendar/TimeGridView.d.ts +4 -2
  220. package/dist/apps/shared/components/calendar/TimeGridView.js +3 -2
  221. package/dist/apps/shared/components/calendar/eventDialogFields.d.ts +28 -0
  222. package/dist/apps/shared/components/calendar/eventDialogFields.js +59 -0
  223. package/dist/apps/shared/components/calendar/eventForm.d.ts +98 -0
  224. package/dist/apps/shared/components/calendar/eventForm.js +1 -0
  225. package/dist/apps/shared/components/calendar/eventFormat.d.ts +80 -0
  226. package/dist/apps/shared/components/calendar/eventFormat.js +190 -0
  227. package/dist/apps/shared/components/calendar/findTimeGrid.d.ts +30 -0
  228. package/dist/apps/shared/components/calendar/findTimeGrid.js +83 -0
  229. package/dist/apps/shared/components/calendar/layout/CalendarShell.js +3 -2
  230. package/dist/apps/shared/components/calendar/swipeNavigation.d.ts +9 -0
  231. package/dist/apps/shared/components/calendar/swipeNavigation.js +8 -0
  232. package/dist/apps/shared/components/contacts/ContactsSidebar.js +1 -1
  233. package/dist/apps/shared/components/contacts/ContactsToolbar.d.ts +3 -1
  234. package/dist/apps/shared/components/contacts/ContactsToolbar.js +4 -2
  235. package/dist/apps/shared/components/contacts/layout/ContactsShell.js +4 -3
  236. package/dist/apps/shared/components/layout/FloatingActionButton.d.ts +13 -0
  237. package/dist/apps/shared/components/layout/FloatingActionButton.js +9 -0
  238. package/dist/apps/shared/components/layout/UserMenu.d.ts +14 -9
  239. package/dist/apps/shared/components/layout/UserMenu.js +74 -26
  240. package/dist/apps/shared/components/mail/ConversationList.d.ts +12 -1
  241. package/dist/apps/shared/components/mail/ConversationList.js +21 -4
  242. package/dist/apps/shared/components/mail/ConversationThreadPane.d.ts +4 -1
  243. package/dist/apps/shared/components/mail/ConversationThreadPane.js +127 -22
  244. package/dist/apps/shared/components/mail/InviteCard.d.ts +20 -0
  245. package/dist/apps/shared/components/mail/InviteCard.js +150 -0
  246. package/dist/apps/shared/components/mail/MailSelectionBar.d.ts +6 -1
  247. package/dist/apps/shared/components/mail/MailSelectionBar.js +3 -3
  248. package/dist/apps/shared/components/mail/MessageDetailPane.js +13 -2
  249. package/dist/apps/shared/components/mail/SwipeRow.d.ts +22 -0
  250. package/dist/apps/shared/components/mail/SwipeRow.js +71 -0
  251. package/dist/apps/shared/components/mail/compose/ComposeWindow.js +16 -7
  252. package/dist/apps/shared/components/mail/compose/RecipientInput.d.ts +21 -1
  253. package/dist/apps/shared/components/mail/compose/RecipientInput.js +18 -10
  254. package/dist/apps/shared/components/mail/invite/InviteRowChip.d.ts +23 -0
  255. package/dist/apps/shared/components/mail/invite/InviteRowChip.js +46 -0
  256. package/dist/apps/shared/components/mail/invite/InviteRsvpPopover.d.ts +20 -0
  257. package/dist/apps/shared/components/mail/invite/InviteRsvpPopover.js +141 -0
  258. package/dist/apps/shared/components/mail/invite/InviteTimeline.d.ts +27 -0
  259. package/dist/apps/shared/components/mail/invite/InviteTimeline.js +120 -0
  260. package/dist/apps/shared/components/mail/invite/ProposeTimeForm.d.ts +17 -0
  261. package/dist/apps/shared/components/mail/invite/ProposeTimeForm.js +45 -0
  262. package/dist/apps/shared/components/mail/invite/inviteFormat.d.ts +28 -0
  263. package/dist/apps/shared/components/mail/invite/inviteFormat.js +94 -0
  264. package/dist/apps/shared/components/mail/invite/inviteStore.d.ts +28 -0
  265. package/dist/apps/shared/components/mail/invite/inviteStore.js +95 -0
  266. package/dist/apps/shared/components/mail/layout/FolderBadgeChip.d.ts +6 -0
  267. package/dist/apps/shared/components/mail/layout/FolderBadgeChip.js +9 -0
  268. package/dist/apps/shared/components/mail/layout/MailShell.d.ts +10 -0
  269. package/dist/apps/shared/components/mail/layout/MailShell.js +76 -46
  270. package/dist/apps/shared/components/mail/layout/SidebarSection.d.ts +23 -0
  271. package/dist/apps/shared/components/mail/layout/SidebarSection.js +16 -0
  272. package/dist/apps/shared/components/mail/reading/PendingMessageCard.d.ts +14 -0
  273. package/dist/apps/shared/components/mail/reading/PendingMessageCard.js +16 -0
  274. package/dist/apps/shared/components/settings/layout/SettingsShell.js +7 -5
  275. package/dist/apps/shared/components/tasks/TasksSidebar.js +1 -1
  276. package/dist/apps/shared/components/tasks/layout/TasksShell.js +4 -3
  277. package/dist/apps/shared/gestures/useEnterSlide.d.ts +14 -0
  278. package/dist/apps/shared/gestures/useEnterSlide.js +47 -0
  279. package/dist/apps/shared/gestures/useSwipe.d.ts +45 -0
  280. package/dist/apps/shared/gestures/useSwipe.js +90 -0
  281. package/dist/apps/shared/gestures/useSwipeSlide.d.ts +40 -0
  282. package/dist/apps/shared/gestures/useSwipeSlide.js +95 -0
  283. package/dist/apps/shared/gestures/useWheelPaging.d.ts +32 -0
  284. package/dist/apps/shared/gestures/useWheelPaging.js +85 -0
  285. package/dist/apps/shared/mail/folderCounts.d.ts +10 -0
  286. package/dist/apps/shared/mail/folderCounts.js +12 -0
  287. package/dist/apps/shared/mail/newMailNotifications.d.ts +3 -8
  288. package/dist/apps/shared/mail/newMailNotifications.js +3 -12
  289. package/dist/apps/shared/mail/outbox/outgoingReplies.d.ts +80 -0
  290. package/dist/apps/shared/mail/outbox/outgoingReplies.js +131 -0
  291. package/dist/apps/shared/mail/outbox/sendJob.d.ts +5 -1
  292. package/dist/apps/shared/mail/outbox/sendJob.js +14 -1
  293. package/dist/apps/shared/mail/outbox/sendOutcomes.js +13 -4
  294. package/dist/apps/shared/mail/primaryMailbox.d.ts +29 -0
  295. package/dist/apps/shared/mail/primaryMailbox.js +61 -0
  296. package/dist/apps/shared/mail/useCollapsedSections.d.ts +32 -0
  297. package/dist/apps/shared/mail/useCollapsedSections.js +110 -0
  298. package/dist/apps/shared/mail/useMailConnection.js +3 -1
  299. package/dist/apps/shared/mail/useNewMailNotifications.js +3 -2
  300. package/dist/apps/shared/notifications/preferences.d.ts +13 -0
  301. package/dist/apps/shared/notifications/preferences.js +36 -0
  302. package/dist/apps/shared/notifications/store.d.ts +1 -0
  303. package/dist/apps/shared/notifications/store.js +7 -23
  304. package/dist/apps/shared/search/crossMailboxSearch.d.ts +72 -0
  305. package/dist/apps/shared/search/crossMailboxSearch.js +136 -0
  306. package/dist/apps/shared/styles/app.css +396 -386
  307. package/dist/apps/www/_routes.js +1 -0
  308. package/dist/apps/www/calendar/index.js +78 -7
  309. package/dist/apps/www/contacts/index.js +3 -1
  310. package/dist/apps/www/index.js +548 -210
  311. package/dist/apps/www/messages/[uid].js +13 -5
  312. package/dist/apps/www/settings/profile/index.d.ts +4 -0
  313. package/dist/apps/www/settings/profile/index.js +124 -0
  314. package/package.json +2 -2
@@ -1,253 +1,255 @@
1
- ///////////////////////////////////////////////////////////////////////////////
2
- // Copyright (C) 2026 Jean-Philippe Steinmetz
3
- // SPDX-License-Identifier: MPL-2.0
4
- ///////////////////////////////////////////////////////////////////////////////
5
- import React, { createContext, PropsWithChildren, ReactNode, useContext, useEffect, useMemo, useState } from "react";
6
- import { HiOutlineBars3 } from "react-icons/hi2";
7
- import { ApiRequestError } from "@rapidmx/react-shared/util/api.js";
8
- import Drawer from "@rapidmx/react-shared/components/overlays/Drawer.js";
9
- import { Mailbox, listMailboxes } from "@rapidmx/react-shared/mail/mailApi.js";
10
- import Alert from "@rapidmx/react-shared/components/feedback/Alert.js";
11
- import Skeleton, { SkeletonList } from "@rapidmx/react-shared/components/feedback/Skeleton.js";
12
- import AppShell, { AppShellProps } from "../../layout/AppShell.js";
13
- import { useLocationSearch, useNavigate } from "../../../navigation/AppRouter.js";
14
- import MailboxProvisioning from "../../layout/MailboxProvisioning.js";
15
- import { mergePluginNavItems, PluginNav } from "../../../plugins/pluginNav.js";
16
-
17
- export interface SettingsSectionDef {
18
- id: string;
19
- href: string;
20
- label: string;
21
- }
22
-
23
- /** Every settings section with its own sidebar entry. */
24
- export const SETTINGS_SECTIONS: SettingsSectionDef[] = [
25
- { id: "appearance", href: "/settings/appearance", label: "Appearance" },
26
- { id: "auto-reply", href: "/settings/auto-reply", label: "Automatic Replies" },
27
- { id: "filters", href: "/settings/filters", label: "Mail Filters" },
28
- { id: "signatures", href: "/settings/signatures", label: "Signatures" },
29
- { id: "labels", href: "/settings/labels", label: "Labels" },
30
- { id: "read-receipts", href: "/settings/read-receipts", label: "Read Receipts" },
31
- { id: "encryption", href: "/settings/encryption", label: "Encryption" },
32
- { id: "sharing", href: "/settings/sharing", label: "Sharing" },
33
- { id: "privacy", href: "/settings/privacy", label: "Privacy & Data" },
34
- ];
35
-
36
- /** A `SETTINGS_SECTIONS` id, or a plugin's `settingsSections` item id (see `PluginNav`). */
37
- export type SettingsSectionId = string;
38
-
39
- /** `SETTINGS_SECTIONS` followed by the plugins' `settingsSections` items, core ids winning - see
40
- * `mergePluginNavItems`. */
41
- export function settingsSections(pluginNav?: PluginNav): SettingsSectionDef[] {
42
- return mergePluginNavItems<SettingsSectionDef>(SETTINGS_SECTIONS, pluginNav?.settingsSections, ({ id, href, label }) => ({
43
- id,
44
- href,
45
- label,
46
- }));
47
- }
48
-
49
- export interface SettingsShellProps extends Omit<AppShellProps, "active"> {
50
- /** Which entry in `SETTINGS_SECTIONS` (or plugin `settingsSections` item) is highlighted in this shell's own sidebar — distinct from
51
- * `AppShell`'s own `active` (always hardcoded to `"settings"` below), since Settings isn't a rail
52
- * icon (see `AppShell.tsx`'s `AppShellApp` doc comment) but still needs its own section
53
- * highlighting. Each settings page passes its own section id explicitly, the same "gotcha" this
54
- * plan already calls out for every shell's `active` prop. */
55
- active: SettingsSectionId;
56
- }
57
-
58
- export interface SettingsShellContextValue {
59
- /** The mailbox currently selected (`?mailboxUid=`, or the caller's first accessible mailbox) —
60
- * every settings section so far (Automatic Replies) edits mailbox-scoped fields. */
61
- mailboxUid?: string;
62
- mailboxes: Mailbox[];
63
- }
64
-
65
- const SettingsShellContext = createContext<SettingsShellContextValue>({ mailboxes: [] });
66
-
67
- /** Reads the mailbox Settings is currently scoped to, as resolved by the enclosing `SettingsShell`. */
68
- export function useSettingsShell(): SettingsShellContextValue {
69
- return useContext(SettingsShellContext);
70
- }
71
-
72
- type Status = "checking" | "error" | "ready";
73
-
74
- /**
75
- * The Settings area's shell — reached via a `UserMenu` entry rather than a 5th `AppShell` icon (per
76
- * this plan's own confirmed decision), so it always passes `active="settings"` to `AppShell` regardless
77
- * of which section is showing. Unlike `ContactsShell`/`TasksShell` (whose sidebar is just a mailbox
78
- * switcher, since each has exactly one well-known folder), this shell's sidebar is a real list of
79
- * settings sections (`SETTINGS_SECTIONS`) — full-page navigation between them, same as the top-level
80
- * app rail, since this framework has no client-side router.
81
- */
82
- export default function SettingsShell({
83
- active,
84
- userUid,
85
- authServerUrl,
86
- impersonating,
87
- impersonationBaseUrl,
88
- trusted,
89
- trustedRoles,
90
- pluginNav,
91
- children,
92
- }: PropsWithChildren<SettingsShellProps>) {
93
- const [status, setStatus] = useState<Status>("checking");
94
- const [error, setError] = useState<string | null>(null);
95
- const [mailboxes, setMailboxes] = useState<Mailbox[]>([]);
96
- const [requestedMailboxUid, setRequestedMailboxUid] = useState<string | null>(null);
97
- const [drawerOpen, setDrawerOpen] = useState(false);
98
-
99
- // Read from the router's location, so a mailbox change (a link, or `navigate()`) takes effect without a page load - and in an
100
- // effect, not during render, so the server render and the hydrating render agree.
101
- const search = useLocationSearch();
102
- const navigate = useNavigate();
103
- useEffect(() => {
104
- setRequestedMailboxUid(new URLSearchParams(search).get("mailboxUid"));
105
- }, [search]);
106
- // Choosing a folder (or mailbox) changes the URL without a page load now, so the drawer that held the choice - which used to go
107
- // with the page - is closed here.
108
- useEffect(() => {
109
- setDrawerOpen(false);
110
- }, [search]);
111
-
112
- useEffect(() => {
113
- if (!userUid) {
114
- return;
115
- }
116
- listMailboxes({ limit: 100 })
117
- .then((result) => {
118
- setMailboxes(result);
119
- setStatus("ready");
120
- })
121
- .catch((err) => {
122
- setError(err instanceof ApiRequestError ? err.message : "Could not load your mailboxes.");
123
- setStatus("error");
124
- });
125
- }, [userUid]);
126
-
127
- const mailboxUid: string | undefined =
128
- (requestedMailboxUid && mailboxes.some((mb) => mb.uid === requestedMailboxUid) ? requestedMailboxUid : undefined) ??
129
- mailboxes[0]?.uid;
130
-
131
- const contextValue = useMemo<SettingsShellContextValue>(() => ({ mailboxUid, mailboxes }), [mailboxUid, mailboxes]);
132
-
133
- // A full-screen takeover, not nested inside the rest of the app's chrome — same as ContactsShell/
134
- // TasksShell, there's nothing else for a mailbox-less caller to configure here yet.
135
- if (userUid && status === "ready" && !mailboxUid) {
136
- return <MailboxProvisioning />;
137
- }
138
-
139
- let inner: ReactNode = null;
140
- if (userUid && status === "checking") {
141
- inner = (
142
- <div className="w-56 shrink-0 border-r border-border flex flex-col gap-4 p-3">
143
- <Skeleton height="h-9" />
144
- <SkeletonList count={3} />
145
- </div>
146
- );
147
- } else if (userUid && status === "error") {
148
- inner = (
149
- <div className="flex-1 flex items-center justify-center p-8">
150
- <div className="w-full max-w-md">
151
- <Alert>{error}</Alert>
152
- </div>
153
- </div>
154
- );
155
- } else if (userUid && status === "ready") {
156
- const sections = settingsSections(pluginNav);
157
- // A function, not a plain JSX constant — same reasoning as ContactsShell's identical comment:
158
- // rendered twice (desktop `<aside>` + mobile `Drawer`), possibly simultaneously mounted, so the
159
- // `<select>`'s `id`/its `<label>`'s `htmlFor` need a distinct value per instance.
160
- const sidebarContent = (idPrefix: string) => (
161
- <>
162
- {mailboxes.length > 1 && (
163
- <div>
164
- <label
165
- className="block text-xs font-bold uppercase tracking-wide text-text-muted mb-1"
166
- htmlFor={`${idPrefix}-settings-mailbox-switcher`}
167
- >
168
- Mailbox
169
- </label>
170
- <select
171
- id={`${idPrefix}-settings-mailbox-switcher`}
172
- className="w-full text-sm border border-border rounded-sm py-1.5 px-2 bg-surface"
173
- value={mailboxUid}
174
- onChange={(e) => {
175
- // Every core settings page passes its own section id (see
176
- // `SettingsShellProps.active`), but a plugin page's section is missing when the
177
- // server didn't send its nav item, so that falls back to the current path.
178
- const href = sections.find((s) => s.id === active)?.href ?? window.location.pathname;
179
- navigate(`${href}?mailboxUid=${encodeURIComponent(e.target.value)}`);
180
- }}
181
- >
182
- {mailboxes.map((mb) => (
183
- <option key={mb.uid} value={mb.uid}>
184
- {mb.displayName}
185
- {mb.ownerUserUid ? "" : " (shared)"}
186
- </option>
187
- ))}
188
- </select>
189
- </div>
190
- )}
191
- <nav aria-label="Settings sections" className="flex flex-col gap-0.5">
192
- {sections.map((section) => (
193
- <a
194
- key={section.id}
195
- // `inner` (this whole branch) is only ever computed once `status === "ready"`
196
- // and `mailboxUid` has already resolved truthy — a falsy `mailboxUid` returns
197
- // `<MailboxProvisioning />` above instead (and TypeScript's own narrowing of
198
- // this `const` already reflects that, no `!` needed) — so no fallback is
199
- // needed here, matching this plan's established "dead guard the UI
200
- // structurally can't trigger" removal precedent (e.g.
201
- // `DomainDetailContent.handleVerify`).
202
- href={`${section.href}?mailboxUid=${encodeURIComponent(mailboxUid)}`}
203
- aria-current={section.id === active ? "page" : undefined}
204
- className={[
205
- "block px-2.5 py-1.5 rounded-sm text-sm",
206
- section.id === active ? "bg-primary/10 text-primary-dark font-medium" : "text-text hover:bg-surface-alt",
207
- ].join(" ")}
208
- >
209
- {section.label}
210
- </a>
211
- ))}
212
- </nav>
213
- </>
214
- );
215
-
216
- inner = (
217
- <>
218
- <aside className="hidden md:flex w-56 shrink-0 bg-surface border-r border-border flex-col p-3 gap-3">
219
- {sidebarContent("desktop")}
220
- </aside>
221
- <Drawer open={drawerOpen} onClose={() => setDrawerOpen(false)} title="Settings">
222
- <div className="flex flex-col gap-3">{sidebarContent("mobile")}</div>
223
- </Drawer>
224
- <main className="flex-1 min-w-0 flex flex-col">
225
- <button
226
- type="button"
227
- className="md:hidden m-3 self-start w-9 h-9 flex items-center justify-center rounded-sm text-text-muted hover:bg-surface-alt hover:text-text"
228
- aria-label="Open settings menu"
229
- onClick={() => setDrawerOpen(true)}
230
- >
231
- <HiOutlineBars3 size={20} aria-hidden="true" />
232
- </button>
233
- <SettingsShellContext.Provider value={contextValue}>{children}</SettingsShellContext.Provider>
234
- </main>
235
- </>
236
- );
237
- }
238
-
239
- return (
240
- <AppShell
241
- active="settings"
242
- userUid={userUid}
243
- authServerUrl={authServerUrl}
244
- impersonating={impersonating}
245
- impersonationBaseUrl={impersonationBaseUrl}
246
- trusted={trusted}
247
- trustedRoles={trustedRoles}
248
- pluginNav={pluginNav}
249
- >
250
- {inner}
251
- </AppShell>
252
- );
253
- }
1
+ ///////////////////////////////////////////////////////////////////////////////
2
+ // Copyright (C) 2026 Jean-Philippe Steinmetz
3
+ // SPDX-License-Identifier: MPL-2.0
4
+ ///////////////////////////////////////////////////////////////////////////////
5
+ import React, { createContext, PropsWithChildren, ReactNode, useContext, useEffect, useMemo, useState } from "react";
6
+ import { HiOutlineBars3 } from "react-icons/hi2";
7
+ import { ApiRequestError } from "@rapidmx/react-shared/util/api.js";
8
+ import Drawer from "@rapidmx/react-shared/components/overlays/Drawer.js";
9
+ import { Mailbox, listMailboxes } from "@rapidmx/react-shared/mail/mailApi.js";
10
+ import Alert from "@rapidmx/react-shared/components/feedback/Alert.js";
11
+ import Skeleton, { SkeletonList } from "@rapidmx/react-shared/components/feedback/Skeleton.js";
12
+ import AppShell, { AppShellProps } from "../../layout/AppShell.js";
13
+ import { useLocationSearch, useNavigate } from "../../../navigation/AppRouter.js";
14
+ import MailboxProvisioning from "../../layout/MailboxProvisioning.js";
15
+ import { orderMailboxes, primaryMailboxUid } from "../../../mail/primaryMailbox.js";
16
+ import { mergePluginNavItems, PluginNav } from "../../../plugins/pluginNav.js";
17
+
18
+ export interface SettingsSectionDef {
19
+ id: string;
20
+ href: string;
21
+ label: string;
22
+ }
23
+
24
+ /** Every settings section with its own sidebar entry. */
25
+ export const SETTINGS_SECTIONS: SettingsSectionDef[] = [
26
+ { id: "profile", href: "/settings/profile", label: "Profile" },
27
+ { id: "appearance", href: "/settings/appearance", label: "Appearance" },
28
+ { id: "auto-reply", href: "/settings/auto-reply", label: "Automatic Replies" },
29
+ { id: "filters", href: "/settings/filters", label: "Mail Filters" },
30
+ { id: "signatures", href: "/settings/signatures", label: "Signatures" },
31
+ { id: "labels", href: "/settings/labels", label: "Labels" },
32
+ { id: "read-receipts", href: "/settings/read-receipts", label: "Read Receipts" },
33
+ { id: "encryption", href: "/settings/encryption", label: "Encryption" },
34
+ { id: "sharing", href: "/settings/sharing", label: "Sharing" },
35
+ { id: "privacy", href: "/settings/privacy", label: "Privacy & Data" },
36
+ ];
37
+
38
+ /** A `SETTINGS_SECTIONS` id, or a plugin's `settingsSections` item id (see `PluginNav`). */
39
+ export type SettingsSectionId = string;
40
+
41
+ /** `SETTINGS_SECTIONS` followed by the plugins' `settingsSections` items, core ids winning - see
42
+ * `mergePluginNavItems`. */
43
+ export function settingsSections(pluginNav?: PluginNav): SettingsSectionDef[] {
44
+ return mergePluginNavItems<SettingsSectionDef>(SETTINGS_SECTIONS, pluginNav?.settingsSections, ({ id, href, label }) => ({
45
+ id,
46
+ href,
47
+ label,
48
+ }));
49
+ }
50
+
51
+ export interface SettingsShellProps extends Omit<AppShellProps, "active"> {
52
+ /** Which entry in `SETTINGS_SECTIONS` (or plugin `settingsSections` item) is highlighted in this shell's own sidebar — distinct from
53
+ * `AppShell`'s own `active` (always hardcoded to `"settings"` below), since Settings isn't a rail
54
+ * icon (see `AppShell.tsx`'s `AppShellApp` doc comment) but still needs its own section
55
+ * highlighting. Each settings page passes its own section id explicitly, the same "gotcha" this
56
+ * plan already calls out for every shell's `active` prop. */
57
+ active: SettingsSectionId;
58
+ }
59
+
60
+ export interface SettingsShellContextValue {
61
+ /** The mailbox currently selected (`?mailboxUid=`, or the caller's first accessible mailbox) —
62
+ * every settings section so far (Automatic Replies) edits mailbox-scoped fields. */
63
+ mailboxUid?: string;
64
+ mailboxes: Mailbox[];
65
+ }
66
+
67
+ const SettingsShellContext = createContext<SettingsShellContextValue>({ mailboxes: [] });
68
+
69
+ /** Reads the mailbox Settings is currently scoped to, as resolved by the enclosing `SettingsShell`. */
70
+ export function useSettingsShell(): SettingsShellContextValue {
71
+ return useContext(SettingsShellContext);
72
+ }
73
+
74
+ type Status = "checking" | "error" | "ready";
75
+
76
+ /**
77
+ * The Settings area's shell — reached via a `UserMenu` entry rather than a 5th `AppShell` icon (per
78
+ * this plan's own confirmed decision), so it always passes `active="settings"` to `AppShell` regardless
79
+ * of which section is showing. Unlike `ContactsShell`/`TasksShell` (whose sidebar is just a mailbox
80
+ * switcher, since each has exactly one well-known folder), this shell's sidebar is a real list of
81
+ * settings sections (`SETTINGS_SECTIONS`) — full-page navigation between them, same as the top-level
82
+ * app rail, since this framework has no client-side router.
83
+ */
84
+ export default function SettingsShell({
85
+ active,
86
+ userUid,
87
+ authServerUrl,
88
+ impersonating,
89
+ impersonationBaseUrl,
90
+ trusted,
91
+ trustedRoles,
92
+ pluginNav,
93
+ children,
94
+ }: PropsWithChildren<SettingsShellProps>) {
95
+ const [status, setStatus] = useState<Status>("checking");
96
+ const [error, setError] = useState<string | null>(null);
97
+ const [mailboxes, setMailboxes] = useState<Mailbox[]>([]);
98
+ const [requestedMailboxUid, setRequestedMailboxUid] = useState<string | null>(null);
99
+ const [drawerOpen, setDrawerOpen] = useState(false);
100
+
101
+ // Read from the router's location, so a mailbox change (a link, or `navigate()`) takes effect without a page load - and in an
102
+ // effect, not during render, so the server render and the hydrating render agree.
103
+ const search = useLocationSearch();
104
+ const navigate = useNavigate();
105
+ useEffect(() => {
106
+ setRequestedMailboxUid(new URLSearchParams(search).get("mailboxUid"));
107
+ }, [search]);
108
+ // Choosing a folder (or mailbox) changes the URL without a page load now, so the drawer that held the choice - which used to go
109
+ // with the page - is closed here.
110
+ useEffect(() => {
111
+ setDrawerOpen(false);
112
+ }, [search]);
113
+
114
+ useEffect(() => {
115
+ if (!userUid) {
116
+ return;
117
+ }
118
+ listMailboxes({ limit: 100 })
119
+ .then((result) => {
120
+ setMailboxes(orderMailboxes(result, userUid));
121
+ setStatus("ready");
122
+ })
123
+ .catch((err) => {
124
+ setError(err instanceof ApiRequestError ? err.message : "Could not load your mailboxes.");
125
+ setStatus("error");
126
+ });
127
+ }, [userUid]);
128
+
129
+ const mailboxUid: string | undefined =
130
+ (requestedMailboxUid && mailboxes.some((mb) => mb.uid === requestedMailboxUid) ? requestedMailboxUid : undefined) ??
131
+ primaryMailboxUid(mailboxes, userUid);
132
+
133
+ const contextValue = useMemo<SettingsShellContextValue>(() => ({ mailboxUid, mailboxes }), [mailboxUid, mailboxes]);
134
+
135
+ // A full-screen takeover, not nested inside the rest of the app's chrome — same as ContactsShell/
136
+ // TasksShell, there's nothing else for a mailbox-less caller to configure here yet.
137
+ if (userUid && status === "ready" && !mailboxUid) {
138
+ return <MailboxProvisioning />;
139
+ }
140
+
141
+ let inner: ReactNode = null;
142
+ if (userUid && status === "checking") {
143
+ inner = (
144
+ <div className="w-56 shrink-0 border-r border-border flex flex-col gap-4 p-3">
145
+ <Skeleton height="h-9" />
146
+ <SkeletonList count={3} />
147
+ </div>
148
+ );
149
+ } else if (userUid && status === "error") {
150
+ inner = (
151
+ <div className="flex-1 flex items-center justify-center p-8">
152
+ <div className="w-full max-w-md">
153
+ <Alert>{error}</Alert>
154
+ </div>
155
+ </div>
156
+ );
157
+ } else if (userUid && status === "ready") {
158
+ const sections = settingsSections(pluginNav);
159
+ // A function, not a plain JSX constant — same reasoning as ContactsShell's identical comment:
160
+ // rendered twice (desktop `<aside>` + mobile `Drawer`), possibly simultaneously mounted, so the
161
+ // `<select>`'s `id`/its `<label>`'s `htmlFor` need a distinct value per instance.
162
+ const sidebarContent = (idPrefix: string) => (
163
+ <>
164
+ {mailboxes.length > 1 && (
165
+ <div>
166
+ <label
167
+ className="block text-xs font-bold uppercase tracking-wide text-text-muted mb-1"
168
+ htmlFor={`${idPrefix}-settings-mailbox-switcher`}
169
+ >
170
+ Mailbox
171
+ </label>
172
+ <select
173
+ id={`${idPrefix}-settings-mailbox-switcher`}
174
+ className="w-full text-sm border border-border rounded-sm py-1.5 px-2 bg-surface"
175
+ value={mailboxUid}
176
+ onChange={(e) => {
177
+ // Every core settings page passes its own section id (see
178
+ // `SettingsShellProps.active`), but a plugin page's section is missing when the
179
+ // server didn't send its nav item, so that falls back to the current path.
180
+ const href = sections.find((s) => s.id === active)?.href ?? window.location.pathname;
181
+ navigate(`${href}?mailboxUid=${encodeURIComponent(e.target.value)}`);
182
+ }}
183
+ >
184
+ {mailboxes.map((mb) => (
185
+ <option key={mb.uid} value={mb.uid}>
186
+ {mb.displayName}
187
+ {mb.ownerUserUid ? "" : " (shared)"}
188
+ </option>
189
+ ))}
190
+ </select>
191
+ </div>
192
+ )}
193
+ <nav aria-label="Settings sections" className="flex flex-col gap-0.5">
194
+ {sections.map((section) => (
195
+ <a
196
+ key={section.id}
197
+ // `inner` (this whole branch) is only ever computed once `status === "ready"`
198
+ // and `mailboxUid` has already resolved truthy — a falsy `mailboxUid` returns
199
+ // `<MailboxProvisioning />` above instead (which is what the `!` below records,
200
+ // `primaryMailboxUid()` being honest that it may find none) — so no fallback is
201
+ // needed here, matching this plan's established "dead guard the UI
202
+ // structurally can't trigger" removal precedent (e.g.
203
+ // `DomainDetailContent.handleVerify`).
204
+ href={`${section.href}?mailboxUid=${encodeURIComponent(mailboxUid!)}`}
205
+ aria-current={section.id === active ? "page" : undefined}
206
+ className={[
207
+ "block px-2.5 py-1.5 rounded-sm text-sm",
208
+ section.id === active ? "bg-primary/10 text-primary-dark font-medium" : "text-text hover:bg-surface-alt",
209
+ ].join(" ")}
210
+ >
211
+ {section.label}
212
+ </a>
213
+ ))}
214
+ </nav>
215
+ </>
216
+ );
217
+
218
+ inner = (
219
+ <>
220
+ <aside className="hidden md:flex w-56 shrink-0 bg-surface border-r border-border flex-col p-3 gap-3">
221
+ {sidebarContent("desktop")}
222
+ </aside>
223
+ <Drawer open={drawerOpen} onClose={() => setDrawerOpen(false)} title="Settings" fullScreen>
224
+ <div className="flex flex-col gap-3">{sidebarContent("mobile")}</div>
225
+ </Drawer>
226
+ <main className="flex-1 min-w-0 flex flex-col">
227
+ <button
228
+ type="button"
229
+ className="md:hidden m-3 self-start w-9 h-9 flex items-center justify-center rounded-sm text-text-muted hover:bg-surface-alt hover:text-text"
230
+ aria-label="Open settings menu"
231
+ onClick={() => setDrawerOpen(true)}
232
+ >
233
+ <HiOutlineBars3 size={20} aria-hidden="true" />
234
+ </button>
235
+ <SettingsShellContext.Provider value={contextValue}>{children}</SettingsShellContext.Provider>
236
+ </main>
237
+ </>
238
+ );
239
+ }
240
+
241
+ return (
242
+ <AppShell
243
+ active="settings"
244
+ userUid={userUid}
245
+ authServerUrl={authServerUrl}
246
+ impersonating={impersonating}
247
+ impersonationBaseUrl={impersonationBaseUrl}
248
+ trusted={trusted}
249
+ trustedRoles={trustedRoles}
250
+ pluginNav={pluginNav}
251
+ >
252
+ {inner}
253
+ </AppShell>
254
+ );
255
+ }
@@ -195,7 +195,7 @@ export default function TasksSidebar({ mailboxUid, tasks, userUid, active, onSel
195
195
  <nav aria-label="Tasks" className="hidden lg:flex w-56 shrink-0 border-r border-border flex-col gap-4 p-3 overflow-y-auto">
196
196
  {navContent("desktop")}
197
197
  </nav>
198
- <Drawer open={drawerOpen} onClose={() => setDrawerOpen(false)} title="Tasks">
198
+ <Drawer open={drawerOpen} onClose={() => setDrawerOpen(false)} title="Tasks" fullScreen>
199
199
  <div className="flex flex-col gap-4">{navContent("mobile")}</div>
200
200
  </Drawer>
201
201
  </>