@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
@@ -86,59 +86,59 @@ export function PostEditor({ id, onNavigate }: PostEditorProps) {
86
86
 
87
87
  if (!isNew && loading) {
88
88
  return (
89
- <div className="h-full flex items-center justify-center">
90
- <Loader2 className="w-6 h-6 animate-spin text-blue-600" />
89
+ <div className="flex h-full items-center justify-center">
90
+ <Loader2 className="h-6 w-6 animate-spin text-blue-600" />
91
91
  </div>
92
92
  )
93
93
  }
94
94
 
95
95
  return (
96
- <div className="h-full flex flex-col bg-white">
96
+ <div className="flex h-full flex-col bg-white">
97
97
  {error && (
98
98
  <div className="mx-4 mt-3 flex items-center gap-3 rounded-lg border border-red-200 bg-red-50 p-3">
99
- <AlertTriangle className="w-5 h-5 text-red-600 shrink-0" />
100
- <span className="text-sm text-red-800 flex-1">{error}</span>
99
+ <AlertTriangle className="h-5 w-5 shrink-0 text-red-600" />
100
+ <span className="flex-1 text-sm text-red-800">{error}</span>
101
101
  </div>
102
102
  )}
103
103
 
104
- <div className="border-b border-gray-200 px-3 sm:px-4 py-3">
104
+ <div className="border-b border-gray-200 px-3 py-3 sm:px-4">
105
105
  <div className="flex items-center justify-between">
106
106
  <button
107
107
  onClick={() => onNavigate?.('/posts')}
108
- className="inline-flex items-center gap-2 text-sm text-gray-600 hover:text-gray-900 transition-colors"
108
+ className="inline-flex items-center gap-2 text-sm text-gray-600 transition-colors hover:text-gray-900"
109
109
  >
110
- <ArrowLeft className="w-4 h-4" />
110
+ <ArrowLeft className="h-4 w-4" />
111
111
  <span className="hidden sm:inline">Back to Posts</span>
112
112
  <span className="sm:hidden">Back</span>
113
113
  </button>
114
114
  <div className="flex items-center gap-2">
115
- <button className="px-3 py-1.5 text-sm border border-gray-300 rounded-lg flex items-center gap-2 hover:bg-gray-50 transition-colors">
116
- <Eye className="w-4 h-4" />
115
+ <button className="flex items-center gap-2 rounded-lg border border-gray-300 px-3 py-1.5 text-sm transition-colors hover:bg-gray-50">
116
+ <Eye className="h-4 w-4" />
117
117
  <span className="hidden sm:inline">Preview</span>
118
118
  </button>
119
119
  </div>
120
120
  </div>
121
121
  </div>
122
122
 
123
- <div className="flex-1 overflow-hidden flex flex-col lg:flex-row">
123
+ <div className="flex flex-1 flex-col overflow-hidden lg:flex-row">
124
124
  <div className="flex-1 overflow-y-auto">
125
- <div className="max-w-4xl mx-auto p-3 pr-6 sm:p-4 sm:pr-8">
125
+ <div className="mx-auto max-w-4xl p-3 pr-6 sm:p-4 sm:pr-8">
126
126
  <input
127
127
  type="text"
128
128
  value={title}
129
129
  onChange={(e) => setTitle(e.target.value)}
130
130
  placeholder="Post title"
131
- className="w-full text-2xl sm:text-3xl font-bold mb-4 px-0 border-none focus:outline-none focus:ring-0 placeholder:text-gray-300"
131
+ className="mb-4 w-full border-none px-0 text-2xl font-bold placeholder:text-gray-300 focus:ring-0 focus:outline-none sm:text-3xl"
132
132
  />
133
133
 
134
134
  <div className="mb-4">
135
- <label className="block text-xs font-medium text-gray-600 mb-1">URL Slug</label>
135
+ <label className="mb-1 block text-xs font-medium text-gray-600">URL Slug</label>
136
136
  <input
137
137
  type="text"
138
138
  value={slug}
139
139
  onChange={(e) => setSlug(e.target.value)}
140
140
  placeholder="url-slug"
141
- className="w-full px-3 py-1.5 text-sm border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
141
+ className="w-full rounded-lg border border-gray-300 px-3 py-1.5 text-sm focus:ring-2 focus:ring-blue-500 focus:outline-none"
142
142
  />
143
143
  </div>
144
144
 
@@ -148,35 +148,35 @@ export function PostEditor({ id, onNavigate }: PostEditorProps) {
148
148
  </div>
149
149
  </div>
150
150
 
151
- <div className="hidden lg:block w-[30%] border-l border-gray-200 overflow-y-auto bg-gray-50">
152
- <div className="p-4 space-y-4">
153
- <div className="bg-white rounded-lg border border-gray-200 p-4">
154
- <h3 className="font-semibold text-gray-900 mb-3 text-sm">Publish</h3>
151
+ <div className="hidden w-[30%] overflow-y-auto border-l border-gray-200 bg-gray-50 lg:block">
152
+ <div className="space-y-4 p-4">
153
+ <div className="rounded-lg border border-gray-200 bg-white p-4">
154
+ <h3 className="mb-3 text-sm font-semibold text-gray-900">Publish</h3>
155
155
  <div className="space-y-3">
156
156
  <div>
157
- <label className="block text-xs font-medium text-gray-700 mb-1">Status</label>
157
+ <label className="mb-1 block text-xs font-medium text-gray-700">Status</label>
158
158
  <select
159
159
  value={status}
160
160
  onChange={(e) => setStatus(e.target.value as 'draft' | 'published')}
161
- className="w-full px-3 py-1.5 text-sm border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
161
+ className="w-full rounded-lg border border-gray-300 px-3 py-1.5 text-sm focus:ring-2 focus:ring-blue-500 focus:outline-none"
162
162
  >
163
163
  <option value="draft">Draft</option>
164
164
  <option value="published">Published</option>
165
165
  </select>
166
166
  </div>
167
167
  <div>
168
- <label className="block text-xs font-medium text-gray-700 mb-1">
168
+ <label className="mb-1 block text-xs font-medium text-gray-700">
169
169
  Publish Date
170
170
  </label>
171
171
  <input
172
172
  type="datetime-local"
173
- className="w-full px-3 py-1.5 text-sm border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
173
+ className="w-full rounded-lg border border-gray-300 px-3 py-1.5 text-sm focus:ring-2 focus:ring-blue-500 focus:outline-none"
174
174
  />
175
175
  </div>
176
176
  <button
177
177
  onClick={savePost}
178
178
  disabled={saving}
179
- className="w-full py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors text-sm font-medium disabled:opacity-50"
179
+ className="w-full rounded-lg bg-blue-600 py-2 text-sm font-medium text-white transition-colors hover:bg-blue-700 disabled:opacity-50"
180
180
  >
181
181
  {saving ? 'Saving...' : 'Save Post'}
182
182
  </button>
@@ -184,7 +184,7 @@ export function PostEditor({ id, onNavigate }: PostEditorProps) {
184
184
  <button
185
185
  onClick={publishPost}
186
186
  disabled={saving}
187
- className="w-full py-2 bg-green-600 text-white rounded-lg hover:bg-green-700 transition-colors text-sm font-medium disabled:opacity-50"
187
+ className="w-full rounded-lg bg-green-600 py-2 text-sm font-medium text-white transition-colors hover:bg-green-700 disabled:opacity-50"
188
188
  >
189
189
  {saving ? 'Publishing...' : 'Publish'}
190
190
  </button>
@@ -192,31 +192,31 @@ export function PostEditor({ id, onNavigate }: PostEditorProps) {
192
192
  </div>
193
193
  </div>
194
194
 
195
- <div className="bg-white rounded-lg border border-gray-200 p-4">
196
- <h3 className="font-semibold text-gray-900 mb-3 text-sm">Categories & Tags</h3>
195
+ <div className="rounded-lg border border-gray-200 bg-white p-4">
196
+ <h3 className="mb-3 text-sm font-semibold text-gray-900">Categories & Tags</h3>
197
197
  <div className="space-y-3">
198
198
  <div>
199
- <label className="block text-xs font-medium text-gray-700 mb-1">Category</label>
200
- <select className="w-full px-3 py-1.5 text-sm border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500">
199
+ <label className="mb-1 block text-xs font-medium text-gray-700">Category</label>
200
+ <select className="w-full rounded-lg border border-gray-300 px-3 py-1.5 text-sm focus:ring-2 focus:ring-blue-500 focus:outline-none">
201
201
  <option>Technology</option>
202
202
  <option>Design</option>
203
203
  <option>Business</option>
204
204
  </select>
205
205
  </div>
206
206
  <div>
207
- <label className="block text-xs font-medium text-gray-700 mb-1">Tags</label>
207
+ <label className="mb-1 block text-xs font-medium text-gray-700">Tags</label>
208
208
  <input
209
209
  type="text"
210
210
  placeholder="Add tags..."
211
- className="w-full px-3 py-1.5 text-sm border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
211
+ className="w-full rounded-lg border border-gray-300 px-3 py-1.5 text-sm focus:ring-2 focus:ring-blue-500 focus:outline-none"
212
212
  />
213
213
  </div>
214
214
  </div>
215
215
  </div>
216
216
 
217
- <div className="bg-white rounded-lg border border-gray-200 p-4">
218
- <h3 className="font-semibold text-gray-900 mb-3 text-sm">Featured Image</h3>
219
- <button className="w-full py-2 border-2 border-dashed border-gray-300 rounded-lg hover:border-gray-400 transition-colors text-sm text-gray-600">
217
+ <div className="rounded-lg border border-gray-200 bg-white p-4">
218
+ <h3 className="mb-3 text-sm font-semibold text-gray-900">Featured Image</h3>
219
+ <button className="w-full rounded-lg border-2 border-dashed border-gray-300 py-2 text-sm text-gray-600 transition-colors hover:border-gray-400">
220
220
  Upload Image
221
221
  </button>
222
222
  </div>
@@ -231,12 +231,12 @@ export function PostEditor({ id, onNavigate }: PostEditorProps) {
231
231
  </div>
232
232
  </div>
233
233
 
234
- <div className="lg:hidden border-t border-gray-200 p-3 bg-white">
234
+ <div className="border-t border-gray-200 bg-white p-3 lg:hidden">
235
235
  <div className="flex gap-2">
236
236
  <button
237
237
  onClick={savePost}
238
238
  disabled={saving}
239
- className="flex-1 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors text-sm font-medium disabled:opacity-50"
239
+ className="flex-1 rounded-lg bg-blue-600 py-2 text-sm font-medium text-white transition-colors hover:bg-blue-700 disabled:opacity-50"
240
240
  >
241
241
  {saving ? 'Saving...' : 'Save Post'}
242
242
  </button>
@@ -244,7 +244,7 @@ export function PostEditor({ id, onNavigate }: PostEditorProps) {
244
244
  <button
245
245
  onClick={publishPost}
246
246
  disabled={saving}
247
- className="flex-1 py-2 bg-green-600 text-white rounded-lg hover:bg-green-700 transition-colors text-sm font-medium disabled:opacity-50"
247
+ className="flex-1 rounded-lg bg-green-600 py-2 text-sm font-medium text-white transition-colors hover:bg-green-700 disabled:opacity-50"
248
248
  >
249
249
  Publish
250
250
  </button>
@@ -98,17 +98,17 @@ export function Posts({ onNavigate }: PostsProps) {
98
98
  <button
99
99
  type="button"
100
100
  onClick={() => setSortConfig(toggleSort(sortConfig, sortKey))}
101
- className="flex items-center gap-1 text-xs font-medium text-gray-700 hover:text-gray-900 transition-colors"
101
+ className="flex items-center gap-1 text-xs font-medium text-gray-700 transition-colors hover:text-gray-900"
102
102
  >
103
103
  {label}
104
104
  {active ? (
105
105
  sortConfig!.direction === 'asc' ? (
106
- <ArrowUp className="w-3 h-3" />
106
+ <ArrowUp className="h-3 w-3" />
107
107
  ) : (
108
- <ArrowDown className="w-3 h-3" />
108
+ <ArrowDown className="h-3 w-3" />
109
109
  )
110
110
  ) : (
111
- <ArrowUpDown className="w-3 h-3 text-gray-400" />
111
+ <ArrowUpDown className="h-3 w-3 text-gray-400" />
112
112
  )}
113
113
  </button>
114
114
  )
@@ -116,59 +116,59 @@ export function Posts({ onNavigate }: PostsProps) {
116
116
 
117
117
  if (loading) {
118
118
  return (
119
- <div className="p-3 pr-6 sm:p-4 sm:pr-8 flex items-center justify-center h-64">
120
- <Loader2 className="w-6 h-6 animate-spin text-blue-600" />
119
+ <div className="flex h-64 items-center justify-center p-3 pr-6 sm:p-4 sm:pr-8">
120
+ <Loader2 className="h-6 w-6 animate-spin text-blue-600" />
121
121
  </div>
122
122
  )
123
123
  }
124
124
 
125
125
  return (
126
- <div className="p-3 pr-6 sm:p-4 sm:pr-8 h-full flex flex-col">
126
+ <div className="flex h-full flex-col p-3 pr-6 sm:p-4 sm:pr-8">
127
127
  {error && (
128
128
  <div className="mb-4 flex items-center gap-3 rounded-lg border border-red-200 bg-red-50 p-3">
129
- <AlertTriangle className="w-5 h-5 text-red-600 shrink-0" />
130
- <span className="text-sm text-red-800 flex-1">{error}</span>
129
+ <AlertTriangle className="h-5 w-5 shrink-0 text-red-600" />
130
+ <span className="flex-1 text-sm text-red-800">{error}</span>
131
131
  <button
132
132
  onClick={refetch}
133
- className="px-3 py-1 text-sm text-red-700 border border-red-300 rounded-lg hover:bg-red-100 transition-colors"
133
+ className="rounded-lg border border-red-300 px-3 py-1 text-sm text-red-700 transition-colors hover:bg-red-100"
134
134
  >
135
135
  Retry
136
136
  </button>
137
137
  </div>
138
138
  )}
139
139
 
140
- <div className="flex flex-col sm:flex-row sm:items-center justify-between mb-4 gap-3">
140
+ <div className="mb-4 flex flex-col justify-between gap-3 sm:flex-row sm:items-center">
141
141
  <div>
142
- <h1 className="text-xl sm:text-2xl font-semibold text-gray-900 mb-1">Posts</h1>
142
+ <h1 className="mb-1 text-xl font-semibold text-gray-900 sm:text-2xl">Posts</h1>
143
143
  <p className="text-sm text-gray-600">{filteredAndSorted.length} total posts</p>
144
144
  </div>
145
145
  <button
146
146
  onClick={() => onNavigate?.('/posts/new')}
147
- 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"
147
+ 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"
148
148
  >
149
- <Plus className="w-4 h-4" />
149
+ <Plus className="h-4 w-4" />
150
150
  <span className="hidden sm:inline">New Post</span>
151
151
  <span className="sm:hidden">New</span>
152
152
  </button>
153
153
  </div>
154
154
 
155
- <div className="bg-white rounded-lg border border-gray-200 mb-4">
156
- <div className="p-3 flex flex-col gap-3">
155
+ <div className="mb-4 rounded-lg border border-gray-200 bg-white">
156
+ <div className="flex flex-col gap-3 p-3">
157
157
  <div className="relative">
158
- <Search className="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-gray-400" />
158
+ <Search className="absolute top-1/2 left-3 h-4 w-4 -translate-y-1/2 text-gray-400" />
159
159
  <input
160
160
  type="text"
161
161
  placeholder="Search posts..."
162
162
  value={searchQuery}
163
163
  onChange={(e) => setSearchQuery(e.target.value)}
164
- 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"
164
+ 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"
165
165
  />
166
166
  </div>
167
- <div className="flex flex-col sm:flex-row gap-2">
167
+ <div className="flex flex-col gap-2 sm:flex-row">
168
168
  <select
169
169
  value={filterStatus}
170
170
  onChange={(e) => setFilterStatus(e.target.value)}
171
- className="flex-1 px-3 py-2 text-sm border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
171
+ className="flex-1 rounded-lg border border-gray-300 px-3 py-2 text-sm focus:ring-2 focus:ring-blue-500 focus:outline-none"
172
172
  >
173
173
  <option value="all">All Status</option>
174
174
  <option value="published">Published</option>
@@ -177,7 +177,7 @@ export function Posts({ onNavigate }: PostsProps) {
177
177
  <select
178
178
  value={filterCategory}
179
179
  onChange={(e) => setFilterCategory(e.target.value)}
180
- className="flex-1 px-3 py-2 text-sm border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
180
+ className="flex-1 rounded-lg border border-gray-300 px-3 py-2 text-sm focus:ring-2 focus:ring-blue-500 focus:outline-none"
181
181
  >
182
182
  <option value="all">All Categories</option>
183
183
  <option value="technology">Technology</option>
@@ -186,9 +186,9 @@ export function Posts({ onNavigate }: PostsProps) {
186
186
  </select>
187
187
  <button
188
188
  type="button"
189
- className="flex items-center justify-center gap-2 px-3 py-2 text-sm border border-gray-300 rounded-lg hover:bg-gray-50 transition-colors"
189
+ className="flex items-center justify-center gap-2 rounded-lg border border-gray-300 px-3 py-2 text-sm transition-colors hover:bg-gray-50"
190
190
  >
191
- <SlidersHorizontal className="w-4 h-4" />
191
+ <SlidersHorizontal className="h-4 w-4" />
192
192
  <span className="hidden sm:inline">More Filters</span>
193
193
  </button>
194
194
  </div>
@@ -196,8 +196,8 @@ export function Posts({ onNavigate }: PostsProps) {
196
196
  </div>
197
197
 
198
198
  {selectedPosts.length > 0 && (
199
- <div className="bg-blue-50 border border-blue-200 rounded-lg p-3 mb-4">
200
- <div className="flex flex-col sm:flex-row sm:items-center justify-between gap-2">
199
+ <div className="mb-4 rounded-lg border border-blue-200 bg-blue-50 p-3">
200
+ <div className="flex flex-col justify-between gap-2 sm:flex-row sm:items-center">
201
201
  <span className="text-sm text-blue-900">
202
202
  {selectedPosts.length} post{selectedPosts.length !== 1 ? 's' : ''} selected
203
203
  </span>
@@ -205,14 +205,14 @@ export function Posts({ onNavigate }: PostsProps) {
205
205
  <button
206
206
  type="button"
207
207
  onClick={handleBulkDelete}
208
- className="flex-1 sm:flex-none px-3 py-1.5 text-sm bg-red-600 text-white rounded-lg hover:bg-red-700 transition-colors"
208
+ className="flex-1 rounded-lg bg-red-600 px-3 py-1.5 text-sm text-white transition-colors hover:bg-red-700 sm:flex-none"
209
209
  >
210
210
  Delete
211
211
  </button>
212
212
  <button
213
213
  type="button"
214
214
  onClick={() => setSelectedPosts([])}
215
- className="flex-1 sm:flex-none px-3 py-1.5 text-sm border border-gray-300 bg-white rounded-lg hover:bg-gray-50 transition-colors"
215
+ className="flex-1 rounded-lg border border-gray-300 bg-white px-3 py-1.5 text-sm transition-colors hover:bg-gray-50 sm:flex-none"
216
216
  >
217
217
  Cancel
218
218
  </button>
@@ -222,21 +222,21 @@ export function Posts({ onNavigate }: PostsProps) {
222
222
  )}
223
223
 
224
224
  {filteredAndSorted.length === 0 && !error ? (
225
- <div className="bg-white rounded-lg border border-gray-200 p-8 text-center flex-1 flex flex-col items-center justify-center">
226
- <p className="text-sm text-gray-500 mb-2">No posts yet</p>
225
+ <div className="flex flex-1 flex-col items-center justify-center rounded-lg border border-gray-200 bg-white p-8 text-center">
226
+ <p className="mb-2 text-sm text-gray-500">No posts yet</p>
227
227
  <button
228
228
  onClick={() => onNavigate?.('/posts/new')}
229
- className="px-4 py-2 text-sm bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors"
229
+ className="rounded-lg bg-blue-600 px-4 py-2 text-sm text-white transition-colors hover:bg-blue-700"
230
230
  >
231
231
  Create your first post
232
232
  </button>
233
233
  </div>
234
234
  ) : (
235
235
  <>
236
- <div className="hidden md:block bg-white rounded-lg border border-gray-200 flex-1 overflow-hidden">
237
- <div className="overflow-x-auto h-full">
236
+ <div className="hidden flex-1 overflow-hidden rounded-lg border border-gray-200 bg-white md:block">
237
+ <div className="h-full overflow-x-auto">
238
238
  <table className="w-full">
239
- <thead className="bg-gray-50 border-b border-gray-200 sticky top-0">
239
+ <thead className="sticky top-0 border-b border-gray-200 bg-gray-50">
240
240
  <tr>
241
241
  <th className="w-8 px-3 py-2 text-left">
242
242
  <input
@@ -271,7 +271,7 @@ export function Posts({ onNavigate }: PostsProps) {
271
271
  </thead>
272
272
  <tbody className="divide-y divide-gray-200">
273
273
  {filteredAndSorted.map((post: any) => (
274
- <tr key={post.id} className="hover:bg-gray-50 transition-colors">
274
+ <tr key={post.id} className="transition-colors hover:bg-gray-50">
275
275
  <td className="px-3 py-2">
276
276
  <input
277
277
  type="checkbox"
@@ -284,7 +284,7 @@ export function Posts({ onNavigate }: PostsProps) {
284
284
  <button
285
285
  type="button"
286
286
  onClick={() => onNavigate?.(`/posts/${post.id}`)}
287
- className="font-medium text-gray-900 hover:text-blue-600 text-sm text-left"
287
+ className="text-left text-sm font-medium text-gray-900 hover:text-blue-600"
288
288
  >
289
289
  {post.title}
290
290
  </button>
@@ -293,7 +293,7 @@ export function Posts({ onNavigate }: PostsProps) {
293
293
  <td className="px-3 py-2 text-sm text-gray-600">{post.category}</td>
294
294
  <td className="px-3 py-2">
295
295
  <span
296
- className={`inline-flex items-center px-2 py-0.5 rounded-full text-xs font-medium ${post.status === 'Published' ? 'bg-green-100 text-green-800' : 'bg-gray-100 text-gray-800'}`}
296
+ className={`inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium ${post.status === 'Published' ? 'bg-green-100 text-green-800' : 'bg-gray-100 text-gray-800'}`}
297
297
  >
298
298
  {post.status}
299
299
  </span>
@@ -304,18 +304,18 @@ export function Posts({ onNavigate }: PostsProps) {
304
304
  <button
305
305
  type="button"
306
306
  onClick={() => onNavigate?.(`/posts/${post.id}`)}
307
- className="p-1.5 hover:bg-gray-100 rounded transition-colors"
307
+ className="rounded p-1.5 transition-colors hover:bg-gray-100"
308
308
  title="Edit"
309
309
  >
310
- <Pencil className="w-4 h-4 text-gray-600" />
310
+ <Pencil className="h-4 w-4 text-gray-600" />
311
311
  </button>
312
312
  <button
313
313
  type="button"
314
314
  onClick={() => handleDelete(post.id)}
315
- className="p-1.5 hover:bg-gray-100 rounded transition-colors"
315
+ className="rounded p-1.5 transition-colors hover:bg-gray-100"
316
316
  title="Delete"
317
317
  >
318
- <Trash2 className="w-4 h-4 text-red-600" />
318
+ <Trash2 className="h-4 w-4 text-red-600" />
319
319
  </button>
320
320
  </div>
321
321
  </td>
@@ -326,7 +326,7 @@ export function Posts({ onNavigate }: PostsProps) {
326
326
  </div>
327
327
  </div>
328
328
 
329
- <div className="md:hidden bg-white rounded-lg border border-gray-200 flex-1 overflow-auto">
329
+ <div className="flex-1 overflow-auto rounded-lg border border-gray-200 bg-white md:hidden">
330
330
  <div className="divide-y divide-gray-200">
331
331
  {filteredAndSorted.map((post: any) => (
332
332
  <div key={post.id} className="p-3">
@@ -335,22 +335,22 @@ export function Posts({ onNavigate }: PostsProps) {
335
335
  type="checkbox"
336
336
  checked={selectedPosts.includes(post.id)}
337
337
  onChange={() => handleSelectPost(post.id)}
338
- className="rounded border-gray-300 mt-1"
338
+ className="mt-1 rounded border-gray-300"
339
339
  />
340
- <div className="flex-1 min-w-0">
340
+ <div className="min-w-0 flex-1">
341
341
  <button
342
342
  type="button"
343
343
  onClick={() => onNavigate?.(`/posts/${post.id}`)}
344
- className="font-medium text-sm text-gray-900 hover:text-blue-600 block mb-1 text-left"
344
+ className="mb-1 block text-left text-sm font-medium text-gray-900 hover:text-blue-600"
345
345
  >
346
346
  {post.title}
347
347
  </button>
348
- <div className="flex flex-wrap items-center gap-2 text-xs text-gray-600 mb-2">
348
+ <div className="mb-2 flex flex-wrap items-center gap-2 text-xs text-gray-600">
349
349
  <span>{post.author}</span>
350
350
  <span>•</span>
351
351
  <span>{post.date}</span>
352
352
  <span
353
- className={`px-2 py-0.5 rounded-full text-xs font-medium ${post.status === 'Published' ? 'bg-green-100 text-green-800' : 'bg-gray-100 text-gray-800'}`}
353
+ className={`rounded-full px-2 py-0.5 text-xs font-medium ${post.status === 'Published' ? 'bg-green-100 text-green-800' : 'bg-gray-100 text-gray-800'}`}
354
354
  >
355
355
  {post.status}
356
356
  </span>
@@ -359,9 +359,9 @@ export function Posts({ onNavigate }: PostsProps) {
359
359
  <button
360
360
  type="button"
361
361
  onClick={() => handleDelete(post.id)}
362
- className="p-1.5 hover:bg-gray-100 rounded transition-colors"
362
+ className="rounded p-1.5 transition-colors hover:bg-gray-100"
363
363
  >
364
- <Trash2 className="w-4 h-4 text-red-600" />
364
+ <Trash2 className="h-4 w-4 text-red-600" />
365
365
  </button>
366
366
  </div>
367
367
  </div>
@@ -101,17 +101,17 @@ export function Redirects({ onNavigate }: RedirectsProps) {
101
101
  <button
102
102
  type="button"
103
103
  onClick={() => setSortConfig(toggleSort(sortConfig, sortKey))}
104
- className="flex items-center gap-1 text-xs font-medium text-gray-700 hover:text-gray-900 transition-colors"
104
+ className="flex items-center gap-1 text-xs font-medium text-gray-700 transition-colors hover:text-gray-900"
105
105
  >
106
106
  {label}
107
107
  {active ? (
108
108
  sortConfig!.direction === 'asc' ? (
109
- <ArrowUp className="w-3 h-3" />
109
+ <ArrowUp className="h-3 w-3" />
110
110
  ) : (
111
- <ArrowDown className="w-3 h-3" />
111
+ <ArrowDown className="h-3 w-3" />
112
112
  )
113
113
  ) : (
114
- <ArrowUpDown className="w-3 h-3 text-gray-400" />
114
+ <ArrowUpDown className="h-3 w-3 text-gray-400" />
115
115
  )}
116
116
  </button>
117
117
  )
@@ -119,8 +119,8 @@ export function Redirects({ onNavigate }: RedirectsProps) {
119
119
 
120
120
  if (loading) {
121
121
  return (
122
- <div className="p-3 pr-6 sm:p-4 sm:pr-8 flex items-center justify-center h-64">
123
- <Loader2 className="w-6 h-6 animate-spin text-blue-600" />
122
+ <div className="flex h-64 items-center justify-center p-3 pr-6 sm:p-4 sm:pr-8">
123
+ <Loader2 className="h-6 w-6 animate-spin text-blue-600" />
124
124
  </div>
125
125
  )
126
126
  }
@@ -129,11 +129,11 @@ export function Redirects({ onNavigate }: RedirectsProps) {
129
129
  <div className="p-3 pr-6 sm:p-4 sm:pr-8">
130
130
  {error && (
131
131
  <div className="mb-4 flex items-center gap-3 rounded-lg border border-red-200 bg-red-50 p-3">
132
- <AlertTriangle className="w-5 h-5 text-red-600 shrink-0" />
133
- <span className="text-sm text-red-800 flex-1">{error}</span>
132
+ <AlertTriangle className="h-5 w-5 shrink-0 text-red-600" />
133
+ <span className="flex-1 text-sm text-red-800">{error}</span>
134
134
  <button
135
135
  onClick={refetch}
136
- className="px-3 py-1 text-sm text-red-700 border border-red-300 rounded-lg hover:bg-red-100 transition-colors"
136
+ className="rounded-lg border border-red-300 px-3 py-1 text-sm text-red-700 transition-colors hover:bg-red-100"
137
137
  >
138
138
  Retry
139
139
  </button>
@@ -155,22 +155,22 @@ export function Redirects({ onNavigate }: RedirectsProps) {
155
155
  </button>
156
156
  </div>
157
157
 
158
- <div className="bg-white rounded-lg border border-gray-200 mb-4">
159
- <div className="p-3 flex flex-col sm:flex-row gap-3">
158
+ <div className="mb-4 rounded-lg border border-gray-200 bg-white">
159
+ <div className="flex flex-col gap-3 p-3 sm:flex-row">
160
160
  <div className="relative flex-1">
161
- <Search className="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-gray-400" />
161
+ <Search className="absolute top-1/2 left-3 h-4 w-4 -translate-y-1/2 text-gray-400" />
162
162
  <input
163
163
  type="text"
164
164
  placeholder="Search by source or destination URL..."
165
165
  value={searchQuery}
166
166
  onChange={(e) => setSearchQuery(e.target.value)}
167
- 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"
167
+ 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"
168
168
  />
169
169
  </div>
170
170
  <select
171
171
  value={filterType}
172
172
  onChange={(e) => setFilterType(e.target.value)}
173
- className="px-3 py-2 text-sm border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
173
+ className="rounded-lg border border-gray-300 px-3 py-2 text-sm focus:ring-2 focus:ring-blue-500 focus:outline-none"
174
174
  >
175
175
  <option value="all">All Types</option>
176
176
  <option value="301">301 (Permanent)</option>
@@ -181,10 +181,10 @@ export function Redirects({ onNavigate }: RedirectsProps) {
181
181
 
182
182
  {filteredAndSorted.length === 0 && !loading ? (
183
183
  <div className="flex flex-col items-center justify-center py-16 text-center">
184
- <div className="w-12 h-12 rounded-full bg-gray-100 flex items-center justify-center mb-4">
185
- <ArrowRightLeft className="w-6 h-6 text-gray-400" />
184
+ <div className="mb-4 flex h-12 w-12 items-center justify-center rounded-full bg-gray-100">
185
+ <ArrowRightLeft className="h-6 w-6 text-gray-400" />
186
186
  </div>
187
- <h3 className="text-sm font-medium text-gray-900 mb-1">No redirects yet</h3>
187
+ <h3 className="mb-1 text-sm font-medium text-gray-900">No redirects yet</h3>
188
188
  <p className="text-sm text-gray-500">Add your first redirect to get started.</p>
189
189
  </div>
190
190
  ) : (
@@ -280,7 +280,7 @@ export function Redirects({ onNavigate }: RedirectsProps) {
280
280
  <Dialog.Root open={showAddDialog} onOpenChange={setShowAddDialog}>
281
281
  <Dialog.Portal>
282
282
  <Dialog.Overlay className="fixed inset-0 z-50 bg-black/50" />
283
- <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">
283
+ <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">
284
284
  <Dialog.Title className="mb-4 text-lg font-semibold text-gray-900">
285
285
  Add Redirect
286
286
  </Dialog.Title>
@@ -292,7 +292,7 @@ export function Redirects({ onNavigate }: RedirectsProps) {
292
292
  value={newRedirect.source}
293
293
  onChange={(e) => setNewRedirect({ ...newRedirect, source: e.target.value })}
294
294
  placeholder="/old-page"
295
- 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"
295
+ 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"
296
296
  required
297
297
  />
298
298
  </div>
@@ -305,7 +305,7 @@ export function Redirects({ onNavigate }: RedirectsProps) {
305
305
  value={newRedirect.destination}
306
306
  onChange={(e) => setNewRedirect({ ...newRedirect, destination: e.target.value })}
307
307
  placeholder="/new-page"
308
- 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"
308
+ 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"
309
309
  required
310
310
  />
311
311
  </div>
@@ -318,7 +318,7 @@ export function Redirects({ onNavigate }: RedirectsProps) {
318
318
  onChange={(e) =>
319
319
  setNewRedirect({ ...newRedirect, type: e.target.value as '301' | '302' })
320
320
  }
321
- 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"
321
+ 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"
322
322
  >
323
323
  <option value="301">301 (Permanent)</option>
324
324
  <option value="302">302 (Temporary)</option>