@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
@@ -75,7 +75,7 @@ function MediaPreview({ item }: { item: MediaItem }) {
75
75
  )
76
76
  }
77
77
 
78
- return <FileImage className="w-6 h-6 sm:w-8 sm:h-8 text-muted-foreground" />
78
+ return <FileImage className="text-muted-foreground h-6 w-6 sm:h-8 sm:w-8" />
79
79
  }
80
80
 
81
81
  type MediaSortKey = 'name' | 'type' | 'size' | 'date'
@@ -348,17 +348,17 @@ export function MediaBrowser({ onNavigate }: MediaBrowserProps) {
348
348
  <button
349
349
  type="button"
350
350
  onClick={() => setSortConfig(toggleSort(sortConfig, sortKey))}
351
- className="flex items-center gap-1 text-xs font-medium text-gray-700 hover:text-gray-900 transition-colors"
351
+ className="flex items-center gap-1 text-xs font-medium text-gray-700 transition-colors hover:text-gray-900"
352
352
  >
353
353
  {label}
354
354
  {active ? (
355
355
  sortConfig!.direction === 'asc' ? (
356
- <ArrowUp className="w-3 h-3" />
356
+ <ArrowUp className="h-3 w-3" />
357
357
  ) : (
358
- <ArrowDown className="w-3 h-3" />
358
+ <ArrowDown className="h-3 w-3" />
359
359
  )
360
360
  ) : (
361
- <ArrowUpDown className="w-3 h-3 text-gray-400" />
361
+ <ArrowUpDown className="h-3 w-3 text-gray-400" />
362
362
  )}
363
363
  </button>
364
364
  )
