@actuate-media/cms-admin 0.10.0 → 0.11.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 (284) hide show
  1. package/dist/AdminRoot.d.ts.map +1 -1
  2. package/dist/AdminRoot.js +8 -5
  3. package/dist/AdminRoot.js.map +1 -1
  4. package/dist/__tests__/layout/primitives.test.d.ts +2 -0
  5. package/dist/__tests__/layout/primitives.test.d.ts.map +1 -0
  6. package/dist/__tests__/layout/primitives.test.js +34 -0
  7. package/dist/__tests__/layout/primitives.test.js.map +1 -0
  8. package/dist/__tests__/lib/cv.test.d.ts +2 -0
  9. package/dist/__tests__/lib/cv.test.d.ts.map +1 -0
  10. package/dist/__tests__/lib/cv.test.js +66 -0
  11. package/dist/__tests__/lib/cv.test.js.map +1 -0
  12. package/dist/actuate-admin.css +1 -1
  13. package/dist/assets/actuate-logo.d.ts +36 -0
  14. package/dist/assets/actuate-logo.d.ts.map +1 -0
  15. package/dist/assets/actuate-logo.js +15 -0
  16. package/dist/assets/actuate-logo.js.map +1 -0
  17. package/dist/components/Breadcrumbs.js +2 -2
  18. package/dist/components/CommandPalette.js +10 -10
  19. package/dist/components/ContentOverviewChart.js +3 -3
  20. package/dist/components/ErrorBoundary.js +1 -1
  21. package/dist/components/FocalPointPicker.js +2 -2
  22. package/dist/components/FolderTree.js +20 -20
  23. package/dist/components/LivePreview.js +3 -3
  24. package/dist/components/LocaleSwitcher.js +1 -1
  25. package/dist/components/MediaPickerModal.js +4 -4
  26. package/dist/components/PresenceIndicator.js +1 -1
  27. package/dist/components/SEOConfigPanel.d.ts +2 -0
  28. package/dist/components/SEOConfigPanel.d.ts.map +1 -0
  29. package/dist/components/SEOConfigPanel.js +174 -0
  30. package/dist/components/SEOConfigPanel.js.map +1 -0
  31. package/dist/components/SEOPanel.js +9 -9
  32. package/dist/components/SEOPerformance.js +2 -2
  33. package/dist/components/SchedulePublishDialog.js +1 -1
  34. package/dist/components/SharePreviewLinkDialog.js +1 -1
  35. package/dist/components/TipTapEditor.js +5 -5
  36. package/dist/components/VersionHistory.js +2 -2
  37. package/dist/components/ui/Badge.d.ts +33 -3
  38. package/dist/components/ui/Badge.d.ts.map +1 -1
  39. package/dist/components/ui/Badge.js +42 -8
  40. package/dist/components/ui/Badge.js.map +1 -1
  41. package/dist/components/ui/Button.d.ts +19 -8
  42. package/dist/components/ui/Button.d.ts.map +1 -1
  43. package/dist/components/ui/Button.js +35 -14
  44. package/dist/components/ui/Button.js.map +1 -1
  45. package/dist/components/ui/Card.d.ts +26 -0
  46. package/dist/components/ui/Card.d.ts.map +1 -0
  47. package/dist/components/ui/Card.js +45 -0
  48. package/dist/components/ui/Card.js.map +1 -0
  49. package/dist/components/ui/DataTable.js +1 -1
  50. package/dist/components/ui/Input.d.ts +15 -0
  51. package/dist/components/ui/Input.d.ts.map +1 -0
  52. package/dist/components/ui/Input.js +23 -0
  53. package/dist/components/ui/Input.js.map +1 -0
  54. package/dist/components/ui/SearchInput.js +1 -1
  55. package/dist/components/ui/Select.d.ts +16 -0
  56. package/dist/components/ui/Select.d.ts.map +1 -0
  57. package/dist/components/ui/Select.js +25 -0
  58. package/dist/components/ui/Select.js.map +1 -0
  59. package/dist/components/ui/Toast.js +1 -1
  60. package/dist/components/ui/index.d.ts +10 -4
  61. package/dist/components/ui/index.d.ts.map +1 -1
  62. package/dist/components/ui/index.js +5 -2
  63. package/dist/components/ui/index.js.map +1 -1
  64. package/dist/fields/BlockBuilderField.js +3 -3
  65. package/dist/fields/DateField.js +1 -1
  66. package/dist/fields/RelationshipField.js +3 -3
  67. package/dist/fields/TextField.js +1 -1
  68. package/dist/index.d.ts +2 -0
  69. package/dist/index.d.ts.map +1 -1
  70. package/dist/index.js +3 -0
  71. package/dist/index.js.map +1 -1
  72. package/dist/layout/Header.js +1 -1
  73. package/dist/layout/Layout.d.ts +14 -0
  74. package/dist/layout/Layout.d.ts.map +1 -1
  75. package/dist/layout/Layout.js +17 -11
  76. package/dist/layout/Layout.js.map +1 -1
  77. package/dist/layout/Sidebar.d.ts.map +1 -1
  78. package/dist/layout/Sidebar.js +21 -11
  79. package/dist/layout/Sidebar.js.map +1 -1
  80. package/dist/layout/primitives/AdminShell.d.ts +43 -0
  81. package/dist/layout/primitives/AdminShell.d.ts.map +1 -0
  82. package/dist/layout/primitives/AdminShell.js +51 -0
  83. package/dist/layout/primitives/AdminShell.js.map +1 -0
  84. package/dist/layout/primitives/Box.d.ts +19 -0
  85. package/dist/layout/primitives/Box.d.ts.map +1 -0
  86. package/dist/layout/primitives/Box.js +12 -0
  87. package/dist/layout/primitives/Box.js.map +1 -0
  88. package/dist/layout/primitives/Cluster.d.ts +27 -0
  89. package/dist/layout/primitives/Cluster.d.ts.map +1 -0
  90. package/dist/layout/primitives/Cluster.js +37 -0
  91. package/dist/layout/primitives/Cluster.js.map +1 -0
  92. package/dist/layout/primitives/Grid.d.ts +45 -0
  93. package/dist/layout/primitives/Grid.d.ts.map +1 -0
  94. package/dist/layout/primitives/Grid.js +59 -0
  95. package/dist/layout/primitives/Grid.js.map +1 -0
  96. package/dist/layout/primitives/PageContainer.d.ts +36 -0
  97. package/dist/layout/primitives/PageContainer.d.ts.map +1 -0
  98. package/dist/layout/primitives/PageContainer.js +41 -0
  99. package/dist/layout/primitives/PageContainer.js.map +1 -0
  100. package/dist/layout/primitives/Split.d.ts +34 -0
  101. package/dist/layout/primitives/Split.d.ts.map +1 -0
  102. package/dist/layout/primitives/Split.js +27 -0
  103. package/dist/layout/primitives/Split.js.map +1 -0
  104. package/dist/layout/primitives/Stack.d.ts +23 -0
  105. package/dist/layout/primitives/Stack.d.ts.map +1 -0
  106. package/dist/layout/primitives/Stack.js +34 -0
  107. package/dist/layout/primitives/Stack.js.map +1 -0
  108. package/dist/layout/primitives/index.d.ts +30 -0
  109. package/dist/layout/primitives/index.d.ts.map +1 -0
  110. package/dist/layout/primitives/index.js +22 -0
  111. package/dist/layout/primitives/index.js.map +1 -0
  112. package/dist/layout/primitives/tokens.d.ts +48 -0
  113. package/dist/layout/primitives/tokens.d.ts.map +1 -0
  114. package/dist/layout/primitives/tokens.js +54 -0
  115. package/dist/layout/primitives/tokens.js.map +1 -0
  116. package/dist/lib/cv.d.ts +53 -0
  117. package/dist/lib/cv.d.ts.map +1 -0
  118. package/dist/lib/cv.js +39 -0
  119. package/dist/lib/cv.js.map +1 -0
  120. package/dist/views/ApiKeys.js +7 -7
  121. package/dist/views/CollectionList.js +8 -8
  122. package/dist/views/Dashboard.d.ts.map +1 -1
  123. package/dist/views/Dashboard.js +333 -78
  124. package/dist/views/Dashboard.js.map +1 -1
  125. package/dist/views/DocumentEdit.js +3 -3
  126. package/dist/views/ForgotPassword.js +2 -2
  127. package/dist/views/FormEditor.js +5 -5
  128. package/dist/views/FormSubmissions.js +6 -6
  129. package/dist/views/Forms.js +2 -2
  130. package/dist/views/Login.d.ts +16 -1
  131. package/dist/views/Login.d.ts.map +1 -1
  132. package/dist/views/Login.js +17 -7
  133. package/dist/views/Login.js.map +1 -1
  134. package/dist/views/MediaBrowser.js +16 -16
  135. package/dist/views/PageEditor.js +2 -2
  136. package/dist/views/Pages.js +10 -10
  137. package/dist/views/PostEditor.js +2 -2
  138. package/dist/views/Posts.js +4 -4
  139. package/dist/views/Redirects.js +4 -4
  140. package/dist/views/ResetPassword.js +2 -2
  141. package/dist/views/SEO.js +6 -6
  142. package/dist/views/ScriptTagEditor.js +4 -4
  143. package/dist/views/ScriptTags.js +2 -2
  144. package/dist/views/Settings.d.ts.map +1 -1
  145. package/dist/views/Settings.js +9 -8
  146. package/dist/views/Settings.js.map +1 -1
  147. package/dist/views/SetupWizard.js +2 -2
  148. package/dist/views/Users.js +4 -4
  149. package/dist/views/page-builder/AIBlockAssist.js +1 -1
  150. package/dist/views/page-builder/AIGenerateDialog.js +10 -10
  151. package/dist/views/page-builder/BlockEditor.js +10 -10
  152. package/dist/views/page-builder/BlockPicker.js +4 -4
  153. package/dist/views/page-builder/BottomBar.js +1 -1
  154. package/dist/views/page-builder/BuilderToolbar.js +2 -2
  155. package/dist/views/page-builder/ContextPanel.js +2 -2
  156. package/dist/views/page-builder/DesignScore.js +9 -9
  157. package/dist/views/page-builder/NodeSettings.js +8 -8
  158. package/dist/views/page-builder/PageBuilder.js +3 -3
  159. package/dist/views/page-builder/PageSettings.js +1 -1
  160. package/dist/views/page-builder/PageTemplates.js +2 -2
  161. package/dist/views/page-builder/SEOPanel.js +13 -13
  162. package/dist/views/page-builder/SavedSections.js +5 -5
  163. package/dist/views/page-builder/TemplatePicker.js +2 -2
  164. package/dist/views/page-builder/block-renderers/CTAPreview.js +5 -5
  165. package/dist/views/page-builder/block-renderers/CardsPreview.js +1 -1
  166. package/dist/views/page-builder/block-renderers/CodePreview.js +1 -1
  167. package/dist/views/page-builder/block-renderers/FAQPreview.js +3 -3
  168. package/dist/views/page-builder/block-renderers/FallbackPreview.js +1 -1
  169. package/dist/views/page-builder/block-renderers/FormPreview.js +3 -3
  170. package/dist/views/page-builder/block-renderers/GalleryPreview.js +5 -5
  171. package/dist/views/page-builder/block-renderers/HeroPreview.js +3 -3
  172. package/dist/views/page-builder/block-renderers/ImagePreview.js +3 -3
  173. package/dist/views/page-builder/block-renderers/TextPreview.js +3 -3
  174. package/dist/views/page-builder/block-renderers/VideoPreview.js +4 -4
  175. package/dist/views/page-builder/canvas/BlockRenderer.js +1 -1
  176. package/dist/views/page-builder/canvas/BuilderCanvas.js +3 -3
  177. package/dist/views/page-builder/canvas/ColumnRenderer.js +2 -2
  178. package/dist/views/page-builder/canvas/ContainerRenderer.js +2 -2
  179. package/dist/views/page-builder/canvas/RowRenderer.js +2 -2
  180. package/dist/views/page-builder/canvas/SectionRenderer.js +2 -2
  181. package/package.json +6 -2
  182. package/src/AdminRoot.tsx +21 -11
  183. package/src/__tests__/layout/primitives.test.ts +37 -0
  184. package/src/__tests__/lib/cv.test.ts +74 -0
  185. package/src/assets/actuate-logo.tsx +72 -0
  186. package/src/components/Breadcrumbs.tsx +6 -6
  187. package/src/components/CommandPalette.tsx +34 -34
  188. package/src/components/ContentOverviewChart.tsx +3 -3
  189. package/src/components/ErrorBoundary.tsx +3 -3
  190. package/src/components/FocalPointPicker.tsx +4 -4
  191. package/src/components/FolderTree.tsx +38 -38
  192. package/src/components/LivePreview.tsx +16 -16
  193. package/src/components/LocaleSwitcher.tsx +7 -7
  194. package/src/components/MediaPickerModal.tsx +21 -21
  195. package/src/components/PresenceIndicator.tsx +2 -2
  196. package/src/components/SEOConfigPanel.tsx +582 -0
  197. package/src/components/SEOPanel.tsx +46 -46
  198. package/src/components/SEOPerformance.tsx +21 -21
  199. package/src/components/SchedulePublishDialog.tsx +4 -4
  200. package/src/components/SharePreviewLinkDialog.tsx +1 -1
  201. package/src/components/TipTapEditor.tsx +33 -33
  202. package/src/components/VersionHistory.tsx +16 -16
  203. package/src/components/ui/Badge.tsx +66 -14
  204. package/src/components/ui/Button.tsx +70 -33
  205. package/src/components/ui/Card.tsx +101 -0
  206. package/src/components/ui/DataTable.tsx +1 -1
  207. package/src/components/ui/Input.tsx +35 -0
  208. package/src/components/ui/SearchInput.tsx +4 -4
  209. package/src/components/ui/Select.tsx +56 -0
  210. package/src/components/ui/Toast.tsx +1 -1
  211. package/src/components/ui/index.ts +18 -4
  212. package/src/fields/BlockBuilderField.tsx +3 -3
  213. package/src/fields/DateField.tsx +1 -1
  214. package/src/fields/RelationshipField.tsx +10 -10
  215. package/src/fields/TextField.tsx +1 -1
  216. package/src/index.ts +28 -0
  217. package/src/layout/Header.tsx +28 -28
  218. package/src/layout/Layout.tsx +39 -46
  219. package/src/layout/Sidebar.tsx +37 -64
  220. package/src/layout/primitives/AdminShell.tsx +118 -0
  221. package/src/layout/primitives/Box.tsx +30 -0
  222. package/src/layout/primitives/Cluster.tsx +74 -0
  223. package/src/layout/primitives/Grid.tsx +120 -0
  224. package/src/layout/primitives/PageContainer.tsx +96 -0
  225. package/src/layout/primitives/Split.tsx +73 -0
  226. package/src/layout/primitives/Stack.tsx +67 -0
  227. package/src/layout/primitives/index.ts +36 -0
  228. package/src/layout/primitives/tokens.ts +76 -0
  229. package/src/lib/cv.ts +96 -0
  230. package/src/styles/build-input.css +1 -1
  231. package/src/views/ApiKeys.tsx +57 -57
  232. package/src/views/CollectionList.tsx +30 -30
  233. package/src/views/Dashboard.tsx +737 -186
  234. package/src/views/DocumentEdit.tsx +9 -9
  235. package/src/views/ForgotPassword.tsx +18 -18
  236. package/src/views/FormEditor.tsx +75 -75
  237. package/src/views/FormSubmissions.tsx +76 -76
  238. package/src/views/Forms.tsx +27 -27
  239. package/src/views/Login.tsx +65 -25
  240. package/src/views/MediaBrowser.tsx +127 -127
  241. package/src/views/PageEditor.tsx +25 -25
  242. package/src/views/Pages.tsx +59 -59
  243. package/src/views/PostEditor.tsx +37 -37
  244. package/src/views/Posts.tsx +48 -48
  245. package/src/views/Redirects.tsx +21 -21
  246. package/src/views/ResetPassword.tsx +28 -28
  247. package/src/views/SEO.tsx +144 -144
  248. package/src/views/ScriptTagEditor.tsx +24 -24
  249. package/src/views/ScriptTags.tsx +10 -10
  250. package/src/views/Settings.tsx +88 -80
  251. package/src/views/SetupWizard.tsx +28 -28
  252. package/src/views/Users.tsx +20 -20
  253. package/src/views/page-builder/AIBlockAssist.tsx +1 -1
  254. package/src/views/page-builder/AIGenerateDialog.tsx +63 -63
  255. package/src/views/page-builder/BlockEditor.tsx +26 -26
  256. package/src/views/page-builder/BlockPicker.tsx +22 -22
  257. package/src/views/page-builder/BottomBar.tsx +8 -8
  258. package/src/views/page-builder/BuilderToolbar.tsx +17 -17
  259. package/src/views/page-builder/ContextPanel.tsx +3 -3
  260. package/src/views/page-builder/DesignScore.tsx +21 -21
  261. package/src/views/page-builder/NodeSettings.tsx +27 -27
  262. package/src/views/page-builder/PageBuilder.tsx +11 -11
  263. package/src/views/page-builder/PageSettings.tsx +4 -4
  264. package/src/views/page-builder/PageTemplates.tsx +18 -18
  265. package/src/views/page-builder/SEOPanel.tsx +53 -53
  266. package/src/views/page-builder/SavedSections.tsx +37 -37
  267. package/src/views/page-builder/TemplatePicker.tsx +17 -17
  268. package/src/views/page-builder/block-renderers/CTAPreview.tsx +13 -13
  269. package/src/views/page-builder/block-renderers/CardsPreview.tsx +5 -5
  270. package/src/views/page-builder/block-renderers/CodePreview.tsx +6 -6
  271. package/src/views/page-builder/block-renderers/FAQPreview.tsx +13 -13
  272. package/src/views/page-builder/block-renderers/FallbackPreview.tsx +3 -3
  273. package/src/views/page-builder/block-renderers/FormPreview.tsx +20 -20
  274. package/src/views/page-builder/block-renderers/GalleryPreview.tsx +8 -8
  275. package/src/views/page-builder/block-renderers/HeroPreview.tsx +16 -16
  276. package/src/views/page-builder/block-renderers/ImagePreview.tsx +4 -4
  277. package/src/views/page-builder/block-renderers/TextPreview.tsx +14 -14
  278. package/src/views/page-builder/block-renderers/VideoPreview.tsx +12 -12
  279. package/src/views/page-builder/canvas/BlockRenderer.tsx +4 -4
  280. package/src/views/page-builder/canvas/BuilderCanvas.tsx +6 -6
  281. package/src/views/page-builder/canvas/ColumnRenderer.tsx +3 -3
  282. package/src/views/page-builder/canvas/ContainerRenderer.tsx +2 -2
  283. package/src/views/page-builder/canvas/RowRenderer.tsx +2 -2
  284. package/src/views/page-builder/canvas/SectionRenderer.tsx +2 -2
