@actuate-media/cms-admin 0.9.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 (294) 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.d.ts +18 -0
  34. package/dist/components/SchedulePublishDialog.d.ts.map +1 -0
  35. package/dist/components/SchedulePublishDialog.js +106 -0
  36. package/dist/components/SchedulePublishDialog.js.map +1 -0
  37. package/dist/components/SharePreviewLinkDialog.d.ts +17 -0
  38. package/dist/components/SharePreviewLinkDialog.d.ts.map +1 -0
  39. package/dist/components/SharePreviewLinkDialog.js +83 -0
  40. package/dist/components/SharePreviewLinkDialog.js.map +1 -0
  41. package/dist/components/TipTapEditor.js +5 -5
  42. package/dist/components/VersionHistory.js +2 -2
  43. package/dist/components/ui/Badge.d.ts +33 -3
  44. package/dist/components/ui/Badge.d.ts.map +1 -1
  45. package/dist/components/ui/Badge.js +42 -8
  46. package/dist/components/ui/Badge.js.map +1 -1
  47. package/dist/components/ui/Button.d.ts +19 -8
  48. package/dist/components/ui/Button.d.ts.map +1 -1
  49. package/dist/components/ui/Button.js +35 -14
  50. package/dist/components/ui/Button.js.map +1 -1
  51. package/dist/components/ui/Card.d.ts +26 -0
  52. package/dist/components/ui/Card.d.ts.map +1 -0
  53. package/dist/components/ui/Card.js +45 -0
  54. package/dist/components/ui/Card.js.map +1 -0
  55. package/dist/components/ui/DataTable.js +1 -1
  56. package/dist/components/ui/Input.d.ts +15 -0
  57. package/dist/components/ui/Input.d.ts.map +1 -0
  58. package/dist/components/ui/Input.js +23 -0
  59. package/dist/components/ui/Input.js.map +1 -0
  60. package/dist/components/ui/SearchInput.js +1 -1
  61. package/dist/components/ui/Select.d.ts +16 -0
  62. package/dist/components/ui/Select.d.ts.map +1 -0
  63. package/dist/components/ui/Select.js +25 -0
  64. package/dist/components/ui/Select.js.map +1 -0
  65. package/dist/components/ui/Toast.js +1 -1
  66. package/dist/components/ui/index.d.ts +10 -4
  67. package/dist/components/ui/index.d.ts.map +1 -1
  68. package/dist/components/ui/index.js +5 -2
  69. package/dist/components/ui/index.js.map +1 -1
  70. package/dist/fields/BlockBuilderField.js +3 -3
  71. package/dist/fields/DateField.js +1 -1
  72. package/dist/fields/RelationshipField.js +3 -3
  73. package/dist/fields/TextField.js +1 -1
  74. package/dist/index.d.ts +6 -0
  75. package/dist/index.d.ts.map +1 -1
  76. package/dist/index.js +5 -0
  77. package/dist/index.js.map +1 -1
  78. package/dist/layout/Header.js +1 -1
  79. package/dist/layout/Layout.d.ts +14 -0
  80. package/dist/layout/Layout.d.ts.map +1 -1
  81. package/dist/layout/Layout.js +17 -11
  82. package/dist/layout/Layout.js.map +1 -1
  83. package/dist/layout/Sidebar.d.ts.map +1 -1
  84. package/dist/layout/Sidebar.js +21 -11
  85. package/dist/layout/Sidebar.js.map +1 -1
  86. package/dist/layout/primitives/AdminShell.d.ts +43 -0
  87. package/dist/layout/primitives/AdminShell.d.ts.map +1 -0
  88. package/dist/layout/primitives/AdminShell.js +51 -0
  89. package/dist/layout/primitives/AdminShell.js.map +1 -0
  90. package/dist/layout/primitives/Box.d.ts +19 -0
  91. package/dist/layout/primitives/Box.d.ts.map +1 -0
  92. package/dist/layout/primitives/Box.js +12 -0
  93. package/dist/layout/primitives/Box.js.map +1 -0
  94. package/dist/layout/primitives/Cluster.d.ts +27 -0
  95. package/dist/layout/primitives/Cluster.d.ts.map +1 -0
  96. package/dist/layout/primitives/Cluster.js +37 -0
  97. package/dist/layout/primitives/Cluster.js.map +1 -0
  98. package/dist/layout/primitives/Grid.d.ts +45 -0
  99. package/dist/layout/primitives/Grid.d.ts.map +1 -0
  100. package/dist/layout/primitives/Grid.js +59 -0
  101. package/dist/layout/primitives/Grid.js.map +1 -0
  102. package/dist/layout/primitives/PageContainer.d.ts +36 -0
  103. package/dist/layout/primitives/PageContainer.d.ts.map +1 -0
  104. package/dist/layout/primitives/PageContainer.js +41 -0
  105. package/dist/layout/primitives/PageContainer.js.map +1 -0
  106. package/dist/layout/primitives/Split.d.ts +34 -0
  107. package/dist/layout/primitives/Split.d.ts.map +1 -0
  108. package/dist/layout/primitives/Split.js +27 -0
  109. package/dist/layout/primitives/Split.js.map +1 -0
  110. package/dist/layout/primitives/Stack.d.ts +23 -0
  111. package/dist/layout/primitives/Stack.d.ts.map +1 -0
  112. package/dist/layout/primitives/Stack.js +34 -0
  113. package/dist/layout/primitives/Stack.js.map +1 -0
  114. package/dist/layout/primitives/index.d.ts +30 -0
  115. package/dist/layout/primitives/index.d.ts.map +1 -0
  116. package/dist/layout/primitives/index.js +22 -0
  117. package/dist/layout/primitives/index.js.map +1 -0
  118. package/dist/layout/primitives/tokens.d.ts +48 -0
  119. package/dist/layout/primitives/tokens.d.ts.map +1 -0
  120. package/dist/layout/primitives/tokens.js +54 -0
  121. package/dist/layout/primitives/tokens.js.map +1 -0
  122. package/dist/lib/cv.d.ts +53 -0
  123. package/dist/lib/cv.d.ts.map +1 -0
  124. package/dist/lib/cv.js +39 -0
  125. package/dist/lib/cv.js.map +1 -0
  126. package/dist/views/ApiKeys.d.ts.map +1 -1
  127. package/dist/views/ApiKeys.js +13 -11
  128. package/dist/views/ApiKeys.js.map +1 -1
  129. package/dist/views/CollectionList.js +8 -8
  130. package/dist/views/Dashboard.d.ts.map +1 -1
  131. package/dist/views/Dashboard.js +333 -78
  132. package/dist/views/Dashboard.js.map +1 -1
  133. package/dist/views/DocumentEdit.d.ts.map +1 -1
  134. package/dist/views/DocumentEdit.js +17 -5
  135. package/dist/views/DocumentEdit.js.map +1 -1
  136. package/dist/views/ForgotPassword.js +2 -2
  137. package/dist/views/FormEditor.js +5 -5
  138. package/dist/views/FormSubmissions.js +6 -6
  139. package/dist/views/Forms.js +2 -2
  140. package/dist/views/Login.d.ts +16 -1
  141. package/dist/views/Login.d.ts.map +1 -1
  142. package/dist/views/Login.js +17 -7
  143. package/dist/views/Login.js.map +1 -1
  144. package/dist/views/MediaBrowser.js +16 -16
  145. package/dist/views/PageEditor.js +2 -2
  146. package/dist/views/Pages.js +10 -10
  147. package/dist/views/PostEditor.js +2 -2
  148. package/dist/views/Posts.js +4 -4
  149. package/dist/views/Redirects.js +4 -4
  150. package/dist/views/ResetPassword.js +2 -2
  151. package/dist/views/SEO.js +6 -6
  152. package/dist/views/ScriptTagEditor.js +4 -4
  153. package/dist/views/ScriptTags.js +2 -2
  154. package/dist/views/Settings.d.ts.map +1 -1
  155. package/dist/views/Settings.js +9 -8
  156. package/dist/views/Settings.js.map +1 -1
  157. package/dist/views/SetupWizard.js +2 -2
  158. package/dist/views/Users.js +4 -4
  159. package/dist/views/page-builder/AIBlockAssist.js +1 -1
  160. package/dist/views/page-builder/AIGenerateDialog.js +10 -10
  161. package/dist/views/page-builder/BlockEditor.js +10 -10
  162. package/dist/views/page-builder/BlockPicker.js +4 -4
  163. package/dist/views/page-builder/BottomBar.js +1 -1
  164. package/dist/views/page-builder/BuilderToolbar.js +2 -2
  165. package/dist/views/page-builder/ContextPanel.js +2 -2
  166. package/dist/views/page-builder/DesignScore.js +9 -9
  167. package/dist/views/page-builder/NodeSettings.js +8 -8
  168. package/dist/views/page-builder/PageBuilder.js +3 -3
  169. package/dist/views/page-builder/PageSettings.js +1 -1
  170. package/dist/views/page-builder/PageTemplates.js +2 -2
  171. package/dist/views/page-builder/SEOPanel.js +13 -13
  172. package/dist/views/page-builder/SavedSections.js +5 -5
  173. package/dist/views/page-builder/TemplatePicker.js +2 -2
  174. package/dist/views/page-builder/block-renderers/CTAPreview.js +5 -5
  175. package/dist/views/page-builder/block-renderers/CardsPreview.js +1 -1
  176. package/dist/views/page-builder/block-renderers/CodePreview.js +1 -1
  177. package/dist/views/page-builder/block-renderers/FAQPreview.js +3 -3
  178. package/dist/views/page-builder/block-renderers/FallbackPreview.js +1 -1
  179. package/dist/views/page-builder/block-renderers/FormPreview.js +3 -3
  180. package/dist/views/page-builder/block-renderers/GalleryPreview.js +5 -5
  181. package/dist/views/page-builder/block-renderers/HeroPreview.js +3 -3
  182. package/dist/views/page-builder/block-renderers/ImagePreview.js +3 -3
  183. package/dist/views/page-builder/block-renderers/TextPreview.js +3 -3
  184. package/dist/views/page-builder/block-renderers/VideoPreview.js +4 -4
  185. package/dist/views/page-builder/canvas/BlockRenderer.js +1 -1
  186. package/dist/views/page-builder/canvas/BuilderCanvas.js +3 -3
  187. package/dist/views/page-builder/canvas/ColumnRenderer.js +2 -2
  188. package/dist/views/page-builder/canvas/ContainerRenderer.js +2 -2
  189. package/dist/views/page-builder/canvas/RowRenderer.js +2 -2
  190. package/dist/views/page-builder/canvas/SectionRenderer.js +2 -2
  191. package/package.json +6 -2
  192. package/src/AdminRoot.tsx +21 -11
  193. package/src/__tests__/layout/primitives.test.ts +37 -0
  194. package/src/__tests__/lib/cv.test.ts +74 -0
  195. package/src/assets/actuate-logo.tsx +72 -0
  196. package/src/components/Breadcrumbs.tsx +6 -6
  197. package/src/components/CommandPalette.tsx +34 -34
  198. package/src/components/ContentOverviewChart.tsx +3 -3
  199. package/src/components/ErrorBoundary.tsx +3 -3
  200. package/src/components/FocalPointPicker.tsx +4 -4
  201. package/src/components/FolderTree.tsx +38 -38
  202. package/src/components/LivePreview.tsx +16 -16
  203. package/src/components/LocaleSwitcher.tsx +7 -7
  204. package/src/components/MediaPickerModal.tsx +21 -21
  205. package/src/components/PresenceIndicator.tsx +2 -2
  206. package/src/components/SEOConfigPanel.tsx +582 -0
  207. package/src/components/SEOPanel.tsx +46 -46
  208. package/src/components/SEOPerformance.tsx +21 -21
  209. package/src/components/SchedulePublishDialog.tsx +241 -0
  210. package/src/components/SharePreviewLinkDialog.tsx +227 -0
  211. package/src/components/TipTapEditor.tsx +33 -33
  212. package/src/components/VersionHistory.tsx +16 -16
  213. package/src/components/ui/Badge.tsx +66 -14
  214. package/src/components/ui/Button.tsx +70 -33
  215. package/src/components/ui/Card.tsx +101 -0
  216. package/src/components/ui/DataTable.tsx +1 -1
  217. package/src/components/ui/Input.tsx +35 -0
  218. package/src/components/ui/SearchInput.tsx +4 -4
  219. package/src/components/ui/Select.tsx +56 -0
  220. package/src/components/ui/Toast.tsx +1 -1
  221. package/src/components/ui/index.ts +18 -4
  222. package/src/fields/BlockBuilderField.tsx +3 -3
  223. package/src/fields/DateField.tsx +1 -1
  224. package/src/fields/RelationshipField.tsx +10 -10
  225. package/src/fields/TextField.tsx +1 -1
  226. package/src/index.ts +32 -0
  227. package/src/layout/Header.tsx +28 -28
  228. package/src/layout/Layout.tsx +39 -46
  229. package/src/layout/Sidebar.tsx +37 -64
  230. package/src/layout/primitives/AdminShell.tsx +118 -0
  231. package/src/layout/primitives/Box.tsx +30 -0
  232. package/src/layout/primitives/Cluster.tsx +74 -0
  233. package/src/layout/primitives/Grid.tsx +120 -0
  234. package/src/layout/primitives/PageContainer.tsx +96 -0
  235. package/src/layout/primitives/Split.tsx +73 -0
  236. package/src/layout/primitives/Stack.tsx +67 -0
  237. package/src/layout/primitives/index.ts +36 -0
  238. package/src/layout/primitives/tokens.ts +76 -0
  239. package/src/lib/cv.ts +96 -0
  240. package/src/styles/build-input.css +1 -1
  241. package/src/views/ApiKeys.tsx +57 -57
  242. package/src/views/CollectionList.tsx +30 -30
  243. package/src/views/Dashboard.tsx +737 -186
  244. package/src/views/DocumentEdit.tsx +90 -10
  245. package/src/views/ForgotPassword.tsx +18 -18
  246. package/src/views/FormEditor.tsx +75 -75
  247. package/src/views/FormSubmissions.tsx +76 -76
  248. package/src/views/Forms.tsx +27 -27
  249. package/src/views/Login.tsx +65 -25
  250. package/src/views/MediaBrowser.tsx +127 -127
  251. package/src/views/PageEditor.tsx +25 -25
  252. package/src/views/Pages.tsx +59 -59
  253. package/src/views/PostEditor.tsx +37 -37
  254. package/src/views/Posts.tsx +48 -48
  255. package/src/views/Redirects.tsx +21 -21
  256. package/src/views/ResetPassword.tsx +28 -28
  257. package/src/views/SEO.tsx +144 -144
  258. package/src/views/ScriptTagEditor.tsx +24 -24
  259. package/src/views/ScriptTags.tsx +10 -10
  260. package/src/views/Settings.tsx +88 -80
  261. package/src/views/SetupWizard.tsx +28 -28
  262. package/src/views/Users.tsx +20 -20
  263. package/src/views/page-builder/AIBlockAssist.tsx +1 -1
  264. package/src/views/page-builder/AIGenerateDialog.tsx +63 -63
  265. package/src/views/page-builder/BlockEditor.tsx +26 -26
  266. package/src/views/page-builder/BlockPicker.tsx +22 -22
  267. package/src/views/page-builder/BottomBar.tsx +8 -8
  268. package/src/views/page-builder/BuilderToolbar.tsx +17 -17
  269. package/src/views/page-builder/ContextPanel.tsx +3 -3
  270. package/src/views/page-builder/DesignScore.tsx +21 -21
  271. package/src/views/page-builder/NodeSettings.tsx +27 -27
  272. package/src/views/page-builder/PageBuilder.tsx +11 -11
  273. package/src/views/page-builder/PageSettings.tsx +4 -4
  274. package/src/views/page-builder/PageTemplates.tsx +18 -18
  275. package/src/views/page-builder/SEOPanel.tsx +53 -53
  276. package/src/views/page-builder/SavedSections.tsx +37 -37
  277. package/src/views/page-builder/TemplatePicker.tsx +17 -17
  278. package/src/views/page-builder/block-renderers/CTAPreview.tsx +13 -13
  279. package/src/views/page-builder/block-renderers/CardsPreview.tsx +5 -5
  280. package/src/views/page-builder/block-renderers/CodePreview.tsx +6 -6
  281. package/src/views/page-builder/block-renderers/FAQPreview.tsx +13 -13
  282. package/src/views/page-builder/block-renderers/FallbackPreview.tsx +3 -3
  283. package/src/views/page-builder/block-renderers/FormPreview.tsx +20 -20
  284. package/src/views/page-builder/block-renderers/GalleryPreview.tsx +8 -8
  285. package/src/views/page-builder/block-renderers/HeroPreview.tsx +16 -16
  286. package/src/views/page-builder/block-renderers/ImagePreview.tsx +4 -4
  287. package/src/views/page-builder/block-renderers/TextPreview.tsx +14 -14
  288. package/src/views/page-builder/block-renderers/VideoPreview.tsx +12 -12
  289. package/src/views/page-builder/canvas/BlockRenderer.tsx +4 -4
  290. package/src/views/page-builder/canvas/BuilderCanvas.tsx +6 -6
  291. package/src/views/page-builder/canvas/ColumnRenderer.tsx +3 -3
  292. package/src/views/page-builder/canvas/ContainerRenderer.tsx +2 -2
  293. package/src/views/page-builder/canvas/RowRenderer.tsx +2 -2
  294. package/src/views/page-builder/canvas/SectionRenderer.tsx +2 -2
