@actuate-media/cms-admin 0.10.0 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (284) hide show
  1. package/dist/AdminRoot.d.ts.map +1 -1
  2. package/dist/AdminRoot.js +8 -5
  3. package/dist/AdminRoot.js.map +1 -1
  4. package/dist/__tests__/layout/primitives.test.d.ts +2 -0
  5. package/dist/__tests__/layout/primitives.test.d.ts.map +1 -0
  6. package/dist/__tests__/layout/primitives.test.js +34 -0
  7. package/dist/__tests__/layout/primitives.test.js.map +1 -0
  8. package/dist/__tests__/lib/cv.test.d.ts +2 -0
  9. package/dist/__tests__/lib/cv.test.d.ts.map +1 -0
  10. package/dist/__tests__/lib/cv.test.js +66 -0
  11. package/dist/__tests__/lib/cv.test.js.map +1 -0
  12. package/dist/actuate-admin.css +1 -1
  13. package/dist/assets/actuate-logo.d.ts +36 -0
  14. package/dist/assets/actuate-logo.d.ts.map +1 -0
  15. package/dist/assets/actuate-logo.js +15 -0
  16. package/dist/assets/actuate-logo.js.map +1 -0
  17. package/dist/components/Breadcrumbs.js +2 -2
  18. package/dist/components/CommandPalette.js +10 -10
  19. package/dist/components/ContentOverviewChart.js +3 -3
  20. package/dist/components/ErrorBoundary.js +1 -1
  21. package/dist/components/FocalPointPicker.js +2 -2
  22. package/dist/components/FolderTree.js +20 -20
  23. package/dist/components/LivePreview.js +3 -3
  24. package/dist/components/LocaleSwitcher.js +1 -1
  25. package/dist/components/MediaPickerModal.js +4 -4
  26. package/dist/components/PresenceIndicator.js +1 -1
  27. package/dist/components/SEOConfigPanel.d.ts +2 -0
  28. package/dist/components/SEOConfigPanel.d.ts.map +1 -0
  29. package/dist/components/SEOConfigPanel.js +174 -0
  30. package/dist/components/SEOConfigPanel.js.map +1 -0
  31. package/dist/components/SEOPanel.js +9 -9
  32. package/dist/components/SEOPerformance.js +2 -2
  33. package/dist/components/SchedulePublishDialog.js +1 -1
  34. package/dist/components/SharePreviewLinkDialog.js +1 -1
  35. package/dist/components/TipTapEditor.js +5 -5
  36. package/dist/components/VersionHistory.js +2 -2
  37. package/dist/components/ui/Badge.d.ts +33 -3
  38. package/dist/components/ui/Badge.d.ts.map +1 -1
  39. package/dist/components/ui/Badge.js +42 -8
  40. package/dist/components/ui/Badge.js.map +1 -1
  41. package/dist/components/ui/Button.d.ts +19 -8
  42. package/dist/components/ui/Button.d.ts.map +1 -1
  43. package/dist/components/ui/Button.js +35 -14
  44. package/dist/components/ui/Button.js.map +1 -1
  45. package/dist/components/ui/Card.d.ts +26 -0
  46. package/dist/components/ui/Card.d.ts.map +1 -0
  47. package/dist/components/ui/Card.js +45 -0
  48. package/dist/components/ui/Card.js.map +1 -0
  49. package/dist/components/ui/DataTable.js +1 -1
  50. package/dist/components/ui/Input.d.ts +15 -0
  51. package/dist/components/ui/Input.d.ts.map +1 -0
  52. package/dist/components/ui/Input.js +23 -0
  53. package/dist/components/ui/Input.js.map +1 -0
  54. package/dist/components/ui/SearchInput.js +1 -1
  55. package/dist/components/ui/Select.d.ts +16 -0
  56. package/dist/components/ui/Select.d.ts.map +1 -0
  57. package/dist/components/ui/Select.js +25 -0
  58. package/dist/components/ui/Select.js.map +1 -0
  59. package/dist/components/ui/Toast.js +1 -1
  60. package/dist/components/ui/index.d.ts +10 -4
  61. package/dist/components/ui/index.d.ts.map +1 -1
  62. package/dist/components/ui/index.js +5 -2
  63. package/dist/components/ui/index.js.map +1 -1
  64. package/dist/fields/BlockBuilderField.js +3 -3
  65. package/dist/fields/DateField.js +1 -1
  66. package/dist/fields/RelationshipField.js +3 -3
  67. package/dist/fields/TextField.js +1 -1
  68. package/dist/index.d.ts +2 -0
  69. package/dist/index.d.ts.map +1 -1
  70. package/dist/index.js +3 -0
  71. package/dist/index.js.map +1 -1
  72. package/dist/layout/Header.js +1 -1
  73. package/dist/layout/Layout.d.ts +14 -0
  74. package/dist/layout/Layout.d.ts.map +1 -1
  75. package/dist/layout/Layout.js +17 -11
  76. package/dist/layout/Layout.js.map +1 -1
  77. package/dist/layout/Sidebar.d.ts.map +1 -1
  78. package/dist/layout/Sidebar.js +21 -11
  79. package/dist/layout/Sidebar.js.map +1 -1
  80. package/dist/layout/primitives/AdminShell.d.ts +43 -0
  81. package/dist/layout/primitives/AdminShell.d.ts.map +1 -0
  82. package/dist/layout/primitives/AdminShell.js +51 -0
  83. package/dist/layout/primitives/AdminShell.js.map +1 -0
  84. package/dist/layout/primitives/Box.d.ts +19 -0
  85. package/dist/layout/primitives/Box.d.ts.map +1 -0
  86. package/dist/layout/primitives/Box.js +12 -0
  87. package/dist/layout/primitives/Box.js.map +1 -0
  88. package/dist/layout/primitives/Cluster.d.ts +27 -0
  89. package/dist/layout/primitives/Cluster.d.ts.map +1 -0
  90. package/dist/layout/primitives/Cluster.js +37 -0
  91. package/dist/layout/primitives/Cluster.js.map +1 -0
  92. package/dist/layout/primitives/Grid.d.ts +45 -0
  93. package/dist/layout/primitives/Grid.d.ts.map +1 -0
  94. package/dist/layout/primitives/Grid.js +59 -0
  95. package/dist/layout/primitives/Grid.js.map +1 -0
  96. package/dist/layout/primitives/PageContainer.d.ts +36 -0
  97. package/dist/layout/primitives/PageContainer.d.ts.map +1 -0
  98. package/dist/layout/primitives/PageContainer.js +41 -0
  99. package/dist/layout/primitives/PageContainer.js.map +1 -0
  100. package/dist/layout/primitives/Split.d.ts +34 -0
  101. package/dist/layout/primitives/Split.d.ts.map +1 -0
  102. package/dist/layout/primitives/Split.js +27 -0
  103. package/dist/layout/primitives/Split.js.map +1 -0
  104. package/dist/layout/primitives/Stack.d.ts +23 -0
  105. package/dist/layout/primitives/Stack.d.ts.map +1 -0
  106. package/dist/layout/primitives/Stack.js +34 -0
  107. package/dist/layout/primitives/Stack.js.map +1 -0
  108. package/dist/layout/primitives/index.d.ts +30 -0
  109. package/dist/layout/primitives/index.d.ts.map +1 -0
  110. package/dist/layout/primitives/index.js +22 -0
  111. package/dist/layout/primitives/index.js.map +1 -0
  112. package/dist/layout/primitives/tokens.d.ts +48 -0
  113. package/dist/layout/primitives/tokens.d.ts.map +1 -0
  114. package/dist/layout/primitives/tokens.js +54 -0
  115. package/dist/layout/primitives/tokens.js.map +1 -0
  116. package/dist/lib/cv.d.ts +53 -0
  117. package/dist/lib/cv.d.ts.map +1 -0
  118. package/dist/lib/cv.js +39 -0
  119. package/dist/lib/cv.js.map +1 -0
  120. package/dist/views/ApiKeys.js +7 -7
  121. package/dist/views/CollectionList.js +8 -8
  122. package/dist/views/Dashboard.d.ts.map +1 -1
  123. package/dist/views/Dashboard.js +333 -78
  124. package/dist/views/Dashboard.js.map +1 -1
  125. package/dist/views/DocumentEdit.js +3 -3
  126. package/dist/views/ForgotPassword.js +2 -2
  127. package/dist/views/FormEditor.js +5 -5
  128. package/dist/views/FormSubmissions.js +6 -6
  129. package/dist/views/Forms.js +2 -2
  130. package/dist/views/Login.d.ts +16 -1
  131. package/dist/views/Login.d.ts.map +1 -1
  132. package/dist/views/Login.js +17 -7
  133. package/dist/views/Login.js.map +1 -1
  134. package/dist/views/MediaBrowser.js +16 -16
  135. package/dist/views/PageEditor.js +2 -2
  136. package/dist/views/Pages.js +10 -10
  137. package/dist/views/PostEditor.js +2 -2
  138. package/dist/views/Posts.js +4 -4
  139. package/dist/views/Redirects.js +4 -4
  140. package/dist/views/ResetPassword.js +2 -2
  141. package/dist/views/SEO.js +6 -6
  142. package/dist/views/ScriptTagEditor.js +4 -4
  143. package/dist/views/ScriptTags.js +2 -2
  144. package/dist/views/Settings.d.ts.map +1 -1
  145. package/dist/views/Settings.js +9 -8
  146. package/dist/views/Settings.js.map +1 -1
  147. package/dist/views/SetupWizard.js +2 -2
  148. package/dist/views/Users.js +4 -4
  149. package/dist/views/page-builder/AIBlockAssist.js +1 -1
  150. package/dist/views/page-builder/AIGenerateDialog.js +10 -10
  151. package/dist/views/page-builder/BlockEditor.js +10 -10
  152. package/dist/views/page-builder/BlockPicker.js +4 -4
  153. package/dist/views/page-builder/BottomBar.js +1 -1
  154. package/dist/views/page-builder/BuilderToolbar.js +2 -2
  155. package/dist/views/page-builder/ContextPanel.js +2 -2
  156. package/dist/views/page-builder/DesignScore.js +9 -9
  157. package/dist/views/page-builder/NodeSettings.js +8 -8
  158. package/dist/views/page-builder/PageBuilder.js +3 -3
  159. package/dist/views/page-builder/PageSettings.js +1 -1
  160. package/dist/views/page-builder/PageTemplates.js +2 -2
  161. package/dist/views/page-builder/SEOPanel.js +13 -13
  162. package/dist/views/page-builder/SavedSections.js +5 -5
  163. package/dist/views/page-builder/TemplatePicker.js +2 -2
  164. package/dist/views/page-builder/block-renderers/CTAPreview.js +5 -5
  165. package/dist/views/page-builder/block-renderers/CardsPreview.js +1 -1
  166. package/dist/views/page-builder/block-renderers/CodePreview.js +1 -1
  167. package/dist/views/page-builder/block-renderers/FAQPreview.js +3 -3
  168. package/dist/views/page-builder/block-renderers/FallbackPreview.js +1 -1
  169. package/dist/views/page-builder/block-renderers/FormPreview.js +3 -3
  170. package/dist/views/page-builder/block-renderers/GalleryPreview.js +5 -5
  171. package/dist/views/page-builder/block-renderers/HeroPreview.js +3 -3
  172. package/dist/views/page-builder/block-renderers/ImagePreview.js +3 -3
  173. package/dist/views/page-builder/block-renderers/TextPreview.js +3 -3
  174. package/dist/views/page-builder/block-renderers/VideoPreview.js +4 -4
  175. package/dist/views/page-builder/canvas/BlockRenderer.js +1 -1
  176. package/dist/views/page-builder/canvas/BuilderCanvas.js +3 -3
  177. package/dist/views/page-builder/canvas/ColumnRenderer.js +2 -2
  178. package/dist/views/page-builder/canvas/ContainerRenderer.js +2 -2
  179. package/dist/views/page-builder/canvas/RowRenderer.js +2 -2
  180. package/dist/views/page-builder/canvas/SectionRenderer.js +2 -2
  181. package/package.json +6 -2
  182. package/src/AdminRoot.tsx +21 -11
  183. package/src/__tests__/layout/primitives.test.ts +37 -0
  184. package/src/__tests__/lib/cv.test.ts +74 -0
  185. package/src/assets/actuate-logo.tsx +72 -0
  186. package/src/components/Breadcrumbs.tsx +6 -6
  187. package/src/components/CommandPalette.tsx +34 -34
  188. package/src/components/ContentOverviewChart.tsx +3 -3
  189. package/src/components/ErrorBoundary.tsx +3 -3
  190. package/src/components/FocalPointPicker.tsx +4 -4
  191. package/src/components/FolderTree.tsx +38 -38
  192. package/src/components/LivePreview.tsx +16 -16
  193. package/src/components/LocaleSwitcher.tsx +7 -7
  194. package/src/components/MediaPickerModal.tsx +21 -21
  195. package/src/components/PresenceIndicator.tsx +2 -2
  196. package/src/components/SEOConfigPanel.tsx +582 -0
  197. package/src/components/SEOPanel.tsx +46 -46
  198. package/src/components/SEOPerformance.tsx +21 -21
  199. package/src/components/SchedulePublishDialog.tsx +4 -4
  200. package/src/components/SharePreviewLinkDialog.tsx +1 -1
  201. package/src/components/TipTapEditor.tsx +33 -33
  202. package/src/components/VersionHistory.tsx +16 -16
  203. package/src/components/ui/Badge.tsx +66 -14
  204. package/src/components/ui/Button.tsx +70 -33
  205. package/src/components/ui/Card.tsx +101 -0
  206. package/src/components/ui/DataTable.tsx +1 -1
  207. package/src/components/ui/Input.tsx +35 -0
  208. package/src/components/ui/SearchInput.tsx +4 -4
  209. package/src/components/ui/Select.tsx +56 -0
  210. package/src/components/ui/Toast.tsx +1 -1
  211. package/src/components/ui/index.ts +18 -4
  212. package/src/fields/BlockBuilderField.tsx +3 -3
  213. package/src/fields/DateField.tsx +1 -1
  214. package/src/fields/RelationshipField.tsx +10 -10
  215. package/src/fields/TextField.tsx +1 -1
  216. package/src/index.ts +28 -0
  217. package/src/layout/Header.tsx +28 -28
  218. package/src/layout/Layout.tsx +39 -46
  219. package/src/layout/Sidebar.tsx +37 -64
  220. package/src/layout/primitives/AdminShell.tsx +118 -0
  221. package/src/layout/primitives/Box.tsx +30 -0
  222. package/src/layout/primitives/Cluster.tsx +74 -0
  223. package/src/layout/primitives/Grid.tsx +120 -0
  224. package/src/layout/primitives/PageContainer.tsx +96 -0
  225. package/src/layout/primitives/Split.tsx +73 -0
  226. package/src/layout/primitives/Stack.tsx +67 -0
  227. package/src/layout/primitives/index.ts +36 -0
  228. package/src/layout/primitives/tokens.ts +76 -0
  229. package/src/lib/cv.ts +96 -0
  230. package/src/styles/build-input.css +1 -1
  231. package/src/views/ApiKeys.tsx +57 -57
  232. package/src/views/CollectionList.tsx +30 -30
  233. package/src/views/Dashboard.tsx +737 -186
  234. package/src/views/DocumentEdit.tsx +9 -9
  235. package/src/views/ForgotPassword.tsx +18 -18
  236. package/src/views/FormEditor.tsx +75 -75
  237. package/src/views/FormSubmissions.tsx +76 -76
  238. package/src/views/Forms.tsx +27 -27
  239. package/src/views/Login.tsx +65 -25
  240. package/src/views/MediaBrowser.tsx +127 -127
  241. package/src/views/PageEditor.tsx +25 -25
  242. package/src/views/Pages.tsx +59 -59
  243. package/src/views/PostEditor.tsx +37 -37
  244. package/src/views/Posts.tsx +48 -48
  245. package/src/views/Redirects.tsx +21 -21
  246. package/src/views/ResetPassword.tsx +28 -28
  247. package/src/views/SEO.tsx +144 -144
  248. package/src/views/ScriptTagEditor.tsx +24 -24
  249. package/src/views/ScriptTags.tsx +10 -10
  250. package/src/views/Settings.tsx +88 -80
  251. package/src/views/SetupWizard.tsx +28 -28
  252. package/src/views/Users.tsx +20 -20
  253. package/src/views/page-builder/AIBlockAssist.tsx +1 -1
  254. package/src/views/page-builder/AIGenerateDialog.tsx +63 -63
  255. package/src/views/page-builder/BlockEditor.tsx +26 -26
  256. package/src/views/page-builder/BlockPicker.tsx +22 -22
  257. package/src/views/page-builder/BottomBar.tsx +8 -8
  258. package/src/views/page-builder/BuilderToolbar.tsx +17 -17
  259. package/src/views/page-builder/ContextPanel.tsx +3 -3
  260. package/src/views/page-builder/DesignScore.tsx +21 -21
  261. package/src/views/page-builder/NodeSettings.tsx +27 -27
  262. package/src/views/page-builder/PageBuilder.tsx +11 -11
  263. package/src/views/page-builder/PageSettings.tsx +4 -4
  264. package/src/views/page-builder/PageTemplates.tsx +18 -18
  265. package/src/views/page-builder/SEOPanel.tsx +53 -53
  266. package/src/views/page-builder/SavedSections.tsx +37 -37
  267. package/src/views/page-builder/TemplatePicker.tsx +17 -17
  268. package/src/views/page-builder/block-renderers/CTAPreview.tsx +13 -13
  269. package/src/views/page-builder/block-renderers/CardsPreview.tsx +5 -5
  270. package/src/views/page-builder/block-renderers/CodePreview.tsx +6 -6
  271. package/src/views/page-builder/block-renderers/FAQPreview.tsx +13 -13
  272. package/src/views/page-builder/block-renderers/FallbackPreview.tsx +3 -3
  273. package/src/views/page-builder/block-renderers/FormPreview.tsx +20 -20
  274. package/src/views/page-builder/block-renderers/GalleryPreview.tsx +8 -8
  275. package/src/views/page-builder/block-renderers/HeroPreview.tsx +16 -16
  276. package/src/views/page-builder/block-renderers/ImagePreview.tsx +4 -4
  277. package/src/views/page-builder/block-renderers/TextPreview.tsx +14 -14
  278. package/src/views/page-builder/block-renderers/VideoPreview.tsx +12 -12
  279. package/src/views/page-builder/canvas/BlockRenderer.tsx +4 -4
  280. package/src/views/page-builder/canvas/BuilderCanvas.tsx +6 -6
  281. package/src/views/page-builder/canvas/ColumnRenderer.tsx +3 -3
  282. package/src/views/page-builder/canvas/ContainerRenderer.tsx +2 -2
  283. package/src/views/page-builder/canvas/RowRenderer.tsx +2 -2
  284. package/src/views/page-builder/canvas/SectionRenderer.tsx +2 -2
