@prenta/admin 2.6.1 → 2.7.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 (794) hide show
  1. package/CHANGELOG.md +98 -0
  2. package/design-system/tokens.css +179 -85
  3. package/design-system/tokens.json +276 -85
  4. package/design-system/tokens.scss +148 -44
  5. package/design-system/tokens.tailwind.cjs +50 -1
  6. package/dist/AdminRoot.d.ts.map +1 -1
  7. package/dist/AdminRoot.js +42 -20
  8. package/dist/AdminRoot.js.map +1 -1
  9. package/dist/LoginRoot.d.ts.map +1 -1
  10. package/dist/LoginRoot.js +2 -1
  11. package/dist/LoginRoot.js.map +1 -1
  12. package/dist/__tests__/components/author-avatar.test.js +3 -17
  13. package/dist/__tests__/components/author-avatar.test.js.map +1 -1
  14. package/dist/__tests__/components/notification-bell.test.js +86 -15
  15. package/dist/__tests__/components/notification-bell.test.js.map +1 -1
  16. package/dist/__tests__/components/responsive-tiers.render.test.d.ts +2 -0
  17. package/dist/__tests__/components/responsive-tiers.render.test.d.ts.map +1 -0
  18. package/dist/__tests__/components/responsive-tiers.render.test.js +313 -0
  19. package/dist/__tests__/components/responsive-tiers.render.test.js.map +1 -0
  20. package/dist/__tests__/components/serp-preview.render.test.js +6 -3
  21. package/dist/__tests__/components/serp-preview.render.test.js.map +1 -1
  22. package/dist/__tests__/components/shell-primitives.render.test.d.ts +2 -0
  23. package/dist/__tests__/components/shell-primitives.render.test.d.ts.map +1 -0
  24. package/dist/__tests__/components/shell-primitives.render.test.js +716 -0
  25. package/dist/__tests__/components/shell-primitives.render.test.js.map +1 -0
  26. package/dist/__tests__/components/theme-provider-accent.test.js +49 -7
  27. package/dist/__tests__/components/theme-provider-accent.test.js.map +1 -1
  28. package/dist/__tests__/components/toggle.test.js +10 -3
  29. package/dist/__tests__/components/toggle.test.js.map +1 -1
  30. package/dist/__tests__/components/ui-primitives.test.js +3 -7
  31. package/dist/__tests__/components/ui-primitives.test.js.map +1 -1
  32. package/dist/__tests__/layout/build-nav-items.test.js +1 -1
  33. package/dist/__tests__/layout/build-nav-items.test.js.map +1 -1
  34. package/dist/__tests__/layout/shell-nav.render.test.d.ts +2 -0
  35. package/dist/__tests__/layout/shell-nav.render.test.d.ts.map +1 -0
  36. package/dist/__tests__/layout/shell-nav.render.test.js +736 -0
  37. package/dist/__tests__/layout/shell-nav.render.test.js.map +1 -0
  38. package/dist/__tests__/layout/sidebar-forms-submenu.render.test.js +8 -4
  39. package/dist/__tests__/layout/sidebar-forms-submenu.render.test.js.map +1 -1
  40. package/dist/__tests__/layout/sidebar-groups.render.test.d.ts +2 -0
  41. package/dist/__tests__/layout/sidebar-groups.render.test.d.ts.map +1 -0
  42. package/dist/__tests__/layout/sidebar-groups.render.test.js +56 -0
  43. package/dist/__tests__/layout/sidebar-groups.render.test.js.map +1 -0
  44. package/dist/__tests__/layout/sidebar-menus.render.test.d.ts +2 -0
  45. package/dist/__tests__/layout/sidebar-menus.render.test.d.ts.map +1 -0
  46. package/dist/__tests__/layout/sidebar-menus.render.test.js +82 -0
  47. package/dist/__tests__/layout/sidebar-menus.render.test.js.map +1 -0
  48. package/dist/__tests__/layout/sidebar-plugin-nav.test.js +1 -1
  49. package/dist/__tests__/layout/sidebar-plugin-nav.test.js.map +1 -1
  50. package/dist/__tests__/layout/sidebar-posts.test.js +48 -38
  51. package/dist/__tests__/layout/sidebar-posts.test.js.map +1 -1
  52. package/dist/__tests__/layout/sidebar-submenu.render.test.js +26 -10
  53. package/dist/__tests__/layout/sidebar-submenu.render.test.js.map +1 -1
  54. package/dist/__tests__/layout/topbar.render.test.d.ts +2 -0
  55. package/dist/__tests__/layout/topbar.render.test.d.ts.map +1 -0
  56. package/dist/__tests__/layout/topbar.render.test.js +406 -0
  57. package/dist/__tests__/layout/topbar.render.test.js.map +1 -0
  58. package/dist/__tests__/lib/api.test.js +2 -0
  59. package/dist/__tests__/lib/api.test.js.map +1 -1
  60. package/dist/__tests__/lib/job-drawer.test.d.ts +2 -0
  61. package/dist/__tests__/lib/job-drawer.test.d.ts.map +1 -0
  62. package/dist/__tests__/lib/job-drawer.test.js +393 -0
  63. package/dist/__tests__/lib/job-drawer.test.js.map +1 -0
  64. package/dist/__tests__/lib/job-view.test.d.ts +2 -0
  65. package/dist/__tests__/lib/job-view.test.d.ts.map +1 -0
  66. package/dist/__tests__/lib/job-view.test.js +387 -0
  67. package/dist/__tests__/lib/job-view.test.js.map +1 -0
  68. package/dist/__tests__/lib/jobs-service.test.d.ts +2 -0
  69. package/dist/__tests__/lib/jobs-service.test.d.ts.map +1 -0
  70. package/dist/__tests__/lib/jobs-service.test.js +88 -0
  71. package/dist/__tests__/lib/jobs-service.test.js.map +1 -0
  72. package/dist/__tests__/router/admin-route-order.test.d.ts +2 -0
  73. package/dist/__tests__/router/admin-route-order.test.d.ts.map +1 -0
  74. package/dist/__tests__/router/admin-route-order.test.js +36 -0
  75. package/dist/__tests__/router/admin-route-order.test.js.map +1 -0
  76. package/dist/__tests__/styles/ai-gradient-contrast.test.d.ts +2 -0
  77. package/dist/__tests__/styles/ai-gradient-contrast.test.d.ts.map +1 -0
  78. package/dist/__tests__/styles/ai-gradient-contrast.test.js +110 -0
  79. package/dist/__tests__/styles/ai-gradient-contrast.test.js.map +1 -0
  80. package/dist/__tests__/styles/breakpoint-order.test.d.ts +2 -0
  81. package/dist/__tests__/styles/breakpoint-order.test.d.ts.map +1 -0
  82. package/dist/__tests__/styles/breakpoint-order.test.js +52 -0
  83. package/dist/__tests__/styles/breakpoint-order.test.js.map +1 -0
  84. package/dist/__tests__/styles/responsive-layer.test.js +303 -12
  85. package/dist/__tests__/styles/responsive-layer.test.js.map +1 -1
  86. package/dist/__tests__/styles/tailwind-preset.test.d.ts +2 -0
  87. package/dist/__tests__/styles/tailwind-preset.test.d.ts.map +1 -0
  88. package/dist/__tests__/styles/tailwind-preset.test.js +147 -0
  89. package/dist/__tests__/styles/tailwind-preset.test.js.map +1 -0
  90. package/dist/__tests__/styles/theme-token-scope.test.js +9 -3
  91. package/dist/__tests__/styles/theme-token-scope.test.js.map +1 -1
  92. package/dist/__tests__/styles/tiers.test.d.ts +2 -0
  93. package/dist/__tests__/styles/tiers.test.d.ts.map +1 -0
  94. package/dist/__tests__/styles/tiers.test.js +121 -0
  95. package/dist/__tests__/styles/tiers.test.js.map +1 -0
  96. package/dist/__tests__/styles/tokens-drift.test.js +57 -6
  97. package/dist/__tests__/styles/tokens-drift.test.js.map +1 -1
  98. package/dist/__tests__/views/admin-lazy-route.render.test.js +27 -1
  99. package/dist/__tests__/views/admin-lazy-route.render.test.js.map +1 -1
  100. package/dist/__tests__/views/ai-settings.render.test.js +4 -4
  101. package/dist/__tests__/views/appearance-menus-route.render.test.d.ts +2 -0
  102. package/dist/__tests__/views/appearance-menus-route.render.test.d.ts.map +1 -0
  103. package/dist/__tests__/views/appearance-menus-route.render.test.js +50 -0
  104. package/dist/__tests__/views/appearance-menus-route.render.test.js.map +1 -0
  105. package/dist/__tests__/views/appearance-settings.render.test.js +8 -6
  106. package/dist/__tests__/views/appearance-settings.render.test.js.map +1 -1
  107. package/dist/__tests__/views/appearance-theme-provider.render.test.d.ts +2 -0
  108. package/dist/__tests__/views/appearance-theme-provider.render.test.d.ts.map +1 -0
  109. package/dist/__tests__/views/appearance-theme-provider.render.test.js +286 -0
  110. package/dist/__tests__/views/appearance-theme-provider.render.test.js.map +1 -0
  111. package/dist/__tests__/views/dashboard.test.js +37 -0
  112. package/dist/__tests__/views/dashboard.test.js.map +1 -1
  113. package/dist/__tests__/views/document-edit-navigation.render.test.d.ts +2 -0
  114. package/dist/__tests__/views/document-edit-navigation.render.test.d.ts.map +1 -0
  115. package/dist/__tests__/views/document-edit-navigation.render.test.js +101 -0
  116. package/dist/__tests__/views/document-edit-navigation.render.test.js.map +1 -0
  117. package/dist/__tests__/views/document-edit-routes.render.test.d.ts +2 -0
  118. package/dist/__tests__/views/document-edit-routes.render.test.d.ts.map +1 -0
  119. package/dist/__tests__/views/document-edit-routes.render.test.js +113 -0
  120. package/dist/__tests__/views/document-edit-routes.render.test.js.map +1 -0
  121. package/dist/__tests__/views/email-settings.render.test.js +2 -2
  122. package/dist/__tests__/views/form-entries.render.test.js +15 -0
  123. package/dist/__tests__/views/form-entries.render.test.js.map +1 -1
  124. package/dist/__tests__/views/form-submissions.render.test.js +18 -0
  125. package/dist/__tests__/views/form-submissions.render.test.js.map +1 -1
  126. package/dist/__tests__/views/forms-list.render.test.js +12 -0
  127. package/dist/__tests__/views/forms-list.render.test.js.map +1 -1
  128. package/dist/__tests__/views/general-settings.render.test.js +26 -10
  129. package/dist/__tests__/views/general-settings.render.test.js.map +1 -1
  130. package/dist/__tests__/views/jobs-drawer.render.test.d.ts +2 -0
  131. package/dist/__tests__/views/jobs-drawer.render.test.d.ts.map +1 -0
  132. package/dist/__tests__/views/jobs-drawer.render.test.js +908 -0
  133. package/dist/__tests__/views/jobs-drawer.render.test.js.map +1 -0
  134. package/dist/__tests__/views/jobs-list.render.test.d.ts +2 -0
  135. package/dist/__tests__/views/jobs-list.render.test.d.ts.map +1 -0
  136. package/dist/__tests__/views/jobs-list.render.test.js +695 -0
  137. package/dist/__tests__/views/jobs-list.render.test.js.map +1 -0
  138. package/dist/__tests__/views/kpi-grid.test.d.ts +2 -0
  139. package/dist/__tests__/views/kpi-grid.test.d.ts.map +1 -0
  140. package/dist/__tests__/views/kpi-grid.test.js +26 -0
  141. package/dist/__tests__/views/kpi-grid.test.js.map +1 -0
  142. package/dist/__tests__/views/post-section-editor.test.js +3 -1
  143. package/dist/__tests__/views/post-section-editor.test.js.map +1 -1
  144. package/dist/__tests__/views/script-tags.render.test.js +25 -0
  145. package/dist/__tests__/views/script-tags.render.test.js.map +1 -1
  146. package/dist/__tests__/views/security-settings.render.test.js +9 -8
  147. package/dist/__tests__/views/security-settings.render.test.js.map +1 -1
  148. package/dist/__tests__/views/seo-settings.render.test.js +7 -7
  149. package/dist/__tests__/views/seo-settings.render.test.js.map +1 -1
  150. package/dist/__tests__/views/settings-save-bar.render.test.d.ts +2 -0
  151. package/dist/__tests__/views/settings-save-bar.render.test.d.ts.map +1 -0
  152. package/dist/__tests__/views/settings-save-bar.render.test.js +68 -0
  153. package/dist/__tests__/views/settings-save-bar.render.test.js.map +1 -0
  154. package/dist/__tests__/views/settings-save-footer.render.test.js +23 -15
  155. package/dist/__tests__/views/settings-save-footer.render.test.js.map +1 -1
  156. package/dist/__tests__/views/settings-tabs.render.test.d.ts +2 -0
  157. package/dist/__tests__/views/settings-tabs.render.test.d.ts.map +1 -0
  158. package/dist/__tests__/views/settings-tabs.render.test.js +319 -0
  159. package/dist/__tests__/views/settings-tabs.render.test.js.map +1 -0
  160. package/dist/__tests__/views/updates-tab.render.test.js +4 -3
  161. package/dist/__tests__/views/updates-tab.render.test.js.map +1 -1
  162. package/dist/components/Breadcrumbs.d.ts +8 -1
  163. package/dist/components/Breadcrumbs.d.ts.map +1 -1
  164. package/dist/components/Breadcrumbs.js +6 -0
  165. package/dist/components/Breadcrumbs.js.map +1 -1
  166. package/dist/components/CommandPalette.d.ts.map +1 -1
  167. package/dist/components/CommandPalette.js +40 -4
  168. package/dist/components/CommandPalette.js.map +1 -1
  169. package/dist/components/LocaleSwitcher.d.ts.map +1 -1
  170. package/dist/components/LocaleSwitcher.js +1 -1
  171. package/dist/components/LocaleSwitcher.js.map +1 -1
  172. package/dist/components/NotificationBell.d.ts.map +1 -1
  173. package/dist/components/NotificationBell.js +44 -3
  174. package/dist/components/NotificationBell.js.map +1 -1
  175. package/dist/components/OfflineStatus.js +1 -1
  176. package/dist/components/OfflineStatus.js.map +1 -1
  177. package/dist/components/PresenceIndicator.d.ts.map +1 -1
  178. package/dist/components/PresenceIndicator.js +2 -1
  179. package/dist/components/PresenceIndicator.js.map +1 -1
  180. package/dist/components/ReflowMeter.js +2 -2
  181. package/dist/components/ReflowMeter.js.map +1 -1
  182. package/dist/components/SEOPanel.js +2 -2
  183. package/dist/components/SEOPanel.js.map +1 -1
  184. package/dist/components/ThemeProvider.d.ts +24 -4
  185. package/dist/components/ThemeProvider.d.ts.map +1 -1
  186. package/dist/components/ThemeProvider.js +80 -22
  187. package/dist/components/ThemeProvider.js.map +1 -1
  188. package/dist/components/TipTapEditor.d.ts.map +1 -1
  189. package/dist/components/TipTapEditor.js +3 -4
  190. package/dist/components/TipTapEditor.js.map +1 -1
  191. package/dist/components/forms/EmbedPanel.js +1 -1
  192. package/dist/components/forms/EmbedPanel.js.map +1 -1
  193. package/dist/components/forms/FormEntryDetailPane.js +6 -1
  194. package/dist/components/forms/FormEntryDetailPane.js.map +1 -1
  195. package/dist/components/forms/ShortcodeGlossary.d.ts.map +1 -1
  196. package/dist/components/forms/ShortcodeGlossary.js +6 -1
  197. package/dist/components/forms/ShortcodeGlossary.js.map +1 -1
  198. package/dist/components/forms/primitives.d.ts +15 -5
  199. package/dist/components/forms/primitives.d.ts.map +1 -1
  200. package/dist/components/forms/primitives.js +11 -11
  201. package/dist/components/forms/primitives.js.map +1 -1
  202. package/dist/components/pages/tag-badges.d.ts +2 -1
  203. package/dist/components/pages/tag-badges.d.ts.map +1 -1
  204. package/dist/components/pages/tag-badges.js +4 -3
  205. package/dist/components/pages/tag-badges.js.map +1 -1
  206. package/dist/components/seo/PageAuditPanel.js +2 -2
  207. package/dist/components/seo/PageAuditPanel.js.map +1 -1
  208. package/dist/components/seo/SerpPreview.d.ts +4 -4
  209. package/dist/components/seo/SerpPreview.js +1 -1
  210. package/dist/components/seo/SerpPreview.js.map +1 -1
  211. package/dist/components/seo/primitives.js +2 -2
  212. package/dist/components/seo/primitives.js.map +1 -1
  213. package/dist/components/ui/AuthorAvatar.d.ts +4 -4
  214. package/dist/components/ui/AuthorAvatar.d.ts.map +1 -1
  215. package/dist/components/ui/AuthorAvatar.js +11 -10
  216. package/dist/components/ui/AuthorAvatar.js.map +1 -1
  217. package/dist/components/ui/Badge.d.ts +1 -1
  218. package/dist/components/ui/Badge.js +1 -1
  219. package/dist/components/ui/Badge.js.map +1 -1
  220. package/dist/components/ui/Breadcrumb.d.ts +27 -0
  221. package/dist/components/ui/Breadcrumb.d.ts.map +1 -0
  222. package/dist/components/ui/Breadcrumb.js +41 -0
  223. package/dist/components/ui/Breadcrumb.js.map +1 -0
  224. package/dist/components/ui/Button.d.ts +2 -2
  225. package/dist/components/ui/Button.d.ts.map +1 -1
  226. package/dist/components/ui/Button.js +31 -16
  227. package/dist/components/ui/Button.js.map +1 -1
  228. package/dist/components/ui/Card.d.ts +8 -4
  229. package/dist/components/ui/Card.d.ts.map +1 -1
  230. package/dist/components/ui/Card.js +21 -13
  231. package/dist/components/ui/Card.js.map +1 -1
  232. package/dist/components/ui/CardListControls.d.ts +34 -0
  233. package/dist/components/ui/CardListControls.d.ts.map +1 -0
  234. package/dist/components/ui/CardListControls.js +25 -0
  235. package/dist/components/ui/CardListControls.js.map +1 -0
  236. package/dist/components/ui/CountChip.d.ts +20 -0
  237. package/dist/components/ui/CountChip.d.ts.map +1 -0
  238. package/dist/components/ui/CountChip.js +48 -0
  239. package/dist/components/ui/CountChip.js.map +1 -0
  240. package/dist/components/ui/FilterPill.d.ts +2 -1
  241. package/dist/components/ui/FilterPill.d.ts.map +1 -1
  242. package/dist/components/ui/FilterPill.js +3 -2
  243. package/dist/components/ui/FilterPill.js.map +1 -1
  244. package/dist/components/ui/Input.d.ts +1 -1
  245. package/dist/components/ui/InspectorPane.d.ts +1 -1
  246. package/dist/components/ui/InspectorPane.d.ts.map +1 -1
  247. package/dist/components/ui/InspectorPane.js +15 -4
  248. package/dist/components/ui/InspectorPane.js.map +1 -1
  249. package/dist/components/ui/Modal.d.ts.map +1 -1
  250. package/dist/components/ui/Modal.js +10 -2
  251. package/dist/components/ui/Modal.js.map +1 -1
  252. package/dist/components/ui/PageHeader.d.ts +28 -0
  253. package/dist/components/ui/PageHeader.d.ts.map +1 -0
  254. package/dist/components/ui/PageHeader.js +18 -0
  255. package/dist/components/ui/PageHeader.js.map +1 -0
  256. package/dist/components/ui/RowActions.d.ts +5 -0
  257. package/dist/components/ui/RowActions.d.ts.map +1 -1
  258. package/dist/components/ui/RowActions.js +7 -2
  259. package/dist/components/ui/RowActions.js.map +1 -1
  260. package/dist/components/ui/Segmented.d.ts +21 -0
  261. package/dist/components/ui/Segmented.d.ts.map +1 -0
  262. package/dist/components/ui/Segmented.js +41 -0
  263. package/dist/components/ui/Segmented.js.map +1 -0
  264. package/dist/components/ui/Toaster.d.ts +12 -0
  265. package/dist/components/ui/Toaster.d.ts.map +1 -0
  266. package/dist/components/ui/Toaster.js +103 -0
  267. package/dist/components/ui/Toaster.js.map +1 -0
  268. package/dist/components/ui/Toggle.d.ts +4 -3
  269. package/dist/components/ui/Toggle.d.ts.map +1 -1
  270. package/dist/components/ui/Toggle.js +16 -12
  271. package/dist/components/ui/Toggle.js.map +1 -1
  272. package/dist/components/ui/UnderlineTabs.d.ts +56 -0
  273. package/dist/components/ui/UnderlineTabs.d.ts.map +1 -0
  274. package/dist/components/ui/UnderlineTabs.js +205 -0
  275. package/dist/components/ui/UnderlineTabs.js.map +1 -0
  276. package/dist/components/ui/UnsavedBar.d.ts +25 -0
  277. package/dist/components/ui/UnsavedBar.d.ts.map +1 -0
  278. package/dist/components/ui/UnsavedBar.js +22 -0
  279. package/dist/components/ui/UnsavedBar.js.map +1 -0
  280. package/dist/components/ui/admin-links.d.ts +11 -0
  281. package/dist/components/ui/admin-links.d.ts.map +1 -0
  282. package/dist/components/ui/admin-links.js +10 -0
  283. package/dist/components/ui/admin-links.js.map +1 -0
  284. package/dist/components/ui/card-table.d.ts +43 -0
  285. package/dist/components/ui/card-table.d.ts.map +1 -0
  286. package/dist/components/ui/card-table.js +31 -0
  287. package/dist/components/ui/card-table.js.map +1 -0
  288. package/dist/components/virtual-window.d.ts +7 -0
  289. package/dist/components/virtual-window.d.ts.map +1 -1
  290. package/dist/components/virtual-window.js +5 -2
  291. package/dist/components/virtual-window.js.map +1 -1
  292. package/dist/fields/RelationshipField.js +1 -1
  293. package/dist/fields/RelationshipField.js.map +1 -1
  294. package/dist/files/dm-mono-latin-400-normal.woff +0 -0
  295. package/dist/files/dm-mono-latin-400-normal.woff2 +0 -0
  296. package/dist/files/dm-mono-latin-500-normal.woff +0 -0
  297. package/dist/files/dm-mono-latin-500-normal.woff2 +0 -0
  298. package/dist/files/dm-mono-latin-ext-400-normal.woff +0 -0
  299. package/dist/files/dm-mono-latin-ext-400-normal.woff2 +0 -0
  300. package/dist/files/dm-mono-latin-ext-500-normal.woff +0 -0
  301. package/dist/files/dm-mono-latin-ext-500-normal.woff2 +0 -0
  302. package/dist/files/dm-sans-latin-400-normal.woff +0 -0
  303. package/dist/files/dm-sans-latin-400-normal.woff2 +0 -0
  304. package/dist/files/dm-sans-latin-500-normal.woff +0 -0
  305. package/dist/files/dm-sans-latin-500-normal.woff2 +0 -0
  306. package/dist/files/dm-sans-latin-600-normal.woff +0 -0
  307. package/dist/files/dm-sans-latin-600-normal.woff2 +0 -0
  308. package/dist/files/dm-sans-latin-700-normal.woff +0 -0
  309. package/dist/files/dm-sans-latin-700-normal.woff2 +0 -0
  310. package/dist/files/dm-sans-latin-ext-400-normal.woff +0 -0
  311. package/dist/files/dm-sans-latin-ext-400-normal.woff2 +0 -0
  312. package/dist/files/dm-sans-latin-ext-500-normal.woff +0 -0
  313. package/dist/files/dm-sans-latin-ext-500-normal.woff2 +0 -0
  314. package/dist/files/dm-sans-latin-ext-600-normal.woff +0 -0
  315. package/dist/files/dm-sans-latin-ext-600-normal.woff2 +0 -0
  316. package/dist/files/dm-sans-latin-ext-700-normal.woff +0 -0
  317. package/dist/files/dm-sans-latin-ext-700-normal.woff2 +0 -0
  318. package/dist/hooks/useAppearanceBootstrap.d.ts.map +1 -1
  319. package/dist/hooks/useAppearanceBootstrap.js +9 -3
  320. package/dist/hooks/useAppearanceBootstrap.js.map +1 -1
  321. package/dist/index.d.ts +15 -0
  322. package/dist/index.d.ts.map +1 -1
  323. package/dist/index.js +8 -0
  324. package/dist/index.js.map +1 -1
  325. package/dist/layout/Header.d.ts +14 -5
  326. package/dist/layout/Header.d.ts.map +1 -1
  327. package/dist/layout/Header.js +78 -13
  328. package/dist/layout/Header.js.map +1 -1
  329. package/dist/layout/Layout.d.ts +5 -3
  330. package/dist/layout/Layout.d.ts.map +1 -1
  331. package/dist/layout/Layout.js +45 -54
  332. package/dist/layout/Layout.js.map +1 -1
  333. package/dist/layout/MobileTabBar.d.ts +20 -0
  334. package/dist/layout/MobileTabBar.d.ts.map +1 -0
  335. package/dist/layout/MobileTabBar.js +29 -0
  336. package/dist/layout/MobileTabBar.js.map +1 -0
  337. package/dist/layout/Sidebar.d.ts +8 -26
  338. package/dist/layout/Sidebar.d.ts.map +1 -1
  339. package/dist/layout/Sidebar.js +309 -345
  340. package/dist/layout/Sidebar.js.map +1 -1
  341. package/dist/layout/nav-config.d.ts +101 -0
  342. package/dist/layout/nav-config.d.ts.map +1 -0
  343. package/dist/layout/nav-config.js +297 -0
  344. package/dist/layout/nav-config.js.map +1 -0
  345. package/dist/layout/primitives/AdminShell.d.ts +10 -2
  346. package/dist/layout/primitives/AdminShell.d.ts.map +1 -1
  347. package/dist/layout/primitives/AdminShell.js +114 -6
  348. package/dist/layout/primitives/AdminShell.js.map +1 -1
  349. package/dist/layout/topbar-classes.d.ts +8 -0
  350. package/dist/layout/topbar-classes.d.ts.map +1 -0
  351. package/dist/layout/topbar-classes.js +8 -0
  352. package/dist/layout/topbar-classes.js.map +1 -0
  353. package/dist/layout/use-nav-items.d.ts +10 -0
  354. package/dist/layout/use-nav-items.d.ts.map +1 -0
  355. package/dist/layout/use-nav-items.js +39 -0
  356. package/dist/layout/use-nav-items.js.map +1 -0
  357. package/dist/lib/api.d.ts +6 -0
  358. package/dist/lib/api.d.ts.map +1 -1
  359. package/dist/lib/api.js +1 -1
  360. package/dist/lib/api.js.map +1 -1
  361. package/dist/lib/appearance-api.d.ts +3 -1
  362. package/dist/lib/appearance-api.d.ts.map +1 -1
  363. package/dist/lib/appearance-api.js +1 -0
  364. package/dist/lib/appearance-api.js.map +1 -1
  365. package/dist/lib/job-drawer.d.ts +128 -0
  366. package/dist/lib/job-drawer.d.ts.map +1 -0
  367. package/dist/lib/job-drawer.js +351 -0
  368. package/dist/lib/job-drawer.js.map +1 -0
  369. package/dist/lib/job-view.d.ts +187 -0
  370. package/dist/lib/job-view.d.ts.map +1 -0
  371. package/dist/lib/job-view.js +363 -0
  372. package/dist/lib/job-view.js.map +1 -0
  373. package/dist/lib/jobs-service.d.ts +134 -0
  374. package/dist/lib/jobs-service.d.ts.map +1 -0
  375. package/dist/lib/jobs-service.js +179 -0
  376. package/dist/lib/jobs-service.js.map +1 -0
  377. package/dist/lib/sheet-focus.d.ts +24 -0
  378. package/dist/lib/sheet-focus.d.ts.map +1 -0
  379. package/dist/lib/sheet-focus.js +61 -0
  380. package/dist/lib/sheet-focus.js.map +1 -0
  381. package/dist/lib/tiers.d.ts +30 -0
  382. package/dist/lib/tiers.d.ts.map +1 -0
  383. package/dist/lib/tiers.js +43 -0
  384. package/dist/lib/tiers.js.map +1 -0
  385. package/dist/prenta-admin.css +1 -1
  386. package/dist/router/admin-routes.d.ts.map +1 -1
  387. package/dist/router/admin-routes.js +8 -0
  388. package/dist/router/admin-routes.js.map +1 -1
  389. package/dist/router/index.d.ts +5 -1
  390. package/dist/router/index.d.ts.map +1 -1
  391. package/dist/router/index.js +7 -0
  392. package/dist/router/index.js.map +1 -1
  393. package/dist/views/ApiKeys.js +2 -2
  394. package/dist/views/ApiKeys.js.map +1 -1
  395. package/dist/views/AppearanceChrome.d.ts +6 -0
  396. package/dist/views/AppearanceChrome.d.ts.map +1 -0
  397. package/dist/views/AppearanceChrome.js +25 -0
  398. package/dist/views/AppearanceChrome.js.map +1 -0
  399. package/dist/views/CollectionList.d.ts.map +1 -1
  400. package/dist/views/CollectionList.js +73 -53
  401. package/dist/views/CollectionList.js.map +1 -1
  402. package/dist/views/Dashboard.d.ts.map +1 -1
  403. package/dist/views/Dashboard.js +14 -8
  404. package/dist/views/Dashboard.js.map +1 -1
  405. package/dist/views/DocumentEdit.d.ts +6 -1
  406. package/dist/views/DocumentEdit.d.ts.map +1 -1
  407. package/dist/views/DocumentEdit.js +44 -8
  408. package/dist/views/DocumentEdit.js.map +1 -1
  409. package/dist/views/FormDeliveries.d.ts.map +1 -1
  410. package/dist/views/FormDeliveries.js +7 -1
  411. package/dist/views/FormDeliveries.js.map +1 -1
  412. package/dist/views/FormEntries.d.ts.map +1 -1
  413. package/dist/views/FormEntries.js +11 -2
  414. package/dist/views/FormEntries.js.map +1 -1
  415. package/dist/views/FormSubmissions.d.ts +1 -1
  416. package/dist/views/FormSubmissions.d.ts.map +1 -1
  417. package/dist/views/FormSubmissions.js +15 -4
  418. package/dist/views/FormSubmissions.js.map +1 -1
  419. package/dist/views/Forms.d.ts.map +1 -1
  420. package/dist/views/Forms.js +6 -4
  421. package/dist/views/Forms.js.map +1 -1
  422. package/dist/views/FormsSettings.d.ts +2 -0
  423. package/dist/views/FormsSettings.d.ts.map +1 -0
  424. package/dist/views/FormsSettings.js +37 -0
  425. package/dist/views/FormsSettings.js.map +1 -0
  426. package/dist/views/Jobs/BusyButton.d.ts +15 -0
  427. package/dist/views/Jobs/BusyButton.d.ts.map +1 -0
  428. package/dist/views/Jobs/BusyButton.js +26 -0
  429. package/dist/views/Jobs/BusyButton.js.map +1 -0
  430. package/dist/views/Jobs/CancelJobDialog.d.ts +21 -0
  431. package/dist/views/Jobs/CancelJobDialog.d.ts.map +1 -0
  432. package/dist/views/Jobs/CancelJobDialog.js +66 -0
  433. package/dist/views/Jobs/CancelJobDialog.js.map +1 -0
  434. package/dist/views/Jobs/DrawerActivity.d.ts +16 -0
  435. package/dist/views/Jobs/DrawerActivity.d.ts.map +1 -0
  436. package/dist/views/Jobs/DrawerActivity.js +59 -0
  437. package/dist/views/Jobs/DrawerActivity.js.map +1 -0
  438. package/dist/views/Jobs/DrawerOverview.d.ts +28 -0
  439. package/dist/views/Jobs/DrawerOverview.d.ts.map +1 -0
  440. package/dist/views/Jobs/DrawerOverview.js +32 -0
  441. package/dist/views/Jobs/DrawerOverview.js.map +1 -0
  442. package/dist/views/Jobs/DrawerResults.d.ts +25 -0
  443. package/dist/views/Jobs/DrawerResults.d.ts.map +1 -0
  444. package/dist/views/Jobs/DrawerResults.js +50 -0
  445. package/dist/views/Jobs/DrawerResults.js.map +1 -0
  446. package/dist/views/Jobs/DrawerReview.d.ts +44 -0
  447. package/dist/views/Jobs/DrawerReview.d.ts.map +1 -0
  448. package/dist/views/Jobs/DrawerReview.js +110 -0
  449. package/dist/views/Jobs/DrawerReview.js.map +1 -0
  450. package/dist/views/Jobs/JobDrawer.d.ts +31 -0
  451. package/dist/views/Jobs/JobDrawer.d.ts.map +1 -0
  452. package/dist/views/Jobs/JobDrawer.js +353 -0
  453. package/dist/views/Jobs/JobDrawer.js.map +1 -0
  454. package/dist/views/Jobs/JobsTable.d.ts +19 -0
  455. package/dist/views/Jobs/JobsTable.d.ts.map +1 -0
  456. package/dist/views/Jobs/JobsTable.js +80 -0
  457. package/dist/views/Jobs/JobsTable.js.map +1 -0
  458. package/dist/views/Jobs/WorkerStrip.d.ts +22 -0
  459. package/dist/views/Jobs/WorkerStrip.d.ts.map +1 -0
  460. package/dist/views/Jobs/WorkerStrip.js +63 -0
  461. package/dist/views/Jobs/WorkerStrip.js.map +1 -0
  462. package/dist/views/Jobs/atoms.d.ts +19 -0
  463. package/dist/views/Jobs/atoms.d.ts.map +1 -0
  464. package/dist/views/Jobs/atoms.js +52 -0
  465. package/dist/views/Jobs/atoms.js.map +1 -0
  466. package/dist/views/Jobs/focus.d.ts +23 -0
  467. package/dist/views/Jobs/focus.d.ts.map +1 -0
  468. package/dist/views/Jobs/focus.js +54 -0
  469. package/dist/views/Jobs/focus.js.map +1 -0
  470. package/dist/views/Jobs/icons.d.ts +22 -0
  471. package/dist/views/Jobs/icons.d.ts.map +1 -0
  472. package/dist/views/Jobs/icons.js +23 -0
  473. package/dist/views/Jobs/icons.js.map +1 -0
  474. package/dist/views/Jobs/placeholders.d.ts +6 -0
  475. package/dist/views/Jobs/placeholders.d.ts.map +1 -0
  476. package/dist/views/Jobs/placeholders.js +20 -0
  477. package/dist/views/Jobs/placeholders.js.map +1 -0
  478. package/dist/views/Jobs/useJobDetail.d.ts +21 -0
  479. package/dist/views/Jobs/useJobDetail.d.ts.map +1 -0
  480. package/dist/views/Jobs/useJobDetail.js +39 -0
  481. package/dist/views/Jobs/useJobDetail.js.map +1 -0
  482. package/dist/views/Jobs/useJobsFeed.d.ts +35 -0
  483. package/dist/views/Jobs/useJobsFeed.d.ts.map +1 -0
  484. package/dist/views/Jobs/useJobsFeed.js +231 -0
  485. package/dist/views/Jobs/useJobsFeed.js.map +1 -0
  486. package/dist/views/Jobs/useReviewItems.d.ts +39 -0
  487. package/dist/views/Jobs/useReviewItems.d.ts.map +1 -0
  488. package/dist/views/Jobs/useReviewItems.js +140 -0
  489. package/dist/views/Jobs/useReviewItems.js.map +1 -0
  490. package/dist/views/Jobs.d.ts +10 -1
  491. package/dist/views/Jobs.d.ts.map +1 -1
  492. package/dist/views/Jobs.js +126 -35
  493. package/dist/views/Jobs.js.map +1 -1
  494. package/dist/views/MediaBrowser.d.ts.map +1 -1
  495. package/dist/views/MediaBrowser.js +37 -9
  496. package/dist/views/MediaBrowser.js.map +1 -1
  497. package/dist/views/Pages/PagesListView.d.ts +1 -1
  498. package/dist/views/Pages/PagesListView.d.ts.map +1 -1
  499. package/dist/views/Pages/PagesListView.js +34 -5
  500. package/dist/views/Pages/PagesListView.js.map +1 -1
  501. package/dist/views/Posts/NewPostTypeInstructions.d.ts.map +1 -1
  502. package/dist/views/Posts/NewPostTypeInstructions.js +12 -2
  503. package/dist/views/Posts/NewPostTypeInstructions.js.map +1 -1
  504. package/dist/views/Posts/PostTypesView.d.ts.map +1 -1
  505. package/dist/views/Posts/PostTypesView.js +10 -1
  506. package/dist/views/Posts/PostTypesView.js.map +1 -1
  507. package/dist/views/Posts/PostsListView.d.ts +1 -2
  508. package/dist/views/Posts/PostsListView.d.ts.map +1 -1
  509. package/dist/views/Posts/PostsListView.js +31 -3
  510. package/dist/views/Posts/PostsListView.js.map +1 -1
  511. package/dist/views/SEO.d.ts.map +1 -1
  512. package/dist/views/SEO.js +3 -3
  513. package/dist/views/SEO.js.map +1 -1
  514. package/dist/views/ScriptTags.d.ts.map +1 -1
  515. package/dist/views/ScriptTags.js +20 -15
  516. package/dist/views/ScriptTags.js.map +1 -1
  517. package/dist/views/Settings.d.ts.map +1 -1
  518. package/dist/views/Settings.js +115 -51
  519. package/dist/views/Settings.js.map +1 -1
  520. package/dist/views/SpamFolder.d.ts +2 -0
  521. package/dist/views/SpamFolder.d.ts.map +1 -0
  522. package/dist/views/SpamFolder.js +14 -0
  523. package/dist/views/SpamFolder.js.map +1 -0
  524. package/dist/views/Trash.d.ts +6 -1
  525. package/dist/views/Trash.d.ts.map +1 -1
  526. package/dist/views/Trash.js +7 -2
  527. package/dist/views/Trash.js.map +1 -1
  528. package/dist/views/Users.js +2 -2
  529. package/dist/views/Users.js.map +1 -1
  530. package/dist/views/WidgetsPlaceholder.d.ts +2 -0
  531. package/dist/views/WidgetsPlaceholder.d.ts.map +1 -0
  532. package/dist/views/WidgetsPlaceholder.js +15 -0
  533. package/dist/views/WidgetsPlaceholder.js.map +1 -0
  534. package/dist/views/dashboard/kpi-grid.d.ts +18 -0
  535. package/dist/views/dashboard/kpi-grid.d.ts.map +1 -0
  536. package/dist/views/dashboard/kpi-grid.js +36 -0
  537. package/dist/views/dashboard/kpi-grid.js.map +1 -0
  538. package/dist/views/lazy-views.d.ts +4 -0
  539. package/dist/views/lazy-views.d.ts.map +1 -1
  540. package/dist/views/lazy-views.js +4 -0
  541. package/dist/views/lazy-views.js.map +1 -1
  542. package/dist/views/page-editor/PageTab.js +1 -1
  543. package/dist/views/page-editor/PageTab.js.map +1 -1
  544. package/dist/views/page-editor/ReviewBar.js +1 -1
  545. package/dist/views/page-editor/ReviewBar.js.map +1 -1
  546. package/dist/views/page-editor/VersionHistoryPanel.js +1 -1
  547. package/dist/views/page-editor/VersionHistoryPanel.js.map +1 -1
  548. package/dist/views/seo/AuditTab.js +1 -1
  549. package/dist/views/seo/AuditTab.js.map +1 -1
  550. package/dist/views/seo/OverviewTab.d.ts.map +1 -1
  551. package/dist/views/seo/OverviewTab.js +2 -2
  552. package/dist/views/seo/OverviewTab.js.map +1 -1
  553. package/dist/views/seo/ProposalsTab.js +1 -1
  554. package/dist/views/seo/ProposalsTab.js.map +1 -1
  555. package/dist/views/settings/AISettingsTab.d.ts.map +1 -1
  556. package/dist/views/settings/AISettingsTab.js +4 -2
  557. package/dist/views/settings/AISettingsTab.js.map +1 -1
  558. package/dist/views/settings/AccessProtectionCard.js +1 -1
  559. package/dist/views/settings/AccessProtectionCard.js.map +1 -1
  560. package/dist/views/settings/AdminThemeCard.d.ts.map +1 -1
  561. package/dist/views/settings/AdminThemeCard.js +63 -15
  562. package/dist/views/settings/AdminThemeCard.js.map +1 -1
  563. package/dist/views/settings/AppearanceTab.d.ts.map +1 -1
  564. package/dist/views/settings/AppearanceTab.js +4 -2
  565. package/dist/views/settings/AppearanceTab.js.map +1 -1
  566. package/dist/views/settings/BrandPreviewCard.js +1 -1
  567. package/dist/views/settings/BrandPreviewCard.js.map +1 -1
  568. package/dist/views/settings/BrandVoiceCard.js +1 -1
  569. package/dist/views/settings/BrandVoiceCard.js.map +1 -1
  570. package/dist/views/settings/EmailSettingsTab.d.ts.map +1 -1
  571. package/dist/views/settings/EmailSettingsTab.js +5 -3
  572. package/dist/views/settings/EmailSettingsTab.js.map +1 -1
  573. package/dist/views/settings/GeneralSettingsTab.d.ts.map +1 -1
  574. package/dist/views/settings/GeneralSettingsTab.js +4 -2
  575. package/dist/views/settings/GeneralSettingsTab.js.map +1 -1
  576. package/dist/views/settings/ProviderConnectionCard.js +1 -1
  577. package/dist/views/settings/ProviderConnectionCard.js.map +1 -1
  578. package/dist/views/settings/SearchDataCard.js +1 -1
  579. package/dist/views/settings/SearchDataCard.js.map +1 -1
  580. package/dist/views/settings/SecurityStatusCard.js +2 -2
  581. package/dist/views/settings/SecurityStatusCard.js.map +1 -1
  582. package/dist/views/settings/SecurityTab.d.ts.map +1 -1
  583. package/dist/views/settings/SecurityTab.js +4 -2
  584. package/dist/views/settings/SecurityTab.js.map +1 -1
  585. package/dist/views/settings/SeoAutopilotCard.js +2 -2
  586. package/dist/views/settings/SeoAutopilotCard.js.map +1 -1
  587. package/dist/views/settings/SeoSettingsTab.d.ts.map +1 -1
  588. package/dist/views/settings/SeoSettingsTab.js +5 -3
  589. package/dist/views/settings/SeoSettingsTab.js.map +1 -1
  590. package/dist/views/settings/SiteIndexStatusCard.js +1 -1
  591. package/dist/views/settings/SiteIndexStatusCard.js.map +1 -1
  592. package/dist/views/settings/SiteThemeCard.js +1 -1
  593. package/dist/views/settings/UpdatesTab.d.ts.map +1 -1
  594. package/dist/views/settings/UpdatesTab.js +6 -5
  595. package/dist/views/settings/UpdatesTab.js.map +1 -1
  596. package/dist/views/settings/components.d.ts +7 -11
  597. package/dist/views/settings/components.d.ts.map +1 -1
  598. package/dist/views/settings/components.js +18 -12
  599. package/dist/views/settings/components.js.map +1 -1
  600. package/dist/views/settings/useAppearanceSettings.d.ts +7 -1
  601. package/dist/views/settings/useAppearanceSettings.d.ts.map +1 -1
  602. package/dist/views/settings/useAppearanceSettings.js +89 -22
  603. package/dist/views/settings/useAppearanceSettings.js.map +1 -1
  604. package/dist/views/users/UserDetailDrawer.js +1 -1
  605. package/dist/views/users/UserDetailDrawer.js.map +1 -1
  606. package/package.json +10 -8
  607. package/src/AdminRoot.tsx +88 -30
  608. package/src/LoginRoot.tsx +2 -1
  609. package/src/__tests__/components/author-avatar.test.tsx +3 -20
  610. package/src/__tests__/components/notification-bell.test.tsx +146 -14
  611. package/src/__tests__/components/responsive-tiers.render.test.tsx +461 -0
  612. package/src/__tests__/components/serp-preview.render.test.tsx +6 -3
  613. package/src/__tests__/components/shell-primitives.render.test.tsx +951 -0
  614. package/src/__tests__/components/theme-provider-accent.test.tsx +83 -8
  615. package/src/__tests__/components/toggle.test.tsx +11 -3
  616. package/src/__tests__/components/ui-primitives.test.tsx +5 -8
  617. package/src/__tests__/layout/build-nav-items.test.ts +1 -1
  618. package/src/__tests__/layout/shell-nav.render.test.tsx +983 -0
  619. package/src/__tests__/layout/sidebar-forms-submenu.render.test.tsx +8 -4
  620. package/src/__tests__/layout/sidebar-groups.render.test.tsx +116 -0
  621. package/src/__tests__/layout/sidebar-menus.render.test.tsx +116 -0
  622. package/src/__tests__/layout/sidebar-plugin-nav.test.ts +1 -1
  623. package/src/__tests__/layout/sidebar-posts.test.ts +48 -40
  624. package/src/__tests__/layout/sidebar-submenu.render.test.tsx +35 -10
  625. package/src/__tests__/layout/topbar.render.test.tsx +464 -0
  626. package/src/__tests__/lib/api.test.ts +2 -0
  627. package/src/__tests__/lib/job-drawer.test.ts +493 -0
  628. package/src/__tests__/lib/job-view.test.ts +437 -0
  629. package/src/__tests__/lib/jobs-service.test.ts +98 -0
  630. package/src/__tests__/router/admin-route-order.test.ts +39 -0
  631. package/src/__tests__/styles/ai-gradient-contrast.test.ts +135 -0
  632. package/src/__tests__/styles/breakpoint-order.test.ts +68 -0
  633. package/src/__tests__/styles/responsive-layer.test.ts +367 -12
  634. package/src/__tests__/styles/tailwind-preset.test.ts +154 -0
  635. package/src/__tests__/styles/theme-token-scope.test.ts +10 -3
  636. package/src/__tests__/styles/tiers.test.ts +136 -0
  637. package/src/__tests__/styles/tokens-drift.test.ts +67 -6
  638. package/src/__tests__/views/admin-lazy-route.render.test.tsx +41 -1
  639. package/src/__tests__/views/ai-settings.render.test.tsx +4 -4
  640. package/src/__tests__/views/appearance-menus-route.render.test.tsx +58 -0
  641. package/src/__tests__/views/appearance-settings.render.test.tsx +10 -8
  642. package/src/__tests__/views/appearance-theme-provider.render.test.tsx +347 -0
  643. package/src/__tests__/views/dashboard.test.tsx +48 -0
  644. package/src/__tests__/views/document-edit-navigation.render.test.tsx +130 -0
  645. package/src/__tests__/views/document-edit-routes.render.test.tsx +130 -0
  646. package/src/__tests__/views/email-settings.render.test.tsx +2 -2
  647. package/src/__tests__/views/form-entries.render.test.tsx +22 -0
  648. package/src/__tests__/views/form-submissions.render.test.tsx +22 -0
  649. package/src/__tests__/views/forms-list.render.test.tsx +13 -0
  650. package/src/__tests__/views/general-settings.render.test.tsx +38 -11
  651. package/src/__tests__/views/jobs-drawer.render.test.tsx +1047 -0
  652. package/src/__tests__/views/jobs-list.render.test.tsx +850 -0
  653. package/src/__tests__/views/kpi-grid.test.ts +29 -0
  654. package/src/__tests__/views/post-section-editor.test.tsx +5 -1
  655. package/src/__tests__/views/script-tags.render.test.tsx +29 -0
  656. package/src/__tests__/views/security-settings.render.test.tsx +9 -10
  657. package/src/__tests__/views/seo-settings.render.test.tsx +7 -9
  658. package/src/__tests__/views/settings-save-bar.render.test.tsx +91 -0
  659. package/src/__tests__/views/settings-save-footer.render.test.tsx +25 -15
  660. package/src/__tests__/views/settings-tabs.render.test.tsx +371 -0
  661. package/src/__tests__/views/updates-tab.render.test.tsx +4 -3
  662. package/src/components/Breadcrumbs.tsx +7 -1
  663. package/src/components/CommandPalette.tsx +51 -3
  664. package/src/components/LocaleSwitcher.tsx +5 -6
  665. package/src/components/NotificationBell.tsx +74 -18
  666. package/src/components/OfflineStatus.tsx +1 -1
  667. package/src/components/PresenceIndicator.tsx +2 -1
  668. package/src/components/ReflowMeter.tsx +3 -3
  669. package/src/components/SEOPanel.tsx +2 -2
  670. package/src/components/ThemeProvider.tsx +122 -42
  671. package/src/components/TipTapEditor.tsx +3 -4
  672. package/src/components/forms/EmbedPanel.tsx +1 -1
  673. package/src/components/forms/FormEntryDetailPane.tsx +7 -1
  674. package/src/components/forms/ShortcodeGlossary.tsx +7 -1
  675. package/src/components/forms/primitives.tsx +37 -21
  676. package/src/components/pages/tag-badges.tsx +4 -3
  677. package/src/components/seo/PageAuditPanel.tsx +2 -2
  678. package/src/components/seo/SerpPreview.tsx +5 -5
  679. package/src/components/seo/primitives.tsx +2 -2
  680. package/src/components/ui/AuthorAvatar.tsx +11 -10
  681. package/src/components/ui/Badge.tsx +1 -1
  682. package/src/components/ui/Breadcrumb.tsx +109 -0
  683. package/src/components/ui/Button.tsx +40 -15
  684. package/src/components/ui/Card.tsx +35 -32
  685. package/src/components/ui/CardListControls.tsx +90 -0
  686. package/src/components/ui/CountChip.tsx +90 -0
  687. package/src/components/ui/FilterPill.tsx +5 -3
  688. package/src/components/ui/InspectorPane.tsx +21 -7
  689. package/src/components/ui/Modal.tsx +20 -6
  690. package/src/components/ui/PageHeader.tsx +63 -0
  691. package/src/components/ui/RowActions.tsx +7 -2
  692. package/src/components/ui/Segmented.tsx +97 -0
  693. package/src/components/ui/Toaster.tsx +139 -0
  694. package/src/components/ui/Toggle.tsx +18 -14
  695. package/src/components/ui/UnderlineTabs.tsx +373 -0
  696. package/src/components/ui/UnsavedBar.tsx +119 -0
  697. package/src/components/ui/admin-links.tsx +20 -0
  698. package/src/components/ui/card-table.ts +34 -0
  699. package/src/components/virtual-window.tsx +13 -2
  700. package/src/fields/RelationshipField.tsx +1 -1
  701. package/src/hooks/useAppearanceBootstrap.ts +9 -3
  702. package/src/index.ts +19 -0
  703. package/src/layout/Header.tsx +210 -135
  704. package/src/layout/Layout.tsx +61 -108
  705. package/src/layout/MobileTabBar.tsx +92 -0
  706. package/src/layout/Sidebar.tsx +555 -593
  707. package/src/layout/nav-config.tsx +425 -0
  708. package/src/layout/primitives/AdminShell.tsx +154 -6
  709. package/src/layout/topbar-classes.ts +8 -0
  710. package/src/layout/use-nav-items.ts +40 -0
  711. package/src/lib/api.ts +7 -1
  712. package/src/lib/appearance-api.ts +4 -0
  713. package/src/lib/job-drawer.ts +424 -0
  714. package/src/lib/job-view.ts +456 -0
  715. package/src/lib/jobs-service.ts +290 -0
  716. package/src/lib/sheet-focus.ts +71 -0
  717. package/src/lib/tiers.ts +43 -0
  718. package/src/router/admin-routes.ts +8 -0
  719. package/src/router/index.ts +9 -1
  720. package/src/styles/prenta-tokens.css +263 -82
  721. package/src/styles/responsive.css +460 -22
  722. package/src/styles/theme.css +177 -28
  723. package/src/views/ApiKeys.tsx +2 -2
  724. package/src/views/AppearanceChrome.tsx +74 -0
  725. package/src/views/CollectionList.tsx +264 -205
  726. package/src/views/Dashboard.tsx +26 -13
  727. package/src/views/DocumentEdit.tsx +111 -56
  728. package/src/views/FormDeliveries.tsx +30 -17
  729. package/src/views/FormEntries.tsx +28 -20
  730. package/src/views/FormSubmissions.tsx +32 -34
  731. package/src/views/Forms.tsx +55 -34
  732. package/src/views/FormsSettings.tsx +94 -0
  733. package/src/views/Jobs/BusyButton.tsx +56 -0
  734. package/src/views/Jobs/CancelJobDialog.tsx +127 -0
  735. package/src/views/Jobs/DrawerActivity.tsx +142 -0
  736. package/src/views/Jobs/DrawerOverview.tsx +139 -0
  737. package/src/views/Jobs/DrawerResults.tsx +155 -0
  738. package/src/views/Jobs/DrawerReview.tsx +464 -0
  739. package/src/views/Jobs/JobDrawer.tsx +556 -0
  740. package/src/views/Jobs/JobsTable.tsx +260 -0
  741. package/src/views/Jobs/WorkerStrip.tsx +144 -0
  742. package/src/views/Jobs/atoms.tsx +93 -0
  743. package/src/views/Jobs/focus.ts +56 -0
  744. package/src/views/Jobs/icons.tsx +111 -0
  745. package/src/views/Jobs/placeholders.tsx +66 -0
  746. package/src/views/Jobs/useJobDetail.ts +64 -0
  747. package/src/views/Jobs/useJobsFeed.ts +249 -0
  748. package/src/views/Jobs/useReviewItems.ts +187 -0
  749. package/src/views/Jobs.tsx +282 -105
  750. package/src/views/MediaBrowser.tsx +71 -21
  751. package/src/views/Pages/PagesListView.tsx +115 -39
  752. package/src/views/Posts/NewPostTypeInstructions.tsx +15 -10
  753. package/src/views/Posts/PostTypesView.tsx +28 -6
  754. package/src/views/Posts/PostsListView.tsx +130 -40
  755. package/src/views/SEO.tsx +23 -8
  756. package/src/views/ScriptTags.tsx +233 -153
  757. package/src/views/Settings.tsx +215 -256
  758. package/src/views/SpamFolder.tsx +32 -0
  759. package/src/views/Trash.tsx +12 -1
  760. package/src/views/Users.tsx +2 -2
  761. package/src/views/WidgetsPlaceholder.tsx +33 -0
  762. package/src/views/dashboard/kpi-grid.ts +38 -0
  763. package/src/views/lazy-views.tsx +12 -0
  764. package/src/views/page-editor/PageTab.tsx +2 -2
  765. package/src/views/page-editor/ReviewBar.tsx +1 -1
  766. package/src/views/page-editor/VersionHistoryPanel.tsx +1 -1
  767. package/src/views/seo/AuditTab.tsx +1 -1
  768. package/src/views/seo/OverviewTab.tsx +6 -5
  769. package/src/views/seo/ProposalsTab.tsx +1 -1
  770. package/src/views/settings/AISettingsTab.tsx +10 -6
  771. package/src/views/settings/AccessProtectionCard.tsx +1 -1
  772. package/src/views/settings/AdminThemeCard.tsx +228 -35
  773. package/src/views/settings/AppearanceTab.tsx +10 -6
  774. package/src/views/settings/BrandPreviewCard.tsx +1 -1
  775. package/src/views/settings/BrandVoiceCard.tsx +1 -1
  776. package/src/views/settings/EmailSettingsTab.tsx +11 -7
  777. package/src/views/settings/GeneralSettingsTab.tsx +10 -6
  778. package/src/views/settings/ProviderConnectionCard.tsx +1 -1
  779. package/src/views/settings/SearchDataCard.tsx +1 -1
  780. package/src/views/settings/SecurityStatusCard.tsx +2 -2
  781. package/src/views/settings/SecurityTab.tsx +10 -6
  782. package/src/views/settings/SeoAutopilotCard.tsx +2 -2
  783. package/src/views/settings/SeoSettingsTab.tsx +13 -9
  784. package/src/views/settings/SiteIndexStatusCard.tsx +1 -1
  785. package/src/views/settings/SiteThemeCard.tsx +1 -1
  786. package/src/views/settings/UpdatesTab.tsx +107 -101
  787. package/src/views/settings/components.tsx +26 -62
  788. package/src/views/settings/useAppearanceSettings.ts +116 -25
  789. package/src/views/users/UserDetailDrawer.tsx +1 -1
  790. package/dist/components/ui/StatPill.d.ts +0 -18
  791. package/dist/components/ui/StatPill.d.ts.map +0 -1
  792. package/dist/components/ui/StatPill.js +0 -5
  793. package/dist/components/ui/StatPill.js.map +0 -1
  794. package/src/components/ui/StatPill.tsx +0 -37