package/src/views/SEO.tsx CHANGED
@@ -193,9 +193,9 @@ export function SEO({ onNavigate, initialTab = 'pages' }: SEOProps) {
193
193
  return 'bg-red-100 text-red-800'
194
194
  }
195
195
  function scoreIcon(score: number) {
196
- if (score >= 80) return <CheckCircle2 className="w-4 h-4 text-green-600" />
197
- if (score >= 50) return <AlertTriangle className="w-4 h-4 text-yellow-600" />
198
- return <XCircle className="w-4 h-4 text-red-600" />
196
+ if (score >= 80) return <CheckCircle2 className="h-4 w-4 text-green-600" />
197
+ if (score >= 50) return <AlertTriangle className="h-4 w-4 text-yellow-600" />
198
+ return <XCircle className="h-4 w-4 text-red-600" />
199
199
  }
200
200
 
201
201
  const tabClass =
@@ -205,33 +205,33 @@ export function SEO({ onNavigate, initialTab = 'pages' }: SEOProps) {
205
205
 
206
206
  if (isLoading) {
207
207
  return (
208
- <div className="p-3 pr-6 sm:p-4 sm:pr-8 flex items-center justify-center h-64">
209
- <Loader2 className="w-6 h-6 animate-spin text-blue-600" />
208
+ <div className="flex h-64 items-center justify-center p-3 pr-6 sm:p-4 sm:pr-8">
209
+ <Loader2 className="h-6 w-6 animate-spin text-blue-600" />
210
210
  </div>
211
211
  )
212
212
  }
213
213
 
214
214
  return (
215
- <div className="p-3 pr-6 sm:p-4 sm:pr-8 h-full flex flex-col">
215
+ <div className="flex h-full flex-col p-3 pr-6 sm:p-4 sm:pr-8">
216
216
  {(seoError || redirectsError) && (
217
217
  <div className="mb-4 flex items-center gap-3 rounded-lg border border-red-200 bg-red-50 p-3">
218
- <AlertTriangle className="w-5 h-5 text-red-600 shrink-0" />
219
- <span className="text-sm text-red-800 flex-1">{seoError || redirectsError}</span>
218
+ <AlertTriangle className="h-5 w-5 shrink-0 text-red-600" />
219
+ <span className="flex-1 text-sm text-red-800">{seoError || redirectsError}</span>
220
220
  <button
221
221
  onClick={() => {
222
222
  seoRefetch()
223
223
  redirectsRefetch()
224
224
  }}
225
- className="px-3 py-1 text-sm text-red-700 border border-red-300 rounded-lg hover:bg-red-100 transition-colors"
225
+ className="rounded-lg border border-red-300 px-3 py-1 text-sm text-red-700 transition-colors hover:bg-red-100"
226
226
  >
227
227
  Retry
228
228
  </button>
229
229
  </div>
230
230
  )}
231
231
 
232
- <div className="flex flex-col sm:flex-row sm:items-center justify-between mb-4 gap-3">
232
+ <div className="mb-4 flex flex-col justify-between gap-3 sm:flex-row sm:items-center">
233
233
  <div>
234
- <h1 className="text-xl sm:text-2xl font-semibold text-gray-900 mb-1">SEO & Redirects</h1>
234
+ <h1 className="mb-1 text-xl font-semibold text-gray-900 sm:text-2xl">SEO & Redirects</h1>
235
235
  <p className="text-sm text-gray-600">
236
236
  Search optimization, redirects, canonicalization, and link health
237
237
  </p>
@@ -239,103 +239,103 @@ export function SEO({ onNavigate, initialTab = 'pages' }: SEOProps) {
239
239
  <button
240
240
  onClick={handleScan}
241
241
  disabled={scanning}
242
- className="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 disabled:opacity-60"
242
+ className="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 disabled:opacity-60"
243
243
  >
244
- <RefreshCw className={`w-4 h-4 ${scanning ? 'animate-spin' : ''}`} />
244
+ <RefreshCw className={`h-4 w-4 ${scanning ? 'animate-spin' : ''}`} />
245
245
  {scanning ? 'Scanning...' : 'Run SEO Scan'}
246
246
  </button>
247
247
  </div>
248
248
 
249
249
  <Tabs.Root value={activeTab} onValueChange={handleTabChange}>
250
- <Tabs.List className="mb-4 flex gap-1 border-b border-gray-200 overflow-x-auto">
250
+ <Tabs.List className="mb-4 flex gap-1 overflow-x-auto border-b border-gray-200">
251
251
  <Tabs.Trigger value="pages" className={tabClass}>
252
252
  <span className="flex items-center gap-1.5">
253
- <BarChart3 className="w-4 h-4" />
253
+ <BarChart3 className="h-4 w-4" />
254
254
  Pages
255
255
  </span>
256
256
  </Tabs.Trigger>
257
257
  <Tabs.Trigger value="redirects" className={tabClass}>
258
258
  <span className="flex items-center gap-1.5">
259
- <ArrowRightLeft className="w-4 h-4" />
259
+ <ArrowRightLeft className="h-4 w-4" />
260
260
  Redirects
261
261
  </span>
262
262
  </Tabs.Trigger>
263
263
  <Tabs.Trigger value="canonicals" className={tabClass}>
264
264
  <span className="flex items-center gap-1.5">
265
- <Copy className="w-4 h-4" />
265
+ <Copy className="h-4 w-4" />
266
266
  Canonicalization
267
267
  </span>
268
268
  </Tabs.Trigger>
269
269
  <Tabs.Trigger value="links" className={tabClass}>
270
270
  <span className="flex items-center gap-1.5">
271
- <Link2 className="w-4 h-4" />
271
+ <Link2 className="h-4 w-4" />
272
272
  Link Health
273
273
  </span>
274
274
  </Tabs.Trigger>
275
275
  </Tabs.List>
276
276
 
277
277
  {/* PAGES TAB */}
278
- <Tabs.Content value="pages" className="flex flex-col flex-1 min-h-0">
279
- <div className="grid grid-cols-2 lg:grid-cols-4 gap-3 mb-4">
280
- <div className="bg-white rounded-lg border border-gray-200 p-4">
281
- <div className="flex items-center gap-2 mb-2">
282
- <BarChart3 className="w-4 h-4 text-blue-600" />
278
+ <Tabs.Content value="pages" className="flex min-h-0 flex-1 flex-col">
279
+ <div className="mb-4 grid grid-cols-2 gap-3 lg:grid-cols-4">
280
+ <div className="rounded-lg border border-gray-200 bg-white p-4">
281
+ <div className="mb-2 flex items-center gap-2">
282
+ <BarChart3 className="h-4 w-4 text-blue-600" />
283
283
  <span className="text-xs font-medium text-gray-600">Avg SEO Score</span>
284
284
  </div>
285
285
  <div className="text-2xl font-semibold text-gray-900">{avgScore}</div>
286
286
  <div
287
- className={`text-xs mt-1 ${avgScore >= 80 ? 'text-green-600' : avgScore >= 50 ? 'text-yellow-600' : 'text-red-600'}`}
287
+ className={`mt-1 text-xs ${avgScore >= 80 ? 'text-green-600' : avgScore >= 50 ? 'text-yellow-600' : 'text-red-600'}`}
288
288
  >
289
289
  {avgScore >= 80 ? 'Good' : avgScore >= 50 ? 'Needs improvement' : 'Critical'}
290
290
  </div>
291
291
  </div>
292
- <div className="bg-white rounded-lg border border-gray-200 p-4">
293
- <div className="flex items-center gap-2 mb-2">
294
- <AlertTriangle className="w-4 h-4 text-yellow-600" />
292
+ <div className="rounded-lg border border-gray-200 bg-white p-4">
293
+ <div className="mb-2 flex items-center gap-2">
294
+ <AlertTriangle className="h-4 w-4 text-yellow-600" />
295
295
  <span className="text-xs font-medium text-gray-600">Total Issues</span>
296
296
  </div>
297
297
  <div className="text-2xl font-semibold text-gray-900">{totalIssues}</div>
298
- <div className="text-xs text-gray-500 mt-1">
298
+ <div className="mt-1 text-xs text-gray-500">
299
299
  Across {seoPages.filter((p: any) => p.issues > 0).length} pages
300
300
  </div>
301
301
  </div>
302
- <div className="bg-white rounded-lg border border-gray-200 p-4">
303
- <div className="flex items-center gap-2 mb-2">
304
- <FileCode2 className="w-4 h-4 text-purple-600" />
302
+ <div className="rounded-lg border border-gray-200 bg-white p-4">
303
+ <div className="mb-2 flex items-center gap-2">
304
+ <FileCode2 className="h-4 w-4 text-purple-600" />
305
305
  <span className="text-xs font-medium text-gray-600">Missing Meta</span>
306
306
  </div>
307
307
  <div className="text-2xl font-semibold text-gray-900">{missingMeta}</div>
308
- <div className="text-xs text-gray-500 mt-1">Title or description</div>
308
+ <div className="mt-1 text-xs text-gray-500">Title or description</div>
309
309
  </div>
310
- <div className="bg-white rounded-lg border border-gray-200 p-4">
311
- <div className="flex items-center gap-2 mb-2">
312
- <Globe className="w-4 h-4 text-green-600" />
310
+ <div className="rounded-lg border border-gray-200 bg-white p-4">
311
+ <div className="mb-2 flex items-center gap-2">
312
+ <Globe className="h-4 w-4 text-green-600" />
313
313
  <span className="text-xs font-medium text-gray-600">Missing Schema</span>
314
314
  </div>
315
315
  <div className="text-2xl font-semibold text-gray-900">{missingSchema}</div>
316
- <div className="text-xs text-gray-500 mt-1">No Schema.org markup</div>
316
+ <div className="mt-1 text-xs text-gray-500">No Schema.org markup</div>
317
317
  </div>
318
318
  </div>
319
319
 
320
- <div className="bg-linear-to-r from-indigo-50 to-purple-50 border border-indigo-200 rounded-lg p-4 mb-4">
320
+ <div className="mb-4 rounded-lg border border-indigo-200 bg-linear-to-r from-indigo-50 to-purple-50 p-4">
321
321
  <div className="flex items-start gap-3">
322
- <Bot className="w-5 h-5 text-indigo-600 mt-0.5 shrink-0" />
322
+ <Bot className="mt-0.5 h-5 w-5 shrink-0 text-indigo-600" />
323
323
  <div className="flex-1">
324
- <h3 className="text-sm font-semibold text-indigo-900 mb-1">
324
+ <h3 className="mb-1 text-sm font-semibold text-indigo-900">
325
325
  AI SEO Recommendations
326
326
  </h3>
327
- <p className="text-sm text-indigo-700 mb-2">
327
+ <p className="mb-2 text-sm text-indigo-700">
328
328
  {missingMeta} pages missing meta descriptions. {missingCanonical.length} pages
329
329
  without canonical URLs. AI can auto-generate these from page content.
330
330
  </p>
331
331
  <div className="flex items-center gap-2">
332
332
  <button
333
333
  onClick={() => onNavigate?.('/settings')}
334
- className="px-3 py-1.5 text-xs bg-indigo-600 text-white rounded-lg hover:bg-indigo-700 transition-colors"
334
+ className="rounded-lg bg-indigo-600 px-3 py-1.5 text-xs text-white transition-colors hover:bg-indigo-700"
335
335
  >
336
336
  Configure AI
337
337
  </button>
338
- <button className="px-3 py-1.5 text-xs border border-indigo-300 text-indigo-700 rounded-lg hover:bg-indigo-50 transition-colors">
338
+ <button className="rounded-lg border border-indigo-300 px-3 py-1.5 text-xs text-indigo-700 transition-colors hover:bg-indigo-50">
339
339
  Auto-fix All
340
340
  </button>
341
341
  </div>
@@ -343,22 +343,22 @@ export function SEO({ onNavigate, initialTab = 'pages' }: SEOProps) {
343
343
  </div>
344
344
  </div>
345
345
 
346
- <div className="bg-white rounded-lg border border-gray-200 mb-4">
347
- <div className="p-3 flex flex-col sm:flex-row gap-3">
346
+ <div className="mb-4 rounded-lg border border-gray-200 bg-white">
347
+ <div className="flex flex-col gap-3 p-3 sm:flex-row">
348
348
  <div className="relative flex-1">
349
- <Search className="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-gray-400" />
349
+ <Search className="absolute top-1/2 left-3 h-4 w-4 -translate-y-1/2 text-gray-400" />
350
350
  <input
351
351
  type="text"
352
352
  placeholder="Search pages by URL or title..."
353
353
  value={searchQuery}
354
354
  onChange={(e) => setSearchQuery(e.target.value)}
355
- 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"
355
+ 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"
356
356
  />
357
357
  </div>
358
358
  <select
359
359
  value={filterScore}
360
360
  onChange={(e) => setFilterScore(e.target.value)}
361
- className="px-3 py-2 text-sm border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
361
+ className="rounded-lg border border-gray-300 px-3 py-2 text-sm focus:ring-2 focus:ring-blue-500 focus:outline-none"
362
362
  >
363
363
  <option value="all">All Scores</option>
364
364
  <option value="good">Good (80+)</option>
@@ -368,10 +368,10 @@ export function SEO({ onNavigate, initialTab = 'pages' }: SEOProps) {
368
368
  </div>
369
369
  </div>
370
370
 
371
- <div className="bg-white rounded-lg border border-gray-200 flex-1 overflow-hidden">
372
- <div className="overflow-x-auto h-full">
371
+ <div className="flex-1 overflow-hidden rounded-lg border border-gray-200 bg-white">
372
+ <div className="h-full overflow-x-auto">
373
373
  <table className="w-full">
374
- <thead className="bg-gray-50 border-b border-gray-200 sticky top-0">
374
+ <thead className="sticky top-0 border-b border-gray-200 bg-gray-50">
375
375
  <tr>
376
376
  <th className="px-4 py-2 text-left text-xs font-medium text-gray-700">Page</th>
377
377
  <th className="px-4 py-2 text-left text-xs font-medium text-gray-700">Score</th>
@@ -392,7 +392,7 @@ export function SEO({ onNavigate, initialTab = 'pages' }: SEOProps) {
392
392
  </thead>
393
393
  <tbody className="divide-y divide-gray-200">
394
394
  {filtered.map((page: any) => (
395
- <tr key={page.id} className="hover:bg-gray-50 transition-colors">
395
+ <tr key={page.id} className="transition-colors hover:bg-gray-50">
396
396
  <td className="px-4 py-3">
397
397
  <div className="text-sm font-medium text-gray-900">{page.title}</div>
398
398
  <div className="text-xs text-gray-500">{page.url}</div>
@@ -401,7 +401,7 @@ export function SEO({ onNavigate, initialTab = 'pages' }: SEOProps) {
401
401
  <div className="flex items-center gap-2">
402
402
  {scoreIcon(page.score)}
403
403
  <span
404
- className={`px-2 py-0.5 rounded-full text-xs font-medium ${scoreBadge(page.score)}`}
404
+ className={`rounded-full px-2 py-0.5 text-xs font-medium ${scoreBadge(page.score)}`}
405
405
  >
406
406
  {page.score}
407
407
  </span>
@@ -410,7 +410,7 @@ export function SEO({ onNavigate, initialTab = 'pages' }: SEOProps) {
410
410
  <td className="px-4 py-3">
411
411
  {page.readability > 0 ? (
412
412
  <div className="flex items-center gap-2">
413
- <BookOpen className="w-3.5 h-3.5 text-gray-400" />
413
+ <BookOpen className="h-3.5 w-3.5 text-gray-400" />
414
414
  <span
415
415
  className={`text-sm ${page.readability >= 80 ? 'text-green-700' : page.readability >= 60 ? 'text-yellow-700' : 'text-red-700'}`}
416
416
  >
@@ -423,11 +423,11 @@ export function SEO({ onNavigate, initialTab = 'pages' }: SEOProps) {
423
423
  </td>
424
424
  <td className="px-4 py-3">
425
425
  {page.schemaType ? (
426
- <span className="px-2 py-0.5 rounded-full text-xs font-medium bg-purple-100 text-purple-800">
426
+ <span className="rounded-full bg-purple-100 px-2 py-0.5 text-xs font-medium text-purple-800">
427
427
  {page.schemaType}
428
428
  </span>
429
429
  ) : (
430
- <span className="px-2 py-0.5 rounded-full text-xs font-medium bg-red-100 text-red-800">
430
+ <span className="rounded-full bg-red-100 px-2 py-0.5 text-xs font-medium text-red-800">
431
431
  Missing
432
432
  </span>
433
433
  )}
@@ -448,11 +448,11 @@ export function SEO({ onNavigate, initialTab = 'pages' }: SEOProps) {
448
448
  </td>
449
449
  <td className="px-4 py-3">
450
450
  {page.issues > 0 ? (
451
- <span className="px-2 py-0.5 rounded-full text-xs font-medium bg-yellow-100 text-yellow-800">
451
+ <span className="rounded-full bg-yellow-100 px-2 py-0.5 text-xs font-medium text-yellow-800">
452
452
  {page.issues}
453
453
  </span>
454
454
  ) : (
455
- <span className="px-2 py-0.5 rounded-full text-xs font-medium bg-green-100 text-green-800">
455
+ <span className="rounded-full bg-green-100 px-2 py-0.5 text-xs font-medium text-green-800">
456
456
 
457
457
  </span>
458
458
  )}
@@ -461,16 +461,16 @@ export function SEO({ onNavigate, initialTab = 'pages' }: SEOProps) {
461
461
  <div className="flex items-center gap-1">
462
462
  <button
463
463
  onClick={() => onNavigate?.(`/pages/${page.id}`)}
464
- className="p-1.5 hover:bg-gray-100 rounded transition-colors"
464
+ className="rounded p-1.5 transition-colors hover:bg-gray-100"
465
465
  title="Edit"
466
466
  >
467
- <ArrowUpRight className="w-4 h-4 text-gray-600" />
467
+ <ArrowUpRight className="h-4 w-4 text-gray-600" />
468
468
  </button>
469
469
  <button
470
- className="p-1.5 hover:bg-gray-100 rounded transition-colors"
470
+ className="rounded p-1.5 transition-colors hover:bg-gray-100"
471
471
  title="AI analyze"
472
472
  >
473
- <Bot className="w-4 h-4 text-indigo-600" />
473
+ <Bot className="h-4 w-4 text-indigo-600" />
474
474
  </button>
475
475
  </div>
476
476
  </td>
@@ -483,56 +483,56 @@ export function SEO({ onNavigate, initialTab = 'pages' }: SEOProps) {
483
483
  </Tabs.Content>
484
484
 
485
485
  {/* REDIRECTS TAB */}
486
- <Tabs.Content value="redirects" className="flex flex-col flex-1 min-h-0">
487
- <div className="grid grid-cols-2 lg:grid-cols-4 gap-3 mb-4">
488
- <div className="bg-white rounded-lg border border-gray-200 p-4">
489
- <div className="text-xs text-gray-600 mb-1">Total Redirects</div>
486
+ <Tabs.Content value="redirects" className="flex min-h-0 flex-1 flex-col">
487
+ <div className="mb-4 grid grid-cols-2 gap-3 lg:grid-cols-4">
488
+ <div className="rounded-lg border border-gray-200 bg-white p-4">
489
+ <div className="mb-1 text-xs text-gray-600">Total Redirects</div>
490
490
  <div className="text-2xl font-semibold text-gray-900">{redirects.length}</div>
491
491
  </div>
492
- <div className="bg-white rounded-lg border border-gray-200 p-4">
493
- <div className="text-xs text-gray-600 mb-1">Active</div>
492
+ <div className="rounded-lg border border-gray-200 bg-white p-4">
493
+ <div className="mb-1 text-xs text-gray-600">Active</div>
494
494
  <div className="text-2xl font-semibold text-green-600">
495
495
  {redirects.filter((r: any) => r.active).length}
496
496
  </div>
497
497
  </div>
498
- <div className="bg-white rounded-lg border border-gray-200 p-4">
499
- <div className="text-xs text-gray-600 mb-1">Total Hits</div>
498
+ <div className="rounded-lg border border-gray-200 bg-white p-4">
499
+ <div className="mb-1 text-xs text-gray-600">Total Hits</div>
500
500
  <div className="text-2xl font-semibold text-blue-600">
501
501
  {redirects.reduce((s: number, r: any) => s + r.hits, 0).toLocaleString()}
502
502
  </div>
503
503
  </div>
504
- <div className="bg-white rounded-lg border border-gray-200 p-4">
505
- <div className="text-xs text-gray-600 mb-1">301 Permanent</div>
504
+ <div className="rounded-lg border border-gray-200 bg-white p-4">
505
+ <div className="mb-1 text-xs text-gray-600">301 Permanent</div>
506
506
  <div className="text-2xl font-semibold text-gray-900">
507
507
  {redirects.filter((r: any) => r.type === '301').length}
508
508
  </div>
509
509
  </div>
510
510
  </div>
511
511
 
512
- <div className="flex items-center gap-3 mb-4">
513
- <div className="relative flex-1 max-w-md">
514
- <Search className="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-gray-400" />
512
+ <div className="mb-4 flex items-center gap-3">
513
+ <div className="relative max-w-md flex-1">
514
+ <Search className="absolute top-1/2 left-3 h-4 w-4 -translate-y-1/2 text-gray-400" />
515
515
  <input
516
516
  type="text"
517
517
  placeholder="Search redirects..."
518
518
  value={redirectSearch}
519
519
  onChange={(e) => setRedirectSearch(e.target.value)}
520
- className="w-full pl-9 pr-3 py-2 text-sm border border-gray-300 rounded-lg bg-white focus:outline-none focus:ring-2 focus:ring-blue-500"
520
+ className="w-full rounded-lg border border-gray-300 bg-white py-2 pr-3 pl-9 text-sm focus:ring-2 focus:ring-blue-500 focus:outline-none"
521
521
  />
522
522
  </div>
523
523
  <button
524
524
  onClick={() => setShowAddRedirect(true)}
525
- 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 shrink-0"
525
+ className="flex shrink-0 items-center gap-2 rounded-lg bg-blue-600 px-4 py-2 text-sm text-white transition-colors hover:bg-blue-700"
526
526
  >
527
- <Plus className="w-4 h-4" />
527
+ <Plus className="h-4 w-4" />
528
528
  Add Redirect
529
529
  </button>
530
530
  </div>
531
531
 
532
- <div className="bg-white rounded-lg border border-gray-200 flex-1 overflow-hidden">
533
- <div className="overflow-x-auto h-full">
532
+ <div className="flex-1 overflow-hidden rounded-lg border border-gray-200 bg-white">
533
+ <div className="h-full overflow-x-auto">
534
534
  <table className="w-full">
535
- <thead className="bg-gray-50 border-b border-gray-200 sticky top-0">
535
+ <thead className="sticky top-0 border-b border-gray-200 bg-gray-50">
536
536
  <tr>
537
537
  <th className="px-4 py-2 text-left text-xs font-medium text-gray-700">
538
538
  Source
@@ -552,7 +552,7 @@ export function SEO({ onNavigate, initialTab = 'pages' }: SEOProps) {
552
552
  </thead>
553
553
  <tbody className="divide-y divide-gray-200">
554
554
  {filteredRedirects.map((r: any) => (
555
- <tr key={r.id} className="hover:bg-gray-50 transition-colors">
555
+ <tr key={r.id} className="transition-colors hover:bg-gray-50">
556
556
  <td className="px-4 py-3">
557
557
  <code className="rounded bg-gray-100 px-2 py-1 text-xs text-gray-900">
558
558
  {r.from}
@@ -565,7 +565,7 @@ export function SEO({ onNavigate, initialTab = 'pages' }: SEOProps) {
565
565
  </td>
566
566
  <td className="px-4 py-3">
567
567
  <span
568
- className={`px-2 py-0.5 rounded-full text-xs font-medium ${r.type === '301' ? 'bg-blue-100 text-blue-800' : 'bg-purple-100 text-purple-800'}`}
568
+ className={`rounded-full px-2 py-0.5 text-xs font-medium ${r.type === '301' ? 'bg-blue-100 text-blue-800' : 'bg-purple-100 text-purple-800'}`}
569
569
  >
570
570
  {r.type}
571
571
  </span>
@@ -573,21 +573,21 @@ export function SEO({ onNavigate, initialTab = 'pages' }: SEOProps) {
573
573
  <td className="px-4 py-3 text-sm text-gray-600">{r.hits.toLocaleString()}</td>
574
574
  <td className="px-4 py-3">
575
575
  <span
576
- className={`px-2 py-0.5 rounded-full text-xs font-medium ${r.active ? 'bg-green-100 text-green-800' : 'bg-gray-100 text-gray-800'}`}
576
+ className={`rounded-full px-2 py-0.5 text-xs font-medium ${r.active ? 'bg-green-100 text-green-800' : 'bg-gray-100 text-gray-800'}`}
577
577
  >
578
578
  {r.active ? 'Active' : 'Inactive'}
579
579
  </span>
580
580
  </td>
581
581
  <td className="px-4 py-3">
582
582
  <div className="flex items-center gap-2">
583
- <button className="p-1.5 hover:bg-gray-100 rounded transition-colors">
584
- <Pencil className="w-4 h-4 text-gray-600" />
583
+ <button className="rounded p-1.5 transition-colors hover:bg-gray-100">
584
+ <Pencil className="h-4 w-4 text-gray-600" />
585
585
  </button>
586
586
  <button
587
587
  onClick={() => handleDeleteRedirect(r.id)}
588
- className="p-1.5 hover:bg-gray-100 rounded transition-colors"
588
+ className="rounded p-1.5 transition-colors hover:bg-gray-100"
589
589
  >
590
- <Trash2 className="w-4 h-4 text-red-600" />
590
+ <Trash2 className="h-4 w-4 text-red-600" />
591
591
  </button>
592
592
  </div>
593
593
  </td>
@@ -601,7 +601,7 @@ export function SEO({ onNavigate, initialTab = 'pages' }: SEOProps) {
601
601
  <Dialog.Root open={showAddRedirect} onOpenChange={setShowAddRedirect}>
602
602
  <Dialog.Portal>
603
603
  <Dialog.Overlay className="fixed inset-0 z-50 bg-black/50" />
604
- <Dialog.Content className="fixed left-1/2 top-1/2 z-50 w-full max-w-md -translate-x-1/2 -translate-y-1/2 rounded-lg bg-white p-6 shadow-lg">
604
+ <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-lg">
605
605
  <Dialog.Title className="mb-4 text-lg font-semibold text-gray-900">
606
606
  Add Redirect
607
607
  </Dialog.Title>
@@ -615,7 +615,7 @@ export function SEO({ onNavigate, initialTab = 'pages' }: SEOProps) {
615
615
  value={newRedirect.source}
616
616
  onChange={(e) => setNewRedirect({ ...newRedirect, source: e.target.value })}
617
617
  placeholder="/old-page"
618
- className="w-full rounded-lg border border-gray-300 px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500"
618
+ 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"
619
619
  required
620
620
  />
621
621
  </div>
@@ -630,7 +630,7 @@ export function SEO({ onNavigate, initialTab = 'pages' }: SEOProps) {
630
630
  setNewRedirect({ ...newRedirect, destination: e.target.value })
631
631
  }
632
632
  placeholder="/new-page"
633
- className="w-full rounded-lg border border-gray-300 px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500"
633
+ 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"
634
634
  required
635
635
  />
636
636
  </div>
@@ -641,7 +641,7 @@ export function SEO({ onNavigate, initialTab = 'pages' }: SEOProps) {
641
641
  onChange={(e) =>
642
642
  setNewRedirect({ ...newRedirect, type: e.target.value as '301' | '302' })
643
643
  }
644
- className="w-full rounded-lg border border-gray-300 px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500"
644
+ 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"
645
645
  >
646
646
  <option value="301">301 (Permanent)</option>
647
647
  <option value="302">302 (Temporary)</option>
@@ -670,49 +670,49 @@ export function SEO({ onNavigate, initialTab = 'pages' }: SEOProps) {
670
670
  </Tabs.Content>
671
671
 
672
672
  {/* CANONICALIZATION TAB */}
673
- <Tabs.Content value="canonicals" className="flex flex-col flex-1 min-h-0 space-y-4">
674
- <div className="grid grid-cols-2 lg:grid-cols-4 gap-3">
675
- <div className="bg-white rounded-lg border border-gray-200 p-4">
676
- <div className="flex items-center gap-2 mb-2">
677
- <ShieldCheck className="w-4 h-4 text-green-600" />
673
+ <Tabs.Content value="canonicals" className="flex min-h-0 flex-1 flex-col space-y-4">
674
+ <div className="grid grid-cols-2 gap-3 lg:grid-cols-4">
675
+ <div className="rounded-lg border border-gray-200 bg-white p-4">
676
+ <div className="mb-2 flex items-center gap-2">
677
+ <ShieldCheck className="h-4 w-4 text-green-600" />
678
678
  <span className="text-xs font-medium text-gray-600">With Canonical</span>
679
679
  </div>
680
680
  <div className="text-2xl font-semibold text-green-700">{allCanonicals.length}</div>
681
681
  </div>
682
- <div className="bg-white rounded-lg border border-gray-200 p-4">
683
- <div className="flex items-center gap-2 mb-2">
684
- <AlertTriangle className="w-4 h-4 text-red-600" />
682
+ <div className="rounded-lg border border-gray-200 bg-white p-4">
683
+ <div className="mb-2 flex items-center gap-2">
684
+ <AlertTriangle className="h-4 w-4 text-red-600" />
685
685
  <span className="text-xs font-medium text-gray-600">Missing Canonical</span>
686
686
  </div>
687
687
  <div className="text-2xl font-semibold text-red-700">{missingCanonical.length}</div>
688
688
  </div>
689
- <div className="bg-white rounded-lg border border-gray-200 p-4">
690
- <div className="flex items-center gap-2 mb-2">
691
- <Globe className="w-4 h-4 text-blue-600" />
689
+ <div className="rounded-lg border border-gray-200 bg-white p-4">
690
+ <div className="mb-2 flex items-center gap-2">
691
+ <Globe className="h-4 w-4 text-blue-600" />
692
692
  <span className="text-xs font-medium text-gray-600">Canonical Domains</span>
693
693
  </div>
694
694
  <div className="text-2xl font-semibold text-gray-900">{canonicalDomains.length}</div>
695
695
  </div>
696
- <div className="bg-white rounded-lg border border-gray-200 p-4">
697
- <div className="flex items-center gap-2 mb-2">
698
- <CheckCircle2 className="w-4 h-4 text-green-600" />
696
+ <div className="rounded-lg border border-gray-200 bg-white p-4">
697
+ <div className="mb-2 flex items-center gap-2">
698
+ <CheckCircle2 className="h-4 w-4 text-green-600" />
699
699
  <span className="text-xs font-medium text-gray-600">Self-Referencing</span>
700
700
  </div>
701
701
  <div className="text-2xl font-semibold text-green-700">{allCanonicals.length}</div>
702
- <div className="text-xs text-gray-500 mt-1">Correct pattern</div>
702
+ <div className="mt-1 text-xs text-gray-500">Correct pattern</div>
703
703
  </div>
704
704
  </div>
705
705
 
706
706
  {missingCanonical.length > 0 && (
707
- <div className="bg-yellow-50 border border-yellow-200 rounded-lg p-4">
707
+ <div className="rounded-lg border border-yellow-200 bg-yellow-50 p-4">
708
708
  <div className="flex items-start gap-3">
709
- <AlertTriangle className="w-5 h-5 text-yellow-600 mt-0.5 shrink-0" />
709
+ <AlertTriangle className="mt-0.5 h-5 w-5 shrink-0 text-yellow-600" />
710
710
  <div className="flex-1">
711
- <h3 className="text-sm font-semibold text-yellow-900 mb-1">
711
+ <h3 className="mb-1 text-sm font-semibold text-yellow-900">
712
712
  {missingCanonical.length} page{missingCanonical.length !== 1 ? 's' : ''} missing
713
713
  canonical URLs
714
714
  </h3>
715
- <p className="text-sm text-yellow-700 mb-2">
715
+ <p className="mb-2 text-sm text-yellow-700">
716
716
  Without canonical tags, search engines may index duplicate versions of these
717
717
  pages, diluting your ranking signals.
718
718
  </p>
@@ -721,7 +721,7 @@ export function SEO({ onNavigate, initialTab = 'pages' }: SEOProps) {
721
721
  <button
722
722
  key={p.id}
723
723
  onClick={() => onNavigate?.(`/pages/${p.id}`)}
724
- className="px-2.5 py-1 text-xs bg-yellow-100 text-yellow-900 rounded-lg hover:bg-yellow-200 transition-colors"
724
+ className="rounded-lg bg-yellow-100 px-2.5 py-1 text-xs text-yellow-900 transition-colors hover:bg-yellow-200"
725
725
  >
726
726
  {p.title} ({p.url})
727
727
  </button>
@@ -732,10 +732,10 @@ export function SEO({ onNavigate, initialTab = 'pages' }: SEOProps) {
732
732
  </div>
733
733
  )}
734
734
 
735
- <div className="bg-white rounded-lg border border-gray-200 flex-1 overflow-hidden">
736
- <div className="overflow-x-auto h-full">
735
+ <div className="flex-1 overflow-hidden rounded-lg border border-gray-200 bg-white">
736
+ <div className="h-full overflow-x-auto">
737
737
  <table className="w-full">
738
- <thead className="bg-gray-50 border-b border-gray-200 sticky top-0">
738
+ <thead className="sticky top-0 border-b border-gray-200 bg-gray-50">
739
739
  <tr>
740
740
  <th className="px-4 py-2 text-left text-xs font-medium text-gray-700">Page</th>
741
741
  <th className="px-4 py-2 text-left text-xs font-medium text-gray-700">URL</th>
@@ -752,29 +752,29 @@ export function SEO({ onNavigate, initialTab = 'pages' }: SEOProps) {
752
752
  </thead>
753
753
  <tbody className="divide-y divide-gray-200">
754
754
  {seoPages.map((page: any) => (
755
- <tr key={page.id} className="hover:bg-gray-50 transition-colors">
755
+ <tr key={page.id} className="transition-colors hover:bg-gray-50">
756
756
  <td className="px-4 py-3 text-sm font-medium text-gray-900">{page.title}</td>
757
757
  <td className="px-4 py-3">
758
- <code className="text-xs bg-gray-100 px-2 py-1 rounded text-gray-700">
758
+ <code className="rounded bg-gray-100 px-2 py-1 text-xs text-gray-700">
759
759
  {page.url}
760
760
  </code>
761
761
  </td>
762
762
  <td className="px-4 py-3">
763
763
  {page.canonical ? (
764
- <code className="text-xs bg-gray-100 px-2 py-1 rounded text-gray-700 truncate max-w-[200px] block">
764
+ <code className="block max-w-[200px] truncate rounded bg-gray-100 px-2 py-1 text-xs text-gray-700">
765
765
  {page.canonical}
766
766
  </code>
767
767
  ) : (
768
- <span className="text-xs text-red-600 font-medium">Not set</span>
768
+ <span className="text-xs font-medium text-red-600">Not set</span>
769
769
  )}
770
770
  </td>
771
771
  <td className="px-4 py-3">
772
772
  {page.canonical ? (
773
- <span className="px-2 py-0.5 rounded-full text-xs font-medium bg-green-100 text-green-800">
773
+ <span className="rounded-full bg-green-100 px-2 py-0.5 text-xs font-medium text-green-800">
774
774
  ✓ Set
775
775
  </span>
776
776
  ) : (
777
- <span className="px-2 py-0.5 rounded-full text-xs font-medium bg-red-100 text-red-800">
777
+ <span className="rounded-full bg-red-100 px-2 py-0.5 text-xs font-medium text-red-800">
778
778
  Missing
779
779
  </span>
780
780
  )}
@@ -782,10 +782,10 @@ export function SEO({ onNavigate, initialTab = 'pages' }: SEOProps) {
782
782
  <td className="px-4 py-3">
783
783
  <button
784
784
  onClick={() => onNavigate?.(`/pages/${page.id}`)}
785
- className="p-1.5 hover:bg-gray-100 rounded transition-colors"
785
+ className="rounded p-1.5 transition-colors hover:bg-gray-100"
786
786
  title="Edit"
787
787
  >
788
- <Pencil className="w-4 h-4 text-gray-600" />
788
+ <Pencil className="h-4 w-4 text-gray-600" />
789
789
  </button>
790
790
  </td>
791
791
  </tr>
@@ -797,38 +797,38 @@ export function SEO({ onNavigate, initialTab = 'pages' }: SEOProps) {
797
797
  </Tabs.Content>
798
798
 
799
799
  {/* LINK HEALTH TAB */}
800
- <Tabs.Content value="links" className="flex flex-col flex-1 min-h-0 space-y-4">
801
- <div className="grid grid-cols-2 lg:grid-cols-4 gap-3">
802
- <div className="bg-white rounded-lg border border-gray-200 p-4">
803
- <div className="text-xs text-gray-600 mb-1">Broken Links</div>
800
+ <Tabs.Content value="links" className="flex min-h-0 flex-1 flex-col space-y-4">
801
+ <div className="grid grid-cols-2 gap-3 lg:grid-cols-4">
802
+ <div className="rounded-lg border border-gray-200 bg-white p-4">
803
+ <div className="mb-1 text-xs text-gray-600">Broken Links</div>
804
804
  <div className="text-2xl font-semibold text-red-600">
805
805
  {linkHealth.filter((l: any) => l.status === 404).length}
806
806
  </div>
807
807
  </div>
808
- <div className="bg-white rounded-lg border border-gray-200 p-4">
809
- <div className="text-xs text-gray-600 mb-1">Redirect Chains</div>
808
+ <div className="rounded-lg border border-gray-200 bg-white p-4">
809
+ <div className="mb-1 text-xs text-gray-600">Redirect Chains</div>
810
810
  <div className="text-2xl font-semibold text-yellow-600">
811
811
  {linkHealth.filter((l: any) => l.status === 301).length}
812
812
  </div>
813
813
  </div>
814
- <div className="bg-white rounded-lg border border-gray-200 p-4">
815
- <div className="text-xs text-gray-600 mb-1">Internal Issues</div>
814
+ <div className="rounded-lg border border-gray-200 bg-white p-4">
815
+ <div className="mb-1 text-xs text-gray-600">Internal Issues</div>
816
816
  <div className="text-2xl font-semibold text-gray-900">
817
817
  {linkHealth.filter((l: any) => l.type === 'internal').length}
818
818
  </div>
819
819
  </div>
820
- <div className="bg-white rounded-lg border border-gray-200 p-4">
821
- <div className="text-xs text-gray-600 mb-1">External Issues</div>
820
+ <div className="rounded-lg border border-gray-200 bg-white p-4">
821
+ <div className="mb-1 text-xs text-gray-600">External Issues</div>
822
822
  <div className="text-2xl font-semibold text-gray-900">
823
823
  {linkHealth.filter((l: any) => l.type === 'external').length}
824
824
  </div>
825
825
  </div>
826
826
  </div>
827
827
 
828
- <div className="bg-white rounded-lg border border-gray-200 flex-1 overflow-hidden">
829
- <div className="overflow-x-auto h-full">
828
+ <div className="flex-1 overflow-hidden rounded-lg border border-gray-200 bg-white">
829
+ <div className="h-full overflow-x-auto">
830
830
  <table className="w-full">
831
- <thead className="bg-gray-50 border-b border-gray-200 sticky top-0">
831
+ <thead className="sticky top-0 border-b border-gray-200 bg-gray-50">
832
832
  <tr>
833
833
  <th className="px-4 py-2 text-left text-xs font-medium text-gray-700">
834
834
  Found On
@@ -850,27 +850,27 @@ export function SEO({ onNavigate, initialTab = 'pages' }: SEOProps) {
850
850
  </thead>
851
851
  <tbody className="divide-y divide-gray-200">
852
852
  {linkHealth.map((link: any) => (
853
- <tr key={link.id} className="hover:bg-gray-50 transition-colors">
853
+ <tr key={link.id} className="transition-colors hover:bg-gray-50">
854
854
  <td className="px-4 py-3">
855
- <code className="text-xs bg-gray-100 px-2 py-1 rounded text-gray-700">
855
+ <code className="rounded bg-gray-100 px-2 py-1 text-xs text-gray-700">
856
856
  {link.page}
857
857
  </code>
858
858
  </td>
859
859
  <td className="px-4 py-3">
860
- <code className="text-xs bg-red-50 px-2 py-1 rounded text-red-800 truncate max-w-[200px] block">
860
+ <code className="block max-w-[200px] truncate rounded bg-red-50 px-2 py-1 text-xs text-red-800">
861
861
  {link.url}
862
862
  </code>
863
863
  </td>
864
864
  <td className="px-4 py-3">
865
865
  <span
866
- className={`px-2 py-0.5 rounded-full text-xs font-medium ${link.status === 404 ? 'bg-red-100 text-red-800' : 'bg-yellow-100 text-yellow-800'}`}
866
+ className={`rounded-full px-2 py-0.5 text-xs font-medium ${link.status === 404 ? 'bg-red-100 text-red-800' : 'bg-yellow-100 text-yellow-800'}`}
867
867
  >
868
868
  {link.status}
869
869
  </span>
870
870
  </td>
871
871
  <td className="px-4 py-3">
872
872
  <span
873
- className={`px-2 py-0.5 rounded-full text-xs font-medium ${link.type === 'internal' ? 'bg-blue-100 text-blue-800' : 'bg-gray-100 text-gray-800'}`}
873
+ className={`rounded-full px-2 py-0.5 text-xs font-medium ${link.type === 'internal' ? 'bg-blue-100 text-blue-800' : 'bg-gray-100 text-gray-800'}`}
874
874
  >
875
875
  {link.type}
876
876
  </span>
@@ -879,16 +879,16 @@ export function SEO({ onNavigate, initialTab = 'pages' }: SEOProps) {
879
879
  <td className="px-4 py-3">
880
880
  <div className="flex items-center gap-1">
881
881
  <button
882
- className="p-1.5 hover:bg-gray-100 rounded transition-colors"
882
+ className="rounded p-1.5 transition-colors hover:bg-gray-100"
883
883
  title="Create redirect"
884
884
  >
885
- <ArrowRightLeft className="w-4 h-4 text-gray-600" />
885
+ <ArrowRightLeft className="h-4 w-4 text-gray-600" />
886
886
  </button>
887
887
  <button
888
- className="p-1.5 hover:bg-gray-100 rounded transition-colors"
888
+ className="rounded p-1.5 transition-colors hover:bg-gray-100"
889
889
  title="Open URL"
890
890
  >
891
- <ExternalLink className="w-4 h-4 text-gray-600" />
891
+ <ExternalLink className="h-4 w-4 text-gray-600" />
892
892
  </button>
893
893
  </div>
894
894
  </td>