web-mojo 2.2.100 → 2.2.102

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 (195) hide show
  1. package/CHANGELOG.md +598 -0
  2. package/README.md +2 -2
  3. package/dist/admin-models.cjs.js +2 -0
  4. package/dist/admin-models.cjs.js.map +1 -0
  5. package/dist/admin-models.es.js +2 -0
  6. package/dist/admin-models.es.js.map +1 -0
  7. package/dist/admin.cjs.js +1 -1
  8. package/dist/admin.css +42 -0
  9. package/dist/admin.es.js +1 -1
  10. package/dist/auth.cjs.js +1 -1
  11. package/dist/auth.es.js +1 -1
  12. package/dist/charts.cjs.js +1 -1
  13. package/dist/charts.cjs.js.map +1 -1
  14. package/dist/charts.css +897 -1
  15. package/dist/charts.es.js +1 -1
  16. package/dist/charts.es.js.map +1 -1
  17. package/dist/chat.css +96 -0
  18. package/dist/chunks/AssistantPanelView-CMRTtoqS.js +2 -0
  19. package/dist/chunks/AssistantPanelView-CMRTtoqS.js.map +1 -0
  20. package/dist/chunks/AssistantPanelView-CaVkWhVD.js +2 -0
  21. package/dist/chunks/AssistantPanelView-CaVkWhVD.js.map +1 -0
  22. package/dist/chunks/ChatView-B73uox2v.js +2 -0
  23. package/dist/chunks/ChatView-B73uox2v.js.map +1 -0
  24. package/dist/chunks/ChatView-W8daOwIo.js +2 -0
  25. package/dist/chunks/ChatView-W8daOwIo.js.map +1 -0
  26. package/dist/chunks/Collection-BZlmtcuL.js +2 -0
  27. package/dist/chunks/Collection-BZlmtcuL.js.map +1 -0
  28. package/dist/chunks/Collection-Bwoq6muu.js +2 -0
  29. package/dist/chunks/Collection-Bwoq6muu.js.map +1 -0
  30. package/dist/chunks/ContextMenu-BPPtuqKk.js +2 -0
  31. package/dist/chunks/ContextMenu-BPPtuqKk.js.map +1 -0
  32. package/dist/chunks/ContextMenu-q76hjQb6.js +2 -0
  33. package/dist/chunks/ContextMenu-q76hjQb6.js.map +1 -0
  34. package/dist/chunks/DataView-BbrwHMV4.js +2 -0
  35. package/dist/chunks/{DataView-6lhf855r.js.map → DataView-BbrwHMV4.js.map} +1 -1
  36. package/dist/chunks/DataView-k-7wmk5_.js +2 -0
  37. package/dist/chunks/{DataView-Bb83ww5U.js.map → DataView-k-7wmk5_.js.map} +1 -1
  38. package/dist/chunks/FormView-DPSuwWMq.js +3 -0
  39. package/dist/chunks/{FormView-DEROOklJ.js.map → FormView-DPSuwWMq.js.map} +1 -1
  40. package/dist/chunks/FormView-Dcy7XOtC.js +3 -0
  41. package/dist/chunks/{FormView-UmvPskWT.js.map → FormView-Dcy7XOtC.js.map} +1 -1
  42. package/dist/chunks/ListView-DHC-yBIw.js +2 -0
  43. package/dist/chunks/ListView-DHC-yBIw.js.map +1 -0
  44. package/dist/chunks/ListView-iGBsD4a7.js +2 -0
  45. package/dist/chunks/ListView-iGBsD4a7.js.map +1 -0
  46. package/dist/chunks/MetricsCountryMapView-CAD9wR_T.js +2 -0
  47. package/dist/chunks/MetricsCountryMapView-CAD9wR_T.js.map +1 -0
  48. package/dist/chunks/MetricsCountryMapView-Dzk3Yrzx.js +2 -0
  49. package/dist/chunks/MetricsCountryMapView-Dzk3Yrzx.js.map +1 -0
  50. package/dist/chunks/Modal-DBJU16cc.js +3 -0
  51. package/dist/chunks/Modal-DBJU16cc.js.map +1 -0
  52. package/dist/chunks/Modal-DuULCMFZ.js +3 -0
  53. package/dist/chunks/Modal-DuULCMFZ.js.map +1 -0
  54. package/dist/chunks/Passkeys-CGRZ8ZMv.js +2 -0
  55. package/dist/chunks/{Passkeys-CIRjqi7n.js.map → Passkeys-CGRZ8ZMv.js.map} +1 -1
  56. package/dist/chunks/Passkeys-Dr8-oSm9.js +2 -0
  57. package/dist/chunks/{Passkeys-BPV1gNkR.js.map → Passkeys-Dr8-oSm9.js.map} +1 -1
  58. package/dist/chunks/TokenManager-CFsr1qUV.js +2 -0
  59. package/dist/chunks/TokenManager-CFsr1qUV.js.map +1 -0
  60. package/dist/chunks/TokenManager-CHQxK_e5.js +2 -0
  61. package/dist/chunks/TokenManager-CHQxK_e5.js.map +1 -0
  62. package/dist/chunks/User-DNQhdBtI.js +2 -0
  63. package/dist/chunks/User-DNQhdBtI.js.map +1 -0
  64. package/dist/chunks/User-Dg7xpYEI.js +2 -0
  65. package/dist/chunks/User-Dg7xpYEI.js.map +1 -0
  66. package/dist/chunks/UserProfileView-B5nczdfw.js +2 -0
  67. package/dist/chunks/UserProfileView-B5nczdfw.js.map +1 -0
  68. package/dist/chunks/UserProfileView-Bpz3VZmP.js +2 -0
  69. package/dist/chunks/UserProfileView-Bpz3VZmP.js.map +1 -0
  70. package/dist/chunks/View-C5n3sIFi.js +2 -0
  71. package/dist/chunks/View-C5n3sIFi.js.map +1 -0
  72. package/dist/chunks/View-Yazho7OL.js +2 -0
  73. package/dist/chunks/View-Yazho7OL.js.map +1 -0
  74. package/dist/chunks/WebApp-CeiDNV6L.js +2 -0
  75. package/dist/chunks/WebApp-CeiDNV6L.js.map +1 -0
  76. package/dist/chunks/WebApp-irKlhuFX.js +2 -0
  77. package/dist/chunks/WebApp-irKlhuFX.js.map +1 -0
  78. package/dist/chunks/admin-BkxeK68u.js +2 -0
  79. package/dist/chunks/admin-BkxeK68u.js.map +1 -0
  80. package/dist/chunks/admin-vjoNbv_1.js +2 -0
  81. package/dist/chunks/admin-vjoNbv_1.js.map +1 -0
  82. package/dist/chunks/exportChart-DbsHDCxw.js +2 -0
  83. package/dist/chunks/exportChart-DbsHDCxw.js.map +1 -0
  84. package/dist/chunks/exportChart-Dk8D_du5.js +2 -0
  85. package/dist/chunks/exportChart-Dk8D_du5.js.map +1 -0
  86. package/dist/chunks/index-BNjCQA7q.js +2 -0
  87. package/dist/chunks/{index-CSmG_P2r.js.map → index-BNjCQA7q.js.map} +1 -1
  88. package/dist/chunks/index-DBsIDOAa.js +2 -0
  89. package/dist/chunks/{index-uo77m1wt.js.map → index-DBsIDOAa.js.map} +1 -1
  90. package/dist/chunks/{version-CRfGMZSI.js → version-B0cBv8MN.js} +2 -2
  91. package/dist/chunks/{version-CRfGMZSI.js.map → version-B0cBv8MN.js.map} +1 -1
  92. package/dist/chunks/{version-D-5X69D6.js → version-DtqCY0ZY.js} +2 -2
  93. package/dist/chunks/{version-D-5X69D6.js.map → version-DtqCY0ZY.js.map} +1 -1
  94. package/dist/core.css +306 -0
  95. package/dist/css/web-mojo.css +1 -1
  96. package/dist/docit.cjs.js +1 -1
  97. package/dist/docit.cjs.js.map +1 -1
  98. package/dist/docit.es.js +1 -1
  99. package/dist/docit.es.js.map +1 -1
  100. package/dist/index.cjs.js +1 -1
  101. package/dist/index.cjs.js.map +1 -1
  102. package/dist/index.es.js +1 -1
  103. package/dist/index.es.js.map +1 -1
  104. package/dist/lightbox.cjs.js +1 -1
  105. package/dist/lightbox.cjs.js.map +1 -1
  106. package/dist/lightbox.es.js +1 -1
  107. package/dist/lightbox.es.js.map +1 -1
  108. package/dist/map.cjs.js +1 -1
  109. package/dist/map.cjs.js.map +1 -1
  110. package/dist/map.es.js +1 -1
  111. package/dist/map.es.js.map +1 -1
  112. package/dist/portal.css +86 -0
  113. package/dist/timeline.cjs.js +1 -1
  114. package/dist/timeline.cjs.js.map +1 -1
  115. package/dist/timeline.es.js +1 -1
  116. package/dist/timeline.es.js.map +1 -1
  117. package/dist/user-profile.cjs.js +1 -1
  118. package/dist/user-profile.es.js +1 -1
  119. package/dist/web-mojo.lite.iife.js +4185 -3872
  120. package/dist/web-mojo.lite.iife.js.map +1 -1
  121. package/dist/web-mojo.lite.iife.min.js +301 -323
  122. package/dist/web-mojo.lite.iife.min.js.map +1 -1
  123. package/package.json +7 -2
  124. package/dist/chunks/AssistantPanelView-CZhZmVSG.js +0 -2
  125. package/dist/chunks/AssistantPanelView-CZhZmVSG.js.map +0 -1
  126. package/dist/chunks/AssistantPanelView-WFHYQjq7.js +0 -2
  127. package/dist/chunks/AssistantPanelView-WFHYQjq7.js.map +0 -1
  128. package/dist/chunks/ChatView-Bj3Tvx7a.js +0 -2
  129. package/dist/chunks/ChatView-Bj3Tvx7a.js.map +0 -1
  130. package/dist/chunks/ChatView-Uoqp80PU.js +0 -2
  131. package/dist/chunks/ChatView-Uoqp80PU.js.map +0 -1
  132. package/dist/chunks/Collection-C39Oy2q0.js +0 -2
  133. package/dist/chunks/Collection-C39Oy2q0.js.map +0 -1
  134. package/dist/chunks/Collection-CyK0u557.js +0 -2
  135. package/dist/chunks/Collection-CyK0u557.js.map +0 -1
  136. package/dist/chunks/ContextMenu-D-C7V6J6.js +0 -2
  137. package/dist/chunks/ContextMenu-D-C7V6J6.js.map +0 -1
  138. package/dist/chunks/ContextMenu-hjqR1pGW.js +0 -2
  139. package/dist/chunks/ContextMenu-hjqR1pGW.js.map +0 -1
  140. package/dist/chunks/DataView-6lhf855r.js +0 -2
  141. package/dist/chunks/DataView-Bb83ww5U.js +0 -2
  142. package/dist/chunks/Dialog-B0r9puaZ.js +0 -3
  143. package/dist/chunks/Dialog-B0r9puaZ.js.map +0 -1
  144. package/dist/chunks/Dialog-GzCkpMad.js +0 -3
  145. package/dist/chunks/Dialog-GzCkpMad.js.map +0 -1
  146. package/dist/chunks/FormView-DEROOklJ.js +0 -3
  147. package/dist/chunks/FormView-UmvPskWT.js +0 -3
  148. package/dist/chunks/ListView-D_hOtfWZ.js +0 -2
  149. package/dist/chunks/ListView-D_hOtfWZ.js.map +0 -1
  150. package/dist/chunks/ListView-Jkke6pU1.js +0 -2
  151. package/dist/chunks/ListView-Jkke6pU1.js.map +0 -1
  152. package/dist/chunks/MetricsCountryMapView-UdvJWArx.js +0 -2
  153. package/dist/chunks/MetricsCountryMapView-UdvJWArx.js.map +0 -1
  154. package/dist/chunks/MetricsCountryMapView-jLWCL6Hm.js +0 -2
  155. package/dist/chunks/MetricsCountryMapView-jLWCL6Hm.js.map +0 -1
  156. package/dist/chunks/MetricsMiniChartWidget-CV-McxOl.js +0 -2
  157. package/dist/chunks/MetricsMiniChartWidget-CV-McxOl.js.map +0 -1
  158. package/dist/chunks/MetricsMiniChartWidget-DG0DeDuR.js +0 -2
  159. package/dist/chunks/MetricsMiniChartWidget-DG0DeDuR.js.map +0 -1
  160. package/dist/chunks/MiniPieChart-B3sM4Bjv.js +0 -2
  161. package/dist/chunks/MiniPieChart-B3sM4Bjv.js.map +0 -1
  162. package/dist/chunks/MiniPieChart-DL5Rynvm.js +0 -2
  163. package/dist/chunks/MiniPieChart-DL5Rynvm.js.map +0 -1
  164. package/dist/chunks/MiniSeriesChart-C4DPVbU_.js +0 -2
  165. package/dist/chunks/MiniSeriesChart-C4DPVbU_.js.map +0 -1
  166. package/dist/chunks/MiniSeriesChart-DdNMLwfh.js +0 -2
  167. package/dist/chunks/MiniSeriesChart-DdNMLwfh.js.map +0 -1
  168. package/dist/chunks/Modal-jWZGSSOo.js +0 -2
  169. package/dist/chunks/Modal-jWZGSSOo.js.map +0 -1
  170. package/dist/chunks/Modal-xSaurlfZ.js +0 -2
  171. package/dist/chunks/Modal-xSaurlfZ.js.map +0 -1
  172. package/dist/chunks/Passkeys-BPV1gNkR.js +0 -2
  173. package/dist/chunks/Passkeys-CIRjqi7n.js +0 -2
  174. package/dist/chunks/TokenManager-CKgK0MIz.js +0 -2
  175. package/dist/chunks/TokenManager-CKgK0MIz.js.map +0 -1
  176. package/dist/chunks/TokenManager-Cu0YmxAx.js +0 -2
  177. package/dist/chunks/TokenManager-Cu0YmxAx.js.map +0 -1
  178. package/dist/chunks/UserProfileView-BXT8COCF.js +0 -2
  179. package/dist/chunks/UserProfileView-BXT8COCF.js.map +0 -1
  180. package/dist/chunks/UserProfileView-Slj-9C__.js +0 -2
  181. package/dist/chunks/UserProfileView-Slj-9C__.js.map +0 -1
  182. package/dist/chunks/WebApp-CXkNqtZX.js +0 -2
  183. package/dist/chunks/WebApp-CXkNqtZX.js.map +0 -1
  184. package/dist/chunks/WebApp-m6YeJFWY.js +0 -2
  185. package/dist/chunks/WebApp-m6YeJFWY.js.map +0 -1
  186. package/dist/chunks/WebSocketClient-BQAZr8C4.js +0 -2
  187. package/dist/chunks/WebSocketClient-BQAZr8C4.js.map +0 -1
  188. package/dist/chunks/WebSocketClient-YR5d82h8.js +0 -2
  189. package/dist/chunks/WebSocketClient-YR5d82h8.js.map +0 -1
  190. package/dist/chunks/admin-CpLR06pX.js +0 -2
  191. package/dist/chunks/admin-CpLR06pX.js.map +0 -1
  192. package/dist/chunks/admin-JtLeoEHZ.js +0 -2
  193. package/dist/chunks/admin-JtLeoEHZ.js.map +0 -1
  194. package/dist/chunks/index-CSmG_P2r.js +0 -2
  195. package/dist/chunks/index-uo77m1wt.js +0 -2