@@ -93,43 +93,43 @@ export function ApiKeys(_props: ApiKeysProps) {
93
93
 
94
94
  if (loading) {
95
95
  return (
96
- <div className="p-4 sm:p-6 flex items-center justify-center h-64">
97
- <Loader2 className="w-6 h-6 animate-spin text-blue-600" />
96
+ <div className="flex h-64 items-center justify-center p-4 sm:p-6">
97
+ <Loader2 className="h-6 w-6 animate-spin text-blue-600" />
98
98
  </div>
99
99
  )
100
100
  }
101
101
 
102
102
  return (
103
103
  <div className="p-4 sm:p-6">
104
- <div className="flex flex-col sm:flex-row sm:items-center justify-between gap-3 mb-6">
104
+ <div className="mb-6 flex flex-col justify-between gap-3 sm:flex-row sm:items-center">
105
105
  <div>
106
- <h1 className="text-xl sm:text-2xl font-semibold text-gray-900 flex items-center gap-2">
107
- <KeyRound className="w-5 h-5 text-gray-500" />
106
+ <h1 className="flex items-center gap-2 text-xl font-semibold text-gray-900 sm:text-2xl">
107
+ <KeyRound className="h-5 w-5 text-gray-500" />
108
108
  API Keys
109
109
  </h1>
110
- <p className="text-sm text-gray-500 mt-1">
110
+ <p className="mt-1 text-sm text-gray-500">
111
111
  Long-lived credentials for programmatic access. Use the{' '}
112
- <code className="px-1 py-0.5 rounded bg-gray-100 text-xs">Authorization: Bearer</code>{' '}
112
+ <code className="rounded bg-gray-100 px-1 py-0.5 text-xs">Authorization: Bearer</code>{' '}
113
113
  header instead of session cookies. API key requests skip CSRF.
114
114
  </p>
115
115
  </div>
116
116
  <button
117
117
  type="button"
118
118
  onClick={() => setShowCreate(true)}
119
- className="inline-flex items-center justify-center gap-2 px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors text-sm"
119
+ className="inline-flex items-center justify-center gap-2 rounded-lg bg-blue-600 px-4 py-2 text-sm text-white transition-colors hover:bg-blue-700"
120
120
  >
121
- <Plus className="w-4 h-4" />
121
+ <Plus className="h-4 w-4" />
122
122
  New API Key
123
123
  </button>
124
124
  </div>
125
125
 
126
126
  {error && (
127
127
  <div className="mb-4 flex items-center gap-3 rounded-lg border border-red-200 bg-red-50 p-3">
128
- <AlertTriangle className="w-5 h-5 text-red-600 shrink-0" />
129
- <span className="text-sm text-red-800 flex-1">{error}</span>
128
+ <AlertTriangle className="h-5 w-5 shrink-0 text-red-600" />
129
+ <span className="flex-1 text-sm text-red-800">{error}</span>
130
130
  <button
131
131
  onClick={refetch}
132
- className="px-3 py-1 text-sm text-red-700 border border-red-300 rounded-lg hover:bg-red-100 transition-colors"
132
+ className="rounded-lg border border-red-300 px-3 py-1 text-sm text-red-700 transition-colors hover:bg-red-100"
133
133
  >
134
134
  Retry
135
135
  </button>
@@ -137,26 +137,26 @@ export function ApiKeys(_props: ApiKeysProps) {
137
137
  )}
138
138
 
139
139
  {keys.length === 0 ? (
140
- <div className="bg-white rounded-lg border border-gray-200 p-10 text-center">
141
- <KeyRound className="w-8 h-8 text-gray-300 mx-auto mb-3" />
142
- <p className="text-sm text-gray-500 mb-1">No API keys yet</p>
143
- <p className="text-xs text-gray-400 mb-4">
140
+ <div className="rounded-lg border border-gray-200 bg-white p-10 text-center">
141
+ <KeyRound className="mx-auto mb-3 h-8 w-8 text-gray-300" />
142
+ <p className="mb-1 text-sm text-gray-500">No API keys yet</p>
143
+ <p className="mb-4 text-xs text-gray-400">
144
144
  Create one to let AI agents, CI jobs, or external integrations call the CMS API.
145
145
  </p>
146
146
  <button
147
147
  type="button"
148
148
  onClick={() => setShowCreate(true)}
149
- className="inline-flex items-center justify-center gap-2 px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors text-sm"
149
+ className="inline-flex items-center justify-center gap-2 rounded-lg bg-blue-600 px-4 py-2 text-sm text-white transition-colors hover:bg-blue-700"
150
150
  >
151
- <Plus className="w-4 h-4" />
151
+ <Plus className="h-4 w-4" />
152
152
  Create your first API key
153
153
  </button>
154
154
  </div>
155
155
  ) : (
156
- <div className="bg-white rounded-lg border border-gray-200 overflow-hidden">
156
+ <div className="overflow-hidden rounded-lg border border-gray-200 bg-white">
157
157
  <div className="overflow-x-auto">
158
158
  <table className="w-full">
159
- <thead className="bg-gray-50 border-b border-gray-200">
159
+ <thead className="border-b border-gray-200 bg-gray-50">
160
160
  <tr>
161
161
  <th className="px-4 py-2 text-left text-xs font-medium text-gray-700">Name</th>
162
162
  <th className="px-4 py-2 text-left text-xs font-medium text-gray-700">Token</th>
@@ -183,8 +183,8 @@ export function ApiKeys(_props: ApiKeysProps) {
183
183
  </div>
184
184
  )}
185
185
  </td>
186
- <td className="px-4 py-3 text-sm font-mono text-gray-700">{k.keyPrefix}…</td>
187
- <td className="px-4 py-3 text-sm text-gray-700 max-w-xs">
186
+ <td className="px-4 py-3 font-mono text-sm text-gray-700">{k.keyPrefix}…</td>
187
+ <td className="max-w-xs px-4 py-3 text-sm text-gray-700">
188
188
  {formatScopes(k.scopes)}
189
189
  </td>
190
190
  <td className="px-4 py-3 text-sm text-gray-600">
@@ -193,15 +193,15 @@ export function ApiKeys(_props: ApiKeysProps) {
193
193
  <td className="px-4 py-3 text-sm text-gray-600">{formatDate(k.expiresAt)}</td>
194
194
  <td className="px-4 py-3">
195
195
  {revoked ? (
196
- <span className="inline-flex px-2 py-0.5 rounded-full text-xs font-medium bg-red-100 text-red-700">
196
+ <span className="inline-flex rounded-full bg-red-100 px-2 py-0.5 text-xs font-medium text-red-700">
197
197
  Revoked
198
198
  </span>
199
199
  ) : expired ? (
200
- <span className="inline-flex px-2 py-0.5 rounded-full text-xs font-medium bg-amber-100 text-amber-700">
200
+ <span className="inline-flex rounded-full bg-amber-100 px-2 py-0.5 text-xs font-medium text-amber-700">
201
201
  Expired
202
202
  </span>
203
203
  ) : (
204
- <span className="inline-flex px-2 py-0.5 rounded-full text-xs font-medium bg-green-100 text-green-700">
204
+ <span className="inline-flex rounded-full bg-green-100 px-2 py-0.5 text-xs font-medium text-green-700">
205
205
  Active
206
206
  </span>
207
207
  )}
@@ -211,10 +211,10 @@ export function ApiKeys(_props: ApiKeysProps) {
211
211
  <button
212
212
  type="button"
213
213
  onClick={() => handleRevoke(k.id, k.name)}
214
- className="p-1.5 hover:bg-red-50 rounded transition-colors"
214
+ className="rounded p-1.5 transition-colors hover:bg-red-50"
215
215
  title="Revoke"
216
216
  >
217
- <Trash2 className="w-4 h-4 text-red-600" />
217
+ <Trash2 className="h-4 w-4 text-red-600" />
218
218
  </button>
219
219
  )}
220
220
  </td>
@@ -320,35 +320,35 @@ function CreateApiKeyDialog({ open, onClose, onCreated }: CreateApiKeyDialogProp
320
320
  return (
321
321
  <Dialog.Root open={open} onOpenChange={(o) => !o && onClose()}>
322
322
  <Dialog.Portal>
323
- <Dialog.Overlay className="fixed inset-0 bg-black/40 z-40" />
324
- <Dialog.Content className="fixed top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 bg-white rounded-lg shadow-xl w-full max-w-md p-6 z-50">
325
- <Dialog.Title className="text-lg font-semibold text-gray-900 mb-4 flex items-center gap-2">
326
- <Shield className="w-5 h-5 text-blue-600" />
323
+ <Dialog.Overlay className="fixed inset-0 z-40 bg-black/40" />
324
+ <Dialog.Content className="fixed top-1/2 left-1/2 z-50 w-full max-w-md -translate-x-1/2 -translate-y-1/2 rounded-lg bg-white p-6 shadow-xl">
325
+ <Dialog.Title className="mb-4 flex items-center gap-2 text-lg font-semibold text-gray-900">
326
+ <Shield className="h-5 w-5 text-blue-600" />
327
327
  New API Key
328
328
  </Dialog.Title>
329
329
  <form onSubmit={handleSubmit} className="space-y-4">
330
330
  <div>
331
- <label className="text-sm font-medium text-gray-700 block mb-1">Name</label>
331
+ <label className="mb-1 block text-sm font-medium text-gray-700">Name</label>
332
332
  <input
333
333
  type="text"
334
334
  value={name}
335
335
  onChange={(e) => setName(e.target.value)}
336
336
  placeholder="e.g. AI agent — production"
337
- className="w-full px-3 py-2 text-sm border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
337
+ className="w-full rounded-lg border border-gray-300 px-3 py-2 text-sm focus:ring-2 focus:ring-blue-500 focus:outline-none"
338
338
  required
339
339
  maxLength={100}
340
340
  />
341
341
  </div>
342
342
 
343
343
  <div>
344
- <label className="text-sm font-medium text-gray-700 block mb-2">Preset</label>
344
+ <label className="mb-2 block text-sm font-medium text-gray-700">Preset</label>
345
345
  <div className="grid grid-cols-2 gap-2">
346
346
  {(['content', 'readonly', 'admin', 'custom'] as const).map((p) => (
347
347
  <button
348
348
  key={p}
349
349
  type="button"
350
350
  onClick={() => setPreset(p)}
351
- className={`px-3 py-2 text-sm rounded-lg border transition-colors text-left ${
351
+ className={`rounded-lg border px-3 py-2 text-left text-sm transition-colors ${
352
352
  preset === p
353
353
  ? 'border-blue-500 bg-blue-50 text-blue-900'
354
354
  : 'border-gray-300 bg-white text-gray-700 hover:bg-gray-50'
@@ -367,7 +367,7 @@ function CreateApiKeyDialog({ open, onClose, onCreated }: CreateApiKeyDialogProp
367
367
  </div>
368
368
 
369
369
  {(preset === 'content' || preset === 'custom') && (
370
- <div className="space-y-2 rounded-lg border border-gray-200 p-3 bg-gray-50">
370
+ <div className="space-y-2 rounded-lg border border-gray-200 bg-gray-50 p-3">
371
371
  <label className="flex items-center gap-2 text-sm text-gray-700">
372
372
  <input
373
373
  type="checkbox"
@@ -390,7 +390,7 @@ function CreateApiKeyDialog({ open, onClose, onCreated }: CreateApiKeyDialogProp
390
390
  )}
391
391
 
392
392
  <div>
393
- <label className="text-sm font-medium text-gray-700 block mb-1">
393
+ <label className="mb-1 block text-sm font-medium text-gray-700">
394
394
  Expires in (days)
395
395
  </label>
396
396
  <input
@@ -399,22 +399,22 @@ function CreateApiKeyDialog({ open, onClose, onCreated }: CreateApiKeyDialogProp
399
399
  placeholder="Never (leave blank)"
400
400
  value={expiresInDays}
401
401
  onChange={(e) => setExpiresInDays(e.target.value)}
402
- className="w-full px-3 py-2 text-sm border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
402
+ className="w-full rounded-lg border border-gray-300 px-3 py-2 text-sm focus:ring-2 focus:ring-blue-500 focus:outline-none"
403
403
  />
404
404
  </div>
405
405
 
406
406
  <div>
407
- <label className="text-sm font-medium text-gray-700 block mb-1">
407
+ <label className="mb-1 block text-sm font-medium text-gray-700">
408
408
  Confirm password
409
409
  </label>
410
410
  <input
411
411
  type="password"
412
412
  value={password}
413
413
  onChange={(e) => setPassword(e.target.value)}
414
- className="w-full px-3 py-2 text-sm border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
414
+ className="w-full rounded-lg border border-gray-300 px-3 py-2 text-sm focus:ring-2 focus:ring-blue-500 focus:outline-none"
415
415
  required
416
416
  />
417
- <p className="text-xs text-gray-500 mt-1">
417
+ <p className="mt-1 text-xs text-gray-500">
418
418
  Creating an API key is a sensitive action and requires re-authentication.
419
419
  </p>
420
420
  </div>
@@ -423,14 +423,14 @@ function CreateApiKeyDialog({ open, onClose, onCreated }: CreateApiKeyDialogProp
423
423
  <button
424
424
  type="button"
425
425
  onClick={onClose}
426
- className="px-4 py-2 text-sm border border-gray-300 rounded-lg hover:bg-gray-50 transition-colors"
426
+ className="rounded-lg border border-gray-300 px-4 py-2 text-sm transition-colors hover:bg-gray-50"
427
427
  >
428
428
  Cancel
429
429
  </button>
430
430
  <button
431
431
  type="submit"
432
432
  disabled={submitting}
433
- className="px-4 py-2 text-sm bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors disabled:opacity-50"
433
+ className="rounded-lg bg-blue-600 px-4 py-2 text-sm text-white transition-colors hover:bg-blue-700 disabled:opacity-50"
434
434
  >
435
435
  {submitting ? 'Creating…' : 'Create key'}
436
436
  </button>
@@ -453,35 +453,35 @@ function RevealKeyDialog({
453
453
  return (
454
454
  <Dialog.Root open onOpenChange={(o) => !o && onClose()}>
455
455
  <Dialog.Portal>
456
- <Dialog.Overlay className="fixed inset-0 bg-black/40 z-40" />
457
- <Dialog.Content className="fixed top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 bg-white rounded-lg shadow-xl w-full max-w-md p-6 z-50">
458
- <Dialog.Title className="text-lg font-semibold text-gray-900 mb-2 flex items-center gap-2">
459
- <Shield className="w-5 h-5 text-green-600" />
456
+ <Dialog.Overlay className="fixed inset-0 z-40 bg-black/40" />
457
+ <Dialog.Content className="fixed top-1/2 left-1/2 z-50 w-full max-w-md -translate-x-1/2 -translate-y-1/2 rounded-lg bg-white p-6 shadow-xl">
458
+ <Dialog.Title className="mb-2 flex items-center gap-2 text-lg font-semibold text-gray-900">
459
+ <Shield className="h-5 w-5 text-green-600" />
460
460
  API key created
461
461
  </Dialog.Title>
462
- <Dialog.Description className="text-sm text-gray-600 mb-4">
462
+ <Dialog.Description className="mb-4 text-sm text-gray-600">
463
463
  Copy this key now — it will not be shown again. Treat it like a password.
464
464
  </Dialog.Description>
465
465
 
466
- <div className="rounded-lg border border-amber-200 bg-amber-50 p-3 mb-4 flex items-start gap-2">
467
- <AlertTriangle className="w-4 h-4 text-amber-600 shrink-0 mt-0.5" />
466
+ <div className="mb-4 flex items-start gap-2 rounded-lg border border-amber-200 bg-amber-50 p-3">
467
+ <AlertTriangle className="mt-0.5 h-4 w-4 shrink-0 text-amber-600" />
468
468
  <p className="text-xs text-amber-900">
469
469
  We only store a hash of this key. If you lose it, you&apos;ll need to revoke and
470
470
  create a new one.
471
471
  </p>
472
472
  </div>
473
473
 
474
- <div className="flex items-center gap-2 mb-4">
475
- <code className="flex-1 px-3 py-2 bg-gray-100 rounded text-sm font-mono break-all">
474
+ <div className="mb-4 flex items-center gap-2">
475
+ <code className="flex-1 rounded bg-gray-100 px-3 py-2 font-mono text-sm break-all">
476
476
  {shown ? created.key : '•'.repeat(Math.min(48, created.key.length))}
477
477
  </code>
478
478
  <button
479
479
  type="button"
480
480
  onClick={() => setShown((s) => !s)}
481
- className="p-2 border border-gray-300 rounded hover:bg-gray-50"
481
+ className="rounded border border-gray-300 p-2 hover:bg-gray-50"
482
482
  title={shown ? 'Hide' : 'Show'}
483
483
  >
484
- {shown ? <EyeOff className="w-4 h-4" /> : <Eye className="w-4 h-4" />}
484
+ {shown ? <EyeOff className="h-4 w-4" /> : <Eye className="h-4 w-4" />}
485
485
  </button>
486
486
  <button
487
487
  type="button"
@@ -489,10 +489,10 @@ function RevealKeyDialog({
489
489
  navigator.clipboard.writeText(created.key)
490
490
  toast.success('Copied to clipboard')
491
491
  }}
492
- className="p-2 border border-gray-300 rounded hover:bg-gray-50"
492
+ className="rounded border border-gray-300 p-2 hover:bg-gray-50"
493
493
  title="Copy"
494
494
  >
495
- <Copy className="w-4 h-4" />
495
+ <Copy className="h-4 w-4" />
496
496
  </button>
497
497
  </div>
498
498
 
@@ -500,7 +500,7 @@ function RevealKeyDialog({
500
500
  <button
501
501
  type="button"
502
502
  onClick={onClose}
503
- className="px-4 py-2 text-sm bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors"
503
+ className="rounded-lg bg-blue-600 px-4 py-2 text-sm text-white transition-colors hover:bg-blue-700"
504
504
  >
505
505
  I&apos;ve saved it
506
506
  </button>
@@ -155,7 +155,7 @@ export function CollectionList({ collectionSlug, config, onNavigate }: Collectio
155
155
  <button
156
156
  type="button"
157
157
  onClick={() => toggleSort(field)}
158
- className="flex items-center gap-1 text-xs font-medium hover:opacity-80 transition-opacity"
158
+ className="flex items-center gap-1 text-xs font-medium transition-opacity hover:opacity-80"
159
159
  style={{ color: 'var(--actuate-text-secondary, #6b7280)' }}
160
160
  >
161
161
  {children}
@@ -165,9 +165,9 @@ export function CollectionList({ collectionSlug, config, onNavigate }: Collectio
165
165
 
166
166
  if (loading && docs.length === 0) {
167
167
  return (
168
- <div className="p-4 flex items-center justify-center h-64">
168
+ <div className="flex h-64 items-center justify-center p-4">
169
169
  <Loader2
170
- className="w-6 h-6 animate-spin"
170
+ className="h-6 w-6 animate-spin"
171
171
  style={{ color: 'var(--actuate-primary, #2563eb)' }}
172
172
  />
173
173
  </div>
@@ -175,12 +175,12 @@ export function CollectionList({ collectionSlug, config, onNavigate }: Collectio
175
175
  }
176
176
 
177
177
  return (
178
- <div className="p-3 pr-6 sm:p-4 sm:pr-8 h-full flex flex-col">
178
+ <div className="flex h-full flex-col p-3 pr-6 sm:p-4 sm:pr-8">
179
179
  {/* Header */}
180
- <div className="flex items-center justify-between mb-4 gap-3 flex-wrap">
180
+ <div className="mb-4 flex flex-wrap items-center justify-between gap-3">
181
181
  <div>
182
182
  <h1
183
- className="text-xl sm:text-2xl font-semibold"
183
+ className="text-xl font-semibold sm:text-2xl"
184
184
  style={{ color: 'var(--actuate-text, #111827)' }}
185
185
  >
186
186
  {labels.plural}
@@ -191,17 +191,17 @@ export function CollectionList({ collectionSlug, config, onNavigate }: Collectio
191
191
  </div>
192
192
  <button
193
193
  onClick={() => onNavigate(`/${collectionSlug}/new`)}
194
- className="flex items-center gap-2 px-4 py-2 rounded-lg text-sm font-medium text-white transition-colors"
194
+ className="flex items-center gap-2 rounded-lg px-4 py-2 text-sm font-medium text-white transition-colors"
195
195
  style={{ background: 'var(--actuate-primary, #2563eb)' }}
196
196
  >
197
- <Plus className="w-4 h-4" /> New {labels.singular}
197
+ <Plus className="h-4 w-4" /> New {labels.singular}
198
198
  </button>
199
199
  </div>
200
200
 
201
201
  {/* Search */}
202
202
  <div className="relative mb-4">
203
203
  <Search
204
- className="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4"
204
+ className="absolute top-1/2 left-3 h-4 w-4 -translate-y-1/2"
205
205
  style={{ color: 'var(--actuate-text-muted, #9ca3af)' }}
206
206
  />
207
207
  <input
@@ -209,7 +209,7 @@ export function CollectionList({ collectionSlug, config, onNavigate }: Collectio
209
209
  placeholder={`Search ${labels.plural.toLowerCase()}...`}
210
210
  value={search}
211
211
  onChange={(e) => setSearch(e.target.value)}
212
- className="w-full pl-9 pr-3 py-2 text-sm rounded-lg border focus:outline-none focus:ring-2"
212
+ className="w-full rounded-lg border py-2 pr-3 pl-9 text-sm focus:ring-2 focus:outline-none"
213
213
  style={{
214
214
  borderColor: 'var(--actuate-border, #d1d5db)',
215
215
  color: 'var(--actuate-text, #111827)',
@@ -220,7 +220,7 @@ export function CollectionList({ collectionSlug, config, onNavigate }: Collectio
220
220
  {/* Bulk actions */}
221
221
  {selected.size > 0 && (
222
222
  <div
223
- className="rounded-lg p-3 mb-4 flex flex-wrap items-center justify-between gap-2"
223
+ className="mb-4 flex flex-wrap items-center justify-between gap-2 rounded-lg p-3"
224
224
  style={{
225
225
  background: 'var(--actuate-info-bg, #eff6ff)',
226
226
  borderColor: 'var(--actuate-info-border, #bfdbfe)',
@@ -234,24 +234,24 @@ export function CollectionList({ collectionSlug, config, onNavigate }: Collectio
234
234
  <div className="flex gap-2">
235
235
  <button
236
236
  onClick={() => bulkAction('publish')}
237
- className="px-3 py-1.5 text-sm text-white rounded-lg"
237
+ className="rounded-lg px-3 py-1.5 text-sm text-white"
238
238
  style={{ background: 'var(--actuate-success, #16a34a)' }}
239
239
  >
240
240
  Publish
241
241
  </button>
242
242
  <button
243
243
  onClick={() => bulkAction('unpublish')}
244
- className="px-3 py-1.5 text-sm text-white rounded-lg"
244
+ className="rounded-lg px-3 py-1.5 text-sm text-white"
245
245
  style={{ background: 'var(--actuate-warning, #ca8a04)' }}
246
246
  >
247
247
  Unpublish
248
248
  </button>
249
249
  <button
250
250
  onClick={() => bulkAction('delete')}
251
- className="px-3 py-1.5 text-sm text-white rounded-lg"
251
+ className="rounded-lg px-3 py-1.5 text-sm text-white"
252
252
  style={{ background: 'var(--actuate-danger, #dc2626)' }}
253
253
  >
254
- <Trash2 className="w-3.5 h-3.5 inline -mt-0.5 mr-1" />
254
+ <Trash2 className="-mt-0.5 mr-1 inline h-3.5 w-3.5" />
255
255
  Delete
256
256
  </button>
257
257
  </div>
@@ -260,7 +260,7 @@ export function CollectionList({ collectionSlug, config, onNavigate }: Collectio
260
260
 
261
261
  {error && (
262
262
  <div
263
- className="rounded-lg p-3 mb-4 text-sm"
263
+ className="mb-4 rounded-lg p-3 text-sm"
264
264
  style={{
265
265
  background: 'var(--actuate-danger-bg, #fef2f2)',
266
266
  color: 'var(--actuate-danger-text, #991b1b)',
@@ -276,17 +276,17 @@ export function CollectionList({ collectionSlug, config, onNavigate }: Collectio
276
276
  {/* Table */}
277
277
  {docs.length === 0 && !loading ? (
278
278
  <div
279
- className="flex-1 flex flex-col items-center justify-center rounded-lg border p-8"
279
+ className="flex flex-1 flex-col items-center justify-center rounded-lg border p-8"
280
280
  style={{
281
281
  borderColor: 'var(--actuate-border, #d1d5db)',
282
282
  color: 'var(--actuate-text-secondary, #6b7280)',
283
283
  }}
284
284
  >
285
- <FileText className="w-10 h-10 mb-3 opacity-40" />
286
- <p className="text-sm mb-3">No {labels.plural.toLowerCase()} found</p>
285
+ <FileText className="mb-3 h-10 w-10 opacity-40" />
286
+ <p className="mb-3 text-sm">No {labels.plural.toLowerCase()} found</p>
287
287
  <button
288
288
  onClick={() => onNavigate(`/${collectionSlug}/new`)}
289
- className="px-4 py-2 text-sm text-white rounded-lg"
289
+ className="rounded-lg px-4 py-2 text-sm text-white"
290
290
  style={{ background: 'var(--actuate-primary, #2563eb)' }}
291
291
  >
292
292
  Create {labels.singular}
@@ -294,7 +294,7 @@ export function CollectionList({ collectionSlug, config, onNavigate }: Collectio
294
294
  </div>
295
295
  ) : (
296
296
  <div
297
- className="flex-1 rounded-lg border overflow-auto"
297
+ className="flex-1 overflow-auto rounded-lg border"
298
298
  style={{ borderColor: 'var(--actuate-border, #d1d5db)' }}
299
299
  >
300
300
  <table className="w-full text-sm">
@@ -350,7 +350,7 @@ export function CollectionList({ collectionSlug, config, onNavigate }: Collectio
350
350
  <button
351
351
  type="button"
352
352
  onClick={() => onNavigate(`/${collectionSlug}/${doc.id}`)}
353
- className="font-medium text-left hover:underline"
353
+ className="text-left font-medium hover:underline"
354
354
  style={{ color: 'var(--actuate-text, #111827)' }}
355
355
  >
356
356
  {doc.title || doc.name || `#${doc.id}`}
@@ -358,7 +358,7 @@ export function CollectionList({ collectionSlug, config, onNavigate }: Collectio
358
358
  </td>
359
359
  <td className="px-3 py-2">
360
360
  <span
361
- className="inline-block px-2 py-0.5 rounded-full text-xs font-medium"
361
+ className="inline-block rounded-full px-2 py-0.5 text-xs font-medium"
362
362
  style={{ background: statusColor(doc.status), color: statusText(doc.status) }}
363
363
  >
364
364
  {doc.status ?? 'DRAFT'}
@@ -374,11 +374,11 @@ export function CollectionList({ collectionSlug, config, onNavigate }: Collectio
374
374
  <button
375
375
  type="button"
376
376
  onClick={() => onNavigate(`/${collectionSlug}/${doc.id}`)}
377
- className="p-1.5 rounded hover:opacity-75 transition-opacity"
377
+ className="rounded p-1.5 transition-opacity hover:opacity-75"
378
378
  title="Edit"
379
379
  >
380
380
  <MoreHorizontal
381
- className="w-4 h-4"
381
+ className="h-4 w-4"
382
382
  style={{ color: 'var(--actuate-text-secondary, #6b7280)' }}
383
383
  />
384
384
  </button>
@@ -393,7 +393,7 @@ export function CollectionList({ collectionSlug, config, onNavigate }: Collectio
393
393
  {/* Pagination */}
394
394
  {totalPages > 1 && (
395
395
  <div
396
- className="flex items-center justify-between mt-4 text-sm"
396
+ className="mt-4 flex items-center justify-between text-sm"
397
397
  style={{ color: 'var(--actuate-text-secondary, #6b7280)' }}
398
398
  >
399
399
  <span>
@@ -403,18 +403,18 @@ export function CollectionList({ collectionSlug, config, onNavigate }: Collectio
403
403
  <button
404
404
  disabled={page <= 1}
405
405
  onClick={() => setPage((p) => p - 1)}
406
- className="flex items-center gap-1 px-3 py-1.5 rounded-lg border disabled:opacity-40 transition-opacity"
406
+ className="flex items-center gap-1 rounded-lg border px-3 py-1.5 transition-opacity disabled:opacity-40"
407
407
  style={{ borderColor: 'var(--actuate-border, #d1d5db)' }}
408
408
  >
409
- <ChevronLeft className="w-4 h-4" /> Previous
409
+ <ChevronLeft className="h-4 w-4" /> Previous
410
410
  </button>
411
411
  <button
412
412
  disabled={page >= totalPages}
413
413
  onClick={() => setPage((p) => p + 1)}
414
- className="flex items-center gap-1 px-3 py-1.5 rounded-lg border disabled:opacity-40 transition-opacity"
414
+ className="flex items-center gap-1 rounded-lg border px-3 py-1.5 transition-opacity disabled:opacity-40"
415
415
  style={{ borderColor: 'var(--actuate-border, #d1d5db)' }}
416
416
  >
417
- Next <ChevronRight className="w-4 h-4" />
417
+ Next <ChevronRight className="h-4 w-4" />
418
418
  </button>
419
419
  </div>
420
420
  </div>