@multiplatform.one/backoffice 6.4.0 → 6.4.2

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 (325) hide show
  1. package/dist/cjs/chrome/CommandPalette.cjs +20 -9
  2. package/dist/cjs/chrome/CommandPalette.native.js +18 -10
  3. package/dist/cjs/chrome/CommandPalette.native.js.map +1 -1
  4. package/dist/cjs/i18n/en.cjs +21 -0
  5. package/dist/cjs/i18n/en.native.js +21 -0
  6. package/dist/cjs/i18n/en.native.js.map +1 -1
  7. package/dist/cjs/index.cjs +49 -1
  8. package/dist/cjs/index.native.js +48 -0
  9. package/dist/cjs/index.native.js.map +1 -1
  10. package/dist/cjs/shared/types.cjs +18 -0
  11. package/dist/cjs/shared/types.native.js +21 -0
  12. package/dist/cjs/shared/types.native.js.map +1 -0
  13. package/dist/cjs/shared/useDocinfo.cjs +116 -0
  14. package/dist/cjs/shared/useDocinfo.native.js +167 -0
  15. package/dist/cjs/shared/useDocinfo.native.js.map +1 -0
  16. package/dist/cjs/shared/useDoctypeMeta.cjs +124 -0
  17. package/dist/cjs/shared/useDoctypeMeta.native.js +158 -0
  18. package/dist/cjs/shared/useDoctypeMeta.native.js.map +1 -0
  19. package/dist/cjs/shared/useRecentVisit.cjs +40 -0
  20. package/dist/cjs/shared/useRecentVisit.native.js +43 -0
  21. package/dist/cjs/shared/useRecentVisit.native.js.map +1 -0
  22. package/dist/cjs/shared/useSessionUserId.cjs +54 -0
  23. package/dist/cjs/shared/useSessionUserId.native.js +59 -0
  24. package/dist/cjs/shared/useSessionUserId.native.js.map +1 -0
  25. package/dist/cjs/shared/useSlugTarget.cjs +138 -0
  26. package/dist/cjs/shared/useSlugTarget.native.js +166 -0
  27. package/dist/cjs/shared/useSlugTarget.native.js.map +1 -0
  28. package/dist/cjs/shared/useUserRoles.cjs +72 -0
  29. package/dist/cjs/shared/useUserRoles.native.js +79 -0
  30. package/dist/cjs/shared/useUserRoles.native.js.map +1 -0
  31. package/dist/cjs/workspace/WorkspaceChartBlock.cjs +136 -0
  32. package/dist/cjs/workspace/WorkspaceChartBlock.native.js +144 -0
  33. package/dist/cjs/workspace/WorkspaceChartBlock.native.js.map +1 -0
  34. package/dist/cjs/workspace/WorkspaceGrid.cjs +91 -0
  35. package/dist/cjs/workspace/WorkspaceGrid.native.js +126 -0
  36. package/dist/cjs/workspace/WorkspaceGrid.native.js.map +1 -0
  37. package/dist/cjs/workspace/WorkspaceLinkCard.cjs +139 -0
  38. package/dist/cjs/workspace/WorkspaceLinkCard.native.js +155 -0
  39. package/dist/cjs/workspace/WorkspaceLinkCard.native.js.map +1 -0
  40. package/dist/cjs/workspace/WorkspaceLinkDirectory.cjs +110 -0
  41. package/dist/cjs/workspace/WorkspaceLinkDirectory.native.js +127 -0
  42. package/dist/cjs/workspace/WorkspaceLinkDirectory.native.js.map +1 -0
  43. package/dist/cjs/workspace/WorkspaceNumberCard.cjs +133 -0
  44. package/dist/cjs/workspace/WorkspaceNumberCard.native.js +138 -0
  45. package/dist/cjs/workspace/WorkspaceNumberCard.native.js.map +1 -0
  46. package/dist/cjs/workspace/WorkspaceQuickList.cjs +112 -0
  47. package/dist/cjs/workspace/WorkspaceQuickList.native.js +130 -0
  48. package/dist/cjs/workspace/WorkspaceQuickList.native.js.map +1 -0
  49. package/dist/cjs/workspace/WorkspaceRecents.cjs +116 -0
  50. package/dist/cjs/workspace/WorkspaceRecents.native.js +132 -0
  51. package/dist/cjs/workspace/WorkspaceRecents.native.js.map +1 -0
  52. package/dist/cjs/workspace/WorkspaceScreen.cjs +291 -0
  53. package/dist/cjs/workspace/WorkspaceScreen.native.js +323 -0
  54. package/dist/cjs/workspace/WorkspaceScreen.native.js.map +1 -0
  55. package/dist/cjs/workspace/WorkspaceShortcut.cjs +185 -0
  56. package/dist/cjs/workspace/WorkspaceShortcut.native.js +202 -0
  57. package/dist/cjs/workspace/WorkspaceShortcut.native.js.map +1 -0
  58. package/dist/cjs/workspace/parseContent.cjs +180 -0
  59. package/dist/cjs/workspace/parseContent.native.js +299 -0
  60. package/dist/cjs/workspace/parseContent.native.js.map +1 -0
  61. package/dist/cjs/workspace/types.cjs +18 -0
  62. package/dist/cjs/workspace/types.native.js +21 -0
  63. package/dist/cjs/workspace/types.native.js.map +1 -0
  64. package/dist/cjs/workspace/useDashboardChart.cjs +96 -0
  65. package/dist/cjs/workspace/useDashboardChart.native.js +110 -0
  66. package/dist/cjs/workspace/useDashboardChart.native.js.map +1 -0
  67. package/dist/cjs/workspace/useWorkspaceDoc.cjs +103 -0
  68. package/dist/cjs/workspace/useWorkspaceDoc.native.js +120 -0
  69. package/dist/cjs/workspace/useWorkspaceDoc.native.js.map +1 -0
  70. package/dist/esm/chrome/CommandPalette.mjs +20 -9
  71. package/dist/esm/chrome/CommandPalette.mjs.map +1 -1
  72. package/dist/esm/chrome/CommandPalette.native.js +18 -10
  73. package/dist/esm/chrome/CommandPalette.native.js.map +1 -1
  74. package/dist/esm/i18n/en.mjs +21 -0
  75. package/dist/esm/i18n/en.mjs.map +1 -1
  76. package/dist/esm/i18n/en.native.js +21 -0
  77. package/dist/esm/i18n/en.native.js.map +1 -1
  78. package/dist/esm/index.mjs +19 -1
  79. package/dist/esm/index.mjs.map +1 -1
  80. package/dist/esm/index.native.js +19 -1
  81. package/dist/esm/index.native.js.map +1 -1
  82. package/dist/esm/shared/types.mjs +2 -0
  83. package/dist/esm/shared/types.mjs.map +1 -0
  84. package/dist/esm/shared/types.native.js +2 -0
  85. package/dist/esm/shared/types.native.js.map +1 -0
  86. package/dist/esm/shared/useDocinfo.mjs +90 -0
  87. package/dist/esm/shared/useDocinfo.mjs.map +1 -0
  88. package/dist/esm/shared/useDocinfo.native.js +138 -0
  89. package/dist/esm/shared/useDocinfo.native.js.map +1 -0
  90. package/dist/esm/shared/useDoctypeMeta.mjs +99 -0
  91. package/dist/esm/shared/useDoctypeMeta.mjs.map +1 -0
  92. package/dist/esm/shared/useDoctypeMeta.native.js +130 -0
  93. package/dist/esm/shared/useDoctypeMeta.native.js.map +1 -0
  94. package/dist/esm/shared/useRecentVisit.mjs +15 -0
  95. package/dist/esm/shared/useRecentVisit.mjs.map +1 -0
  96. package/dist/esm/shared/useRecentVisit.native.js +15 -0
  97. package/dist/esm/shared/useRecentVisit.native.js.map +1 -0
  98. package/dist/esm/shared/useSessionUserId.mjs +29 -0
  99. package/dist/esm/shared/useSessionUserId.mjs.map +1 -0
  100. package/dist/esm/shared/useSessionUserId.native.js +31 -0
  101. package/dist/esm/shared/useSessionUserId.native.js.map +1 -0
  102. package/dist/esm/shared/useSlugTarget.mjs +113 -0
  103. package/dist/esm/shared/useSlugTarget.mjs.map +1 -0
  104. package/dist/esm/shared/useSlugTarget.native.js +138 -0
  105. package/dist/esm/shared/useSlugTarget.native.js.map +1 -0
  106. package/dist/esm/shared/useUserRoles.mjs +47 -0
  107. package/dist/esm/shared/useUserRoles.mjs.map +1 -0
  108. package/dist/esm/shared/useUserRoles.native.js +51 -0
  109. package/dist/esm/shared/useUserRoles.native.js.map +1 -0
  110. package/dist/esm/workspace/WorkspaceChartBlock.mjs +111 -0
  111. package/dist/esm/workspace/WorkspaceChartBlock.mjs.map +1 -0
  112. package/dist/esm/workspace/WorkspaceChartBlock.native.js +116 -0
  113. package/dist/esm/workspace/WorkspaceChartBlock.native.js.map +1 -0
  114. package/dist/esm/workspace/WorkspaceGrid.mjs +66 -0
  115. package/dist/esm/workspace/WorkspaceGrid.mjs.map +1 -0
  116. package/dist/esm/workspace/WorkspaceGrid.native.js +98 -0
  117. package/dist/esm/workspace/WorkspaceGrid.native.js.map +1 -0
  118. package/dist/esm/workspace/WorkspaceLinkCard.mjs +113 -0
  119. package/dist/esm/workspace/WorkspaceLinkCard.mjs.map +1 -0
  120. package/dist/esm/workspace/WorkspaceLinkCard.native.js +126 -0
  121. package/dist/esm/workspace/WorkspaceLinkCard.native.js.map +1 -0
  122. package/dist/esm/workspace/WorkspaceLinkDirectory.mjs +84 -0
  123. package/dist/esm/workspace/WorkspaceLinkDirectory.mjs.map +1 -0
  124. package/dist/esm/workspace/WorkspaceLinkDirectory.native.js +98 -0
  125. package/dist/esm/workspace/WorkspaceLinkDirectory.native.js.map +1 -0
  126. package/dist/esm/workspace/WorkspaceNumberCard.mjs +108 -0
  127. package/dist/esm/workspace/WorkspaceNumberCard.mjs.map +1 -0
  128. package/dist/esm/workspace/WorkspaceNumberCard.native.js +110 -0
  129. package/dist/esm/workspace/WorkspaceNumberCard.native.js.map +1 -0
  130. package/dist/esm/workspace/WorkspaceQuickList.mjs +87 -0
  131. package/dist/esm/workspace/WorkspaceQuickList.mjs.map +1 -0
  132. package/dist/esm/workspace/WorkspaceQuickList.native.js +102 -0
  133. package/dist/esm/workspace/WorkspaceQuickList.native.js.map +1 -0
  134. package/dist/esm/workspace/WorkspaceRecents.mjs +91 -0
  135. package/dist/esm/workspace/WorkspaceRecents.mjs.map +1 -0
  136. package/dist/esm/workspace/WorkspaceRecents.native.js +104 -0
  137. package/dist/esm/workspace/WorkspaceRecents.native.js.map +1 -0
  138. package/dist/esm/workspace/WorkspaceScreen.mjs +266 -0
  139. package/dist/esm/workspace/WorkspaceScreen.mjs.map +1 -0
  140. package/dist/esm/workspace/WorkspaceScreen.native.js +295 -0
  141. package/dist/esm/workspace/WorkspaceScreen.native.js.map +1 -0
  142. package/dist/esm/workspace/WorkspaceShortcut.mjs +159 -0
  143. package/dist/esm/workspace/WorkspaceShortcut.mjs.map +1 -0
  144. package/dist/esm/workspace/WorkspaceShortcut.native.js +173 -0
  145. package/dist/esm/workspace/WorkspaceShortcut.native.js.map +1 -0
  146. package/dist/esm/workspace/parseContent.mjs +148 -0
  147. package/dist/esm/workspace/parseContent.mjs.map +1 -0
  148. package/dist/esm/workspace/parseContent.native.js +264 -0
  149. package/dist/esm/workspace/parseContent.native.js.map +1 -0
  150. package/dist/esm/workspace/types.mjs +2 -0
  151. package/dist/esm/workspace/types.mjs.map +1 -0
  152. package/dist/esm/workspace/types.native.js +2 -0
  153. package/dist/esm/workspace/types.native.js.map +1 -0
  154. package/dist/esm/workspace/useDashboardChart.mjs +71 -0
  155. package/dist/esm/workspace/useDashboardChart.mjs.map +1 -0
  156. package/dist/esm/workspace/useDashboardChart.native.js +82 -0
  157. package/dist/esm/workspace/useDashboardChart.native.js.map +1 -0
  158. package/dist/esm/workspace/useWorkspaceDoc.mjs +77 -0
  159. package/dist/esm/workspace/useWorkspaceDoc.mjs.map +1 -0
  160. package/dist/esm/workspace/useWorkspaceDoc.native.js +91 -0
  161. package/dist/esm/workspace/useWorkspaceDoc.native.js.map +1 -0
  162. package/dist/jsx/chrome/CommandPalette.mjs +20 -9
  163. package/dist/jsx/chrome/CommandPalette.mjs.map +1 -1
  164. package/dist/jsx/chrome/CommandPalette.native.js +18 -10
  165. package/dist/jsx/chrome/CommandPalette.native.js.map +1 -1
  166. package/dist/jsx/i18n/en.mjs +21 -0
  167. package/dist/jsx/i18n/en.mjs.map +1 -1
  168. package/dist/jsx/i18n/en.native.js +21 -0
  169. package/dist/jsx/i18n/en.native.js.map +1 -1
  170. package/dist/jsx/index.js +19 -1
  171. package/dist/jsx/index.js.map +1 -1
  172. package/dist/jsx/index.mjs +19 -1
  173. package/dist/jsx/index.mjs.map +1 -1
  174. package/dist/jsx/index.native.js +48 -0
  175. package/dist/jsx/index.native.js.map +1 -1
  176. package/dist/jsx/shared/types.mjs +2 -0
  177. package/dist/jsx/shared/types.mjs.map +1 -0
  178. package/dist/jsx/shared/types.native.js +21 -0
  179. package/dist/jsx/shared/types.native.js.map +1 -0
  180. package/dist/jsx/shared/useDocinfo.mjs +90 -0
  181. package/dist/jsx/shared/useDocinfo.mjs.map +1 -0
  182. package/dist/jsx/shared/useDocinfo.native.js +167 -0
  183. package/dist/jsx/shared/useDocinfo.native.js.map +1 -0
  184. package/dist/jsx/shared/useDoctypeMeta.mjs +99 -0
  185. package/dist/jsx/shared/useDoctypeMeta.mjs.map +1 -0
  186. package/dist/jsx/shared/useDoctypeMeta.native.js +158 -0
  187. package/dist/jsx/shared/useDoctypeMeta.native.js.map +1 -0
  188. package/dist/jsx/shared/useRecentVisit.mjs +15 -0
  189. package/dist/jsx/shared/useRecentVisit.mjs.map +1 -0
  190. package/dist/jsx/shared/useRecentVisit.native.js +43 -0
  191. package/dist/jsx/shared/useRecentVisit.native.js.map +1 -0
  192. package/dist/jsx/shared/useSessionUserId.mjs +29 -0
  193. package/dist/jsx/shared/useSessionUserId.mjs.map +1 -0
  194. package/dist/jsx/shared/useSessionUserId.native.js +59 -0
  195. package/dist/jsx/shared/useSessionUserId.native.js.map +1 -0
  196. package/dist/jsx/shared/useSlugTarget.mjs +113 -0
  197. package/dist/jsx/shared/useSlugTarget.mjs.map +1 -0
  198. package/dist/jsx/shared/useSlugTarget.native.js +166 -0
  199. package/dist/jsx/shared/useSlugTarget.native.js.map +1 -0
  200. package/dist/jsx/shared/useUserRoles.mjs +47 -0
  201. package/dist/jsx/shared/useUserRoles.mjs.map +1 -0
  202. package/dist/jsx/shared/useUserRoles.native.js +79 -0
  203. package/dist/jsx/shared/useUserRoles.native.js.map +1 -0
  204. package/dist/jsx/workspace/WorkspaceChartBlock.mjs +111 -0
  205. package/dist/jsx/workspace/WorkspaceChartBlock.mjs.map +1 -0
  206. package/dist/jsx/workspace/WorkspaceChartBlock.native.js +144 -0
  207. package/dist/jsx/workspace/WorkspaceChartBlock.native.js.map +1 -0
  208. package/dist/jsx/workspace/WorkspaceGrid.mjs +66 -0
  209. package/dist/jsx/workspace/WorkspaceGrid.mjs.map +1 -0
  210. package/dist/jsx/workspace/WorkspaceGrid.native.js +126 -0
  211. package/dist/jsx/workspace/WorkspaceGrid.native.js.map +1 -0
  212. package/dist/jsx/workspace/WorkspaceLinkCard.mjs +113 -0
  213. package/dist/jsx/workspace/WorkspaceLinkCard.mjs.map +1 -0
  214. package/dist/jsx/workspace/WorkspaceLinkCard.native.js +155 -0
  215. package/dist/jsx/workspace/WorkspaceLinkCard.native.js.map +1 -0
  216. package/dist/jsx/workspace/WorkspaceLinkDirectory.mjs +84 -0
  217. package/dist/jsx/workspace/WorkspaceLinkDirectory.mjs.map +1 -0
  218. package/dist/jsx/workspace/WorkspaceLinkDirectory.native.js +127 -0
  219. package/dist/jsx/workspace/WorkspaceLinkDirectory.native.js.map +1 -0
  220. package/dist/jsx/workspace/WorkspaceNumberCard.mjs +108 -0
  221. package/dist/jsx/workspace/WorkspaceNumberCard.mjs.map +1 -0
  222. package/dist/jsx/workspace/WorkspaceNumberCard.native.js +138 -0
  223. package/dist/jsx/workspace/WorkspaceNumberCard.native.js.map +1 -0
  224. package/dist/jsx/workspace/WorkspaceQuickList.mjs +87 -0
  225. package/dist/jsx/workspace/WorkspaceQuickList.mjs.map +1 -0
  226. package/dist/jsx/workspace/WorkspaceQuickList.native.js +130 -0
  227. package/dist/jsx/workspace/WorkspaceQuickList.native.js.map +1 -0
  228. package/dist/jsx/workspace/WorkspaceRecents.mjs +91 -0
  229. package/dist/jsx/workspace/WorkspaceRecents.mjs.map +1 -0
  230. package/dist/jsx/workspace/WorkspaceRecents.native.js +132 -0
  231. package/dist/jsx/workspace/WorkspaceRecents.native.js.map +1 -0
  232. package/dist/jsx/workspace/WorkspaceScreen.mjs +266 -0
  233. package/dist/jsx/workspace/WorkspaceScreen.mjs.map +1 -0
  234. package/dist/jsx/workspace/WorkspaceScreen.native.js +323 -0
  235. package/dist/jsx/workspace/WorkspaceScreen.native.js.map +1 -0
  236. package/dist/jsx/workspace/WorkspaceShortcut.mjs +159 -0
  237. package/dist/jsx/workspace/WorkspaceShortcut.mjs.map +1 -0
  238. package/dist/jsx/workspace/WorkspaceShortcut.native.js +202 -0
  239. package/dist/jsx/workspace/WorkspaceShortcut.native.js.map +1 -0
  240. package/dist/jsx/workspace/parseContent.mjs +148 -0
  241. package/dist/jsx/workspace/parseContent.mjs.map +1 -0
  242. package/dist/jsx/workspace/parseContent.native.js +299 -0
  243. package/dist/jsx/workspace/parseContent.native.js.map +1 -0
  244. package/dist/jsx/workspace/types.mjs +2 -0
  245. package/dist/jsx/workspace/types.mjs.map +1 -0
  246. package/dist/jsx/workspace/types.native.js +21 -0
  247. package/dist/jsx/workspace/types.native.js.map +1 -0
  248. package/dist/jsx/workspace/useDashboardChart.mjs +71 -0
  249. package/dist/jsx/workspace/useDashboardChart.mjs.map +1 -0
  250. package/dist/jsx/workspace/useDashboardChart.native.js +110 -0
  251. package/dist/jsx/workspace/useDashboardChart.native.js.map +1 -0
  252. package/dist/jsx/workspace/useWorkspaceDoc.mjs +77 -0
  253. package/dist/jsx/workspace/useWorkspaceDoc.mjs.map +1 -0
  254. package/dist/jsx/workspace/useWorkspaceDoc.native.js +120 -0
  255. package/dist/jsx/workspace/useWorkspaceDoc.native.js.map +1 -0
  256. package/package.json +12 -12
  257. package/src/chrome/CommandPalette.tsx +35 -15
  258. package/src/i18n/en.ts +21 -0
  259. package/src/index.ts +69 -0
  260. package/src/shared/types.ts +14 -0
  261. package/src/shared/useDocinfo.ts +163 -0
  262. package/src/shared/useDoctypeMeta.ts +243 -0
  263. package/src/shared/useRecentVisit.ts +33 -0
  264. package/src/shared/useSessionUserId.ts +42 -0
  265. package/src/shared/useSlugTarget.ts +143 -0
  266. package/src/shared/useUserRoles.ts +66 -0
  267. package/src/workspace/WorkspaceChartBlock.tsx +115 -0
  268. package/src/workspace/WorkspaceGrid.tsx +82 -0
  269. package/src/workspace/WorkspaceLinkCard.tsx +134 -0
  270. package/src/workspace/WorkspaceLinkDirectory.tsx +126 -0
  271. package/src/workspace/WorkspaceNumberCard.tsx +126 -0
  272. package/src/workspace/WorkspaceQuickList.tsx +100 -0
  273. package/src/workspace/WorkspaceRecents.tsx +100 -0
  274. package/src/workspace/WorkspaceScreen.tsx +322 -0
  275. package/src/workspace/WorkspaceShortcut.tsx +223 -0
  276. package/src/workspace/parseContent.spec.ts +327 -0
  277. package/src/workspace/parseContent.ts +240 -0
  278. package/src/workspace/types.ts +135 -0
  279. package/src/workspace/useDashboardChart.ts +115 -0
  280. package/src/workspace/useWorkspaceDoc.ts +111 -0
  281. package/types/chrome/CommandPalette.d.ts.map +1 -1
  282. package/types/i18n/en.d.ts +19 -0
  283. package/types/i18n/en.d.ts.map +1 -1
  284. package/types/index.d.ts +34 -0
  285. package/types/index.d.ts.map +1 -1
  286. package/types/shared/types.d.ts +21 -0
  287. package/types/shared/types.d.ts.map +1 -0
  288. package/types/shared/useDocinfo.d.ts +61 -0
  289. package/types/shared/useDocinfo.d.ts.map +1 -0
  290. package/types/shared/useDoctypeMeta.d.ts +118 -0
  291. package/types/shared/useDoctypeMeta.d.ts.map +1 -0
  292. package/types/shared/useRecentVisit.d.ts +10 -0
  293. package/types/shared/useRecentVisit.d.ts.map +1 -0
  294. package/types/shared/useSessionUserId.d.ts +6 -0
  295. package/types/shared/useSessionUserId.d.ts.map +1 -0
  296. package/types/shared/useSlugTarget.d.ts +18 -0
  297. package/types/shared/useSlugTarget.d.ts.map +1 -0
  298. package/types/shared/useUserRoles.d.ts +15 -0
  299. package/types/shared/useUserRoles.d.ts.map +1 -0
  300. package/types/workspace/WorkspaceChartBlock.d.ts +6 -0
  301. package/types/workspace/WorkspaceChartBlock.d.ts.map +1 -0
  302. package/types/workspace/WorkspaceGrid.d.ts +23 -0
  303. package/types/workspace/WorkspaceGrid.d.ts.map +1 -0
  304. package/types/workspace/WorkspaceLinkCard.d.ts +20 -0
  305. package/types/workspace/WorkspaceLinkCard.d.ts.map +1 -0
  306. package/types/workspace/WorkspaceLinkDirectory.d.ts +19 -0
  307. package/types/workspace/WorkspaceLinkDirectory.d.ts.map +1 -0
  308. package/types/workspace/WorkspaceNumberCard.d.ts +19 -0
  309. package/types/workspace/WorkspaceNumberCard.d.ts.map +1 -0
  310. package/types/workspace/WorkspaceQuickList.d.ts +6 -0
  311. package/types/workspace/WorkspaceQuickList.d.ts.map +1 -0
  312. package/types/workspace/WorkspaceRecents.d.ts +2 -0
  313. package/types/workspace/WorkspaceRecents.d.ts.map +1 -0
  314. package/types/workspace/WorkspaceScreen.d.ts +24 -0
  315. package/types/workspace/WorkspaceScreen.d.ts.map +1 -0
  316. package/types/workspace/WorkspaceShortcut.d.ts +27 -0
  317. package/types/workspace/WorkspaceShortcut.d.ts.map +1 -0
  318. package/types/workspace/parseContent.d.ts +77 -0
  319. package/types/workspace/parseContent.d.ts.map +1 -0
  320. package/types/workspace/types.d.ts +112 -0
  321. package/types/workspace/types.d.ts.map +1 -0
  322. package/types/workspace/useDashboardChart.d.ts +29 -0
  323. package/types/workspace/useDashboardChart.d.ts.map +1 -0
  324. package/types/workspace/useWorkspaceDoc.d.ts +18 -0
  325. package/types/workspace/useWorkspaceDoc.d.ts.map +1 -0