@@ -0,0 +1,2 @@
1
+ import{U as e,P as t}from"./UserProfileView-B5nczdfw.js";import{a as i,b as s,c as o,d as l,e as a,f as r,g as n,h as c,i as d,j as g,k as f}from"./UserProfileView-B5nczdfw.js";import{V as m}from"./View-C5n3sIFi.js";import{T as y,f as p,c as b}from"./Passkeys-CGRZ8ZMv.js";class ActivityRow extends b{get logMessage(){const e=this.model?.get("log");if(!e)return"";if("string"==typeof e)try{const t=JSON.parse(e);return t.message||t.type||e.substring(0,120)}catch{return e.length>120?e.substring(0,120)+"…":e}return"object"==typeof e?e.message||e.type||JSON.stringify(e).substring(0,120):String(e)}get levelText(){return this.model?.get("level")||"log"}get levelBadgeClass(){const e=this.model?.get("level");return"error"===e?"bg-danger":"warn"===e?"bg-warning text-dark":"info"===e?"bg-info":"bg-secondary"}get methodPath(){const e=this.model?.get("method")||"",t=this.model?.get("path")||"";return e||t?`${e} ${t}`.trim():""}}class ProfileActivitySection extends m{constructor(e={}){super({className:"profile-activity-section",template:'<div id="activity-table"></div>',...e})}async onInit(){await super.onInit(),this.tableView=new y({containerId:"activity-table",collection:new p({size:10}),defaultQuery:{uid:this.model.id,sort:"-created"},hideActivePillNames:["uid","sort"],itemClass:ActivityRow,columns:[{key:"level",label:"Level",sortable:!0,template:'<span class="badge {{levelBadgeClass}}">{{levelText}}</span>',filter:{type:"select",options:["info","warn","error"]}},{key:"log",label:"Message",template:"{{logMessage}}"},{key:"kind",label:"Kind",sortable:!0,visibility:"md"},{key:"path",label:"Path",visibility:"lg",template:"{{methodPath}}"},{key:"ip",label:"IP",visibility:"xl"},{key:"created|relative",label:"Time",sortable:!0}],searchable:!0,sortable:!0,filterable:!0,paginated:!0,showAdd:!1,showExport:!1,tableOptions:{striped:!1,hover:!0,size:"sm"},emptyMessage:"No activity logs available"}),this.addChild(this.tableView)}}export{t as PasskeySetupView,ProfileActivitySection,i as ProfileApiKeysSection,s as ProfileConnectedSection,o as ProfileDevicesSection,l as ProfileGroupsSection,a as ProfileNotificationsSection,r as ProfileOverviewSection,n as ProfilePermissionsSection,c as ProfilePersonalSection,d as ProfileSecurityEventsSection,g as ProfileSecuritySection,f as ProfileSessionsSection,e as UserProfileView};
2
+ //# sourceMappingURL=index-DBsIDOAa.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index-uo77m1wt.js","sources":["../../src/extensions/user-profile/views/ProfileActivitySection.js"],"sourcesContent":["/**\n * ProfileActivitySection - Activity log tab\n *\n * Uses TableView + LogList to show user activity\n * with parsed log messages, level badges, kind, path, and time.\n * Includes pagination, search, and level filtering.\n */\nimport View from '@core/View.js';\nimport TableView from '@core/views/table/TableView.js';\nimport TableRow from '@core/views/table/TableRow.js';\nimport { LogList } from '@core/models/Log.js';\n\nclass ActivityRow extends TableRow {\n get logMessage() {\n const log = this.model?.get('log');\n if (!log) return '';\n if (typeof log === 'string') {\n try {\n const parsed = JSON.parse(log);\n return parsed.message || parsed.type || log.substring(0, 120);\n } catch {\n return log.length > 120 ? log.substring(0, 120) + '…' : log;\n }\n }\n if (typeof log === 'object') {\n return log.message || log.type || JSON.stringify(log).substring(0, 120);\n }\n return String(log);\n }\n\n get levelText() {\n return this.model?.get('level') || 'log';\n }\n\n get levelBadgeClass() {\n const level = this.model?.get('level');\n if (level === 'error') return 'bg-danger';\n if (level === 'warn') return 'bg-warning text-dark';\n if (level === 'info') return 'bg-info';\n return 'bg-secondary';\n }\n\n get methodPath() {\n const method = this.model?.get('method') || '';\n const path = this.model?.get('path') || '';\n if (!method && !path) return '';\n return `${method} ${path}`.trim();\n }\n}\n\nexport default class ProfileActivitySection extends View {\n constructor(options = {}) {\n super({\n className: 'profile-activity-section',\n template: `<div id=\"activity-table\"></div>`,\n ...options\n });\n }\n\n async onInit() {\n await super.onInit();\n this.tableView = new TableView({\n containerId: 'activity-table',\n collection: new LogList({ size: 10 }),\n defaultQuery: { uid: this.model.id, sort: '-created' },\n hideActivePillNames: ['uid', 'sort'],\n itemClass: ActivityRow,\n columns: [\n {\n key: 'level',\n label: 'Level',\n sortable: true,\n template: '<span class=\"badge {{levelBadgeClass}}\">{{levelText}}</span>',\n filter: { type: 'select', options: ['info', 'warn', 'error'] }\n },\n {\n key: 'log',\n label: 'Message',\n template: '{{logMessage}}'\n },\n { key: 'kind', label: 'Kind', sortable: true, visibility: 'md' },\n {\n key: 'path',\n label: 'Path',\n visibility: 'lg',\n template: '{{methodPath}}'\n },\n { key: 'ip', label: 'IP', visibility: 'xl' },\n { key: 'created|relative', label: 'Time', sortable: true }\n ],\n searchable: true,\n sortable: true,\n filterable: true,\n paginated: true,\n showAdd: false,\n showExport: false,\n tableOptions: {\n striped: false,\n hover: true,\n size: 'sm'\n },\n emptyMessage: 'No activity logs available'\n });\n this.addChild(this.tableView);\n }\n}\n"],"names":["ActivityRow","TableRow","logMessage","log","this","model","get","parsed","JSON","parse","message","type","substring","length","stringify","String","levelText","levelBadgeClass","level","methodPath","method","path","trim","ProfileActivitySection","View","constructor","options","super","className","template","onInit","tableView","TableView","containerId","collection","LogList","size","defaultQuery","uid","id","sort","hideActivePillNames","itemClass","columns","key","label","sortable","filter","visibility","searchable","filterable","paginated","showAdd","showExport","tableOptions","striped","hover","emptyMessage","addChild"],"mappings":"uRAYA,MAAMA,oBAAoBC,EACtB,cAAIC,GACA,MAAMC,EAAMC,KAAKC,OAAOC,IAAI,OAC5B,IAAKH,EAAK,MAAO,GACjB,GAAmB,iBAARA,EACP,IACI,MAAMI,EAASC,KAAKC,MAAMN,GAC1B,OAAOI,EAAOG,SAAWH,EAAOI,MAAQR,EAAIS,UAAU,EAAG,IAC7D,CAAA,MACI,OAAOT,EAAIU,OAAS,IAAMV,EAAIS,UAAU,EAAG,KAAO,IAAMT,CAC5D,CAEJ,MAAmB,iBAARA,EACAA,EAAIO,SAAWP,EAAIQ,MAAQH,KAAKM,UAAUX,GAAKS,UAAU,EAAG,KAEhEG,OAAOZ,EAClB,CAEA,aAAIa,GACA,OAAOZ,KAAKC,OAAOC,IAAI,UAAY,KACvC,CAEA,mBAAIW,GACA,MAAMC,EAAQd,KAAKC,OAAOC,IAAI,SAC9B,MAAc,UAAVY,EAA0B,YAChB,SAAVA,EAAyB,uBACf,SAAVA,EAAyB,UACtB,cACX,CAEA,cAAIC,GACA,MAAMC,EAAShB,KAAKC,OAAOC,IAAI,WAAa,GACtCe,EAAOjB,KAAKC,OAAOC,IAAI,SAAW,GACxC,OAAKc,GAAWC,EACT,GAAGD,KAAUC,IAAOC,OADE,EAEjC,EAGW,MAAMC,+BAA+BC,EAChD,WAAAC,CAAYC,EAAU,IAClBC,MAAM,CACFC,UAAW,2BACXC,SAAU,qCACPH,GAEX,CAEA,YAAMI,SACIH,MAAMG,SACZ1B,KAAK2B,UAAY,IAAIC,EAAU,CAC3BC,YAAa,iBACbC,WAAY,IAAIC,EAAQ,CAAEC,KAAM,KAChCC,aAAc,CAAEC,IAAKlC,KAAKC,MAAMkC,GAAIC,KAAM,YAC1CC,oBAAqB,CAAC,MAAO,QAC7BC,UAAW1C,YACX2C,QAAS,CACL,CACIC,IAAK,QACLC,MAAO,QACPC,UAAU,EACVjB,SAAU,+DACVkB,OAAQ,CAAEpC,KAAM,SAAUe,QAAS,CAAC,OAAQ,OAAQ,WAExD,CACIkB,IAAK,MACLC,MAAO,UACPhB,SAAU,kBAEd,CAAEe,IAAK,OAAQC,MAAO,OAAQC,UAAU,EAAME,WAAY,MAC1D,CACIJ,IAAK,OACLC,MAAO,OACPG,WAAY,KACZnB,SAAU,kBAEd,CAAEe,IAAK,KAAMC,MAAO,KAAMG,WAAY,MACtC,CAAEJ,IAAK,mBAAoBC,MAAO,OAAQC,UAAU,IAExDG,YAAY,EACZH,UAAU,EACVI,YAAY,EACZC,WAAW,EACXC,SAAS,EACTC,YAAY,EACZC,aAAc,CACVC,SAAS,EACTC,OAAO,EACPpB,KAAM,MAEVqB,aAAc,+BAElBrD,KAAKsD,SAAStD,KAAK2B,UACvB"}
1
+ {"version":3,"file":"index-DBsIDOAa.js","sources":["../../src/extensions/user-profile/views/ProfileActivitySection.js"],"sourcesContent":["/**\n * ProfileActivitySection - Activity log tab\n *\n * Uses TableView + LogList to show user activity\n * with parsed log messages, level badges, kind, path, and time.\n * Includes pagination, search, and level filtering.\n */\nimport View from '@core/View.js';\nimport TableView from '@core/views/table/TableView.js';\nimport TableRow from '@core/views/table/TableRow.js';\nimport { LogList } from '@core/models/Log.js';\n\nclass ActivityRow extends TableRow {\n get logMessage() {\n const log = this.model?.get('log');\n if (!log) return '';\n if (typeof log === 'string') {\n try {\n const parsed = JSON.parse(log);\n return parsed.message || parsed.type || log.substring(0, 120);\n } catch {\n return log.length > 120 ? log.substring(0, 120) + '…' : log;\n }\n }\n if (typeof log === 'object') {\n return log.message || log.type || JSON.stringify(log).substring(0, 120);\n }\n return String(log);\n }\n\n get levelText() {\n return this.model?.get('level') || 'log';\n }\n\n get levelBadgeClass() {\n const level = this.model?.get('level');\n if (level === 'error') return 'bg-danger';\n if (level === 'warn') return 'bg-warning text-dark';\n if (level === 'info') return 'bg-info';\n return 'bg-secondary';\n }\n\n get methodPath() {\n const method = this.model?.get('method') || '';\n const path = this.model?.get('path') || '';\n if (!method && !path) return '';\n return `${method} ${path}`.trim();\n }\n}\n\nexport default class ProfileActivitySection extends View {\n constructor(options = {}) {\n super({\n className: 'profile-activity-section',\n template: `<div id=\"activity-table\"></div>`,\n ...options\n });\n }\n\n async onInit() {\n await super.onInit();\n this.tableView = new TableView({\n containerId: 'activity-table',\n collection: new LogList({ size: 10 }),\n defaultQuery: { uid: this.model.id, sort: '-created' },\n hideActivePillNames: ['uid', 'sort'],\n itemClass: ActivityRow,\n columns: [\n {\n key: 'level',\n label: 'Level',\n sortable: true,\n template: '<span class=\"badge {{levelBadgeClass}}\">{{levelText}}</span>',\n filter: { type: 'select', options: ['info', 'warn', 'error'] }\n },\n {\n key: 'log',\n label: 'Message',\n template: '{{logMessage}}'\n },\n { key: 'kind', label: 'Kind', sortable: true, visibility: 'md' },\n {\n key: 'path',\n label: 'Path',\n visibility: 'lg',\n template: '{{methodPath}}'\n },\n { key: 'ip', label: 'IP', visibility: 'xl' },\n { key: 'created|relative', label: 'Time', sortable: true }\n ],\n searchable: true,\n sortable: true,\n filterable: true,\n paginated: true,\n showAdd: false,\n showExport: false,\n tableOptions: {\n striped: false,\n hover: true,\n size: 'sm'\n },\n emptyMessage: 'No activity logs available'\n });\n this.addChild(this.tableView);\n }\n}\n"],"names":["ActivityRow","TableRow","logMessage","log","this","model","get","parsed","JSON","parse","message","type","substring","length","stringify","String","levelText","levelBadgeClass","level","methodPath","method","path","trim","ProfileActivitySection","View","constructor","options","super","className","template","onInit","tableView","TableView","containerId","collection","LogList","size","defaultQuery","uid","id","sort","hideActivePillNames","itemClass","columns","key","label","sortable","filter","visibility","searchable","filterable","paginated","showAdd","showExport","tableOptions","striped","hover","emptyMessage","addChild"],"mappings":"iRAYA,MAAMA,oBAAoBC,EACtB,cAAIC,GACA,MAAMC,EAAMC,KAAKC,OAAOC,IAAI,OAC5B,IAAKH,EAAK,MAAO,GACjB,GAAmB,iBAARA,EACP,IACI,MAAMI,EAASC,KAAKC,MAAMN,GAC1B,OAAOI,EAAOG,SAAWH,EAAOI,MAAQR,EAAIS,UAAU,EAAG,IAC7D,CAAA,MACI,OAAOT,EAAIU,OAAS,IAAMV,EAAIS,UAAU,EAAG,KAAO,IAAMT,CAC5D,CAEJ,MAAmB,iBAARA,EACAA,EAAIO,SAAWP,EAAIQ,MAAQH,KAAKM,UAAUX,GAAKS,UAAU,EAAG,KAEhEG,OAAOZ,EAClB,CAEA,aAAIa,GACA,OAAOZ,KAAKC,OAAOC,IAAI,UAAY,KACvC,CAEA,mBAAIW,GACA,MAAMC,EAAQd,KAAKC,OAAOC,IAAI,SAC9B,MAAc,UAAVY,EAA0B,YAChB,SAAVA,EAAyB,uBACf,SAAVA,EAAyB,UACtB,cACX,CAEA,cAAIC,GACA,MAAMC,EAAShB,KAAKC,OAAOC,IAAI,WAAa,GACtCe,EAAOjB,KAAKC,OAAOC,IAAI,SAAW,GACxC,OAAKc,GAAWC,EACT,GAAGD,KAAUC,IAAOC,OADE,EAEjC,EAGW,MAAMC,+BAA+BC,EAChD,WAAAC,CAAYC,EAAU,IAClBC,MAAM,CACFC,UAAW,2BACXC,SAAU,qCACPH,GAEX,CAEA,YAAMI,SACIH,MAAMG,SACZ1B,KAAK2B,UAAY,IAAIC,EAAU,CAC3BC,YAAa,iBACbC,WAAY,IAAIC,EAAQ,CAAEC,KAAM,KAChCC,aAAc,CAAEC,IAAKlC,KAAKC,MAAMkC,GAAIC,KAAM,YAC1CC,oBAAqB,CAAC,MAAO,QAC7BC,UAAW1C,YACX2C,QAAS,CACL,CACIC,IAAK,QACLC,MAAO,QACPC,UAAU,EACVjB,SAAU,+DACVkB,OAAQ,CAAEpC,KAAM,SAAUe,QAAS,CAAC,OAAQ,OAAQ,WAExD,CACIkB,IAAK,MACLC,MAAO,UACPhB,SAAU,kBAEd,CAAEe,IAAK,OAAQC,MAAO,OAAQC,UAAU,EAAME,WAAY,MAC1D,CACIJ,IAAK,OACLC,MAAO,OACPG,WAAY,KACZnB,SAAU,kBAEd,CAAEe,IAAK,KAAMC,MAAO,KAAMG,WAAY,MACtC,CAAEJ,IAAK,mBAAoBC,MAAO,OAAQC,UAAU,IAExDG,YAAY,EACZH,UAAU,EACVI,YAAY,EACZC,WAAW,EACXC,SAAS,EACTC,YAAY,EACZC,aAAc,CACVC,SAAS,EACTC,OAAO,EACPpB,KAAM,MAEVqB,aAAc,+BAElBrD,KAAKsD,SAAStD,KAAK2B,UACvB"}
@@ -1,2 +1,2 @@
1
- const i="2.2.100",n=2,o=2,s=100,O="2026-04-24T00:39:48.510Z",r={full:i,major:2,minor:2,revision:100,buildTime:O,toString(){return this.full},compare(i){const n=i=>i.split(".").map(Number),[o,s,O]=n(this.full),[r,w,e]=n(i);return o!==r?o-r:s!==w?s-w:O-e}};"undefined"!=typeof window&&(window.MOJO=window.MOJO||{},window.MOJO.VERSION=i,window.MOJO.VERSION_INFO=r,window.MOJO.version=i);export{O as B,i as V,r as a,n as b,o as c,s as d};
2
- //# sourceMappingURL=version-CRfGMZSI.js.map
1
+ const i="2.2.102",n=2,o=2,s=102,O="2026-04-27T13:25:24.756Z",r={full:i,major:2,minor:2,revision:102,buildTime:O,toString(){return this.full},compare(i){const n=i=>i.split(".").map(Number),[o,s,O]=n(this.full),[r,w,e]=n(i);return o!==r?o-r:s!==w?s-w:O-e}};"undefined"!=typeof window&&(window.MOJO=window.MOJO||{},window.MOJO.VERSION=i,window.MOJO.VERSION_INFO=r,window.MOJO.version=i);export{O as B,i as V,r as a,n as b,o as c,s as d};
2
+ //# sourceMappingURL=version-B0cBv8MN.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"version-CRfGMZSI.js","sources":["../../src/version.js"],"sourcesContent":["/**\n * MOJO Framework Version Information\n * Auto-generated on 2026-04-24T00:39:48.510Z\n */\n\nexport const VERSION = '2.2.100';\nexport const VERSION_MAJOR = 2;\nexport const VERSION_MINOR = 2;\nexport const VERSION_REVISION = 100;\nexport const BUILD_TIME = '2026-04-24T00:39:48.510Z';\n\n// Version object for easy access\nexport const VERSION_INFO = {\n full: VERSION,\n major: VERSION_MAJOR,\n minor: VERSION_MINOR,\n revision: VERSION_REVISION,\n buildTime: BUILD_TIME,\n toString() {\n return this.full;\n },\n compare(other) {\n const parseVer = (v) => v.split('.').map(Number);\n const [a1, a2, a3] = parseVer(this.full);\n const [b1, b2, b3] = parseVer(other);\n\n if (a1 !== b1) return a1 - b1;\n if (a2 !== b2) return a2 - b2;\n return a3 - b3;\n }\n};\n\n// Make version globally available if in browser\nif (typeof window !== 'undefined') {\n window.MOJO = window.MOJO || {};\n window.MOJO.VERSION = VERSION;\n window.MOJO.VERSION_INFO = VERSION_INFO;\n\n // Also add to MOJO.version for convenience\n window.MOJO.version = VERSION;\n}\n\nexport default VERSION_INFO;\n"],"names":["VERSION","VERSION_MAJOR","VERSION_MINOR","VERSION_REVISION","BUILD_TIME","VERSION_INFO","full","major","minor","revision","buildTime","toString","this","compare","other","parseVer","v","split","map","Number","a1","a2","a3","b1","b2","b3","window","MOJO","version"],"mappings":"AAKY,MAACA,EAAU,UACVC,EAAgB,EAChBC,EAAgB,EAChBC,EAAmB,IACnBC,EAAa,2BAGbC,EAAe,CACxBC,KAAMN,EACNO,MARyB,EASzBC,MARyB,EASzBC,SAR4B,IAS5BC,UAAWN,EACX,QAAAO,GACI,OAAOC,KAAKN,IAChB,EACA,OAAAO,CAAQC,GACJ,MAAMC,EAAYC,GAAMA,EAAEC,MAAM,KAAKC,IAAIC,SAClCC,EAAIC,EAAIC,GAAMP,EAASH,KAAKN,OAC5BiB,EAAIC,EAAIC,GAAMV,EAASD,GAE9B,OAAIM,IAAOG,EAAWH,EAAKG,EACvBF,IAAOG,EAAWH,EAAKG,EACpBF,EAAKG,CAChB,GAIkB,oBAAXC,SACPA,OAAOC,KAAOD,OAAOC,MAAQ,CAAA,EAC7BD,OAAOC,KAAK3B,QAAUA,EACtB0B,OAAOC,KAAKtB,aAAeA,EAG3BqB,OAAOC,KAAKC,QAAU5B"}
1
+ {"version":3,"file":"version-B0cBv8MN.js","sources":["../../src/version.js"],"sourcesContent":["/**\n * MOJO Framework Version Information\n * Auto-generated on 2026-04-27T13:25:24.756Z\n */\n\nexport const VERSION = '2.2.102';\nexport const VERSION_MAJOR = 2;\nexport const VERSION_MINOR = 2;\nexport const VERSION_REVISION = 102;\nexport const BUILD_TIME = '2026-04-27T13:25:24.756Z';\n\n// Version object for easy access\nexport const VERSION_INFO = {\n full: VERSION,\n major: VERSION_MAJOR,\n minor: VERSION_MINOR,\n revision: VERSION_REVISION,\n buildTime: BUILD_TIME,\n toString() {\n return this.full;\n },\n compare(other) {\n const parseVer = (v) => v.split('.').map(Number);\n const [a1, a2, a3] = parseVer(this.full);\n const [b1, b2, b3] = parseVer(other);\n\n if (a1 !== b1) return a1 - b1;\n if (a2 !== b2) return a2 - b2;\n return a3 - b3;\n }\n};\n\n// Make version globally available if in browser\nif (typeof window !== 'undefined') {\n window.MOJO = window.MOJO || {};\n window.MOJO.VERSION = VERSION;\n window.MOJO.VERSION_INFO = VERSION_INFO;\n\n // Also add to MOJO.version for convenience\n window.MOJO.version = VERSION;\n}\n\nexport default VERSION_INFO;\n"],"names":["VERSION","VERSION_MAJOR","VERSION_MINOR","VERSION_REVISION","BUILD_TIME","VERSION_INFO","full","major","minor","revision","buildTime","toString","this","compare","other","parseVer","v","split","map","Number","a1","a2","a3","b1","b2","b3","window","MOJO","version"],"mappings":"AAKY,MAACA,EAAU,UACVC,EAAgB,EAChBC,EAAgB,EAChBC,EAAmB,IACnBC,EAAa,2BAGbC,EAAe,CACxBC,KAAMN,EACNO,MARyB,EASzBC,MARyB,EASzBC,SAR4B,IAS5BC,UAAWN,EACX,QAAAO,GACI,OAAOC,KAAKN,IAChB,EACA,OAAAO,CAAQC,GACJ,MAAMC,EAAYC,GAAMA,EAAEC,MAAM,KAAKC,IAAIC,SAClCC,EAAIC,EAAIC,GAAMP,EAASH,KAAKN,OAC5BiB,EAAIC,EAAIC,GAAMV,EAASD,GAE9B,OAAIM,IAAOG,EAAWH,EAAKG,EACvBF,IAAOG,EAAWH,EAAKG,EACpBF,EAAKG,CAChB,GAIkB,oBAAXC,SACPA,OAAOC,KAAOD,OAAOC,MAAQ,CAAA,EAC7BD,OAAOC,KAAK3B,QAAUA,EACtB0B,OAAOC,KAAKtB,aAAeA,EAG3BqB,OAAOC,KAAKC,QAAU5B"}
@@ -1,2 +1,2 @@
1
- "use strict";const O="2.2.100",o="2026-04-24T00:39:48.510Z",i={full:O,major:2,minor:2,revision:100,buildTime:o,toString(){return this.full},compare(O){const o=O=>O.split(".").map(Number),[i,r,t]=o(this.full),[e,n,s]=o(O);return i!==e?i-e:r!==n?r-n:t-s}};"undefined"!=typeof window&&(window.MOJO=window.MOJO||{},window.MOJO.VERSION=O,window.MOJO.VERSION_INFO=i,window.MOJO.version=O),exports.BUILD_TIME=o,exports.VERSION=O,exports.VERSION_INFO=i,exports.VERSION_MAJOR=2,exports.VERSION_MINOR=2,exports.VERSION_REVISION=100;
2
- //# sourceMappingURL=version-D-5X69D6.js.map
1
+ "use strict";const O="2.2.102",o="2026-04-27T13:25:24.756Z",i={full:O,major:2,minor:2,revision:102,buildTime:o,toString(){return this.full},compare(O){const o=O=>O.split(".").map(Number),[i,r,t]=o(this.full),[e,n,s]=o(O);return i!==e?i-e:r!==n?r-n:t-s}};"undefined"!=typeof window&&(window.MOJO=window.MOJO||{},window.MOJO.VERSION=O,window.MOJO.VERSION_INFO=i,window.MOJO.version=O),exports.BUILD_TIME=o,exports.VERSION=O,exports.VERSION_INFO=i,exports.VERSION_MAJOR=2,exports.VERSION_MINOR=2,exports.VERSION_REVISION=102;
2
+ //# sourceMappingURL=version-DtqCY0ZY.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"version-D-5X69D6.js","sources":["../../src/version.js"],"sourcesContent":["/**\n * MOJO Framework Version Information\n * Auto-generated on 2026-04-24T00:39:48.510Z\n */\n\nexport const VERSION = '2.2.100';\nexport const VERSION_MAJOR = 2;\nexport const VERSION_MINOR = 2;\nexport const VERSION_REVISION = 100;\nexport const BUILD_TIME = '2026-04-24T00:39:48.510Z';\n\n// Version object for easy access\nexport const VERSION_INFO = {\n full: VERSION,\n major: VERSION_MAJOR,\n minor: VERSION_MINOR,\n revision: VERSION_REVISION,\n buildTime: BUILD_TIME,\n toString() {\n return this.full;\n },\n compare(other) {\n const parseVer = (v) => v.split('.').map(Number);\n const [a1, a2, a3] = parseVer(this.full);\n const [b1, b2, b3] = parseVer(other);\n\n if (a1 !== b1) return a1 - b1;\n if (a2 !== b2) return a2 - b2;\n return a3 - b3;\n }\n};\n\n// Make version globally available if in browser\nif (typeof window !== 'undefined') {\n window.MOJO = window.MOJO || {};\n window.MOJO.VERSION = VERSION;\n window.MOJO.VERSION_INFO = VERSION_INFO;\n\n // Also add to MOJO.version for convenience\n window.MOJO.version = VERSION;\n}\n\nexport default VERSION_INFO;\n"],"names":["VERSION","BUILD_TIME","VERSION_INFO","full","major","minor","revision","buildTime","toString","this","compare","other","parseVer","v","split","map","Number","a1","a2","a3","b1","b2","b3","window","MOJO","version"],"mappings":"aAKY,MAACA,EAAU,UAIVC,EAAa,2BAGbC,EAAe,CACxBC,KAAMH,EACNI,MARyB,EASzBC,MARyB,EASzBC,SAR4B,IAS5BC,UAAWN,EACX,QAAAO,GACI,OAAOC,KAAKN,IAChB,EACA,OAAAO,CAAQC,GACJ,MAAMC,EAAYC,GAAMA,EAAEC,MAAM,KAAKC,IAAIC,SAClCC,EAAIC,EAAIC,GAAMP,EAASH,KAAKN,OAC5BiB,EAAIC,EAAIC,GAAMV,EAASD,GAE9B,OAAIM,IAAOG,EAAWH,EAAKG,EACvBF,IAAOG,EAAWH,EAAKG,EACpBF,EAAKG,CAChB,GAIkB,oBAAXC,SACPA,OAAOC,KAAOD,OAAOC,MAAQ,CAAA,EAC7BD,OAAOC,KAAKxB,QAAUA,EACtBuB,OAAOC,KAAKtB,aAAeA,EAG3BqB,OAAOC,KAAKC,QAAUzB,uFAjCG,wBACA,2BACG"}
1
+ {"version":3,"file":"version-DtqCY0ZY.js","sources":["../../src/version.js"],"sourcesContent":["/**\n * MOJO Framework Version Information\n * Auto-generated on 2026-04-27T13:25:24.756Z\n */\n\nexport const VERSION = '2.2.102';\nexport const VERSION_MAJOR = 2;\nexport const VERSION_MINOR = 2;\nexport const VERSION_REVISION = 102;\nexport const BUILD_TIME = '2026-04-27T13:25:24.756Z';\n\n// Version object for easy access\nexport const VERSION_INFO = {\n full: VERSION,\n major: VERSION_MAJOR,\n minor: VERSION_MINOR,\n revision: VERSION_REVISION,\n buildTime: BUILD_TIME,\n toString() {\n return this.full;\n },\n compare(other) {\n const parseVer = (v) => v.split('.').map(Number);\n const [a1, a2, a3] = parseVer(this.full);\n const [b1, b2, b3] = parseVer(other);\n\n if (a1 !== b1) return a1 - b1;\n if (a2 !== b2) return a2 - b2;\n return a3 - b3;\n }\n};\n\n// Make version globally available if in browser\nif (typeof window !== 'undefined') {\n window.MOJO = window.MOJO || {};\n window.MOJO.VERSION = VERSION;\n window.MOJO.VERSION_INFO = VERSION_INFO;\n\n // Also add to MOJO.version for convenience\n window.MOJO.version = VERSION;\n}\n\nexport default VERSION_INFO;\n"],"names":["VERSION","BUILD_TIME","VERSION_INFO","full","major","minor","revision","buildTime","toString","this","compare","other","parseVer","v","split","map","Number","a1","a2","a3","b1","b2","b3","window","MOJO","version"],"mappings":"aAKY,MAACA,EAAU,UAIVC,EAAa,2BAGbC,EAAe,CACxBC,KAAMH,EACNI,MARyB,EASzBC,MARyB,EASzBC,SAR4B,IAS5BC,UAAWN,EACX,QAAAO,GACI,OAAOC,KAAKN,IAChB,EACA,OAAAO,CAAQC,GACJ,MAAMC,EAAYC,GAAMA,EAAEC,MAAM,KAAKC,IAAIC,SAClCC,EAAIC,EAAIC,GAAMP,EAASH,KAAKN,OAC5BiB,EAAIC,EAAIC,GAAMV,EAASD,GAE9B,OAAIM,IAAOG,EAAWH,EAAKG,EACvBF,IAAOG,EAAWH,EAAKG,EACpBF,EAAKG,CAChB,GAIkB,oBAAXC,SACPA,OAAOC,KAAOD,OAAOC,MAAQ,CAAA,EAC7BD,OAAOC,KAAKxB,QAAUA,EACtBuB,OAAOC,KAAKtB,aAAeA,EAG3BqB,OAAOC,KAAKC,QAAUzB,uFAjCG,wBACA,2BACG"}
package/dist/core.css CHANGED
@@ -173,6 +173,21 @@
173
173
  --bs-danger-text-emphasis: #8a1c24;