@@ -1,137 +1,314 @@
1
1
  'use client'
2
2
 
3
- import { useCallback, useEffect, useState } from 'react'
4
- import { ListTodo } from 'lucide-react'
5
- import { cmsApi } from '../lib/api.js'
6
- import { EmptyState } from '../components/ui/EmptyState.js'
7
- import { Skeleton } from '../components/ui/Skeleton.js'
3
+ import { useEffect, useMemo, useRef, useState } from 'react'
4
+ import { toast } from 'sonner'
5
+ import { Button } from '../components/ui/Button.js'
6
+ import { PageHeader } from '../components/ui/PageHeader.js'
7
+ import { Segmented } from '../components/ui/Segmented.js'
8
+ import {
9
+ JOB_FILTERS,
10
+ JOB_TYPES,
11
+ countJobs,
12
+ jobType,
13
+ matchJob,
14
+ toJobRows,
15
+ type JobFilter,
16
+ type JobRow,
17
+ } from '../lib/job-view.js'
18
+ import {
19
+ JOBS_LIST_LIMIT,
20
+ cancelJob,
21
+ retryJob,
22
+ runJobNow,
23
+ type RunnableJobType,
24
+ } from '../lib/jobs-service.js'
25
+ import { BusyButton } from './Jobs/BusyButton.js'
26
+ import { CancelJobDialog, staleRunning } from './Jobs/CancelJobDialog.js'
27
+ import { focusJobRow } from './Jobs/focus.js'
28
+ import { JobsTable, type JobDrawerTab } from './Jobs/JobsTable.js'
29
+ import { JobIcons } from './Jobs/icons.js'
30
+ import { JobDrawer } from './Jobs/JobDrawer.js'
31
+ import { NewBatchJob } from './Jobs/placeholders.js'
32
+ import { usePageVisible, useJobsFeed } from './Jobs/useJobsFeed.js'
33
+ import { WorkerStrip } from './Jobs/WorkerStrip.js'
8
34
 
