@actuate-media/cms-admin 0.54.0 → 0.56.2

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 (229) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/dist/__tests__/components/posts-badges.test.js +3 -3
  3. package/dist/__tests__/components/posts-badges.test.js.map +1 -1
  4. package/dist/__tests__/lib/page-editor-service.test.js +1 -0
  5. package/dist/__tests__/lib/page-editor-service.test.js.map +1 -1
  6. package/dist/actuate-admin.css +1 -1
  7. package/dist/components/AICoauthorBubbleMenu.js +2 -2
  8. package/dist/components/AICoauthorBubbleMenu.js.map +1 -1
  9. package/dist/components/Breadcrumbs.js +2 -2
  10. package/dist/components/Breadcrumbs.js.map +1 -1
  11. package/dist/components/CoauthorResultPopover.d.ts.map +1 -1
  12. package/dist/components/CoauthorResultPopover.js +1 -1
  13. package/dist/components/CoauthorResultPopover.js.map +1 -1
  14. package/dist/components/CommandPalette.d.ts.map +1 -1
  15. package/dist/components/CommandPalette.js +11 -11
  16. package/dist/components/CommandPalette.js.map +1 -1
  17. package/dist/components/CommentSidePanel.js +11 -11
  18. package/dist/components/CommentSidePanel.js.map +1 -1
  19. package/dist/components/ContentOverviewChart.js +2 -2
  20. package/dist/components/ContentOverviewChart.js.map +1 -1
  21. package/dist/components/FocalPointPicker.js +1 -1
  22. package/dist/components/FocalPointPicker.js.map +1 -1
  23. package/dist/components/LivePreview.d.ts.map +1 -1
  24. package/dist/components/LivePreview.js +5 -5
  25. package/dist/components/LivePreview.js.map +1 -1
  26. package/dist/components/LogoPlaceholder.js +1 -1
  27. package/dist/components/LogoPlaceholder.js.map +1 -1
  28. package/dist/components/MentionableTextarea.js +3 -3
  29. package/dist/components/MentionableTextarea.js.map +1 -1
  30. package/dist/components/NotificationBell.js +1 -1
  31. package/dist/components/NotificationBell.js.map +1 -1
  32. package/dist/components/OfflineStatus.js +8 -8
  33. package/dist/components/OfflineStatus.js.map +1 -1
  34. package/dist/components/PresenceChips.d.ts.map +1 -1
  35. package/dist/components/PresenceChips.js +10 -6
  36. package/dist/components/PresenceChips.js.map +1 -1
  37. package/dist/components/SEOConfigPanel.d.ts.map +1 -1
  38. package/dist/components/SEOConfigPanel.js +10 -10
  39. package/dist/components/SEOConfigPanel.js.map +1 -1
  40. package/dist/components/SEOPanel.js +12 -12
  41. package/dist/components/SEOPanel.js.map +1 -1
  42. package/dist/components/SEOPerformance.d.ts.map +1 -1
  43. package/dist/components/SEOPerformance.js +3 -3
  44. package/dist/components/SEOPerformance.js.map +1 -1
  45. package/dist/components/TipTapEditor.js +6 -6
  46. package/dist/components/TipTapEditor.js.map +1 -1
  47. package/dist/components/pages/tag-badges.js +6 -6
  48. package/dist/components/pages/tag-badges.js.map +1 -1
  49. package/dist/components/posts/badges.d.ts +0 -4
  50. package/dist/components/posts/badges.d.ts.map +1 -1
  51. package/dist/components/posts/badges.js +28 -42
  52. package/dist/components/posts/badges.js.map +1 -1
  53. package/dist/components/ui/Badge.js +5 -5
  54. package/dist/components/ui/Badge.js.map +1 -1
  55. package/dist/components/ui/Toast.d.ts.map +1 -1
  56. package/dist/components/ui/Toast.js +4 -4
  57. package/dist/components/ui/Toast.js.map +1 -1
  58. package/dist/fields/ComponentBlockField.js +2 -2
  59. package/dist/fields/ComponentBlockField.js.map +1 -1
  60. package/dist/fields/FieldRenderer.js +1 -1
  61. package/dist/fields/FieldRenderer.js.map +1 -1
  62. package/dist/fields/PropInput.js +1 -1
  63. package/dist/fields/PropInput.js.map +1 -1
  64. package/dist/fields/RelationshipField.js +5 -5
  65. package/dist/fields/RelationshipField.js.map +1 -1
  66. package/dist/fields/ToggleField.js +1 -1
  67. package/dist/fields/ToggleField.js.map +1 -1
  68. package/dist/lib/seo-service.d.ts +0 -2
  69. package/dist/lib/seo-service.d.ts.map +1 -1
  70. package/dist/lib/seo-service.js.map +1 -1
  71. package/dist/views/Dashboard.js +5 -5
  72. package/dist/views/Dashboard.js.map +1 -1
  73. package/dist/views/DocumentEdit.d.ts.map +1 -1
  74. package/dist/views/DocumentEdit.js +5 -5
  75. package/dist/views/DocumentEdit.js.map +1 -1
  76. package/dist/views/ForgotPassword.d.ts.map +1 -1
  77. package/dist/views/ForgotPassword.js +3 -2
  78. package/dist/views/ForgotPassword.js.map +1 -1
  79. package/dist/views/FormEditor.d.ts.map +1 -1
  80. package/dist/views/FormEditor.js +5 -5
  81. package/dist/views/FormEditor.js.map +1 -1
  82. package/dist/views/Login.d.ts.map +1 -1
  83. package/dist/views/Login.js +17 -17
  84. package/dist/views/Login.js.map +1 -1
  85. package/dist/views/PageEditor.d.ts.map +1 -1
  86. package/dist/views/PageEditor.js +2 -2
  87. package/dist/views/PageEditor.js.map +1 -1
  88. package/dist/views/Pages/PagesListView.js +6 -6
  89. package/dist/views/Pages/PagesListView.js.map +1 -1
  90. package/dist/views/Pages.d.ts.map +1 -1
  91. package/dist/views/Pages.js +16 -19
  92. package/dist/views/Pages.js.map +1 -1
  93. package/dist/views/ResetPassword.d.ts.map +1 -1
  94. package/dist/views/ResetPassword.js +3 -2
  95. package/dist/views/ResetPassword.js.map +1 -1
  96. package/dist/views/Settings.js +2 -2
  97. package/dist/views/Settings.js.map +1 -1
  98. package/dist/views/SetupWizard.d.ts.map +1 -1
  99. package/dist/views/SetupWizard.js +6 -5
  100. package/dist/views/SetupWizard.js.map +1 -1
  101. package/dist/views/page-builder/DesignScore.js +12 -12
  102. package/dist/views/page-builder/DesignScore.js.map +1 -1
  103. package/dist/views/page-builder/SEOPanel.js +9 -9
  104. package/dist/views/page-builder/SEOPanel.js.map +1 -1
  105. package/dist/views/page-editor/EditorCanvas.js +1 -1
  106. package/dist/views/page-editor/EditorCanvas.js.map +1 -1
  107. package/dist/views/page-editor/EditorTopBar.js +2 -2
  108. package/dist/views/page-editor/EditorTopBar.js.map +1 -1
  109. package/dist/views/page-editor/PagePreview.js +1 -1
  110. package/dist/views/page-editor/PagePreview.js.map +1 -1
  111. package/dist/views/page-editor/SectionInspector.js +1 -1
  112. package/dist/views/page-editor/SectionInspector.js.map +1 -1
  113. package/dist/views/page-editor/SitePreviewFrame.js +1 -1
  114. package/dist/views/page-editor/SitePreviewFrame.js.map +1 -1
  115. package/dist/views/page-editor/sections/ArticleBodySection.js +1 -1
  116. package/dist/views/page-editor/sections/ArticleBodySection.js.map +1 -1
  117. package/dist/views/page-editor/sections/AuthorBioSection.js +2 -2
  118. package/dist/views/page-editor/sections/AuthorBioSection.js.map +1 -1
  119. package/dist/views/page-editor/sections/ByTheNumbersSection.js +1 -1
  120. package/dist/views/page-editor/sections/ByTheNumbersSection.js.map +1 -1
  121. package/dist/views/page-editor/sections/CtaBannerSection.js +1 -1
  122. package/dist/views/page-editor/sections/CtaBannerSection.js.map +1 -1
  123. package/dist/views/page-editor/sections/EmbedSection.d.ts +10 -0
  124. package/dist/views/page-editor/sections/EmbedSection.d.ts.map +1 -0
  125. package/dist/views/page-editor/sections/EmbedSection.js +24 -0
  126. package/dist/views/page-editor/sections/EmbedSection.js.map +1 -0
  127. package/dist/views/page-editor/sections/FeatureHighlightSection.d.ts.map +1 -1
  128. package/dist/views/page-editor/sections/FeatureHighlightSection.js +2 -2
  129. package/dist/views/page-editor/sections/FeatureHighlightSection.js.map +1 -1
  130. package/dist/views/page-editor/sections/GallerySection.d.ts.map +1 -1
  131. package/dist/views/page-editor/sections/GallerySection.js +1 -1
  132. package/dist/views/page-editor/sections/GallerySection.js.map +1 -1
  133. package/dist/views/page-editor/sections/HeroBannerSection.js +1 -1
  134. package/dist/views/page-editor/sections/HeroBannerSection.js.map +1 -1
  135. package/dist/views/page-editor/sections/MissionSection.d.ts.map +1 -1
  136. package/dist/views/page-editor/sections/MissionSection.js +1 -1
  137. package/dist/views/page-editor/sections/MissionSection.js.map +1 -1
  138. package/dist/views/page-editor/sections/PullQuoteSection.js +1 -1
  139. package/dist/views/page-editor/sections/PullQuoteSection.js.map +1 -1
  140. package/dist/views/page-editor/sections/RelatedPostsSection.js +1 -1
  141. package/dist/views/page-editor/sections/RelatedPostsSection.js.map +1 -1
  142. package/dist/views/page-editor/sections/SectionRenderer.d.ts.map +1 -1
  143. package/dist/views/page-editor/sections/SectionRenderer.js +5 -1
  144. package/dist/views/page-editor/sections/SectionRenderer.js.map +1 -1
  145. package/dist/views/page-editor/sections/parts.js +6 -6
  146. package/dist/views/page-editor/sections/parts.js.map +1 -1
  147. package/dist/views/post-editor/PostEditorCanvas.js +2 -2
  148. package/dist/views/post-editor/PostEditorCanvas.js.map +1 -1
  149. package/dist/views/post-editor/PostHeader.js +2 -2
  150. package/dist/views/post-editor/PostHeader.js.map +1 -1
  151. package/dist/views/post-editor/PostHeaderPanel.js +1 -1
  152. package/dist/views/post-editor/PostHeaderPanel.js.map +1 -1
  153. package/dist/views/post-editor/PostPreview.js +1 -1
  154. package/dist/views/post-editor/PostPreview.js.map +1 -1
  155. package/dist/views/profile/AccountSecurity.js +1 -1
  156. package/dist/views/profile/AccountSecurity.js.map +1 -1
  157. package/dist/views/seo/TechnicalTab.d.ts.map +1 -1
  158. package/dist/views/seo/TechnicalTab.js +0 -10
  159. package/dist/views/seo/TechnicalTab.js.map +1 -1
  160. package/dist/views/settings/components.js +1 -1
  161. package/dist/views/settings/components.js.map +1 -1
  162. package/package.json +2 -2
  163. package/src/__tests__/components/posts-badges.test.tsx +3 -3
  164. package/src/__tests__/lib/page-editor-service.test.ts +1 -0
  165. package/src/components/AICoauthorBubbleMenu.tsx +4 -4
  166. package/src/components/Breadcrumbs.tsx +5 -5
  167. package/src/components/CoauthorResultPopover.tsx +26 -23
  168. package/src/components/CommandPalette.tsx +41 -39
  169. package/src/components/CommentSidePanel.tsx +20 -20
  170. package/src/components/ContentOverviewChart.tsx +4 -4
  171. package/src/components/FocalPointPicker.tsx +2 -2
  172. package/src/components/LivePreview.tsx +20 -17
  173. package/src/components/LogoPlaceholder.tsx +1 -1
  174. package/src/components/MentionableTextarea.tsx +5 -5
  175. package/src/components/NotificationBell.tsx +10 -10
  176. package/src/components/OfflineStatus.tsx +8 -8
  177. package/src/components/PresenceChips.tsx +12 -8
  178. package/src/components/SEOConfigPanel.tsx +40 -38
  179. package/src/components/SEOPanel.tsx +15 -15
  180. package/src/components/SEOPerformance.tsx +25 -23
  181. package/src/components/TipTapEditor.tsx +7 -7
  182. package/src/components/pages/tag-badges.tsx +6 -6
  183. package/src/components/posts/badges.tsx +28 -46
  184. package/src/components/ui/Badge.tsx +5 -5
  185. package/src/components/ui/Toast.tsx +4 -5
  186. package/src/fields/ComponentBlockField.tsx +2 -2
  187. package/src/fields/FieldRenderer.tsx +1 -1
  188. package/src/fields/PropInput.tsx +1 -1
  189. package/src/fields/RelationshipField.tsx +5 -5
  190. package/src/fields/ToggleField.tsx +1 -1
  191. package/src/lib/seo-service.ts +0 -2
  192. package/src/views/Dashboard.tsx +5 -5
  193. package/src/views/DocumentEdit.tsx +13 -11
  194. package/src/views/ForgotPassword.tsx +21 -18
  195. package/src/views/FormEditor.tsx +74 -69
  196. package/src/views/Login.tsx +45 -39
  197. package/src/views/PageEditor.tsx +26 -22
  198. package/src/views/Pages/PagesListView.tsx +6 -6
  199. package/src/views/Pages.tsx +64 -65
  200. package/src/views/ResetPassword.tsx +32 -29
  201. package/src/views/Settings.tsx +2 -2
  202. package/src/views/SetupWizard.tsx +42 -33
  203. package/src/views/page-builder/DesignScore.tsx +12 -12
  204. package/src/views/page-builder/SEOPanel.tsx +12 -12
  205. package/src/views/page-editor/EditorCanvas.tsx +1 -1
  206. package/src/views/page-editor/EditorTopBar.tsx +2 -2
  207. package/src/views/page-editor/PagePreview.tsx +1 -1
  208. package/src/views/page-editor/SectionInspector.tsx +1 -1
  209. package/src/views/page-editor/SitePreviewFrame.tsx +1 -1
  210. package/src/views/page-editor/sections/ArticleBodySection.tsx +5 -5
  211. package/src/views/page-editor/sections/AuthorBioSection.tsx +6 -6
  212. package/src/views/page-editor/sections/ByTheNumbersSection.tsx +5 -5
  213. package/src/views/page-editor/sections/CtaBannerSection.tsx +1 -1
  214. package/src/views/page-editor/sections/EmbedSection.tsx +43 -0
  215. package/src/views/page-editor/sections/FeatureHighlightSection.tsx +7 -5
  216. package/src/views/page-editor/sections/GallerySection.tsx +6 -4
  217. package/src/views/page-editor/sections/HeroBannerSection.tsx +2 -2
  218. package/src/views/page-editor/sections/MissionSection.tsx +4 -2
  219. package/src/views/page-editor/sections/PullQuoteSection.tsx +4 -4
  220. package/src/views/page-editor/sections/RelatedPostsSection.tsx +5 -5
  221. package/src/views/page-editor/sections/SectionRenderer.tsx +6 -2
  222. package/src/views/page-editor/sections/parts.tsx +6 -6
  223. package/src/views/post-editor/PostEditorCanvas.tsx +4 -4
  224. package/src/views/post-editor/PostHeader.tsx +5 -5
  225. package/src/views/post-editor/PostHeaderPanel.tsx +1 -1
  226. package/src/views/post-editor/PostPreview.tsx +1 -1
  227. package/src/views/profile/AccountSecurity.tsx +1 -1
  228. package/src/views/seo/TechnicalTab.tsx +0 -10
  229. package/src/views/settings/components.tsx +1 -1