174
174
  }
175
175
 
176
+ /* Framework dark theme — deep mission-control surfaces.
177
+ Re-skins Bootstrap's dark-mode tokens so every dark page in a consuming
178
+ app reads as NOC tooling instead of the default washed-out gray.
179
+ No !important — downstream apps that set their own --bs-body-bg etc.
180
+ under [data-bs-theme="dark"] still win on source order. */
181
+ :root[data-bs-theme="dark"] {
182
+ --bs-body-bg: #0a0d11;
183
+ --bs-tertiary-bg: #11161d;
184
+ --bs-secondary-bg: #161b22;
185
+ --bs-border-color: #1f2630;
186
+ --bs-border-color-translucent: rgba(255, 255, 255, 0.04);
187
+ --bs-emphasis-color: #e6ecf3;
188
+ --bs-secondary-color: #8a96a6;
189
+ }
190
+
176
191
  :root {
177
192
  /* MOJO Framework Colors - Inherit from Bootstrap */
178
193
  --mojo-primary: var(--bs-primary);
@@ -1374,6 +1389,297 @@ button.dropdown-toggle:has(.multiselect-button-text)::after {
1374
1389
  margin-right: 0;
1375
1390
  }
1376
1391
 
1392
+ /* ==============================================
1393
+ Modal xxl size
1394
+
1395
+ Bootstrap 5 ships .modal-sm / .modal-lg / .modal-xl but stops there.
1396
+ Dialog accepts size: 'xxl' and emits .modal-xxl, so we provide a
1397
+ matching rule that follows Bootstrap's --bs-modal-width pattern at
1398
+ the xxl breakpoint (1400px).
1399
+ ============================================== */
1400
+ @media (min-width: 1400px) {
1401
+ .modal-xxl {
1402
+ --bs-modal-width: 1320px;
1403
+ }
1404
+ }
1405
+
1406
+ /* ==============================================
1407
+ Dialog / Modal Chrome — "Hero Band + Tinted Card"
1408
+
1409
+ Direction picked from planning/mockups/modals/05-merged-refined.html.
1410
+ - 6px colored hero band along the top of the card carries the type signal
1411
+ - Tinted card background (5% accent on white, 10% accent on dark)
1412
+ makes the type color felt across the whole surface, not just a stripe
1413
+ - Header gets no separate tint — the band + card-bg do the work
1414
+ - The X close button sits inside the card, top-right
1415
+ - Accent color comes from --mojo-dialog-accent (defaults to var(--bs-primary))
1416
+ and the four typed variants (success/warning/error/danger) override it.
1417
+ Modal.alert sets `modal-alert modal-alert-{type}` on the modal root.
1418
+ - Untyped surfaces (Modal.show / Modal.showForm without a type, etc.) inherit
1419
+ the default info accent, so every dialog reads as part of the same family.
1420
+ ============================================== */
1421
+
1422
+ :root {
1423
+ --mojo-dialog-accent: var(--bs-primary);
1424
+ --mojo-dialog-success: #198754;
1425
+ --mojo-dialog-warning: #ffc107;
1426
+ --mojo-dialog-error: #dc3545;
1427
+ }
1428
+
1429
+ /* ── Card chrome ───────────────────────────────────────── */
1430
+ /* Applies to every dialog. NOTE: no overflow:hidden — the hero band's
1431
+ ::before pseudo-element carries its own matching `border-radius:
1432
+ 14px 14px 0 0` (see below) so ancestor clipping isn't needed.
1433
+ Keeping overflow visible lets descendant popovers (Bootstrap
1434
+ .dropdown-menu, MultiSelectDropdown, ComboBox, context menus)
1435
+ escape the card edge instead of being clipped. */
1436
+ .modal-content {
1437
+ --mojo-current-accent: var(--mojo-dialog-accent);
1438
+ border-radius: 14px;
1439
+ border: none;
1440
+ box-shadow:
1441
+ 0 1px 2px rgba(12, 17, 28, 0.06),
1442
+ 0 8px 16px -4px rgba(12, 17, 28, 0.1),
1443
+ 0 30px 60px -12px rgba(12, 17, 28, 0.28);
1444
+ position: relative;
1445
+ background:
1446
+ linear-gradient(
1447
+ 180deg,
1448
+ color-mix(in srgb, var(--mojo-current-accent) 5%, var(--bs-modal-bg, #fff)) 0%,
1449
+ var(--bs-modal-bg, #fff) 100%
1450
+ );
1451
+ }
1452
+
1453
+ /* Hero band — solid colored slab across the top, with the type label
1454
+ centered and the close X anchored to the right side. Eyebrow text
1455
+ comes from `--mojo-eyebrow` (set inline by each Modal helper). The
1456
+ close X is positioned via separate CSS rules below so it can be
1457
+ interactive (the band itself stays pointer-events: none). */
1458
+ .modal-content::before {
1459
+ content: var(--mojo-eyebrow, "");
1460
+ display: flex;
1461
+ align-items: center;
1462
+ justify-content: center;
1463
+ position: absolute;
1464
+ top: 0;
1465
+ left: 0;
1466
+ right: 0;
1467
+ height: 28px;
1468
+ padding: 0 1.5rem;
1469
+ background: var(--mojo-current-accent);
1470
+ color: #fff;
1471
+ font-family: ui-monospace, "JetBrains Mono", "SF Mono", "SFMono-Regular", Menlo, Consolas, monospace;
1472
+ font-size: 0.6875rem;
1473
+ font-weight: 700;
1474
+ letter-spacing: 0.16em;
1475
+ text-transform: uppercase;
1476
+ line-height: 1;
1477
+ border-radius: 14px 14px 0 0;
1478
+ pointer-events: none;
1479
+ z-index: 1;
1480
+ box-sizing: border-box;
1481
+ }
1482
+
1483
+ /* The eyebrow text comes from `--mojo-eyebrow` set inline on the modal
1484
+ root by each Modal helper (alert / confirm / prompt / show / form / etc.).
1485
+ No per-type CSS rules needed — every helper passes its own default. */
1486
+
1487
+ /* Warning band uses dark text on yellow for AAA contrast */
1488
+ .modal.modal-alert.modal-alert-warning .modal-content::before { color: #1a1a1a; }
1489
+
1490
+ /* Primary action button picks up the type color so visual hierarchy is
1491
+ consistent: red band → red button, green band → green button, etc.
1492
+ --mojo-current-accent cascades from .modal-content. */
1493
+ .modal.modal-alert .modal-footer .btn-primary {
1494
+ --bs-btn-bg: var(--mojo-current-accent);
1495
+ --bs-btn-border-color: var(--mojo-current-accent);
1496
+ --bs-btn-hover-bg: color-mix(in srgb, var(--mojo-current-accent) 88%, #000);
1497
+ --bs-btn-hover-border-color: color-mix(in srgb, var(--mojo-current-accent) 85%, #000);
1498
+ --bs-btn-active-bg: color-mix(in srgb, var(--mojo-current-accent) 80%, #000);
1499
+ --bs-btn-active-border-color: color-mix(in srgb, var(--mojo-current-accent) 78%, #000);
1500
+ }
1501
+
1502
+ /* Warning button needs dark text on yellow for AAA contrast */
1503
+ .modal.modal-alert.modal-alert-warning .modal-footer .btn-primary {
1504
+ --bs-btn-color: #1a1a1a;
1505
+ --bs-btn-hover-color: #1a1a1a;
1506
+ --bs-btn-active-color: #1a1a1a;
1507
+ }
1508
+
1509
+ /* Header — flush against the band, no divider of its own
1510
+ (the band + card-bg communicate the boundary). */
1511
+ .modal-header {
1512
+ position: relative;
1513
+ border-bottom: none;
1514
+ border-radius: 14px 14px 0 0;
1515
+ background: transparent;
1516
+ padding: calc(0.75rem + 28px) 1.5rem 0.5rem;
1517
+ }
1518
+
1519
+ /* Modal title — when present in the header (i.e. not auto-suppressed
1520
+ because it duplicated the eyebrow), render as a bold sans headline. */
1521
+ .modal-header .modal-title {
1522
+ font-size: 1.125rem;
1523
+ font-weight: 700;
1524
+ letter-spacing: -0.015em;
1525
+ line-height: 1.3;
1526
+ margin: 0;
1527
+ }
1528
+
1529
+ /* Close X — anchored to the right side of the hero band itself. The
1530
+ band has pointer-events: none; the X sits above it (z-index) so
1531
+ clicks register. White on most bands; dark on warning. */
1532
+ .modal-header .btn-close {
1533
+ position: absolute;
1534
+ top: 0;
1535
+ right: 0.5rem;
1536
+ width: 28px;
1537
+ height: 28px;
1538
+ padding: 0;
1539
+ margin: 0;
1540
+ background-color: transparent;
1541
+ background-size: 10px;
1542
+ border-radius: 6px;
1543
+ opacity: 0.85;
1544
+ z-index: 2;
1545
+ /* Invert the default Bootstrap close-icon SVG so it's white on
1546
+ colored bands. Warning override below restores dark. */
1547
+ filter: brightness(0) invert(1);
1548
+ transition: opacity 0.15s ease-in-out, background-color 0.15s ease-in-out;
1549
+ }
1550
+ .modal-header .btn-close:hover {
1551
+ opacity: 1;
1552
+ background-color: rgba(255, 255, 255, 0.18);
1553
+ }
1554
+ .modal-header .btn-close:focus {
1555
+ opacity: 1;
1556
+ outline: none;
1557
+ box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.6);
1558
+ }
1559
+
1560
+ /* Warning band uses dark text; restore dark X glyph too */
1561
+ .modal.modal-alert.modal-alert-warning .modal-header .btn-close {
1562
+ filter: none;
1563
+ }
1564
+ .modal.modal-alert.modal-alert-warning .modal-header .btn-close:hover {
1565
+ background-color: rgba(0, 0, 0, 0.1);
1566
+ }
1567
+
1568
+ /* Footer — clean, no divider line; band/tinted bg already separates regions */
1569
+ .modal-content .modal-footer {
1570
+ border-top: none;
1571
+ padding: 0.5rem 1.5rem 1.25rem;
1572
+ }
1573
+ .modal-content .modal-body {
1574
+ padding: 0.25rem 1.5rem 1rem;
1575
+ }
1576
+
1577
+ /* Modals without a header still need the band to clear the body padding */
1578
+ .modal-content > .modal-body:first-child {
1579
+ padding-top: calc(1rem + 28px);
1580
+ }
1581
+
1582
+ /* Bandless modals — caller supplied their own header content/view or disabled
1583
+ the header entirely. ModalView adds `modal-bandless` to the .modal root in
1584
+ those cases. Hide the hero band and drop the band-related top padding so
1585
+ custom header chrome paints flush against the rounded top corners. */
1586
+ .modal.modal-bandless .modal-content::before { display: none; }
1587
+ .modal.modal-bandless .modal-header { padding: 0.75rem 1.5rem 0.5rem; }
1588
+ .modal.modal-bandless .modal-content > .modal-body:first-child { padding-top: 1rem; }
1589
+
1590
+ /* ── Typed alerts ──────────────────────────────────────────
1591
+ Root class (modal-alert modal-alert-{type}) is set by Modal.alert.
1592
+ Each type swaps --mojo-current-accent on .modal-content; everything else
1593
+ (band, tinted bg, focus ring, primary buttons) reads from that token. */
1594
+
1595
+ .modal.modal-alert.modal-alert-success .modal-content { --mojo-current-accent: var(--mojo-dialog-success); }
1596
+ .modal.modal-alert.modal-alert-warning .modal-content { --mojo-current-accent: var(--mojo-dialog-warning); }
1597
+ .modal.modal-alert.modal-alert-error .modal-content { --mojo-current-accent: var(--mojo-dialog-error); }
1598
+
1599
+ /* Title typography for typed alerts — eyebrow micro-label above headline.
1600
+ Both spans live inside Bootstrap's <h5 class="modal-title"> wrapper; we
1601
+ reset that h5 so our spans control the styling. */
1602
+ .modal.modal-alert .modal-title {
1603
+ display: block;
1604
+ font-size: inherit;
1605
+ font-weight: inherit;
1606
+ line-height: inherit;
1607
+ margin: 0;
1608
+ padding-right: 1.75rem; /* clear the close X */
1609
+ }
1610
+
1611
+ /* Headline = the actual title text. The hero band's eyebrow carries the
1612
+ type label; the headline is just the user-supplied title. */
1613
+ .modal-alert-headline {
1614
+ display: block;
1615
+ font-size: 1.125rem;
1616
+ font-weight: 700;
1617
+ letter-spacing: -0.015em;
1618
+ line-height: 1.3;
1619
+ color: var(--bs-body-color, #212529);
1620
+ }
1621
+
1622
+ .modal.modal-alert .modal-body .modal-alert-message {
1623
+ margin: 0;
1624
+ font-size: 0.9375rem;
1625
+ line-height: 1.55;
1626
+ color: var(--bs-secondary-color, #5b6478);
1627
+ }
1628
+
1629
+ /* Backwards-compat: any inline `<i class="bi">` still passed in via custom
1630
+ title HTML just renders inline (no synthetic colored circle). */
1631
+ .modal.modal-alert .modal-title i.bi {
1632
+ margin-right: 0.4rem;
1633
+ vertical-align: -0.05em;
1634
+ }
1635
+
1636
+ /* ── Dark mode ─────────────────────────────────────────────
1637
+ Brighter accents read against dark surfaces; tint bumped 5% → 10%
1638
+ because dark backgrounds absorb color. */
1639
+ @media (prefers-color-scheme: dark) {
1640
+ :root {
1641
+ --mojo-dialog-success: #4ade80;
1642
+ --mojo-dialog-warning: #fbbf24;
1643
+ --mojo-dialog-error: #f87171;
1644
+ }
1645
+ .modal-content {
1646
+ box-shadow:
1647
+ 0 1px 0 rgba(0, 0, 0, 0.4),
1648
+ 0 24px 60px -16px rgba(0, 0, 0, 0.6);
1649
+ background:
1650
+ linear-gradient(
1651
+ 180deg,
1652
+ color-mix(in srgb, var(--mojo-current-accent) 10%, var(--bs-modal-bg, #14181f)) 0%,
1653
+ var(--bs-modal-bg, #14181f) 100%
1654
+ );
1655
+ }
1656
+ .modal-header {
1657
+ border-bottom-color: rgba(255, 255, 255, 0.08);
1658
+ }
1659
+ .modal-header .btn-close:hover {
1660
+ background-color: rgba(255, 255, 255, 0.08);
1661
+ }
1662
+ }
1663
+
1664
+ /* Same rules under explicit Bootstrap dark theme attribute */
1665
+ [data-bs-theme="dark"] .modal-content {
1666
+ box-shadow:
1667
+ 0 1px 0 rgba(0, 0, 0, 0.4),
1668
+ 0 24px 60px -16px rgba(0, 0, 0, 0.6);
1669
+ background:
1670
+ linear-gradient(
1671
+ 180deg,
1672
+ color-mix(in srgb, var(--mojo-current-accent) 10%, var(--bs-modal-bg, #14181f)) 0%,
1673
+ var(--bs-modal-bg, #14181f) 100%
1674
+ );
1675
+ }
1676
+ [data-bs-theme="dark"] .modal-header {
1677
+ border-bottom-color: rgba(255, 255, 255, 0.08);
1678
+ }
1679
+ [data-bs-theme="dark"] .modal-header .btn-close:hover {
1680
+ background-color: rgba(255, 255, 255, 0.08);
1681
+ }
1682
+
1377
1683
  /* ========================================================================
1378
1684
  Field Status Indicators
1379
1685
  ======================================================================== */