@@ -0,0 +1,82 @@
1
+ /**
2
+ * 12-column workspace grid — desk parity for the editorjs block layout.
3
+ *
4
+ * Blocks carry a `col` span (3 = shortcut, 4 = card, 12 = full row).
5
+ * Consecutive blocks accumulate into rows of up to 12 columns and each row
6
+ * lays out with flex ratios, so no pixel math is needed. The container
7
+ * measures itself with `onLayout` (cross-platform — no media queries, no
8
+ * DOM) and collapses spans on narrow widths: everything full-width on
9
+ * phones, two-up on mid widths, desk's ~3–4 column layout when wide.
10
+ */
11
+ import { XStack, YStack, type YStackProps } from "@multiplatform.one/components";
12
+ import { useResolvedKnobs } from "@multiplatform.one/theme";
13
+ import { useState, type ReactNode } from "react";
14
+
15
+ /** Container width below which every block is full-width. */
16
+ const NARROW_MAX = 640;
17
+ /** Container width below which small blocks go two-up. */
18
+ const MEDIUM_MAX = 960;
19
+
20
+ export interface WorkspaceGridItem {
21
+ key: string;
22
+ /** 12-column span requested by the block (defaults to 12). */
23
+ col?: number;
24
+ node: ReactNode;
25
+ }
26
+
27
+ function effectiveSpan(raw: number | undefined, width: number): number {
28
+ const span = Math.min(Math.max(Math.round(raw ?? 12), 1), 12);
29
+ if (width <= 0) return span; // not measured yet — desk-wide layout
30
+ if (width < NARROW_MAX) return 12;
31
+ if (width < MEDIUM_MAX) return span <= 6 ? 6 : 12;
32
+ return span;
33
+ }
34
+
35
+ export interface WorkspaceGridProps extends YStackProps {
36
+ items: WorkspaceGridItem[];
37
+ }
38
+
39
+ export function WorkspaceGrid({ items, ...stackProps }: WorkspaceGridProps) {
40
+ const { knobProps } = useResolvedKnobs();
41
+ const [width, setWidth] = useState(0);
42
+
43
+ // Chunk consecutive blocks into rows of up to 12 columns (desk behavior).
44
+ const rows: Array<Array<{ item: WorkspaceGridItem; span: number }>> = [];
45
+ let current: Array<{ item: WorkspaceGridItem; span: number }> = [];
46
+ let used = 0;
47
+ for (const item of items) {
48
+ const span = effectiveSpan(item.col, width);
49
+ if (used + span > 12 && current.length > 0) {
50
+ rows.push(current);
51
+ current = [];
52
+ used = 0;
53
+ }
54
+ current.push({ item, span });
55
+ used += span;
56
+ }
57
+ if (current.length > 0) rows.push(current);
58
+
59
+ return (
60
+ <YStack
61
+ {...knobProps.gap}
62
+ onLayout={(event) => setWidth(event.nativeEvent.layout.width)}
63
+ {...stackProps}
64
+ >
65
+ {rows.map((row, rowIndex) => {
66
+ const rowUsed = row.reduce((sum, cell) => sum + cell.span, 0);
67
+ return (
68
+ <XStack key={row[0]?.item.key ?? rowIndex} {...knobProps.gap} alignItems="stretch">
69
+ {row.map(({ item, span }) => (
70
+ <YStack key={item.key} flexGrow={span} flexShrink={1} flexBasis={0} minWidth={0}>
71
+ {item.node}
72
+ </YStack>
73
+ ))}
74
+ {/* Filler keeps a partial row's cells at their 12-col width
75
+ (a lone col-3 shortcut stays ~25%, like desk). */}
76
+ {rowUsed < 12 ? <YStack flexGrow={12 - rowUsed} flexBasis={0} /> : null}
77
+ </XStack>
78
+ );
79
+ })}
80
+ </YStack>
81
+ );
82
+ }
@@ -0,0 +1,134 @@
1
+ /**
2
+ * Workspace link card — desk parity for the `card` content block: a titled
3
+ * card listing the Link rows that follow the matching "Card Break" row in
4
+ * the `links` child table. DocType links navigate to the doctype list;
5
+ * Report/Page links go through the slug router best-effort (see
6
+ * `resolveLinkTarget`).
7
+ *
8
+ * Rendering gates: link rows targeting doctypes outside the provider's
9
+ * `doctypes` scope are hidden, and DocType/Report rows (list-surface
10
+ * navigations) are hidden entirely when the `views` capability is off.
11
+ */
12
+ import { Card, SizableText, XStack, YStack } from "@multiplatform.one/components";
13
+ import { useResolvedKnobs } from "@multiplatform.one/theme";
14
+ import { useTranslation } from "react-i18next";
15
+ import {
16
+ useBackofficeCapabilities,
17
+ useBackofficeNavigator,
18
+ useBackofficePaths,
19
+ useIsDoctypeAllowed,
20
+ } from "../config/BackofficeProvider";
21
+ import { BACKOFFICE_I18N_NAMESPACE } from "../i18n";
22
+ import { createBackofficePaths, type BackofficePaths } from "../navigation/paths";
23
+ import type { WorkspaceLinkGroup, WorkspaceLinkRow } from "./types";
24
+
25
+ const defaultPaths = createBackofficePaths();
26
+
27
+ /**
28
+ * Resolve a Workspace Link row to a router path (basePath-aware when the
29
+ * provider's `paths` are passed; defaults to the canonical "/backoffice").
30
+ * - DocType → paths.list(link_to)
31
+ * - Report → paths.list(link_to) fallback (no query-report route yet — the
32
+ * slug router decides; documented gap)
33
+ * - Page → `{base}/<link_to>` (page names are already slugs)
34
+ * - anything else → disabled
35
+ */
36
+ export function resolveLinkTarget(
37
+ row: WorkspaceLinkRow,
38
+ paths: BackofficePaths = defaultPaths,
39
+ ): {
40
+ path?: string;
41
+ disabled?: boolean;
42
+ } {
43
+ const target = row.link_to ?? "";
44
+ if (!target) return { disabled: true };
45
+ const prefix = paths.base === "/" ? "" : paths.base;
46
+ switch (row.link_type) {
47
+ case "DocType":
48
+ return { path: paths.list(target) };
49
+ case "Report":
50
+ return { path: paths.list(target) };
51
+ case "Page":
52
+ return { path: `${prefix}/${target}` };
53
+ default:
54
+ return { disabled: true };
55
+ }
56
+ }
57
+
58
+ function LinkRow({ row }: { row: WorkspaceLinkRow }) {
59
+ const navigator = useBackofficeNavigator();
60
+ const paths = useBackofficePaths();
61
+ const target = resolveLinkTarget(row, paths);
62
+ return (
63
+ <XStack
64
+ onPress={target.disabled ? undefined : () => target.path && navigator.navigate(target.path)}
65
+ disabled={target.disabled}
66
+ opacity={target.disabled ? 0.5 : 1}
67
+ cursor={target.disabled ? "default" : "pointer"}
68
+ paddingVertical="$1.5"
69
+ alignItems="center"
70
+ role="link"
71
+ aria-label={row.label}
72
+ hoverStyle={target.disabled ? undefined : { backgroundColor: "$color3" }}
73
+ borderRadius="$2"
74
+ >
75
+ <SizableText
76
+ size="$3"
77
+ color={target.disabled ? "$color10" : "$color12"}
78
+ numberOfLines={1}
79
+ flexShrink={1}
80
+ hoverStyle={target.disabled ? undefined : { color: "$color12" }}
81
+ >
82
+ {row.label}
83
+ </SizableText>
84
+ </XStack>
85
+ );
86
+ }
87
+
88
+ export interface WorkspaceLinkCardProps {
89
+ group: WorkspaceLinkGroup;
90
+ }
91
+
92
+ export function WorkspaceLinkCard({ group }: WorkspaceLinkCardProps) {
93
+ const { knobProps } = useResolvedKnobs();
94
+ const { t } = useTranslation(BACKOFFICE_I18N_NAMESPACE);
95
+ const { views } = useBackofficeCapabilities();
96
+ const isDoctypeAllowed = useIsDoctypeAllowed();
97
+
98
+ // Visibility gates: doctype scope + the views capability (DocType/Report
99
+ // rows navigate to list surfaces). Defaults (scope open, views on) keep
100
+ // every authored row, desk parity.
101
+ const visibleLinks = group.links.filter((row) => {
102
+ if (row.link_type === "DocType" || row.link_type === "Report") {
103
+ if (!views.enabled) return false;
104
+ if (row.link_type === "DocType" && row.link_to && !isDoctypeAllowed(row.link_to)) {
105
+ return false;
106
+ }
107
+ }
108
+ return true;
109
+ });
110
+
111
+ return (
112
+ <Card flexGrow={1} height="100%">
113
+ <YStack {...knobProps.panelPadding} {...knobProps.gap} flex={1}>
114
+ {/* Catalog list-group caption (Sidebar section-label treatment):
115
+ small-caps muted label, no underline rule — a full-width rule
116
+ under uneven columns read as table chrome (Axiom 16). */}
117
+ <SizableText size="$2" fontWeight="600" textTransform="uppercase" color="$color11">
118
+ {group.label}
119
+ </SizableText>
120
+ {visibleLinks.length === 0 ? (
121
+ <SizableText size="$2" color="$color10">
122
+ {t("workspaceCardEmpty", "No links in this section")}
123
+ </SizableText>
124
+ ) : (
125
+ <YStack>
126
+ {visibleLinks.map((row) => (
127
+ <LinkRow key={row.name} row={row} />
128
+ ))}
129
+ </YStack>
130
+ )}
131
+ </YStack>
132
+ </Card>
133
+ );
134
+ }
@@ -0,0 +1,126 @@
1
+ /**
2
+ * "Browse all" disclosure for the workspace link farm (MOD-11): the grouped
3
+ * link cards render inside one collapsible region with a local type-to-filter
4
+ * input, so 20–30 links stay fully reachable and searchable (capability
5
+ * parity with desk) without owning the top of the landing page. Expanded by
6
+ * default on desktop-width viewports, collapsed on phones and native.
7
+ */
8
+ import { EmptyState, Accordion, YStack } from "@multiplatform.one/components";
9
+ import { SearchInput, useViewportGtSm } from "@multiplatform.one/forms";
10
+ import { useResolvedKnobs } from "@multiplatform.one/theme";
11
+ import { useMemo, useState } from "react";
12
+ import { useTranslation } from "react-i18next";
13
+ import { BACKOFFICE_I18N_NAMESPACE } from "../i18n";
14
+ import type { WorkspaceLinkGroup } from "./types";
15
+ import { WorkspaceGrid, type WorkspaceGridItem } from "./WorkspaceGrid";
16
+ import { WorkspaceLinkCard } from "./WorkspaceLinkCard";
17
+
18
+ export interface WorkspaceLinkDirectoryItem {
19
+ /** Stable key from the authored card block. */
20
+ key: string;
21
+ /** Authored 12-column span (defaults to 4, desk's card width). */
22
+ col?: number;
23
+ group: WorkspaceLinkGroup;
24
+ }
25
+
26
+ export interface WorkspaceLinkDirectoryProps {
27
+ items: WorkspaceLinkDirectoryItem[];
28
+ }
29
+
30
+ const DIRECTORY_VALUE = "links";
31
+
32
+ /**
33
+ * Case-insensitive filter over a link group: a match on the group label
34
+ * keeps the whole card; otherwise the card narrows to its matching links
35
+ * (and disappears when none match).
36
+ */
37
+ export function filterLinkGroup(
38
+ group: WorkspaceLinkGroup,
39
+ query: string,
40
+ ): WorkspaceLinkGroup | undefined {
41
+ const needle = query.trim().toLowerCase();
42
+ if (!needle) return group;
43
+ if (group.label.toLowerCase().includes(needle)) return group;
44
+ const links = group.links.filter((row) => row.label.toLowerCase().includes(needle));
45
+ return links.length > 0 ? { ...group, links } : undefined;
46
+ }
47
+
48
+ export function WorkspaceLinkDirectory({ items }: WorkspaceLinkDirectoryProps) {
49
+ const { t } = useTranslation(BACKOFFICE_I18N_NAMESPACE);
50
+ const { knobProps } = useResolvedKnobs();
51
+ const viewportGtSm = useViewportGtSm();
52
+ const [filter, setFilter] = useState("");
53
+ // Uncontrolled-once default: open on desktop-width viewports, collapsed on
54
+ // phones/native (SPA render — the viewport is known at first render).
55
+ // Later resizes don't override the user's toggle.
56
+ const [openValue, setOpenValue] = useState(() => (viewportGtSm ? DIRECTORY_VALUE : ""));
57
+
58
+ const totalLinks = useMemo(
59
+ () => items.reduce((sum, item) => sum + item.group.links.length, 0),
60
+ [items],
61
+ );
62
+
63
+ const filteredItems = useMemo<WorkspaceGridItem[]>(
64
+ () =>
65
+ items.flatMap((item) => {
66
+ const group = filterLinkGroup(item.group, filter);
67
+ if (!group) return [];
68
+ return [
69
+ {
70
+ key: item.key,
71
+ col: item.col ?? 4,
72
+ node: <WorkspaceLinkCard group={group} />,
73
+ },
74
+ ];
75
+ }),
76
+ [items, filter],
77
+ );
78
+
79
+ return (
80
+ <Accordion
81
+ type="single"
82
+ collapsible
83
+ variant="card"
84
+ value={openValue}
85
+ onValueChange={setOpenValue}
86
+ >
87
+ <Accordion.Item value={DIRECTORY_VALUE}>
88
+ <Accordion.Trigger
89
+ // Count-based plural via i18next suffix resolution ("1 link" /
90
+ // "N links"); defaultValue_* carries the en fallback per form.
91
+ description={t("workspaceBrowseAllCount", {
92
+ count: totalLinks,
93
+ defaultValue_one: "{{count}} link",
94
+ defaultValue_other: "{{count}} links",
95
+ })}
96
+ >
97
+ {t("workspaceBrowseAll", "Browse all")}
98
+ </Accordion.Trigger>
99
+ <Accordion.Content>
100
+ <YStack {...knobProps.gap}>
101
+ <SearchInput
102
+ value={filter}
103
+ onChange={setFilter}
104
+ debounceMs={0}
105
+ compact
106
+ placeholder={t("workspaceFilterLinks", "Filter links...")}
107
+ aria-label={t("workspaceFilterLinks", "Filter links...")}
108
+ />
109
+ {filteredItems.length === 0 ? (
110
+ <EmptyState
111
+ compact
112
+ title={t(
113
+ "workspaceFilterNoMatch",
114
+ 'No links match "{{query}}"',
115
+ { query: filter.trim() },
116
+ )}
117
+ />
118
+ ) : (
119
+ <WorkspaceGrid items={filteredItems} />
120
+ )}
121
+ </YStack>
122
+ </Accordion.Content>
123
+ </Accordion.Item>
124
+ </Accordion>
125
+ );
126
+ }
@@ -0,0 +1,126 @@
1
+ /**
2
+ * Workspace number card block — renders a Number Card doc by name.
3
+ *
4
+ * "Document Type" cards (the default) map cleanly onto the live aggregate
5
+ * widget: `function` (Count/Sum/Average/Minimum/Maximum) +
6
+ * `aggregate_function_based_on` + `filters_json` become a FrappeKPICard
7
+ * data source, so the value is realtime like desk. "Report" and "Custom"
8
+ * cards need server-side evaluation
9
+ * (`frappe.desk.doctype.number_card.number_card.get_result`) and are
10
+ * rendered as an informational card for now (documented gap).
11
+ */
12
+ import { Card, SizableText, Skeleton, YStack } from "@multiplatform.one/components";
13
+ import {
14
+ FrappeKPICard,
15
+ type FrappeAggregateOperation,
16
+ type FrappeKPIDataSource,
17
+ } from "@multiplatform.one/frappe-ui";
18
+ import { useResolvedKnobs } from "@multiplatform.one/theme";
19
+ import { useMemo } from "react";
20
+ import { useTranslation } from "react-i18next";
21
+ import { BACKOFFICE_I18N_NAMESPACE } from "../i18n";
22
+ import { parseFrappeFilters } from "./parseContent";
23
+ import type { WorkspaceNumberCardRow } from "./types";
24
+ import { useFrappeDoc } from "./useWorkspaceDoc";
25
+
26
+ export interface NumberCardDoc {
27
+ name: string;
28
+ doctype: string;
29
+ label?: string;
30
+ /** "Document Type" | "Report" | "Custom" */
31
+ type?: string;
32
+ document_type?: string;
33
+ /** "Count" | "Sum" | "Average" | "Minimum" | "Maximum" */
34
+ function?: string;
35
+ aggregate_function_based_on?: string;
36
+ filters_json?: string;
37
+ [key: string]: unknown;
38
+ }
39
+
40
+ const FUNCTION_MAP: Record<string, FrappeAggregateOperation> = {
41
+ Count: "count",
42
+ Sum: "sum",
43
+ Average: "avg",
44
+ Minimum: "min",
45
+ Maximum: "max",
46
+ };
47
+
48
+ export interface WorkspaceNumberCardProps {
49
+ row: WorkspaceNumberCardRow;
50
+ }
51
+
52
+ export function WorkspaceNumberCard({ row }: WorkspaceNumberCardProps) {
53
+ const { t } = useTranslation(BACKOFFICE_I18N_NAMESPACE);
54
+ const { knobProps } = useResolvedKnobs();
55
+ const { doc, isLoading, error } = useFrappeDoc<NumberCardDoc>(
56
+ "Number Card",
57
+ row.number_card_name,
58
+ );
59
+
60
+ const title = row.label || doc?.label || row.number_card_name;
61
+
62
+ const dataSource = useMemo<FrappeKPIDataSource | undefined>(() => {
63
+ if (!doc?.document_type) return undefined;
64
+ if (doc.type && doc.type !== "Document Type") return undefined;
65
+ const aggregate = FUNCTION_MAP[doc.function ?? "Count"] ?? "count";
66
+ return {
67
+ doctype: doc.document_type,
68
+ aggregate,
69
+ field: aggregate === "count" ? undefined : doc.aggregate_function_based_on,
70
+ filters: parseFrappeFilters(doc.filters_json),
71
+ };
72
+ }, [doc]);
73
+
74
+ if (isLoading) {
75
+ return (
76
+ <Card flexGrow={1} aria-busy aria-label={t("loading", "Loading")}>
77
+ <YStack {...knobProps.panelPadding} {...knobProps.gap}>
78
+ <Skeleton width="60%" height={12} />
79
+ <Skeleton width="40%" height={28} />
80
+ </YStack>
81
+ </Card>
82
+ );
83
+ }
84
+
85
+ if (error || !doc) {
86
+ return (
87
+ <Card flexGrow={1}>
88
+ <YStack {...knobProps.panelPadding} {...knobProps.gap}>
89
+ <SizableText size="$3" fontWeight="600">
90
+ {title}
91
+ </SizableText>
92
+ <SizableText size="$2" color="$color10">
93
+ {t("workspaceNumberCardError", "Couldn't load number card")}
94
+ </SizableText>
95
+ </YStack>
96
+ </Card>
97
+ );
98
+ }
99
+
100
+ if (!dataSource) {
101
+ // Report / Custom cards need server-side evaluation — not wired yet.
102
+ return (
103
+ <Card flexGrow={1}>
104
+ <YStack {...knobProps.panelPadding} {...knobProps.gap}>
105
+ <SizableText size="$3" fontWeight="600">
106
+ {title}
107
+ </SizableText>
108
+ <SizableText size="$2" color="$color10">
109
+ {t(
110
+ "workspaceNumberCardUnsupported",
111
+ "This card type is only available in desk",
112
+ )}
113
+ </SizableText>
114
+ </YStack>
115
+ </Card>
116
+ );
117
+ }
118
+
119
+ return (
120
+ <FrappeKPICard
121
+ config={{ id: `workspace-number-card-${row.name}`, title, value: "—" }}
122
+ dataSource={dataSource}
123
+ flexGrow={1}
124
+ />
125
+ );
126
+ }
@@ -0,0 +1,100 @@
1
+ /**
2
+ * Workspace quick list block — a compact live list of a doctype with the
3
+ * row's `quick_list_filter` applied, plus a "View All" jump to the full
4
+ * list page. Rows navigate to the document form. Rows show the document
5
+ * name — desk shows the meta title field, which needs a DocType meta
6
+ * fetch (documented simplification).
7
+ */
8
+ import { Card, Separator, SizableText, XStack, YStack } from "@multiplatform.one/components";
9
+ import { FrappeList } from "@multiplatform.one/frappe-ui";
10
+ import { useResolvedKnobs } from "@multiplatform.one/theme";
11
+ import { useMemo } from "react";
12
+ import { useTranslation } from "react-i18next";
13
+ import { useBackofficeNavigator, useBackofficePaths } from "../config/BackofficeProvider";
14
+ import { BACKOFFICE_I18N_NAMESPACE } from "../i18n";
15
+ import { parseFrappeFilters } from "./parseContent";
16
+ import type { WorkspaceQuickListRow } from "./types";
17
+
18
+ interface QuickListDoc {
19
+ name: string;
20
+ doctype: string;
21
+ }
22
+
23
+ // Generic JSX (`<FrappeList<QuickListDoc> …/>`) breaks one-dev's source
24
+ // annotation transform; instantiate the type argument outside JSX instead.
25
+ const QuickList = FrappeList<QuickListDoc>;
26
+
27
+ /** Fixed viewport for the compact list (~4 rows + load-more headroom). */
28
+ const QUICK_LIST_HEIGHT = 220;
29
+
30
+ export interface WorkspaceQuickListProps {
31
+ row: WorkspaceQuickListRow;
32
+ }
33
+
34
+ export function WorkspaceQuickList({ row }: WorkspaceQuickListProps) {
35
+ const navigator = useBackofficeNavigator();
36
+ const paths = useBackofficePaths();
37
+ const { knobProps } = useResolvedKnobs();
38
+ const { t } = useTranslation(BACKOFFICE_I18N_NAMESPACE);
39
+
40
+ const filters = useMemo(() => parseFrappeFilters(row.quick_list_filter), [row.quick_list_filter]);
41
+
42
+ const title = row.label || row.document_type;
43
+
44
+ return (
45
+ <Card flexGrow={1}>
46
+ <YStack {...knobProps.panelPadding} {...knobProps.gap}>
47
+ <XStack justifyContent="space-between" alignItems="center" {...knobProps.gap}>
48
+ <SizableText size="$4" fontWeight="700" numberOfLines={1} flexShrink={1}>
49
+ {title}
50
+ </SizableText>
51
+ <SizableText
52
+ size="$2"
53
+ color="$color11"
54
+ cursor="pointer"
55
+ role="link"
56
+ hoverStyle={{ color: "$color12" }}
57
+ onPress={() => navigator.navigate(paths.list(row.document_type))}
58
+ >
59
+ {t("workspaceQuickListViewAll", "View All")}
60
+ </SizableText>
61
+ </XStack>
62
+ <Separator />
63
+ {/* Fixed-height box: FrappeList's internal flex-basis:0 stack
64
+ contributes no intrinsic height, so an unclamped Card collapses
65
+ and the rows paint past the frame (LC-10). The box gives the
66
+ flex chain a definite height to fill. */}
67
+ <YStack height={QUICK_LIST_HEIGHT} overflow="hidden">
68
+ <QuickList
69
+ doctype={row.document_type}
70
+ fields={["name"]}
71
+ filters={filters as Array<["name", string, unknown]> | undefined}
72
+ pageSize={4}
73
+ height={QUICK_LIST_HEIGHT}
74
+ estimateSize={44}
75
+ aria-label={title}
76
+ renderItem={(item) => (
77
+ <XStack
78
+ paddingVertical="$2"
79
+ paddingHorizontal="$2"
80
+ alignItems="center"
81
+ cursor="pointer"
82
+ borderRadius="$2"
83
+ hoverStyle={{ backgroundColor: "$color3" }}
84
+ onPress={() =>
85
+ item.name && navigator.navigate(paths.form(row.document_type, item.name))
86
+ }
87
+ role="link"
88
+ aria-label={item.name}
89
+ >
90
+ <SizableText size="$3" numberOfLines={1} flexShrink={1}>
91
+ {item.name}
92
+ </SizableText>
93
+ </XStack>
94
+ )}
95
+ />
96
+ </YStack>
97
+ </YStack>
98
+ </Card>
99
+ );
100
+ }
@@ -0,0 +1,100 @@
1
+ /**
2
+ * "Continue where you left off" strip (MOD-11) — a wrapping band of chips
3
+ * for the most recent backoffice visits, read from the shared desk recents
4
+ * store (chrome/awesomebar-data's readRecentItems over the same
5
+ * "frappe-desk-recent" key frappe-ui's addToRecent writes — one list across
6
+ * navbar recents, sidebar recents, and this strip; no new store).
7
+ *
8
+ * Renders nothing while the store is unread or empty — the strip is
9
+ * discovery chrome, not data the page promised (no skeleton, D-10).
10
+ * Refreshes on mount and on window focus (web); paths outside the
11
+ * provider's basePath (e.g. the frappe-ui `/desk` demo shell writes there
12
+ * too) are filtered out so every chip stays navigable in this app.
13
+ */
14
+ import { ClockCounterClockwiseIcon } from "@phosphor-icons/react";
15
+ import { Card, PageSection, SizableText, XStack, useTheme } from "@multiplatform.one/components";
16
+ import { useResolvedKnobs } from "@multiplatform.one/theme";
17
+ import { useCallback, useEffect, useRef, useState } from "react";
18
+ import { useTranslation } from "react-i18next";
19
+ import { readRecentItems, type RecentItem } from "../chrome/awesomebar-data";
20
+ import { useBackofficeNavigator, useBackofficePaths } from "../config/BackofficeProvider";
21
+ import { BACKOFFICE_I18N_NAMESPACE } from "../i18n";
22
+
23
+ /** Last N visits shown (MOD-11: "last 5 items from the shared recents store"). */
24
+ const MAX_RECENTS = 5;
25
+
26
+ export function WorkspaceRecents() {
27
+ const navigator = useBackofficeNavigator();
28
+ const paths = useBackofficePaths();
29
+ const { knobProps } = useResolvedKnobs();
30
+ const { t } = useTranslation(BACKOFFICE_I18N_NAMESPACE);
31
+ const theme = useTheme();
32
+ // Phosphor icons take a resolved color string, not a tamagui token —
33
+ // read the theme value so native/GTK get a real color (not a CSS var).
34
+ const iconColor = typeof theme.color11?.val === "string" ? theme.color11.val : undefined;
35
+ const [recents, setRecents] = useState<RecentItem[]>([]);
36
+
37
+ const mountedRef = useRef(true);
38
+ useEffect(() => {
39
+ mountedRef.current = true;
40
+ return () => {
41
+ mountedRef.current = false;
42
+ };
43
+ }, []);
44
+
45
+ const base = paths.base;
46
+ const refresh = useCallback(() => {
47
+ void readRecentItems().then((stored) => {
48
+ if (!mountedRef.current) return;
49
+ setRecents(stored.filter((item) => item.path.startsWith(base)).slice(0, MAX_RECENTS));
50
+ });
51
+ }, [base]);
52
+
53
+ // Fresh on mount and whenever the window regains focus (another surface
54
+ // may have pushed a visit since) — same staleness contract as the
55
+ // awesomebar's refresh-on-open.
56
+ useEffect(() => {
57
+ refresh();
58
+ if (typeof window === "undefined" || typeof window.addEventListener !== "function") {
59
+ return undefined;
60
+ }
61
+ const onFocus = () => refresh();
62
+ window.addEventListener("focus", onFocus);
63
+ return () => window.removeEventListener("focus", onFocus);
64
+ }, [refresh]);
65
+
66
+ if (recents.length === 0) return null;
67
+
68
+ return (
69
+ // Section heading on the shared sectionHeading scale (LC-17); no
70
+ // divider rule over a chip band (Axiom 16 chrome-earns-role).
71
+ <PageSection
72
+ title={t("workspaceRecents", "Continue where you left off")}
73
+ divider={false}
74
+ >
75
+ <XStack flexWrap="wrap" {...knobProps.gap}>
76
+ {recents.map((item) => (
77
+ <Card
78
+ key={item.path}
79
+ // Chip-scale surface: eject the Card's default panelPadding —
80
+ // the inner row owns the compact inset (LC-18 eject-last).
81
+ padding={0}
82
+ onPress={() => navigator.navigate(item.path)}
83
+ cursor="pointer"
84
+ hoverStyle={{ borderColor: "$accentBackground" }}
85
+ pressStyle={{ scale: 0.98 }}
86
+ role="link"
87
+ aria-label={item.label}
88
+ >
89
+ <XStack paddingHorizontal="$3" minHeight={44} alignItems="center" {...knobProps.gap}>
90
+ <ClockCounterClockwiseIcon size={14} color={iconColor} aria-hidden />
91
+ <SizableText size="$3" numberOfLines={1} flexShrink={1}>
92
+ {item.label}
93
+ </SizableText>
94
+ </XStack>
95
+ </Card>
96
+ ))}
97
+ </XStack>
98
+ </PageSection>
99
+ );
100
+ }