@@ -228,13 +228,13 @@ export function CommentSidePanel({
228
228
  [api, onError, refresh, activeCommentId, setActive],
229
229
  )
230
230
 
231
- const wrapperClass = `flex h-full flex-col gap-3 border-l border-gray-200 bg-white p-3 ${className ?? ''}`
231
+ const wrapperClass = `flex h-full flex-col gap-3 border-l border-border bg-card p-3 ${className ?? ''}`
232
232
 
233
233
  return (
234
234
  <aside className={wrapperClass} data-testid="comment-side-panel">
235
235
  <header className="flex items-center justify-between">
236
- <h2 className="text-sm font-medium text-gray-900">Comments</h2>
237
- <label className="flex cursor-pointer items-center gap-1 text-xs text-gray-600">
236
+ <h2 className="text-foreground text-sm font-medium">Comments</h2>
237
+ <label className="text-muted-foreground flex cursor-pointer items-center gap-1 text-xs">
238
238
  <input
239
239
  type="checkbox"
240
240
  checked={includeResolved}
@@ -247,7 +247,7 @@ export function CommentSidePanel({
247
247
 
248
248
  <section className="flex flex-col gap-1.5">
249
249
  <MentionableTextarea
250
- className="w-full resize-none rounded border border-gray-300 p-2 text-sm focus:border-blue-500 focus:outline-none"
250
+ className="border-border focus-visible:border-ring w-full resize-none rounded border p-2 text-sm focus:outline-none"
251
251
  rows={3}
252
252
  placeholder="Write a comment… Type @ to mention a teammate."
253
253
  value={draft}
@@ -258,7 +258,7 @@ export function CommentSidePanel({
258
258
  <div className="flex justify-end">
259
259
  <button
260
260
  type="button"
261
- className="rounded bg-blue-600 px-3 py-1 text-xs font-medium text-white hover:bg-blue-500 disabled:opacity-50"
261
+ className="bg-primary hover:bg-info rounded px-3 py-1 text-xs font-medium text-white disabled:opacity-50"
262
262
  disabled={!draft.trim()}
263
263
  onClick={handleCompose}
264
264
  data-testid="comment-submit"
@@ -270,9 +270,9 @@ export function CommentSidePanel({
270
270
 
271
271
  <section className="flex-1 overflow-y-auto" aria-busy={loading} data-testid="comment-list">
272
272
  {loading ? (
273
- <p className="text-xs text-gray-500">Loading…</p>
273
+ <p className="text-muted-foreground text-xs">Loading…</p>
274
274
  ) : threads.length === 0 ? (
275
- <p className="text-xs text-gray-500">No comments yet.</p>
275
+ <p className="text-muted-foreground text-xs">No comments yet.</p>
276
276
  ) : (
277
277
  <ul className="flex flex-col gap-2">
278
278
  {threads.map((thread) => (
@@ -323,8 +323,8 @@ function CommentThreadView({
323
323
  mentionSearch,
324
324
  }: CommentThreadViewProps): React.JSX.Element {
325
325
  const [replyDraft, setReplyDraft] = useState('')
326
- const cardClass = `rounded border bg-gray-50 p-2 ${
327
- isActive ? 'border-yellow-400 ring-1 ring-yellow-300' : 'border-gray-200'
326
+ const cardClass = `rounded border bg-muted p-2 ${
327
+ isActive ? 'border-yellow-400 ring-1 ring-yellow-300' : 'border-border'
328
328
  }`
329
329
 
330
330
  return (
@@ -344,7 +344,7 @@ function CommentThreadView({
344
344
  mentionSearch={mentionSearch}
345
345
  />
346
346
  {thread.replies.length > 0 && (
347
- <ul className="mt-2 flex flex-col gap-1 border-l-2 border-gray-200 pl-2">
347
+ <ul className="border-border mt-2 flex flex-col gap-1 border-l-2 pl-2">
348
348
  {thread.replies.map((reply) => (
349
349
  <li key={reply.id}>
350
350
  <CommentRow
@@ -365,7 +365,7 @@ function CommentThreadView({
365
365
  <div className="mt-2 flex items-start gap-1">
366
366
  <div className="flex-1">
367
367
  <MentionableTextarea
368
- className="w-full resize-none rounded border border-gray-300 px-2 py-1 text-xs focus:border-blue-500 focus:outline-none"
368
+ className="border-border focus-visible:border-ring w-full resize-none rounded border px-2 py-1 text-xs focus:outline-none"
369
369
  placeholder="Reply… Type @ to mention."
370
370
  rows={1}
371
371
  value={replyDraft}
@@ -377,7 +377,7 @@ function CommentThreadView({
377
377
  </div>
378
378
  <button
379
379
  type="button"
380
- className="rounded bg-gray-700 px-2 py-1 text-xs font-medium text-white hover:bg-gray-600 disabled:opacity-50"
380
+ className="bg-foreground hover:bg-foreground/90 rounded px-2 py-1 text-xs font-medium text-white disabled:opacity-50"
381
381
  disabled={!replyDraft.trim()}
382
382
  onClick={(e) => {
383
383
  e.stopPropagation()
@@ -420,7 +420,7 @@ function CommentRow({
420
420
 
421
421
  const canMutate = isAdmin || comment.userId === currentUserId
422
422
  const meta = (
423
- <div className="text-xs text-gray-500">
423
+ <div className="text-muted-foreground text-xs">
424
424
  {comment.userId ?? 'deleted user'} · {formatRelative(comment.createdAt)}
425
425
  {comment.isResolved ? ' · resolved' : null}
426
426
  </div>
@@ -432,7 +432,7 @@ function CommentRow({
432
432
  {editing ? (
433
433
  <>
434
434
  <MentionableTextarea
435
- className="w-full resize-none rounded border border-gray-300 p-1 text-sm"
435
+ className="border-border w-full resize-none rounded border p-1 text-sm"
436
436
  rows={3}
437
437
  value={draft}
438
438
  onChange={setDraft}
@@ -443,7 +443,7 @@ function CommentRow({
443
443
  <div className="flex gap-1">
444
444
  <button
445
445
  type="button"
446
- className="rounded bg-blue-600 px-2 py-1 text-xs font-medium text-white"
446
+ className="bg-primary rounded px-2 py-1 text-xs font-medium text-white"
447
447
  onClick={async (e) => {
448
448
  e.stopPropagation()
449
449
  const ok = await onEdit(comment.id, draft)
@@ -455,7 +455,7 @@ function CommentRow({
455
455
  </button>
456
456
  <button
457
457
  type="button"
458
- className="rounded border border-gray-300 px-2 py-1 text-xs"
458
+ className="border-border rounded border px-2 py-1 text-xs"
459
459
  onClick={(e) => {
460
460
  e.stopPropagation()
461
461
  setDraft(comment.body)
@@ -469,7 +469,7 @@ function CommentRow({
469
469
  </>
470
470
  ) : (
471
471
  <p
472
- className="text-sm whitespace-pre-wrap text-gray-900"
472
+ className="text-foreground text-sm whitespace-pre-wrap"
473
473
  data-testid={`comment-body-${comment.id}`}
474
474
  >
475
475
  {comment.body}
@@ -480,7 +480,7 @@ function CommentRow({
480
480
  {canMutate && (
481
481
  <button
482
482
  type="button"
483
- className="text-gray-600 hover:text-gray-900"
483
+ className="text-muted-foreground hover:text-foreground"
484
484
  onClick={(e) => {
485
485
  e.stopPropagation()
486
486
  setEditing(true)
@@ -493,7 +493,7 @@ function CommentRow({
493
493
  {onToggleResolve && (
494
494
  <button
495
495
  type="button"
496
- className="text-gray-600 hover:text-gray-900"
496
+ className="text-muted-foreground hover:text-foreground"
497
497
  onClick={(e) => {
498
498
  e.stopPropagation()
499
499
  onToggleResolve()
@@ -506,7 +506,7 @@ function CommentRow({
506
506
  {canMutate && (
507
507
  <button
508
508
  type="button"
509
- className="text-red-600 hover:text-red-700"
509
+ className="text-destructive hover:text-destructive"
510
510
  onClick={(e) => {
511
511
  e.stopPropagation()
512
512
  onDelete()
@@ -20,7 +20,7 @@ export function ContentOverviewChart({ published, drafts, scheduled }: ContentOv
20
20
 
21
21
  if (total === 0) {
22
22
  return (
23
- <div className="flex h-full items-center justify-center text-sm text-gray-400">
23
+ <div className="text-muted-foreground flex h-full items-center justify-center text-sm">
24
24
  No content yet
25
25
  </div>
26
26
  )
@@ -58,12 +58,12 @@ export function ContentOverviewChart({ published, drafts, scheduled }: ContentOv
58
58
  style={{ backgroundColor: COLORS[idx] }}
59
59
  />
60
60
  <div className="min-w-0">
61
- <span className="text-sm text-gray-700">{entry.name}</span>
61
+ <span className="text-foreground text-sm">{entry.name}</span>
62
62
  <div className="flex items-baseline gap-2">
63
- <span className="text-lg font-medium text-gray-900">
63
+ <span className="text-foreground text-lg font-medium">
64
64
  {entry.value.toLocaleString()}
65
65
  </span>
66
- <span className="text-xs text-gray-400">{pct}%</span>
66
+ <span className="text-muted-foreground text-xs">{pct}%</span>
67
67
  </div>
68
68
  </div>
69
69
  </div>
@@ -50,10 +50,10 @@ export function FocalPointPicker({ imageUrl, focalX, focalY, onChange }: FocalPo
50
50
  draggable={false}
51
51
  />
52
52
  <div
53
- className="pointer-events-none absolute -mt-3 -ml-3 h-6 w-6 rounded-full border-2 border-white bg-blue-500/50 shadow-lg"
53
+ className="bg-info/50 pointer-events-none absolute -mt-3 -ml-3 h-6 w-6 rounded-full border-2 border-white shadow-lg"
54
54
  style={{ left: `${focalX * 100}%`, top: `${focalY * 100}%` }}
55
55
  >
56
- <div className="absolute inset-1 rounded-full bg-white" />
56
+ <div className="bg-card absolute inset-1 rounded-full" />
57
57
  </div>
58
58
  </div>
59
59
  <p className="text-xs text-[var(--muted-foreground)]">
@@ -155,13 +155,16 @@ export function LivePreview({
155
155
 
156
156
  if (!previewSrc) {
157
157
  return (
158
- <div className="flex h-full flex-col items-center justify-center rounded-lg border border-dashed border-gray-300 bg-gray-50 p-8">
159
- <p className="text-center text-sm text-gray-500">
158
+ <div className="border-border bg-muted flex h-full flex-col items-center justify-center rounded-lg border border-dashed p-8">
159
+ <p className="text-muted-foreground text-center text-sm">
160
160
  {!documentId
161
161
  ? 'Save the document first to enable preview'
162
162
  : 'Configure a preview URL in the collection settings to enable live preview'}
163
163
  </p>
164
- <button onClick={onClose} className="mt-4 text-xs text-gray-400 hover:text-gray-600">
164
+ <button
165
+ onClick={onClose}
166
+ className="text-muted-foreground hover:text-muted-foreground mt-4 text-xs"
167
+ >
165
168
  Close Preview
166
169
  </button>
167
170
  </div>
@@ -169,8 +172,8 @@ export function LivePreview({
169
172
  }
170
173
 
171
174
  return (
172
- <div className="flex h-full flex-col border-l border-gray-200 bg-white">
173
- <div className="flex items-center justify-between border-b border-gray-200 bg-gray-50 px-3 py-2">
175
+ <div className="border-border bg-card flex h-full flex-col border-l">
176
+ <div className="border-border bg-muted flex items-center justify-between border-b px-3 py-2">
174
177
  <div className="flex items-center gap-1">
175
178
  {(
176
179
  [
@@ -182,14 +185,14 @@ export function LivePreview({
182
185
  <button
183
186
  key={vp}
184
187
  onClick={() => setViewport(vp)}
185
- className={`rounded p-1.5 ${viewport === vp ? 'bg-white text-blue-600 shadow-sm' : 'text-gray-400 hover:text-gray-600'}`}
188
+ className={`rounded p-1.5 ${viewport === vp ? 'bg-card text-primary shadow-sm' : 'text-muted-foreground hover:text-muted-foreground'}`}
186
189
  title={vp}
187
190
  >
188
191
  <Icon className="h-4 w-4" />
189
192
  </button>
190
193
  ))}
191
194
  <span
192
- className="ml-2 inline-flex items-center gap-1 rounded-full bg-white px-2 py-0.5 text-[10px] font-medium text-gray-600"
195
+ className="bg-card text-muted-foreground ml-2 inline-flex items-center gap-1 rounded-full px-2 py-0.5 text-[10px] font-medium"
193
196
  title={
194
197
  streamStatus === 'connected'
195
198
  ? 'Live preview is streaming updates from the server.'
@@ -202,19 +205,19 @@ export function LivePreview({
202
205
  >
203
206
  {streamStatus === 'connected' ? (
204
207
  <>
205
- <Wifi className="h-3 w-3 text-green-600" aria-hidden /> Live
208
+ <Wifi className="text-success h-3 w-3" aria-hidden /> Live
206
209
  </>
207
210
  ) : streamStatus === 'connecting' ? (
208
211
  <>
209
- <Wifi className="h-3 w-3 animate-pulse text-blue-500" aria-hidden /> Connecting
212
+ <Wifi className="text-info h-3 w-3 animate-pulse" aria-hidden /> Connecting
210
213
  </>
211
214
  ) : streamStatus === 'offline' ? (
212
215
  <>
213
- <WifiOff className="h-3 w-3 text-amber-500" aria-hidden /> Reconnecting
216
+ <WifiOff className="text-warning h-3 w-3" aria-hidden /> Reconnecting
214
217
  </>
215
218
  ) : (
216
219
  <>
217
- <WifiOff className="h-3 w-3 text-gray-400" aria-hidden /> Idle
220
+ <WifiOff className="text-muted-foreground h-3 w-3" aria-hidden /> Idle
218
221
  </>
219
222
  )}
220
223
  </span>
@@ -222,21 +225,21 @@ export function LivePreview({
222
225
  <div className="flex items-center gap-1">
223
226
  <button
224
227
  onClick={handleRefresh}
225
- className="rounded p-1.5 text-gray-400 hover:text-gray-600"
228
+ className="text-muted-foreground hover:text-muted-foreground rounded p-1.5"
226
229
  title="Refresh"
227
230
  >
228
231
  <RefreshCw className="h-4 w-4" />
229
232
  </button>
230
233
  <button
231
234
  onClick={handleOpenExternal}
232
- className="rounded p-1.5 text-gray-400 hover:text-gray-600"
235
+ className="text-muted-foreground hover:text-muted-foreground rounded p-1.5"
233
236
  title="Open in new tab"
234
237
  >
235
238
  <ExternalLink className="h-4 w-4" />
236
239
  </button>
237
240
  <button
238
241
  onClick={onClose}
239
- className="rounded p-1.5 text-gray-400 hover:text-gray-600"
242
+ className="text-muted-foreground hover:text-muted-foreground rounded p-1.5"
240
243
  title="Close"
241
244
  >
242
245
  <X className="h-4 w-4" />
@@ -244,20 +247,20 @@ export function LivePreview({
244
247
  </div>
245
248
  </div>
246
249
 
247
- <div className="flex flex-1 justify-center overflow-auto bg-gray-100 p-4">
250
+ <div className="bg-muted flex flex-1 justify-center overflow-auto p-4">
248
251
  <div
249
252
  style={{ width: VIEWPORT_WIDTHS[viewport], maxWidth: '100%', transition: 'width 0.3s' }}
250
253
  className="relative"
251
254
  >
252
255
  {loading && (
253
- <div className="absolute inset-0 z-10 flex items-center justify-center rounded-lg bg-white/80">
256
+ <div className="bg-card/80 absolute inset-0 z-10 flex items-center justify-center rounded-lg">
254
257
  <div className="h-8 w-8 animate-spin rounded-full border-b-2 border-blue-600" />
255
258
  </div>
256
259
  )}
257
260
  <iframe
258
261
  ref={iframeRef}
259
262
  src={previewSrc}
260
- className="h-full w-full rounded-lg border border-gray-200 bg-white shadow-lg"
263
+ className="border-border bg-card h-full w-full rounded-lg border shadow-lg"
261
264
  style={{ minHeight: '600px' }}
262
265
  onLoad={() => setLoading(false)}
263
266
  title="Page Preview"
@@ -25,7 +25,7 @@ export function LogoPlaceholder({ tone, label }: LogoPlaceholderProps) {
25
25
  role="img"
26
26
  aria-label="Logo placeholder"
27
27
  title="Add a logo in Settings → Appearance"
28
- className="mx-auto mb-4 flex h-14 w-14 items-center justify-center rounded-lg border border-dashed border-gray-300 text-gray-400"
28
+ className="border-border text-muted-foreground mx-auto mb-4 flex h-14 w-14 items-center justify-center rounded-lg border border-dashed"
29
29
  >
30
30
  <ImagePlus className="h-6 w-6" aria-hidden="true" />
31
31
  </span>
@@ -283,11 +283,11 @@ export function MentionableTextarea({
283
283
  id={pickerId}
284
284
  role="listbox"
285
285
  aria-label="Mention a teammate"
286
- className="absolute top-full left-0 z-30 mt-1 max-h-56 w-64 overflow-y-auto rounded border border-gray-200 bg-white shadow-lg"
286
+ className="border-border bg-card absolute top-full left-0 z-30 mt-1 max-h-56 w-64 overflow-y-auto rounded border shadow-lg"
287
287
  data-testid={testId ? `${testId}-picker` : 'mention-picker'}
288
288
  >
289
289
  {picker.users.length === 0 ? (
290
- <p className="px-3 py-2 text-xs text-gray-500">
290
+ <p className="text-muted-foreground px-3 py-2 text-xs">
291
291
  {picker.query ? 'No matches' : 'Type a name…'}
292
292
  </p>
293
293
  ) : (
@@ -309,13 +309,13 @@ export function MentionableTextarea({
309
309
  onMouseEnter={() => setPicker((s) => ({ ...s, highlight: idx }))}
310
310
  className={`block w-full px-3 py-1.5 text-left text-xs ${
311
311
  idx === picker.highlight
312
- ? 'bg-blue-50 text-blue-900'
313
- : 'text-gray-800 hover:bg-gray-50'
312
+ ? 'bg-info/10 text-foreground'
313
+ : 'text-foreground hover:bg-accent'
314
314
  }`}
315
315
  data-testid={testId ? `${testId}-picker-row-${u.id}` : `mention-row-${u.id}`}
316
316
  >
317
317
  <div className="font-medium">{formatLabel(u)}</div>
318
- <div className="text-[10px] text-gray-500">{u.email}</div>
318
+ <div className="text-muted-foreground text-[10px]">{u.email}</div>
319
319
  </button>
320
320
  </li>
321
321
  ))}
@@ -246,7 +246,7 @@ export function NotificationBell({
246
246
  <div className={`relative ${className ?? ''}`} data-testid="notification-bell">
247
247
  <button
248
248
  type="button"
249
- className="relative rounded p-1.5 text-gray-600 hover:bg-gray-100 hover:text-gray-900"
249
+ className="text-muted-foreground hover:bg-accent hover:text-foreground relative rounded p-1.5"
250
250
  aria-label="Notifications"
251
251
  aria-haspopup="menu"
252
252
  aria-expanded={open}
@@ -256,7 +256,7 @@ export function NotificationBell({
256
256
  <BellIcon />
257
257
  {unread > 0 && (
258
258
  <span
259
- className="absolute -top-0.5 -right-0.5 inline-flex h-4 min-w-4 items-center justify-center rounded-full bg-red-600 px-1 text-[10px] font-medium text-white"
259
+ className="bg-destructive absolute -top-0.5 -right-0.5 inline-flex h-4 min-w-4 items-center justify-center rounded-full px-1 text-[10px] font-medium text-white"
260
260
  data-testid="bell-badge"
261
261
  >
262
262
  {unread > 99 ? '99+' : unread}
@@ -266,14 +266,14 @@ export function NotificationBell({
266
266
  {open && (
267
267
  <div
268
268
  role="menu"
269
- className="absolute right-0 z-50 mt-1 w-80 rounded border border-gray-200 bg-white shadow-lg"
269
+ className="border-border bg-card absolute right-0 z-50 mt-1 w-80 rounded border shadow-lg"
270
270
  data-testid="bell-dropdown"
271
271
  >
272
272
  <header className="flex items-center justify-between border-b border-gray-100 px-3 py-2">
273
- <span className="text-sm font-medium text-gray-900">Notifications</span>
273
+ <span className="text-foreground text-sm font-medium">Notifications</span>
274
274
  <button
275
275
  type="button"
276
- className="text-xs text-gray-600 hover:text-gray-900 disabled:opacity-50"
276
+ className="text-muted-foreground hover:text-foreground text-xs disabled:opacity-50"
277
277
  onClick={handleMarkAll}
278
278
  disabled={unread === 0}
279
279
  data-testid="bell-mark-all"
@@ -283,9 +283,9 @@ export function NotificationBell({
283
283
  </header>
284
284
  <div className="max-h-80 overflow-y-auto" aria-busy={loading} data-testid="bell-list">
285
285
  {loading ? (
286
- <p className="px-3 py-2 text-xs text-gray-500">Loading…</p>
286
+ <p className="text-muted-foreground px-3 py-2 text-xs">Loading…</p>
287
287
  ) : items.length === 0 ? (
288
- <p className="px-3 py-2 text-xs text-gray-500">All caught up.</p>
288
+ <p className="text-muted-foreground px-3 py-2 text-xs">All caught up.</p>
289
289
  ) : (
290
290
  <ul>
291
291
  {items.map((n) => (
@@ -293,15 +293,15 @@ export function NotificationBell({
293
293
  <button
294
294
  type="button"
295
295
  role="menuitem"
296
- className={`block w-full px-3 py-2 text-left text-xs hover:bg-gray-50 ${
297
- n.readAt ? 'text-gray-500' : 'font-medium text-gray-900'
296
+ className={`hover:bg-accent block w-full px-3 py-2 text-left text-xs ${
297
+ n.readAt ? 'text-muted-foreground' : 'text-foreground font-medium'
298
298
  }`}
299
299
  onClick={() => handleClickRow(n)}
300
300
  data-testid={`bell-row-${n.id}`}
301
301
  data-read={n.readAt ? 'true' : 'false'}
302
302
  >
303
303
  <div>{notificationSummary(n)}</div>
304
- <div className="mt-0.5 text-[10px] text-gray-400">{n.createdAt}</div>
304
+ <div className="text-muted-foreground mt-0.5 text-[10px]">{n.createdAt}</div>
305
305
  </button>
306
306
  </li>
307
307
  ))}
@@ -51,17 +51,17 @@ export function OfflineStatus({ connection, offline }: OfflineStatusProps): Reac
51
51
  export type OfflineTone = 'good' | 'warn' | 'info' | 'bad'
52
52
 
53
53
  const TONE_CLASSES: Record<OfflineTone, string> = {
54
- good: 'bg-emerald-50 text-emerald-700',
55
- warn: 'bg-amber-50 text-amber-800',
56
- info: 'bg-blue-50 text-blue-700',
57
- bad: 'bg-red-50 text-red-700',
54
+ good: 'bg-success/10 text-emerald-700',
55
+ warn: 'bg-warning/10 text-warning',
56
+ info: 'bg-info/10 text-info',
57
+ bad: 'bg-destructive/10 text-destructive',
58
58
  }
59
59
 
60
60
  const DOT_CLASSES: Record<OfflineTone, string> = {
61
- good: 'bg-emerald-500',
62
- warn: 'bg-amber-500',
63
- info: 'bg-blue-500',
64
- bad: 'bg-red-500',
61
+ good: 'bg-success',
62
+ warn: 'bg-warning',
63
+ info: 'bg-info',
64
+ bad: 'bg-destructive',
65
65
  }
66
66
 
67
67
  /**
@@ -70,7 +70,7 @@ export function PresenceChips({
70
70
  >
71
71
  {status && <StatusPill status={status} />}
72
72
  {shown.length === 0 && status !== 'connecting' && (
73
- <span className="text-gray-500" data-testid="presence-empty">
73
+ <span className="text-muted-foreground" data-testid="presence-empty">
74
74
  You're the only one here
75
75
  </span>
76
76
  )}
@@ -79,7 +79,7 @@ export function PresenceChips({
79
79
  ))}
80
80
  {overflow > 0 && (
81
81
  <span
82
- className="rounded-full bg-gray-100 px-2 py-0.5 text-gray-700"
82
+ className="bg-muted text-foreground rounded-full px-2 py-0.5"
83
83
  data-testid="presence-overflow"
84
84
  >
85
85
  +{overflow}
@@ -91,14 +91,18 @@ export function PresenceChips({
91
91
 
92
92
  function StatusPill({ status }: { status: CollaborationStatus }) {
93
93
  const palette: Record<CollaborationStatus, { dot: string; label: string; text: string }> = {
94
- connected: { dot: 'bg-emerald-500', label: 'Live', text: 'text-emerald-700' },
95
- connecting: { dot: 'bg-amber-400 animate-pulse', label: 'Connecting', text: 'text-amber-700' },
96
- disconnected: { dot: 'bg-gray-300', label: 'Offline', text: 'text-gray-500' },
94
+ connected: { dot: 'bg-success', label: 'Live', text: 'text-emerald-700' },
95
+ connecting: { dot: 'bg-amber-400 animate-pulse', label: 'Connecting', text: 'text-warning' },
96
+ disconnected: {
97
+ dot: 'bg-muted-foreground/30',
98
+ label: 'Offline',
99
+ text: 'text-muted-foreground',
100
+ },
97
101
  }
98
102
  const cfg = palette[status]
99
103
  return (
100
104
  <span
101
- className={`inline-flex items-center gap-1 rounded-full bg-gray-50 px-2 py-0.5 ${cfg.text}`}
105
+ className={`bg-muted inline-flex items-center gap-1 rounded-full px-2 py-0.5 ${cfg.text}`}
102
106
  data-testid={`presence-status-${status}`}
103
107
  >
104
108
  <span className={`h-1.5 w-1.5 rounded-full ${cfg.dot}`} />
@@ -111,7 +115,7 @@ function Chip({ name, color, avatarUrl }: { name: string; color: string; avatarU
111
115
  const initials = nameToInitials(name)
112
116
  return (
113
117
  <span
114
- className="inline-flex items-center gap-1 rounded-full bg-white px-1.5 py-0.5 ring-1 ring-gray-200"
118
+ className="bg-card inline-flex items-center gap-1 rounded-full px-1.5 py-0.5 ring-1 ring-gray-200"
115
119
  title={name}
116
120
  data-testid="presence-chip"
117
121
  >
@@ -131,7 +135,7 @@ function Chip({ name, color, avatarUrl }: { name: string; color: string; avatarU
131
135
  {initials}
132
136
  </span>
133
137
  )}
134
- <span className="max-w-[80px] truncate text-gray-700">{name}</span>
138
+ <span className="text-foreground max-w-[80px] truncate">{name}</span>
135
139
  </span>
136
140
  )
137
141
  }