@@ -366,39 +366,39 @@ export function MediaBrowser({ onNavigate }: MediaBrowserProps) {
366
366
 
367
367
  if (loading) {
368
368
  return (
369
- <div className="p-3 pr-6 sm:p-4 sm:pr-8 flex items-center justify-center h-64">
370
- <Loader2 className="w-6 h-6 animate-spin text-blue-600" />
369
+ <div className="flex h-64 items-center justify-center p-3 pr-6 sm:p-4 sm:pr-8">
370
+ <Loader2 className="h-6 w-6 animate-spin text-blue-600" />
371
371
  </div>
372
372
  )
373
373
  }
374
374
 
375
375
  return (
376
- <div className="p-3 pr-6 sm:p-4 sm:pr-8 h-full flex flex-col">
376
+ <div className="flex h-full flex-col p-3 pr-6 sm:p-4 sm:pr-8">
377
377
  {error && (
378
378
  <div className="mb-4 flex items-center gap-3 rounded-lg border border-red-200 bg-red-50 p-3">
379
- <AlertTriangle className="w-5 h-5 text-red-600 shrink-0" />
380
- <span className="text-sm text-red-800 flex-1">{error}</span>
379
+ <AlertTriangle className="h-5 w-5 shrink-0 text-red-600" />
380
+ <span className="flex-1 text-sm text-red-800">{error}</span>
381
381
  <button
382
382
  onClick={refetch}
383
- className="px-3 py-1 text-sm text-red-700 border border-red-300 rounded-lg hover:bg-red-100 transition-colors"
383
+ className="rounded-lg border border-red-300 px-3 py-1 text-sm text-red-700 transition-colors hover:bg-red-100"
384
384
  >
385
385
  Retry
386
386
  </button>
387
387
  </div>
388
388
  )}
389
389
 
390
- <div className="flex items-center justify-between mb-4">
390
+ <div className="mb-4 flex items-center justify-between">
391
391
  <div className="flex items-center gap-3">
392
392
  <button
393
393
  type="button"
394
394
  onClick={() => setSidebarOpen((prev) => !prev)}
395
- className="p-1.5 rounded-lg hover:bg-gray-100 transition-colors"
395
+ className="rounded-lg p-1.5 transition-colors hover:bg-gray-100"
396
396
  title={sidebarOpen ? 'Hide folders' : 'Show folders'}
397
397
  >
398
- <FolderInput className="w-5 h-5 text-gray-600" />
398
+ <FolderInput className="h-5 w-5 text-gray-600" />
399
399
  </button>
400
400
  <div>
401
- <h1 className="text-xl sm:text-2xl font-semibold text-gray-900 mb-1">Media Library</h1>
401
+ <h1 className="mb-1 text-xl font-semibold text-gray-900 sm:text-2xl">Media Library</h1>
402
402
  <p className="text-sm text-gray-600">{filteredAndSorted.length} files</p>
403
403
  </div>
404
404
  </div>
@@ -414,21 +414,21 @@ export function MediaBrowser({ onNavigate }: MediaBrowserProps) {
414
414
  <button
415
415
  onClick={() => fileInputRef.current?.click()}
416
416
  disabled={uploading}
417
- className="flex items-center gap-2 px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors text-sm disabled:opacity-50"
417
+ className="flex items-center gap-2 rounded-lg bg-blue-600 px-4 py-2 text-sm text-white transition-colors hover:bg-blue-700 disabled:opacity-50"
418
418
  >
419
419
  {uploading ? (
420
- <Loader2 className="w-4 h-4 animate-spin" />
420
+ <Loader2 className="h-4 w-4 animate-spin" />
421
421
  ) : (
422
- <Upload className="w-4 h-4" />
422
+ <Upload className="h-4 w-4" />
423
423
  )}
424
424
  {uploading ? 'Uploading...' : 'Upload Files'}
425
425
  </button>
426
426
  </div>
427
427
  </div>
428
428
 
429
- <div className="flex gap-4 flex-1 min-h-0 overflow-hidden">
429
+ <div className="flex min-h-0 flex-1 gap-4 overflow-hidden">
430
430
  {sidebarOpen && (
431
- <div className="w-56 shrink-0 bg-white rounded-lg border border-gray-200 overflow-hidden flex flex-col">
431
+ <div className="flex w-56 shrink-0 flex-col overflow-hidden rounded-lg border border-gray-200 bg-white">
432
432
  <FolderTree
433
433
  scope="media"
434
434
  selected={folderSel}
@@ -443,24 +443,24 @@ export function MediaBrowser({ onNavigate }: MediaBrowserProps) {
443
443
  </div>
444
444
  )}
445
445
 
446
- <div className="flex-1 flex flex-col min-w-0">
447
- <div className="bg-white rounded-lg border border-gray-200 mb-4">
448
- <div className="p-3 flex items-center justify-between">
449
- <div className="flex items-center gap-3 flex-1">
450
- <div className="flex-1 max-w-md relative">
451
- <Search className="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-gray-400" />
446
+ <div className="flex min-w-0 flex-1 flex-col">
447
+ <div className="mb-4 rounded-lg border border-gray-200 bg-white">
448
+ <div className="flex items-center justify-between p-3">
449
+ <div className="flex flex-1 items-center gap-3">
450
+ <div className="relative max-w-md flex-1">
451
+ <Search className="absolute top-1/2 left-3 h-4 w-4 -translate-y-1/2 text-gray-400" />
452
452
  <input
453
453
  type="text"
454
454
  placeholder="Search media..."
455
455
  value={searchQuery}
456
456
  onChange={(e) => setSearchQuery(e.target.value)}
457
- className="w-full pl-9 pr-3 py-2 text-sm border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
457
+ className="w-full rounded-lg border border-gray-300 py-2 pr-3 pl-9 text-sm focus:ring-2 focus:ring-blue-500 focus:outline-none"
458
458
  />
459
459
  </div>
460
460
  <select
461
461
  value={filterType}
462
462
  onChange={(e) => setFilterType(e.target.value)}
463
- className="px-3 py-2 text-sm border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
463
+ className="rounded-lg border border-gray-300 px-3 py-2 text-sm focus:ring-2 focus:ring-blue-500 focus:outline-none"
464
464
  >
465
465
  <option value="all">All Types</option>
466
466
  <option value="image">Images</option>
@@ -468,25 +468,25 @@ export function MediaBrowser({ onNavigate }: MediaBrowserProps) {
468
468
  <option value="document">Documents</option>
469
469
  </select>
470
470
  </div>
471
- <div className="flex items-center gap-1 bg-gray-100 p-1 rounded-lg">
471
+ <div className="flex items-center gap-1 rounded-lg bg-gray-100 p-1">
472
472
  <button
473
473
  onClick={() => setViewMode('grid')}
474
- className={`p-1.5 rounded transition-colors ${viewMode === 'grid' ? 'bg-white text-gray-900 shadow-sm' : 'text-gray-600 hover:text-gray-900'}`}
474
+ className={`rounded p-1.5 transition-colors ${viewMode === 'grid' ? 'bg-white text-gray-900 shadow-sm' : 'text-gray-600 hover:text-gray-900'}`}
475
475
  >
476
- <Grid3x3 className="w-4 h-4" />
476
+ <Grid3x3 className="h-4 w-4" />
477
477
  </button>
478
478
  <button
479
479
  onClick={() => setViewMode('list')}
480
- className={`p-1.5 rounded transition-colors ${viewMode === 'list' ? 'bg-white text-gray-900 shadow-sm' : 'text-gray-600 hover:text-gray-900'}`}
480
+ className={`rounded p-1.5 transition-colors ${viewMode === 'list' ? 'bg-white text-gray-900 shadow-sm' : 'text-gray-600 hover:text-gray-900'}`}
481
481
  >
482
- <List className="w-4 h-4" />
482
+ <List className="h-4 w-4" />
483
483
  </button>
484
484
  </div>
485
485
  </div>
486
486
  </div>
487
487
 
488
488
  {selectedMedia.length > 0 && (
489
- <div className="bg-blue-50 border border-blue-200 rounded-lg p-3 mb-4">
489
+ <div className="mb-4 rounded-lg border border-blue-200 bg-blue-50 p-3">
490
490
  <div className="flex items-center justify-between">
491
491
  <span className="text-sm text-blue-900">
492
492
  {selectedMedia.length} file{selectedMedia.length !== 1 ? 's' : ''} selected
@@ -497,13 +497,13 @@ export function MediaBrowser({ onNavigate }: MediaBrowserProps) {
497
497
  for (const id of selectedMedia) await deleteMedia(id)
498
498
  setSelectedMedia([])
499
499
  }}
500
- className="px-3 py-1.5 text-sm bg-red-600 text-white rounded-lg hover:bg-red-700 transition-colors"
500
+ className="rounded-lg bg-red-600 px-3 py-1.5 text-sm text-white transition-colors hover:bg-red-700"
501
501
  >
502
502
  Delete Selected
503
503
  </button>
504
504
  <button
505
505
  onClick={() => setSelectedMedia([])}
506
- className="px-3 py-1.5 text-sm border border-gray-300 bg-white rounded-lg hover:bg-gray-50 transition-colors"
506
+ className="rounded-lg border border-gray-300 bg-white px-3 py-1.5 text-sm transition-colors hover:bg-gray-50"
507
507
  >
508
508
  Cancel
509
509
  </button>
@@ -514,10 +514,10 @@ export function MediaBrowser({ onNavigate }: MediaBrowserProps) {
514
514
 
515
515
  {filteredAndSorted.length === 0 && !loading ? (
516
516
  <div className="flex flex-col items-center justify-center py-16 text-center">
517
- <div className="w-12 h-12 rounded-full bg-gray-100 flex items-center justify-center mb-4">
518
- <ImageIcon className="w-6 h-6 text-gray-400" />
517
+ <div className="mb-4 flex h-12 w-12 items-center justify-center rounded-full bg-gray-100">
518
+ <ImageIcon className="h-6 w-6 text-gray-400" />
519
519
  </div>
520
- <h3 className="text-sm font-medium text-gray-900 mb-1">
520
+ <h3 className="mb-1 text-sm font-medium text-gray-900">
521
521
  {folderSel.type === 'smart' && folderSel.smart === 'uncategorized'
522
522
  ? 'No uncategorized media'
523
523
  : folderSel.type === 'folder'
@@ -527,13 +527,13 @@ export function MediaBrowser({ onNavigate }: MediaBrowserProps) {
527
527
  <p className="text-sm text-gray-500">Upload your first file to get started.</p>
528
528
  </div>
529
529
  ) : (
530
- <div className="flex gap-4 flex-1 overflow-hidden min-h-0">
530
+ <div className="flex min-h-0 flex-1 gap-4 overflow-hidden">
531
531
  <div
532
- className={`bg-white rounded-lg border border-gray-200 overflow-hidden transition-all duration-200 ${panelOpen ? 'flex-1 min-w-0' : 'w-full'}`}
532
+ className={`overflow-hidden rounded-lg border border-gray-200 bg-white transition-all duration-200 ${panelOpen ? 'min-w-0 flex-1' : 'w-full'}`}
533
533
  >
534
534
  {viewMode === 'grid' ? (
535
535
  <div
536
- className={`grid gap-2 sm:gap-3 p-2 sm:p-3 overflow-y-auto h-full ${
536
+ className={`grid h-full gap-2 overflow-y-auto p-2 sm:gap-3 sm:p-3 ${
537
537
  panelOpen
538
538
  ? 'grid-cols-2 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4'
539
539
  : 'grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5 xl:grid-cols-6 2xl:grid-cols-8'
@@ -545,7 +545,7 @@ export function MediaBrowser({ onNavigate }: MediaBrowserProps) {
545
545
  return (
546
546
  <div
547
547
  key={item.id}
548
- className={`group relative aspect-square rounded-lg border-2 overflow-hidden cursor-pointer transition-all ${
548
+ className={`group relative aspect-square cursor-pointer overflow-hidden rounded-lg border-2 transition-all ${
549
549
  isActive
550
550
  ? 'border-blue-500 ring-2 ring-blue-200'
551
551
  : selectedMedia.includes(item.id)
@@ -556,36 +556,36 @@ export function MediaBrowser({ onNavigate }: MediaBrowserProps) {
556
556
  draggable
557
557
  onDragStart={(e) => handleDragStart(e, item.id)}
558
558
  >
559
- <div className="w-full h-full bg-gray-100 flex items-center justify-center">
559
+ <div className="flex h-full w-full items-center justify-center bg-gray-100">
560
560
  <MediaPreview item={item} />
561
561
  </div>
562
- <div className="absolute inset-0 bg-linear-to-t from-black/60 to-transparent opacity-0 group-hover:opacity-100 transition-opacity">
563
- <div className="absolute bottom-0 left-0 right-0 p-2">
564
- <p className="text-white text-xs font-medium truncate">{item.name}</p>
565
- <p className="text-white/80 text-xs">{item.size}</p>
562
+ <div className="absolute inset-0 bg-linear-to-t from-black/60 to-transparent opacity-0 transition-opacity group-hover:opacity-100">
563
+ <div className="absolute right-0 bottom-0 left-0 p-2">
564
+ <p className="truncate text-xs font-medium text-white">{item.name}</p>
565
+ <p className="text-xs text-white/80">{item.size}</p>
566
566
  </div>
567
567
  </div>
568
568
  {hasIssues && (
569
569
  <div
570
- className="absolute top-1.5 left-1.5 w-5 h-5 bg-yellow-500 rounded-full flex items-center justify-center"
570
+ className="absolute top-1.5 left-1.5 flex h-5 w-5 items-center justify-center rounded-full bg-yellow-500"
571
571
  title="Needs attention"
572
572
  >
573
- <AlertTriangle className="w-3 h-3 text-white" />
573
+ <AlertTriangle className="h-3 w-3 text-white" />
574
574
  </div>
575
575
  )}
576
576
  <div
577
- className="absolute top-1.5 right-1.5 opacity-0 group-hover:opacity-100 transition-opacity"
577
+ className="absolute top-1.5 right-1.5 opacity-0 transition-opacity group-hover:opacity-100"
578
578
  onClick={(e) => handleCheckbox(e, item.id)}
579
579
  >
580
580
  <div
581
- className={`w-5 h-5 rounded border-2 flex items-center justify-center transition-colors ${
581
+ className={`flex h-5 w-5 items-center justify-center rounded border-2 transition-colors ${
582
582
  selectedMedia.includes(item.id)
583
- ? 'bg-blue-600 border-blue-600'
584
- : 'bg-white/80 border-gray-400'
583
+ ? 'border-blue-600 bg-blue-600'
584
+ : 'border-gray-400 bg-white/80'
585
585
  }`}
586
586
  >
587
587
  {selectedMedia.includes(item.id) && (
588
- <svg className="w-3 h-3 text-white" fill="none" viewBox="0 0 12 12">
588
+ <svg className="h-3 w-3 text-white" fill="none" viewBox="0 0 12 12">
589
589
  <path
590
590
  d="M10 3L4.5 8.5L2 6"
591
591
  stroke="currentColor"
@@ -602,9 +602,9 @@ export function MediaBrowser({ onNavigate }: MediaBrowserProps) {
602
602
  })}
603
603
  </div>
604
604
  ) : (
605
- <div className="overflow-y-auto h-full">
605
+ <div className="h-full overflow-y-auto">
606
606
  <table className="w-full">
607
- <thead className="bg-gray-50 border-b border-gray-200 sticky top-0">
607
+ <thead className="sticky top-0 border-b border-gray-200 bg-gray-50">
608
608
  <tr>
609
609
  <th className="w-8 px-3 py-2 text-left">
610
610
  <input
@@ -642,7 +642,7 @@ export function MediaBrowser({ onNavigate }: MediaBrowserProps) {
642
642
  return (
643
643
  <tr
644
644
  key={item.id}
645
- className={`transition-colors cursor-pointer ${isActive ? 'bg-blue-50' : 'hover:bg-gray-50'}`}
645
+ className={`cursor-pointer transition-colors ${isActive ? 'bg-blue-50' : 'hover:bg-gray-50'}`}
646
646
  onClick={() => openDetail(item)}
647
647
  draggable
648
648
  onDragStart={(e) => handleDragStart(e, item.id)}
@@ -660,12 +660,12 @@ export function MediaBrowser({ onNavigate }: MediaBrowserProps) {
660
660
  className="rounded border-gray-300"
661
661
  />
662
662
  </td>
663
- <td className="px-1 py-2 cursor-grab">
664
- <GripVertical className="w-4 h-4 text-gray-300" />
663
+ <td className="cursor-grab px-1 py-2">
664
+ <GripVertical className="h-4 w-4 text-gray-300" />
665
665
  </td>
666
666
  <td className="px-3 py-2">
667
667
  <div className="flex items-center gap-3">
668
- <div className="w-10 h-10 bg-gray-100 rounded flex items-center justify-center overflow-hidden">
668
+ <div className="flex h-10 w-10 items-center justify-center overflow-hidden rounded bg-gray-100">
669
669
  <MediaPreview item={item} />
670
670
  </div>
671
671
  <span className="text-sm font-medium text-gray-900">
@@ -680,11 +680,11 @@ export function MediaBrowser({ onNavigate }: MediaBrowserProps) {
680
680
  <td className="px-3 py-2 text-sm text-gray-600">{item.date}</td>
681
681
  <td className="px-3 py-2">
682
682
  {hasIssues ? (
683
- <span className="inline-flex items-center gap-1 px-2 py-0.5 rounded-full text-xs font-medium bg-yellow-100 text-yellow-800">
684
- <AlertTriangle className="w-3 h-3" /> Needs attention
683
+ <span className="inline-flex items-center gap-1 rounded-full bg-yellow-100 px-2 py-0.5 text-xs font-medium text-yellow-800">
684
+ <AlertTriangle className="h-3 w-3" /> Needs attention
685
685
  </span>
686
686
  ) : (
687
- <span className="inline-flex items-center px-2 py-0.5 rounded-full text-xs font-medium bg-green-100 text-green-800">
687
+ <span className="inline-flex items-center rounded-full bg-green-100 px-2 py-0.5 text-xs font-medium text-green-800">
688
688
  Complete
689
689
  </span>
690
690
  )}
@@ -699,37 +699,37 @@ export function MediaBrowser({ onNavigate }: MediaBrowserProps) {
699
699
  </div>
700
700
 
701
701
  {panelOpen && activeItem && (
702
- <div className="w-80 lg:w-96 bg-white rounded-lg border border-gray-200 overflow-y-auto shrink-0 flex flex-col">
703
- <div className="flex items-center justify-between p-4 border-b border-gray-200 sticky top-0 bg-white z-10">
704
- <h3 className="text-sm font-semibold text-gray-900 truncate">
702
+ <div className="flex w-80 shrink-0 flex-col overflow-y-auto rounded-lg border border-gray-200 bg-white lg:w-96">
703
+ <div className="sticky top-0 z-10 flex items-center justify-between border-b border-gray-200 bg-white p-4">
704
+ <h3 className="truncate text-sm font-semibold text-gray-900">
705
705
  {activeItem.name}
706
706
  </h3>
707
707
  <button
708
708
  onClick={closeDetail}
709
- className="p-1 hover:bg-gray-100 rounded transition-colors"
709
+ className="rounded p-1 transition-colors hover:bg-gray-100"
710
710
  aria-label="Close panel"
711
711
  >
712
- <X className="w-4 h-4 text-gray-500" />
712
+ <X className="h-4 w-4 text-gray-500" />
713
713
  </button>
714
714
  </div>
715
715
 
716
716
  <div className="flex-1 overflow-y-auto">
717
- <div className="p-4 border-b border-gray-200">
718
- <div className="aspect-video bg-gray-100 rounded-lg flex items-center justify-center overflow-hidden">
717
+ <div className="border-b border-gray-200 p-4">
718
+ <div className="flex aspect-video items-center justify-center overflow-hidden rounded-lg bg-gray-100">
719
719
  {isImageMedia(activeItem) ? (
720
720
  <MediaPreview item={activeItem} />
721
721
  ) : (
722
- <ImageIcon className="w-12 h-12 text-gray-300" />
722
+ <ImageIcon className="h-12 w-12 text-gray-300" />
723
723
  )}
724
724
  </div>
725
725
  </div>
726
726
 
727
727
  {issues.length > 0 && (
728
- <div className="mx-4 mt-4 p-3 bg-yellow-50 border border-yellow-200 rounded-lg">
728
+ <div className="mx-4 mt-4 rounded-lg border border-yellow-200 bg-yellow-50 p-3">
729
729
  <div className="flex items-start gap-2">
730
- <AlertTriangle className="w-4 h-4 text-yellow-600 mt-0.5 shrink-0" />
730
+ <AlertTriangle className="mt-0.5 h-4 w-4 shrink-0 text-yellow-600" />
731
731
  <div>
732
- <p className="text-xs font-semibold text-yellow-900 mb-1">
732
+ <p className="mb-1 text-xs font-semibold text-yellow-900">
733
733
  {issues.length} issue{issues.length !== 1 ? 's' : ''} found
734
734
  </p>
735
735
  <ul className="space-y-0.5">
@@ -748,78 +748,78 @@ export function MediaBrowser({ onNavigate }: MediaBrowserProps) {
748
748
  if (!activeItem.title) await handleAiGenerate('title')
749
749
  if (activeItem.sizeBytes > 2000000) await handleAiGenerate('optimize')
750
750
  }}
751
- className="mt-2 w-full flex items-center justify-center gap-1.5 px-3 py-1.5 text-xs bg-yellow-600 text-white rounded-lg hover:bg-yellow-700 transition-colors"
751
+ className="mt-2 flex w-full items-center justify-center gap-1.5 rounded-lg bg-yellow-600 px-3 py-1.5 text-xs text-white transition-colors hover:bg-yellow-700"
752
752
  >
753
- <Sparkles className="w-3.5 h-3.5" />
753
+ <Sparkles className="h-3.5 w-3.5" />
754
754
  AI Fix All Issues
755
755
  </button>
756
756
  </div>
757
757
  )}
758
758
 
759
- <div className="p-4 border-b border-gray-200 space-y-3">
760
- <h4 className="text-xs font-semibold text-gray-500 uppercase tracking-wide">
759
+ <div className="space-y-3 border-b border-gray-200 p-4">
760
+ <h4 className="text-xs font-semibold tracking-wide text-gray-500 uppercase">
761
761
  File Information
762
762
  </h4>
763
763
  <div className="grid grid-cols-2 gap-3">
764
764
  <div>
765
- <div className="text-xs text-gray-500 mb-0.5">Format</div>
765
+ <div className="mb-0.5 text-xs text-gray-500">Format</div>
766
766
  <div className="text-sm text-gray-900">
767
767
  {activeItem.format ?? 'Unknown'}
768
768
  </div>
769
769
  </div>
770
770
  <div>
771
- <div className="text-xs text-gray-500 mb-0.5">File Size</div>
772
- <div className="text-sm text-gray-900 flex items-center gap-1">
771
+ <div className="mb-0.5 text-xs text-gray-500">File Size</div>
772
+ <div className="flex items-center gap-1 text-sm text-gray-900">
773
773
  {activeItem.size}
774
774
  {activeItem.sizeBytes > 2000000 && (
775
- <span className="text-yellow-600 text-xs">(large)</span>
775
+ <span className="text-xs text-yellow-600">(large)</span>
776
776
  )}
777
777
  </div>
778
778
  </div>
779
779
  <div>
780
- <div className="text-xs text-gray-500 mb-0.5">Dimensions</div>
780
+ <div className="mb-0.5 text-xs text-gray-500">Dimensions</div>
781
781
  <div className="text-sm text-gray-900">
782
782
  {activeItem.dimensions ?? '—'}
783
783
  </div>
784
784
  </div>
785
785
  <div>
786
- <div className="text-xs text-gray-500 mb-0.5">Uploaded</div>
786
+ <div className="mb-0.5 text-xs text-gray-500">Uploaded</div>
787
787
  <div className="text-sm text-gray-900">{activeItem.date}</div>
788
788
  </div>
789
789
  </div>
790
790
 
791
791
  <div>
792
- <div className="text-xs text-gray-500 mb-1">URL</div>
792
+ <div className="mb-1 text-xs text-gray-500">URL</div>
793
793
  <div className="flex items-center gap-1">
794
- <code className="flex-1 text-xs bg-gray-50 border border-gray-200 px-2 py-1.5 rounded text-gray-700 truncate">
794
+ <code className="flex-1 truncate rounded border border-gray-200 bg-gray-50 px-2 py-1.5 text-xs text-gray-700">
795
795
  {activeItem.url}
796
796
  </code>
797
797
  <button
798
798
  onClick={handleCopyUrl}
799
- className="p-1.5 hover:bg-gray-100 rounded transition-colors shrink-0"
799
+ className="shrink-0 rounded p-1.5 transition-colors hover:bg-gray-100"
800
800
  title="Copy URL"
801
801
  >
802
- <Copy className="w-3.5 h-3.5 text-gray-500" />
802
+ <Copy className="h-3.5 w-3.5 text-gray-500" />
803
803
  </button>
804
804
  </div>
805
805
  </div>
806
806
  </div>
807
807
 
808
- <div className="p-4 border-b border-gray-200 space-y-4">
809
- <h4 className="text-xs font-semibold text-gray-500 uppercase tracking-wide">
808
+ <div className="space-y-4 border-b border-gray-200 p-4">
809
+ <h4 className="text-xs font-semibold tracking-wide text-gray-500 uppercase">
810
810
  SEO & Accessibility
811
811
  </h4>
812
812
 
813
813
  <div>
814
- <div className="flex items-center justify-between mb-1">
814
+ <div className="mb-1 flex items-center justify-between">
815
815
  <label className="text-sm font-medium text-gray-700">Alt Tag</label>
816
816
  <button
817
817
  type="button"
818
818
  onClick={() => handleAiGenerate('alt')}
819
819
  disabled={aiGenerating === 'alt'}
820
- className="flex items-center gap-1 text-xs text-indigo-600 hover:text-indigo-700 disabled:opacity-50 transition-colors"
820
+ className="flex items-center gap-1 text-xs text-indigo-600 transition-colors hover:text-indigo-700 disabled:opacity-50"
821
821
  >
822
- <Bot className="w-3.5 h-3.5" />
822
+ <Bot className="h-3.5 w-3.5" />
823
823
  {aiGenerating === 'alt' ? 'Generating...' : 'AI Generate'}
824
824
  </button>
825
825
  </div>
@@ -828,25 +828,25 @@ export function MediaBrowser({ onNavigate }: MediaBrowserProps) {
828
828
  onChange={(e) => setEditAlt(e.target.value)}
829
829
  placeholder="Describe this image for accessibility..."
830
830
  rows={2}
831
- className="w-full text-sm border border-gray-300 rounded-lg px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500 resize-none"
831
+ className="w-full resize-none rounded-lg border border-gray-300 px-3 py-2 text-sm focus:ring-2 focus:ring-blue-500 focus:outline-none"
832
832
  />
833
833
  {!editAlt && (
834
- <p className="text-xs text-red-500 mt-1">
834
+ <p className="mt-1 text-xs text-red-500">
835
835
  Required for accessibility and SEO
836
836
  </p>
837
837
  )}
838
838
  </div>
839
839
 
840
840
  <div>
841
- <div className="flex items-center justify-between mb-1">
841
+ <div className="mb-1 flex items-center justify-between">
842
842
  <label className="text-sm font-medium text-gray-700">Title</label>
843
843
  <button
844
844
  type="button"
845
845
  onClick={() => handleAiGenerate('title')}
846
846
  disabled={aiGenerating === 'title'}
847
- className="flex items-center gap-1 text-xs text-indigo-600 hover:text-indigo-700 disabled:opacity-50 transition-colors"
847
+ className="flex items-center gap-1 text-xs text-indigo-600 transition-colors hover:text-indigo-700 disabled:opacity-50"
848
848
  >
849
- <Bot className="w-3.5 h-3.5" />
849
+ <Bot className="h-3.5 w-3.5" />
850
850
  {aiGenerating === 'title' ? 'Generating...' : 'AI Generate'}
851
851
  </button>
852
852
  </div>
@@ -855,25 +855,25 @@ export function MediaBrowser({ onNavigate }: MediaBrowserProps) {
855
855
  value={editTitle}
856
856
  onChange={(e) => setEditTitle(e.target.value)}
857
857
  placeholder="Image title..."
858
- className="w-full text-sm border border-gray-300 rounded-lg px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500"
858
+ 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"
859
859
  />
860
860
  </div>
861
861
 
862
862
  <div>
863
- <label className="text-sm font-medium text-gray-700 mb-1 block">
863
+ <label className="mb-1 block text-sm font-medium text-gray-700">
864
864
  File Name
865
865
  </label>
866
866
  <input
867
867
  type="text"
868
868
  value={editFilename}
869
869
  onChange={(e) => setEditFilename(e.target.value)}
870
- className="w-full text-sm border border-gray-300 rounded-lg px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500"
870
+ 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"
871
871
  />
872
872
  </div>
873
873
  </div>
874
874
 
875
875
  {isImageMedia(activeItem) && activeItem.url && (
876
- <div className="p-4 border-b border-gray-200">
876
+ <div className="border-b border-gray-200 p-4">
877
877
  <FocalPointPicker
878
878
  imageUrl={activeItem.url}
879
879
  focalX={focalX}
@@ -886,8 +886,8 @@ export function MediaBrowser({ onNavigate }: MediaBrowserProps) {
886
886
  </div>
887
887
  )}
888
888
 
889
- <div className="p-4 border-b border-gray-200">
890
- <h4 className="text-xs font-semibold text-gray-500 uppercase tracking-wide mb-3">
889
+ <div className="border-b border-gray-200 p-4">
890
+ <h4 className="mb-3 text-xs font-semibold tracking-wide text-gray-500 uppercase">
891
891
  Used On {activeItem.usedOn && `(${activeItem.usedOn.length})`}
892
892
  </h4>
893
893
  {activeItem.usedOn && activeItem.usedOn.length > 0 ? (
@@ -897,23 +897,23 @@ export function MediaBrowser({ onNavigate }: MediaBrowserProps) {
897
897
  key={i}
898
898
  type="button"
899
899
  onClick={() => onNavigate?.(usage.path)}
900
- className="w-full flex items-center gap-2 p-2 rounded-lg border border-gray-200 hover:bg-gray-50 transition-colors text-left"
900
+ className="flex w-full items-center gap-2 rounded-lg border border-gray-200 p-2 text-left transition-colors hover:bg-gray-50"
901
901
  >
902
- <Link2 className="w-4 h-4 text-gray-400 shrink-0" />
903
- <span className="text-sm text-gray-900 flex-1 truncate">
902
+ <Link2 className="h-4 w-4 shrink-0 text-gray-400" />
903
+ <span className="flex-1 truncate text-sm text-gray-900">
904
904
  {usage.page}
905
905
  </span>
906
- <ExternalLink className="w-3.5 h-3.5 text-gray-400 shrink-0" />
906
+ <ExternalLink className="h-3.5 w-3.5 shrink-0 text-gray-400" />
907
907
  </button>
908
908
  ))}
909
909
  </div>
910
910
  ) : (
911
- <div className="p-3 bg-orange-50 border border-orange-200 rounded-lg">
911
+ <div className="rounded-lg border border-orange-200 bg-orange-50 p-3">
912
912
  <div className="flex items-start gap-2">
913
- <AlertTriangle className="w-4 h-4 text-orange-600 mt-0.5 shrink-0" />
913
+ <AlertTriangle className="mt-0.5 h-4 w-4 shrink-0 text-orange-600" />
914
914
  <div>
915
915
  <p className="text-xs font-medium text-orange-900">Orphaned media</p>
916
- <p className="text-xs text-orange-700 mt-0.5">
916
+ <p className="mt-0.5 text-xs text-orange-700">
917
917
  This file isn&apos;t used on any page. Consider deleting it to save
918
918
  storage.
919
919
  </p>
@@ -923,38 +923,38 @@ export function MediaBrowser({ onNavigate }: MediaBrowserProps) {
923
923
  )}
924
924
  </div>
925
925
 
926
- <div className="p-4 space-y-3">
927
- <h4 className="text-xs font-semibold text-gray-500 uppercase tracking-wide">
926
+ <div className="space-y-3 p-4">
927
+ <h4 className="text-xs font-semibold tracking-wide text-gray-500 uppercase">
928
928
  AI Optimization
929
929
  </h4>
930
930
  <button
931
931
  type="button"
932
932
  onClick={() => handleAiGenerate('optimize')}
933
933
  disabled={aiGenerating === 'optimize'}
934
- className="w-full flex items-center gap-2 p-3 rounded-lg border border-indigo-200 bg-indigo-50 hover:bg-indigo-100 transition-colors text-left disabled:opacity-50"
934
+ className="flex w-full items-center gap-2 rounded-lg border border-indigo-200 bg-indigo-50 p-3 text-left transition-colors hover:bg-indigo-100 disabled:opacity-50"
935
935
  >
936
936
  <Sparkles
937
- className={`w-5 h-5 text-indigo-600 shrink-0 ${aiGenerating === 'optimize' ? 'animate-spin' : ''}`}
937
+ className={`h-5 w-5 shrink-0 text-indigo-600 ${aiGenerating === 'optimize' ? 'animate-spin' : ''}`}
938
938
  />
939
939
  <div className="flex-1">
940
940
  <div className="text-sm font-medium text-indigo-900">
941
941
  {aiGenerating === 'optimize' ? 'Optimizing...' : 'Optimize Image'}
942
942
  </div>
943
- <div className="text-xs text-indigo-700 mt-0.5">
943
+ <div className="mt-0.5 text-xs text-indigo-700">
944
944
  Compress and convert to modern format (WebP/AVIF)
945
945
  </div>
946
946
  </div>
947
947
  </button>
948
948
  <button
949
949
  type="button"
950
- className="w-full flex items-center gap-2 p-3 rounded-lg border border-gray-200 hover:bg-gray-50 transition-colors text-left"
950
+ className="flex w-full items-center gap-2 rounded-lg border border-gray-200 p-3 text-left transition-colors hover:bg-gray-50"
951
951
  >
952
- <Bot className="w-5 h-5 text-gray-500 shrink-0" />
952
+ <Bot className="h-5 w-5 shrink-0 text-gray-500" />
953
953
  <div className="flex-1">
954
954
  <div className="text-sm font-medium text-gray-900">
955
955
  AI Content Analysis
956
956
  </div>
957
- <div className="text-xs text-gray-600 mt-0.5">
957
+ <div className="mt-0.5 text-xs text-gray-600">
958
958
  Detect objects, faces, text, and suggest categories
959
959
  </div>
960
960
  </div>
@@ -962,30 +962,30 @@ export function MediaBrowser({ onNavigate }: MediaBrowserProps) {
962
962
  </div>
963
963
  </div>
964
964
 
965
- <div className="p-4 border-t border-gray-200 bg-white sticky bottom-0 flex items-center gap-2">
965
+ <div className="sticky bottom-0 flex items-center gap-2 border-t border-gray-200 bg-white p-4">
966
966
  <button
967
967
  type="button"
968
968
  onClick={handleSaveDetails}
969
969
  disabled={saving}
970
- className="flex-1 px-4 py-2 text-sm bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors disabled:opacity-50 flex items-center justify-center gap-2"
970
+ className="flex flex-1 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 disabled:opacity-50"
971
971
  >
972
- {saving && <Loader2 className="w-4 h-4 animate-spin" />}
972
+ {saving && <Loader2 className="h-4 w-4 animate-spin" />}
973
973
  {saving ? 'Saving...' : 'Save Changes'}
974
974
  </button>
975
975
  <button
976
976
  type="button"
977
- className="p-2 hover:bg-gray-100 rounded-lg transition-colors"
977
+ className="rounded-lg p-2 transition-colors hover:bg-gray-100"
978
978
  title="Download"
979
979
  >
980
- <Download className="w-4 h-4 text-gray-600" />
980
+ <Download className="h-4 w-4 text-gray-600" />
981
981
  </button>
982
982
  <button
983
983
  type="button"
984
984
  onClick={() => deleteMedia(activeItem.id)}
985
- className="p-2 hover:bg-gray-100 rounded-lg transition-colors"
985
+ className="rounded-lg p-2 transition-colors hover:bg-gray-100"
986
986
  title="Delete"
987
987
  >
988
- <Trash2 className="w-4 h-4 text-red-600" />
988
+ <Trash2 className="h-4 w-4 text-red-600" />
989
989
  </button>
990
990
  </div>
991
991
  </div>