9
35
  export interface JobsProps {
10
36
  onNavigate: (path: string) => void
11
37
  }
12
38
 
13
- interface JobProgress {
14
- completed: number
15
- total: number
16
- message?: string
17
- }
39
+ const FILTER_OPTIONS = JOB_FILTERS.map(({ id, label }) => ({ id, label }))
18
40
 
19
- interface JobRow {
20
- id: string
21
- type: string
22
- status: string
23
- attempts: number
24
- maxAttempts: number
25
- lastError: string | null
26
- progress: JobProgress
27
- updatedAt: string
41
+ /** `.jb-livebtn`: pauses and resumes the 5-second refresh. */
42
+ function LiveButton({ live, onToggle }: { live: boolean; onToggle: () => void }) {
43
+ return (
44
+ <button
45
+ type="button"
46
+ aria-pressed={live}
47
+ title="Updates every 5 seconds"
48
+ onClick={onToggle}
49
+ className="rounded-8 border-bdr bg-card text-sub text-sm2 inline-flex h-[34px] cursor-pointer items-center gap-[7px] border px-[11px] font-semibold"
50
+ >
51
+ <i
52
+ aria-hidden="true"
53
+ className={`size-[7px] shrink-0 rounded-full ${
54
+ live ? 'bg-suc shadow-[0_0_0_3px_var(--suc-l)]' : 'bg-faint'
55
+ }`}
56
+ />
57
+ {live ? 'Live' : 'Paused'}
58
+ </button>
59
+ )
28
60
  }
29
61
 
30
- function progressLabel(progress: JobProgress | undefined): string {
31
- if (!progress) return '—'
32
- if (progress.message) return progress.message
33
- if (progress.total > 0) return `${progress.completed} of ${progress.total}`
34
- return '—'
35
- }
62
+ /**
63
+ * Settings → Jobs (jobs-view.jsx): the worker strip, failure and review
64
+ * alerts, filters with counts, and the newest 50 jobs, refreshed every 5
65
+ * seconds while Live is on and the tab is visible. Filters and counts work
66
+ * on the loaded rows.
67
+ *
68
+ * Opening a job sets `open` and shows its drawer (P-18). The batch wizard
69
+ * (P-20) renders from `./Jobs/placeholders.js` until it's built.
70
+ */
71
+ export function Jobs({ onNavigate }: JobsProps) {
72
+ const [live, setLive] = useState(true)
73
+ const visible = usePageVisible()
74
+ const feed = useJobsFeed(live && visible)
75
+ const { upsert, reload } = feed
76
+ const [filter, setFilter] = useState<JobFilter>('all')
77
+ const [type, setType] = useState('all')
78
+ const [open, setOpen] = useState<{ id: string; tab: JobDrawerTab } | null>(null)
79
+ const [cancelTarget, setCancelTarget] = useState<JobRow | null>(null)
80
+ const cancelledId = useRef<string | null>(null)
81
+ const [wizard, setWizard] = useState(false)
82
+ const [retryingId, setRetryingId] = useState<string | null>(null)
83
+ /** A row whose action button just went away; its open button takes focus if focus was lost. */
84
+ const refocus = useRef<string | null>(null)
36
85
 
37
- export function Jobs(_props: JobsProps) {
38
- const [jobs, setJobs] = useState<JobRow[]>([])
39
- const [loading, setLoading] = useState(true)
40
- const [error, setError] = useState<string | null>(null)
86
+ useEffect(() => {
87
+ const id = refocus.current
88
+ if (!id) return
89
+ refocus.current = null
90
+ const current = document.activeElement
91
+ if (current && current !== document.body && current.isConnected) return
92
+ focusJobRow(id)
93
+ })
94
+
95
+ const rows = useMemo(
96
+ () => toJobRows(feed.jobs, feed.fetchedAt, feed.worker),
97
+ [feed.jobs, feed.fetchedAt, feed.worker],
98
+ )
99
+ const scoped = type === 'all' ? rows : rows.filter((row) => row.type === type)
100
+ const list = scoped.filter((row) => matchJob(row, filter))
101
+ const counts = countJobs(scoped)
102
+ const dead = rows.filter((row) => row.state === 'dead')
103
+ const revJobs = rows.filter(
104
+ (row) =>
105
+ row.type === 'batch-ai' &&
106
+ row.pending > 0 &&
107
+ row.state !== 'cancelled' &&
108
+ row.state !== 'dead',
109
+ )
110
+ const revN = revJobs.reduce((sum, row) => sum + row.pending, 0)
111
+ const openJob = open ? feed.jobs.find((job) => job.id === open.id) : undefined
112
+ const openRow = open ? rows.find((row) => row.id === open.id) : undefined
113
+ const ready = feed.status === 'ready'
41
114
 
42
- const load = useCallback(async () => {
43
- const res = await cmsApi<{ jobs?: JobRow[] }>('/jobs')
44
- if (res.error) {
45
- setError(res.error)
46
- setLoading(false)
115
+ const openAt = (id: string, tab: JobDrawerTab = null) => setOpen({ id, tab })
116
+
117
+ async function runNow(t: RunnableJobType) {
118
+ const res = await runJobNow(t)
119
+ if (!res.ok) {
120
+ toast.error(`${JOB_TYPES[t].label} didn’t start: ${res.error}`)
47
121
  return
48
122
  }
49
- setError(null)
50
- setJobs(res.data?.jobs ?? [])
51
- setLoading(false)
52
- }, [])
123
+ const { job, reused } = res.value
124
+ upsert(job)
125
+ if (reused) {
126
+ toast(`${JOB_TYPES[t].label} is already ${job.status}. Reusing that job.`)
127
+ openAt(job.id)
128
+ } else {
129
+ toast(`${JOB_TYPES[t].label} queued. It starts on the next worker run.`)
130
+ }
131
+ void reload()
132
+ }
53
133
 
54
- useEffect(() => {
55
- void load()
56
- const timer = window.setInterval(() => {
57
- void load()
58
- }, 5000)
59
- return () => window.clearInterval(timer)
60
- }, [load])
134
+ async function retry(j: JobRow) {
135
+ setRetryingId(j.id)
136
+ const res = await retryJob(j.id)
137
+ setRetryingId(null)
138
+ if (!res.ok) {
139
+ toast.error(`“${j.title}” wasn’t retried: ${res.error}`)
140
+ return
141
+ }
142
+ refocus.current = j.id
143
+ upsert(res.value)
144
+ toast(`Retrying from ${jobType(j.type).unit === 'pages' ? 'page' : 'document'} ${j.done + 1}`)
145
+ void reload()
146
+ }
147
+
148
+ async function confirmCancel(j: JobRow) {
149
+ const res = await cancelJob(j.id)
150
+ if (!res.ok) {
151
+ toast.error(`“${j.title}” wasn’t cancelled: ${res.error}`)
152
+ return
153
+ }
154
+ const job = res.value
155
+ upsert(job)
156
+ if (job.status === 'cancelled') toast('Job cancelled')
157
+ else if (staleRunning(j)) toast('Stopping on the next worker run')
158
+ else if (job.status === 'queued' || job.status === 'running') toast('Stopping after this slice')
159
+ else toast(`“${j.title}” had already finished.`)
160
+ void reload()
161
+ }
162
+
163
+ const deadFirst = dead[0]
164
+ const firstReview = revJobs[0]
165
+ const deadCause = deadFirst?.error?.replace(/\.\s*$/, '')
61
166
 
62
167
  return (
63
- <div className="flex flex-col gap-6 p-6">
64
- <div className="flex items-center justify-between gap-4">
65
- <div>
66
- <h1 className="text-foreground text-2xl font-medium">Jobs</h1>
67
- <p className="text-muted-foreground text-sm">
68
- SEO audits, content health, and batch AI. Failed jobs retry, then land in the dead
69
- letter.
70
- </p>
71
- </div>
72
- <button
73
- type="button"
74
- onClick={() => void load()}
75
- className="bg-primary text-primary-foreground focus-visible:ring-ring inline-flex min-h-11 items-center rounded-md px-4 py-2 text-base font-medium hover:opacity-90 focus-visible:ring-2 focus-visible:outline-none"
76
- >
77
- Refresh
78
- </button>
79
- </div>
168
+ <div className="mobile:px-3.5 mobile:pt-4 mobile:pb-[100px] flex min-w-0 flex-col gap-4 px-7 pt-[22px] pb-24 leading-[normal]">
169
+ <PageHeader
170
+ flush
171
+ title="Jobs"
172
+ subtitle="Background work that’s too big to finish in one request: SEO scans, content health checks and batch AI changes. Long jobs run one slice a minute and pick up where they left off."
173
+ actions={
174
+ <>
175
+ <LiveButton live={live} onToggle={() => setLive((value) => !value)} />
176
+ <Button
177
+ data-jobs-new=""
178
+ leftIcon={<JobIcons.spark size={14} />}
179
+ onClick={() => setWizard(true)}
180
+ >
181
+ New batch AI job
182
+ </Button>
183
+ </>
184
+ }
185
+ />
80
186
 
81
- {loading ? <Skeleton lines={6} /> : null}
187
+ <WorkerStrip
188
+ worker={feed.worker}
189
+ workerError={feed.workerError}
190
+ skewMs={feed.skewMs}
191
+ loading={feed.status === 'loading'}
192
+ rows={rows}
193
+ ticking={live && visible}
194
+ onRunNow={runNow}
195
+ />
82
196
 
83
- {!loading && error ? (
197
+ {deadFirst ? (
84
198
  <div
85
- className="border-border bg-card flex flex-col gap-3 rounded-lg border p-6"
86
199
  role="alert"
200
+ className="rounded-10 bg-err-l text-body text-err flex flex-wrap items-center gap-3 px-3.5 py-[11px]"
87
201
  >
88
- <p className="text-foreground text-base">{error}</p>
89
- <button
90
- type="button"
91
- onClick={() => void load()}
92
- className="border-border text-foreground hover:bg-accent focus-visible:ring-ring inline-flex min-h-11 w-fit items-center rounded-md border px-4 py-2 text-base font-medium focus-visible:ring-2 focus-visible:outline-none"
202
+ <JobIcons.alert size={16} />
203
+ <span className="text-txt min-w-0 flex-[1_1_260px]">
204
+ <b className="font-bold">
205
+ {dead.length} job{dead.length > 1 ? 's' : ''} failed after {deadFirst.maxAttempts}{' '}
206
+ attempts.
207
+ </b>{' '}
208
+ {deadCause ? `${deadFirst.title}: ${deadCause}.` : `${deadFirst.title} stopped.`}{' '}
209
+ Finished work is kept.
210
+ </span>
211
+ <Button variant="secondary" size="sm" onClick={() => openAt(deadFirst.id, 'overview')}>
212
+ See why
213
+ </Button>
214
+ <BusyButton
215
+ size="sm"
216
+ leftIcon={<JobIcons.retry size={12} />}
217
+ busy={retryingId === deadFirst.id}
218
+ onClick={() => void retry(deadFirst)}
93
219
  >
94
- Try again
95
- </button>
220
+ Retry
221
+ </BusyButton>
96
222
  </div>
97
223
  ) : null}
98
224
 
99
- {!loading && !error && jobs.length === 0 ? (
100
- <EmptyState
101
- icon={<ListTodo size={24} aria-hidden />}
102
- title="No jobs yet"
103
- description="Scheduled SEO and content-health scans show up here with their progress."
104
- />
225
+ {revN > 0 && firstReview ? (
226
+ <div className="rounded-10 bg-acc-l text-body text-acc flex flex-wrap items-center gap-3 px-3.5 py-[11px]">
227
+ <JobIcons.spark size={16} />
228
+ <span className="text-txt min-w-0 flex-[1_1_260px]">
229
+ <b className="font-bold">
230
+ {revN} AI {revN === 1 ? 'change is' : 'changes are'} waiting for review
231
+ </b>{' '}
232
+ across {revJobs.length} job{revJobs.length > 1 ? 's' : ''}. Nothing is applied until
233
+ someone approves it.
234
+ </span>
235
+ <Button size="sm" onClick={() => openAt(firstReview.id, 'review')}>
236
+ Review changes
237
+ </Button>
238
+ </div>
105
239
  ) : null}
106
240
 
107
- {!loading && !error && jobs.length > 0 ? (
108
- <div className="border-border overflow-x-auto rounded-lg border">
109
- <table className="w-full text-left text-base" aria-label="Background jobs">
110
- <thead className="bg-muted text-foreground">
111
- <tr>
112
- <th className="px-4 py-3 font-medium">Type</th>
113
- <th className="px-4 py-3 font-medium">Status</th>
114
- <th className="px-4 py-3 font-medium">Attempts</th>
115
- <th className="px-4 py-3 font-medium">Progress</th>
116
- <th className="px-4 py-3 font-medium">Last error</th>
117
- </tr>
118
- </thead>
119
- <tbody>
120
- {jobs.map((job) => (
121
- <tr key={job.id} className="border-border border-t">
122
- <td className="text-foreground px-4 py-3">{job.type}</td>
123
- <td className="text-foreground px-4 py-3">{job.status}</td>
124
- <td className="text-muted-foreground px-4 py-3">
125
- {job.attempts}/{job.maxAttempts}
126
- </td>
127
- <td className="text-foreground px-4 py-3">{progressLabel(job.progress)}</td>
128
- <td className="text-muted-foreground px-4 py-3">{job.lastError ?? '—'}</td>
129
- </tr>
130
- ))}
131
- </tbody>
132
- </table>
133
- </div>
241
+ <div data-jobs-filters="" className="flex flex-wrap items-center gap-2">
242
+ <Segmented
243
+ options={FILTER_OPTIONS}
244
+ value={filter}
245
+ onChange={(id) => setFilter(id as JobFilter)}
246
+ label="Filter jobs"
247
+ counts={ready ? counts : undefined}
248
+ />
249
+ <select
250
+ aria-label="Job type"
251
+ value={type}
252
+ onChange={(event) => setType(event.target.value)}
253
+ className="rounded-8 border-bdr bg-card text-txt text-sm2 h-8 border px-[9px]"
254
+ >
255
+ <option value="all">All types</option>
256
+ {Object.entries(JOB_TYPES).map(([key, info]) => (
257
+ <option key={key} value={key}>
258
+ {info.label}
259
+ </option>
260
+ ))}
261
+ </select>
262
+ <span
263
+ role="status"
264
+ className={`text-meta mobile:ml-0 mobile:basis-full ml-auto ${
265
+ ready && feed.error ? 'text-err' : 'text-faint'
266
+ }`}
267
+ >
268
+ {ready && feed.error
269
+ ? `Couldn’t refresh: ${feed.error}. Showing the last update.`
270
+ : `Latest ${JOBS_LIST_LIMIT} jobs · updates every 5 seconds`}
271
+ </span>
272
+ </div>
273
+
274
+ <JobsTable
275
+ rows={list}
276
+ filter={filter}
277
+ selectedId={open?.id ?? null}
278
+ status={feed.status}
279
+ error={feed.error}
280
+ retryingId={retryingId}
281
+ onOpen={openAt}
282
+ onCancel={(row) => {
283
+ cancelledId.current = row.id
284
+ setCancelTarget(row)
285
+ }}
286
+ onRetry={(row) => void retry(row)}
287
+ onReload={reload}
288
+ />
289
+
290
+ {open && openJob && openRow ? (
291
+ <JobDrawer
292
+ key={open.id}
293
+ job={openJob}
294
+ row={openRow}
295
+ tab={open.tab}
296
+ now={feed.fetchedAt}
297
+ worker={feed.worker}
298
+ onClose={() => setOpen(null)}
299
+ onReload={() => void reload()}
300
+ onNavigate={onNavigate}
301
+ />
134
302
  ) : null}
303
+ {wizard ? <NewBatchJob onClose={() => setWizard(false)} /> : null}
304
+ <CancelJobDialog
305
+ job={cancelTarget}
306
+ onClose={() => setCancelTarget(null)}
307
+ onConfirm={confirmCancel}
308
+ onFocusFallback={() => {
309
+ if (cancelledId.current) focusJobRow(cancelledId.current)
310
+ }}
311
+ />
135
312
  </div>
136
313
  )
137
314
  }
@@ -33,8 +33,10 @@ import { cmsApi } from '../lib/api.js'
33
33
  import { useVirtualWindow, VirtualTablePadding } from '../components/virtual-window.js'
34
34
  import { FolderTree, type FolderSelection } from '../components/FolderTree.js'
35
35
  import { Button } from '../components/ui/Button.js'
36
+ import { TIER_MEDIA } from '../lib/tiers.js'
37
+ import { useSheetFocus } from '../lib/sheet-focus.js'
36
38
  import { StatusBadge } from '../components/ui/StatusBadge.js'
37
- import { StatPill } from '../components/ui/StatPill.js'
39
+ import { CountChip } from '../components/ui/CountChip.js'
38
40
  import { hasLowQualityAlt, MediaSeoAudit, type MediaSeoAuditItem } from './MediaSeoAudit.js'
39
41
 
40
42
  interface MediaItem {
@@ -153,6 +155,13 @@ function buildMediaApiUrl(folderSel: FolderSelection): string {
153
155
  export function MediaBrowser({ onNavigate, currentPath }: MediaBrowserProps) {
154
156
  const [folderSel, setFolderSel] = useState<FolderSelection>({ type: 'smart', smart: 'all' })
155
157
  const [sidebarOpen, setSidebarOpen] = useState(true)
158
+ // Below 769px the folder tree stacks above the grid, so it starts closed
159
+ // there; the folder button opens it.
160
+ useEffect(() => {
161
+ if (typeof window.matchMedia === 'function' && window.matchMedia(TIER_MEDIA.mobile).matches) {
162
+ setSidebarOpen(false)
163
+ }
164
+ }, [])
156
165
 
157
166
  const apiUrl = useMemo(() => buildMediaApiUrl(folderSel), [folderSel])
158
167
  const { data, loading, error, refetch } = useApiData<{
@@ -213,6 +222,8 @@ export function MediaBrowser({ onNavigate, currentPath }: MediaBrowserProps) {
213
222
  const gridColumns = useGridColumns(activeItem !== null)
214
223
  const gridScrollRef = useRef<HTMLDivElement>(null)
215
224
  const listScrollRef = useRef<HTMLDivElement>(null)
225
+ /** The grid's or list's scroll position when a card opened the detail panel. */
226
+ const savedListScroll = useRef(0)
216
227
  const gridRowCount = gridColumns > 0 ? Math.ceil(filteredAndSorted.length / gridColumns) : 0
217
228
  const gridWindow = useVirtualWindow({
218
229
  count: gridRowCount,
@@ -243,6 +254,7 @@ export function MediaBrowser({ onNavigate, currentPath }: MediaBrowserProps) {
243
254
  }, [mediaItems])
244
255
 
245
256
  const openDetail = useCallback((item: MediaItem) => {
257
+ savedListScroll.current = (gridScrollRef.current ?? listScrollRef.current)?.scrollTop ?? 0
246
258
  setActiveItem(item)
247
259
  setEditAlt(item.altTag ?? '')
248
260
  setEditIsDecorative(item.isDecorative === true)
@@ -517,6 +529,21 @@ export function MediaBrowser({ onNavigate, currentPath }: MediaBrowserProps) {
517
529
  }
518
530
 
519
531
  const panelOpen = activeItem !== null
532
+ const detailPanelRef = useRef<HTMLDivElement>(null)
533
+ // Below 769px the detail panel is a sheet over the content column
534
+ // (`[data-inspector-open]` in responsive.css hides the grid, tabs and
535
+ // header), so the card that opened it leaves the screen. Focus moves into
536
+ // the panel and back when it closes. The hidden scroll box comes back at the
537
+ // top, and the virtualised window wouldn't follow (no scroll event), so its
538
+ // position, saved when a card opens the panel, goes back first. Grid cards
539
+ // aren't focusable, so focus lands on the list itself.
540
+ useSheetFocus(panelOpen, detailPanelRef, {
541
+ restore: () => {
542
+ const scroller = gridScrollRef.current ?? listScrollRef.current
543
+ if (scroller) scroller.scrollTop = savedListScroll.current
544
+ },
545
+ fallback: () => gridScrollRef.current ?? listScrollRef.current,
546
+ })
520
547
  const issues = activeItem
521
548
  ? [
522
549
  ...(!hasAccessibleAlt(activeItem) ? ['Missing alt tag'] : []),
@@ -574,7 +601,8 @@ export function MediaBrowser({ onNavigate, currentPath }: MediaBrowserProps) {
574
601
  </div>
575
602
  )}
576
603
 
577
- <div className="mb-4 flex items-center justify-between">
604
+ {/* Actions sit level with the title, as in Media.html (`.mc-hdr-row`). */}
605
+ <div className="mb-4 flex items-start justify-between">
578
606
  <div className="flex items-center gap-3">
579
607
  <button
580
608
  type="button"
@@ -586,17 +614,22 @@ export function MediaBrowser({ onNavigate, currentPath }: MediaBrowserProps) {
586
614
  <FolderInput className="text-muted-foreground h-5 w-5" aria-hidden />
587
615
  </button>
588
616
  <div>
589
- <h1 className="text-foreground mb-1">Media Library</h1>
590
- <div className="flex flex-wrap items-center gap-1.5">
591
- <StatPill value={mediaStats.total} label="Total Files" />
592
- <StatPill value={mediaStats.images} label="Images" />
593
- <StatPill value={mediaStats.videos} label="Videos" />
594
- <StatPill value={mediaStats.documents} label="Documents" />
595
- <StatPill value={formatStorage(mediaStats.bytes)} label="Storage used" />
617
+ {/* Title = sidebar label (SHELL.md §4); copy from Media.html. */}
618
+ <h1 className="text-foreground leading-[normal]">Media</h1>
619
+ <p className="text-body text-sub mt-[3px] leading-[normal]">
620
+ Manage and optimize all your media assets
621
+ </p>
622
+ <div className="mt-[18px] flex flex-wrap items-center gap-1.5">
623
+ <CountChip n={mediaStats.total} label="Total Files" />
624
+ <CountChip n={mediaStats.images} label="Images" />
625
+ <CountChip n={mediaStats.videos} label="Videos" />
626
+ <CountChip n={mediaStats.documents} label="Documents" />
627
+ <CountChip n={formatStorage(mediaStats.bytes)} label="Storage used" />
596
628
  </div>
597
629
  </div>
598
630
  </div>
599
- <div>
631
+ {/* Below 769px Upload floats above the tab bar. */}
632
+ <div data-header-actions="">
600
633
  <input
601
634
  ref={fileInputRef}
602
635
  type="file"
@@ -612,6 +645,7 @@ export function MediaBrowser({ onNavigate, currentPath }: MediaBrowserProps) {
612
645
  onClick={() => fileInputRef.current?.click()}
613
646
  loading={uploading}
614
647
  leftIcon={<Upload size={16} aria-hidden />}
648
+ data-fab=""
615
649
  >
616
650
  {uploading ? 'Uploading...' : 'Upload Files'}
617
651
  </Button>
@@ -671,9 +705,9 @@ export function MediaBrowser({ onNavigate, currentPath }: MediaBrowserProps) {
671
705
  onRetry={refetch}
672
706
  />
673
707
  ) : (
674
- <div className="flex min-h-0 flex-1 gap-4 overflow-hidden">
708
+ <div className="mobile:flex-col flex min-h-0 flex-1 gap-4 overflow-hidden">
675
709
  {sidebarOpen && (
676
- <div className="border-border bg-card flex w-56 shrink-0 flex-col overflow-hidden rounded-lg border">
710
+ <div className="border-border bg-card mobile:max-h-[40vh] mobile:w-full flex w-56 shrink-0 flex-col overflow-hidden rounded-lg border">
677
711
  <FolderTree
678
712
  scope="media"
679
713
  selected={folderSel}
@@ -688,7 +722,7 @@ export function MediaBrowser({ onNavigate, currentPath }: MediaBrowserProps) {
688
722
  </div>
689
723
  )}
690
724
 
691
- <div className="flex min-w-0 flex-1 flex-col">
725
+ <div className="mobile:min-h-0 flex min-w-0 flex-1 flex-col">
692
726
  <div className="border-border bg-card mb-4 rounded-lg border">
693
727
  <div className="flex items-center justify-between p-3">
694
728
  <div className="flex flex-1 items-center gap-3">
@@ -794,7 +828,11 @@ export function MediaBrowser({ onNavigate, currentPath }: MediaBrowserProps) {
794
828
  className={`border-border bg-card overflow-hidden rounded-lg border transition-all duration-200 ${panelOpen ? 'min-w-0 flex-1' : 'w-full'}`}
795
829
  >
796
830
  {viewMode === 'grid' ? (
797
- <div ref={gridScrollRef} className="h-full overflow-y-auto p-2 sm:p-3">
831
+ <div
832
+ ref={gridScrollRef}
833
+ tabIndex={-1}
834
+ className="h-full overflow-y-auto p-2 sm:p-3"
835
+ >
798
836
  <div className="relative" style={{ height: gridRowCount * 220 }}>
799
837
  {gridWindow.rows.map((virtualRow) => (
800
838
  <div
@@ -906,7 +944,11 @@ export function MediaBrowser({ onNavigate, currentPath }: MediaBrowserProps) {
906
944
  </div>
907
945
  </div>
908
946
  ) : (
909
- <div ref={listScrollRef} className="h-full overflow-auto">
947
+ <div
948
+ ref={listScrollRef}
949
+ tabIndex={-1}
950
+ className="h-full overflow-auto outline-none"
951
+ >
910
952
  {/* min-w keeps the list columns readable; narrow viewports scroll sideways. */}
911
953
  <table className="w-full min-w-[640px]">
912
954
  <thead className="border-border bg-muted sticky top-0 border-b">
@@ -1009,17 +1051,25 @@ export function MediaBrowser({ onNavigate, currentPath }: MediaBrowserProps) {
1009
1051
  </div>
1010
1052
 
1011
1053
  {panelOpen && activeItem && (
1012
- <div className="border-border bg-card flex w-80 shrink-0 flex-col overflow-y-auto rounded-lg border lg:w-96">
1054
+ <div
1055
+ ref={detailPanelRef}
1056
+ data-inspector-open=""
1057
+ tabIndex={-1}
1058
+ role="region"
1059
+ aria-label={`${activeItem.name} details`}
1060
+ className="border-border bg-card mobile:w-full flex w-80 shrink-0 flex-col overflow-y-auto rounded-lg border lg:w-96"
1061
+ >
1013
1062
  <div className="border-border bg-card sticky top-0 z-10 flex items-center justify-between border-b p-4">
1014
1063
  <h3 className="text-foreground truncate text-sm font-medium">
1015
1064
  {activeItem.name}
1016
1065
  </h3>
1017
1066
  <button
1067
+ type="button"
1018
1068
  onClick={closeDetail}
1019
- className="hover:bg-muted rounded p-1 transition-colors"
1069
+ className="hover:bg-muted prenta-touch-target mobile:-my-2.5 mobile:-mr-2.5 mobile:h-11 mobile:w-11 flex items-center justify-center rounded p-1 transition-colors"
1020
1070
  aria-label="Close panel"
1021
1071
  >
1022
- <X className="text-muted-foreground h-4 w-4" />
1072
+ <X className="text-muted-foreground h-4 w-4" aria-hidden />
1023
1073
  </button>
1024
1074
  </div>
1025
1075
 
@@ -1035,7 +1085,7 @@ export function MediaBrowser({ onNavigate, currentPath }: MediaBrowserProps) {
1035
1085
  </div>
1036
1086
 
1037
1087
  {issues.length > 0 && (
1038
- <div className="border-warning/30 bg-warning/10 mx-4 mt-4 rounded-lg border p-4">
1088
+ <div className="border-warning/30 bg-warn-l mx-4 mt-4 rounded-lg border p-4">
1039
1089
  <div className="flex items-start gap-2">
1040
1090
  <AlertTriangle className="text-warning mt-0.5 h-4 w-4 shrink-0" />
1041
1091
  <div>
@@ -1166,7 +1216,7 @@ export function MediaBrowser({ onNavigate, currentPath }: MediaBrowserProps) {
1166
1216
  {activeItem.aiAltSuggestion !== undefined &&
1167
1217
  editAlt !== activeItem.aiAltSuggestion &&
1168
1218
  !editIsDecorative && (
1169
- <div className="border-warning/40 bg-warning/10 mt-2 flex items-start justify-between gap-2 rounded-lg border p-4 text-xs">
1219
+ <div className="border-warning/40 bg-warn-l mt-2 flex items-start justify-between gap-2 rounded-lg border p-4 text-xs">
1170
1220
  <span className="text-foreground">
1171
1221
  AI suggestion:{' '}
1172
1222
  {activeItem.aiAltSuggestion.trim()
@@ -1301,7 +1351,7 @@ export function MediaBrowser({ onNavigate, currentPath }: MediaBrowserProps) {
1301
1351
  ))}
1302
1352
  </div>
1303
1353
  ) : (
1304
- <div className="border-warning/30 bg-warning/10 rounded-lg border p-4">
1354
+ <div className="border-warning/30 bg-warn-l rounded-lg border p-4">
1305
1355
  <div className="flex items-start gap-2">
1306
1356
  <AlertTriangle className="text-warning mt-0.5 h-4 w-4 shrink-0" />
1307
1357
  <div>