@@ -1,13 +1,25 @@
1
1
  'use client'
2
2
 
3
3
  import { useState, type FormEvent } from 'react'
4
- import { Shield, Eye, EyeOff, AlertTriangle, Loader2 } from 'lucide-react'
4
+ import { Eye, EyeOff, AlertTriangle, Loader2 } from 'lucide-react'
5
+ import { ActuateBrandLogo } from '../assets/actuate-logo.js'
5
6
 
6
7
  export interface CaptchaConfig {
7
8
  provider: 'recaptcha' | 'turnstile' | 'none'
8
9
  siteKey: string | null
9
10
  }
10
11
 
12
+ /**
13
+ * Branding shown on the login screen. Mirrors `config.admin.branding` from the
14
+ * sidebar so integrators only need to set it once. `logo` should be a URL or
15
+ * data URL; pass `null` to opt out of any logo entirely.
16
+ */
17
+ export interface LoginBrandingConfig {
18
+ logo?: string | null
19
+ name?: string
20
+ tagline?: string
21
+ }
22
+
11
23
  export interface LoginProps {
12
24
  onLogin: (
13
25
  email: string,
@@ -17,6 +29,11 @@ export interface LoginProps {
17
29
  onNavigate?: (path: string) => void
18
30
  oauthProviders?: string[]
19
31
  captchaConfig?: CaptchaConfig
32
+ /**
33
+ * Custom branding for the login screen. Falls back to the bundled Actuate
34
+ * Media wordmark + "Actuate CMS" headline when omitted.
35
+ */
36
+ branding?: LoginBrandingConfig
20
37
  }
21
38
 
22
39
  const OAUTH_LABELS: Record<string, string> = {
@@ -48,7 +65,7 @@ const OAUTH_COLORS: Record<string, { border: string; bg: string; text: string; h
48
65
 
49
66
  function GoogleIcon() {
50
67
  return (
51
- <svg className="w-5 h-5" viewBox="0 0 24 24" aria-hidden="true">
68
+ <svg className="h-5 w-5" viewBox="0 0 24 24" aria-hidden="true">
52
69
  <path
53
70
  d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92a5.06 5.06 0 01-2.2 3.32v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.1z"
54
71
  fill="#4285F4"
@@ -71,7 +88,7 @@ function GoogleIcon() {
71
88
 
72
89
  function MicrosoftIcon() {
73
90
  return (
74
- <svg className="w-5 h-5" viewBox="0 0 21 21" aria-hidden="true">
91
+ <svg className="h-5 w-5" viewBox="0 0 21 21" aria-hidden="true">
75
92
  <rect x="1" y="1" width="9" height="9" fill="#F25022" />
76
93
  <rect x="1" y="11" width="9" height="9" fill="#00A4EF" />
77
94
  <rect x="11" y="1" width="9" height="9" fill="#7FBA00" />
@@ -86,7 +103,7 @@ function OAuthIcon({ provider }: { provider: string }) {
86
103
  return <GoogleIcon />
87
104
  case 'github':
88
105
  return (
89
- <svg className="w-5 h-5" viewBox="0 0 24 24" fill="currentColor">
106
+ <svg className="h-5 w-5" viewBox="0 0 24 24" fill="currentColor">
90
107
  <path d="M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385.6.105.825-.255.825-.57 0-.285-.015-1.23-.015-2.235-3.015.555-3.795-.735-4.035-1.41-.135-.345-.72-1.41-1.23-1.695-.42-.225-1.02-.78-.015-.795.945-.015 1.62.87 1.845 1.23 1.08 1.815 2.805 1.305 3.495.99.105-.78.42-1.305.765-1.605-2.67-.3-5.46-1.335-5.46-5.925 0-1.305.465-2.385 1.23-3.225-.12-.3-.54-1.53.12-3.18 0 0 1.005-.315 3.3 1.23.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23.66 1.65.24 2.88.12 3.18.765.84 1.23 1.905 1.23 3.225 0 4.605-2.805 5.625-5.475 5.925.435.375.81 1.095.81 2.22 0 1.605-.015 2.895-.015 3.3 0 .315.225.69.825.57A12.02 12.02 0 0024 12c0-6.63-5.37-12-12-12z" />
91
108
  </svg>
92
109
  )
@@ -170,7 +187,13 @@ async function getCaptchaToken(provider: string, siteKey: string, action: string
170
187
  return ''
171
188
  }
172
189
 
173
- export function Login({ onLogin, onNavigate, oauthProviders, captchaConfig }: LoginProps) {
190
+ export function Login({
191
+ onLogin,
192
+ onNavigate,
193
+ oauthProviders,
194
+ captchaConfig,
195
+ branding,
196
+ }: LoginProps) {
174
197
  const [email, setEmail] = useState('')
175
198
  const [password, setPassword] = useState('')
176
199
  const [showPassword, setShowPassword] = useState(false)
@@ -218,30 +241,47 @@ export function Login({ onLogin, onNavigate, oauthProviders, captchaConfig }: Lo
218
241
  const enabledProviders =
219
242
  oauthProviders?.filter((p) => ['google', 'github', 'microsoft'].includes(p)) ?? []
220
243
 
244
+ // Branding fallbacks: when an integrator doesn't pass `branding`, render the
245
+ // Actuate Media wordmark inline (transparent SVG, no surrounding pill needed).
246
+ // When `branding.logo` is explicitly `null`, render no logo at all (just the
247
+ // headline + tagline) so whitelabel deployments can hide it entirely.
248
+ const customLogo = branding?.logo
249
+ const brandName = branding?.name ?? 'Actuate CMS'
250
+ const brandTagline = branding?.tagline ?? 'Sign in to your account'
251
+ const showLogo = customLogo !== null
252
+
221
253
  return (
222
- <div className="min-h-screen flex items-center justify-center bg-gray-50 px-4">
254
+ <div className="flex min-h-screen items-center justify-center bg-gray-50 px-4">
223
255
  <div className="w-full max-w-md">
224
- <div className="text-center mb-8">
225
- <div className="mx-auto mb-4 w-14 h-14 bg-blue-600 rounded-xl flex items-center justify-center">
226
- <Shield className="w-7 h-7 text-white" />
227
- </div>
228
- <h1 className="text-2xl font-bold text-gray-900">Actuate CMS</h1>
229
- <p className="text-gray-600 mt-2">Sign in to your account</p>
256
+ <div className="mb-8 text-center">
257
+ {showLogo &&
258
+ (customLogo ? (
259
+ <img
260
+ src={customLogo}
261
+ alt={brandName}
262
+ className="mx-auto mb-4 max-h-16 w-auto object-contain"
263
+ draggable={false}
264
+ />
265
+ ) : (
266
+ <ActuateBrandLogo className="mx-auto mb-4 h-14 w-auto" />
267
+ ))}
268
+ <h1 className="text-2xl font-bold text-gray-900">{brandName}</h1>
269
+ <p className="mt-2 text-gray-600">{brandTagline}</p>
230
270
  </div>
231
271
 
232
272
  <form
233
273
  onSubmit={handleSubmit}
234
- className="bg-white rounded-xl border border-gray-200 p-6 shadow-sm space-y-5"
274
+ className="space-y-5 rounded-xl border border-gray-200 bg-white p-6 shadow-sm"
235
275
  >
236
276
  {error && (
237
- <div className="flex items-start gap-3 p-3 bg-red-50 border border-red-200 rounded-lg">
238
- <AlertTriangle className="w-5 h-5 text-red-600 mt-0.5 shrink-0" />
277
+ <div className="flex items-start gap-3 rounded-lg border border-red-200 bg-red-50 p-3">
278
+ <AlertTriangle className="mt-0.5 h-5 w-5 shrink-0 text-red-600" />
239
279
  <p className="text-sm text-red-800">{error}</p>
240
280
  </div>
241
281
  )}
242
282
 
243
283
  <div>
244
- <label htmlFor="login-email" className="block text-sm font-medium text-gray-700 mb-1.5">
284
+ <label htmlFor="login-email" className="mb-1.5 block text-sm font-medium text-gray-700">
245
285
  Email Address
246
286
  </label>
247
287
  <input
@@ -250,7 +290,7 @@ export function Login({ onLogin, onNavigate, oauthProviders, captchaConfig }: Lo
250
290
  value={email}
251
291
  onChange={(e) => setEmail(e.target.value)}
252
292
  placeholder="admin@example.com"
253
- className="w-full px-3 py-2.5 border border-gray-300 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
293
+ className="w-full rounded-lg border border-gray-300 px-3 py-2.5 text-sm focus:border-blue-500 focus:ring-2 focus:ring-blue-500 focus:outline-none"
254
294
  required
255
295
  autoFocus
256
296
  autoComplete="email"
@@ -258,7 +298,7 @@ export function Login({ onLogin, onNavigate, oauthProviders, captchaConfig }: Lo
258
298
  </div>
259
299
 
260
300
  <div>
261
- <div className="flex items-center justify-between mb-1.5">
301
+ <div className="mb-1.5 flex items-center justify-between">
262
302
  <label htmlFor="login-password" className="block text-sm font-medium text-gray-700">
263
303
  Password
264
304
  </label>
@@ -266,7 +306,7 @@ export function Login({ onLogin, onNavigate, oauthProviders, captchaConfig }: Lo
266
306
  <button
267
307
  type="button"
268
308
  onClick={() => onNavigate('/forgot-password')}
269
- className="text-xs text-blue-600 hover:text-blue-700 font-medium"
309
+ className="text-xs font-medium text-blue-600 hover:text-blue-700"
270
310
  >
271
311
  Forgot Password?
272
312
  </button>
@@ -279,17 +319,17 @@ export function Login({ onLogin, onNavigate, oauthProviders, captchaConfig }: Lo
279
319
  value={password}
280
320
  onChange={(e) => setPassword(e.target.value)}
281
321
  placeholder="Enter your password"
282
- className="w-full px-3 py-2.5 pr-10 border border-gray-300 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
322
+ className="w-full rounded-lg border border-gray-300 px-3 py-2.5 pr-10 text-sm focus:border-blue-500 focus:ring-2 focus:ring-blue-500 focus:outline-none"
283
323
  required
284
324
  autoComplete="current-password"
285
325
  />
286
326
  <button
287
327
  type="button"
288
328
  onClick={() => setShowPassword(!showPassword)}
289
- className="absolute right-3 top-1/2 -translate-y-1/2 text-gray-400 hover:text-gray-600"
329
+ className="absolute top-1/2 right-3 -translate-y-1/2 text-gray-400 hover:text-gray-600"
290
330
  tabIndex={-1}
291
331
  >
292
- {showPassword ? <EyeOff className="w-4 h-4" /> : <Eye className="w-4 h-4" />}
332
+ {showPassword ? <EyeOff className="h-4 w-4" /> : <Eye className="h-4 w-4" />}
293
333
  </button>
294
334
  </div>
295
335
  </div>
@@ -297,11 +337,11 @@ export function Login({ onLogin, onNavigate, oauthProviders, captchaConfig }: Lo
297
337
  <button
298
338
  type="submit"
299
339
  disabled={!canSubmit}
300
- className="w-full py-2.5 bg-blue-600 text-white rounded-lg font-medium hover:bg-blue-700 transition-colors disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center gap-2"
340
+ className="flex w-full items-center justify-center gap-2 rounded-lg bg-blue-600 py-2.5 font-medium text-white transition-colors hover:bg-blue-700 disabled:cursor-not-allowed disabled:opacity-50"
301
341
  >
302
342
  {submitting ? (
303
343
  <>
304
- <Loader2 className="w-4 h-4 animate-spin" />
344
+ <Loader2 className="h-4 w-4 animate-spin" />
305
345
  Signing in...
306
346
  </>
307
347
  ) : (
@@ -328,7 +368,7 @@ export function Login({ onLogin, onNavigate, oauthProviders, captchaConfig }: Lo
328
368
  key={provider}
329
369
  type="button"
330
370
  onClick={() => handleOAuthClick(provider)}
331
- className={`w-full flex items-center justify-center gap-3 py-2.5 px-4 border ${colors?.border ?? ''} ${colors?.bg ?? ''} ${colors?.text ?? ''} rounded-lg font-medium text-sm ${colors?.hover ?? ''} transition-colors`}
371
+ className={`flex w-full items-center justify-center gap-3 border px-4 py-2.5 ${colors?.border ?? ''} ${colors?.bg ?? ''} ${colors?.text ?? ''} rounded-lg text-sm font-medium ${colors?.hover ?? ''} transition-colors`}
332
372
  >
333
373
  <OAuthIcon provider={provider} />
334
374
  {OAUTH_LABELS[provider] ?? provider}