@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
@@ -6,7 +6,7 @@ import { useApiData } from '../lib/useApiData.js';
6
6
  function ScoreBadge({ score }) {
7
7
  const color = score >= 80 ? 'text-green-600' : score >= 60 ? 'text-amber-500' : 'text-red-500';
8
8
  const bg = score >= 80 ? 'bg-green-50' : score >= 60 ? 'bg-amber-50' : 'bg-red-50';
9
- return (_jsx("span", { className: `inline-flex items-center justify-center w-9 h-9 rounded-full text-sm font-semibold ${color} ${bg}`, children: score }));
9
+ return (_jsx("span", { className: `inline-flex h-9 w-9 items-center justify-center rounded-full text-sm font-semibold ${color} ${bg}`, children: score }));
10
10
  }
11
11
  export function SEOPerformance({ onNavigate }) {
12
12
  const { data, loading, error } = useApiData('/seo/summary');
@@ -19,6 +19,6 @@ export function SEOPerformance({ onNavigate }) {
19
19
  const topContent = data.topContent ?? [];
20
20
  const totalPages = Math.max(1, Math.ceil(topContent.length / perPage));
21
21
  const visible = topContent.slice(page * perPage, (page + 1) * perPage);
22
- return (_jsxs("div", { className: "bg-white rounded-lg border border-gray-200", children: [_jsxs("div", { className: "p-4 border-b border-gray-200 flex items-center justify-between", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Search, { className: "w-4 h-4 text-gray-500" }), _jsx("h2", { className: "text-sm font-semibold text-gray-900", children: "SEO Performance" })] }), totalIssues > 0 && (_jsxs("span", { className: "text-xs text-gray-500", children: [totalIssues, " issue", totalIssues !== 1 ? 's' : '', " found"] }))] }), _jsxs("div", { className: "grid grid-cols-1 lg:grid-cols-12 divide-y lg:divide-y-0 lg:divide-x divide-gray-200", children: [_jsxs("div", { className: "lg:col-span-7 p-4", children: [_jsx("h3", { className: "text-sm font-medium text-gray-700 mb-3", children: "Top Performing Content" }), _jsxs("div", { className: "space-y-2", children: [visible.map((item) => (_jsxs("div", { className: "flex items-center justify-between py-2", children: [_jsxs("div", { className: "flex-1 min-w-0 mr-3", children: [_jsx("p", { className: "text-sm font-medium text-gray-900 truncate", children: item.title }), _jsx("p", { className: "text-xs text-gray-500 capitalize", children: item.collection })] }), _jsx(ScoreBadge, { score: item.score })] }, item.id))), visible.length === 0 && (_jsx("p", { className: "text-sm text-gray-400 py-4 text-center", children: "No published content yet" }))] }), topContent.length > perPage && (_jsxs("div", { className: "flex items-center justify-between mt-3 pt-3 border-t border-gray-100 text-xs text-gray-500", children: [_jsxs("span", { children: ["Showing ", page * perPage + 1, "-", Math.min((page + 1) * perPage, topContent.length), " of", ' ', topContent.length] }), _jsxs("div", { className: "flex items-center gap-1", children: [_jsx("button", { onClick: () => setPage(Math.max(0, page - 1)), disabled: page === 0, className: "p-1 rounded hover:bg-gray-100 disabled:opacity-30", children: _jsx(ChevronLeft, { className: "w-3.5 h-3.5" }) }), _jsxs("span", { children: ["Page ", page + 1, " of ", totalPages] }), _jsx("button", { onClick: () => setPage(Math.min(totalPages - 1, page + 1)), disabled: page >= totalPages - 1, className: "p-1 rounded hover:bg-gray-100 disabled:opacity-30", children: _jsx(ChevronRight, { className: "w-3.5 h-3.5" }) })] })] }))] }), _jsxs("div", { className: "lg:col-span-5 p-4", children: [_jsx("h3", { className: "text-sm font-medium text-gray-700 mb-3", children: "SEO Issues" }), _jsxs("div", { className: "space-y-3", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(FileWarning, { className: "w-4 h-4 text-red-400" }), _jsx("span", { className: "text-sm text-gray-700", children: "Missing meta descriptions" })] }), _jsx("span", { className: "text-sm font-semibold text-gray-900", children: issues.missingMetaDescriptions })] }), _jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(LinkIcon, { className: "w-4 h-4 text-red-400" }), _jsx("span", { className: "text-sm text-gray-700", children: "Broken internal links" })] }), _jsx("span", { className: "text-sm font-semibold text-gray-900", children: issues.brokenInternalLinks })] }), _jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(ImageOff, { className: "w-4 h-4 text-red-400" }), _jsx("span", { className: "text-sm text-gray-700", children: "Missing alt text" })] }), _jsx("span", { className: "text-sm font-semibold text-gray-900", children: issues.missingAltText })] })] }), totalIssues > 0 && (_jsx("button", { onClick: () => onNavigate?.('/seo'), className: "mt-4 text-sm text-blue-600 hover:text-blue-700 font-medium", children: "View All Issues" }))] })] })] }));
22
+ return (_jsxs("div", { className: "rounded-lg border border-gray-200 bg-white", children: [_jsxs("div", { className: "flex items-center justify-between border-b border-gray-200 p-4", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Search, { className: "h-4 w-4 text-gray-500" }), _jsx("h2", { className: "text-sm font-semibold text-gray-900", children: "SEO Performance" })] }), totalIssues > 0 && (_jsxs("span", { className: "text-xs text-gray-500", children: [totalIssues, " issue", totalIssues !== 1 ? 's' : '', " found"] }))] }), _jsxs("div", { className: "grid grid-cols-1 divide-y divide-gray-200 lg:grid-cols-12 lg:divide-x lg:divide-y-0", children: [_jsxs("div", { className: "p-4 lg:col-span-7", children: [_jsx("h3", { className: "mb-3 text-sm font-medium text-gray-700", children: "Top Performing Content" }), _jsxs("div", { className: "space-y-2", children: [visible.map((item) => (_jsxs("div", { className: "flex items-center justify-between py-2", children: [_jsxs("div", { className: "mr-3 min-w-0 flex-1", children: [_jsx("p", { className: "truncate text-sm font-medium text-gray-900", children: item.title }), _jsx("p", { className: "text-xs text-gray-500 capitalize", children: item.collection })] }), _jsx(ScoreBadge, { score: item.score })] }, item.id))), visible.length === 0 && (_jsx("p", { className: "py-4 text-center text-sm text-gray-400", children: "No published content yet" }))] }), topContent.length > perPage && (_jsxs("div", { className: "mt-3 flex items-center justify-between border-t border-gray-100 pt-3 text-xs text-gray-500", children: [_jsxs("span", { children: ["Showing ", page * perPage + 1, "-", Math.min((page + 1) * perPage, topContent.length), " of", ' ', topContent.length] }), _jsxs("div", { className: "flex items-center gap-1", children: [_jsx("button", { onClick: () => setPage(Math.max(0, page - 1)), disabled: page === 0, className: "rounded p-1 hover:bg-gray-100 disabled:opacity-30", children: _jsx(ChevronLeft, { className: "h-3.5 w-3.5" }) }), _jsxs("span", { children: ["Page ", page + 1, " of ", totalPages] }), _jsx("button", { onClick: () => setPage(Math.min(totalPages - 1, page + 1)), disabled: page >= totalPages - 1, className: "rounded p-1 hover:bg-gray-100 disabled:opacity-30", children: _jsx(ChevronRight, { className: "h-3.5 w-3.5" }) })] })] }))] }), _jsxs("div", { className: "p-4 lg:col-span-5", children: [_jsx("h3", { className: "mb-3 text-sm font-medium text-gray-700", children: "SEO Issues" }), _jsxs("div", { className: "space-y-3", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(FileWarning, { className: "h-4 w-4 text-red-400" }), _jsx("span", { className: "text-sm text-gray-700", children: "Missing meta descriptions" })] }), _jsx("span", { className: "text-sm font-semibold text-gray-900", children: issues.missingMetaDescriptions })] }), _jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(LinkIcon, { className: "h-4 w-4 text-red-400" }), _jsx("span", { className: "text-sm text-gray-700", children: "Broken internal links" })] }), _jsx("span", { className: "text-sm font-semibold text-gray-900", children: issues.brokenInternalLinks })] }), _jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(ImageOff, { className: "h-4 w-4 text-red-400" }), _jsx("span", { className: "text-sm text-gray-700", children: "Missing alt text" })] }), _jsx("span", { className: "text-sm font-semibold text-gray-900", children: issues.missingAltText })] })] }), totalIssues > 0 && (_jsx("button", { onClick: () => onNavigate?.('/seo'), className: "mt-4 text-sm font-medium text-blue-600 hover:text-blue-700", children: "View All Issues" }))] })] })] }));
23
23
  }
24
24
  //# sourceMappingURL=SEOPerformance.js.map
@@ -0,0 +1,18 @@
1
+ export interface SchedulePublishDialogProps {
2
+ collectionSlug: string;
3
+ documentId: string;
4
+ /** Existing scheduled publish time, if any. */
5
+ scheduledAt?: string | null;
6
+ /** Existing scheduled unpublish time, if any. */
7
+ scheduledUnpublishAt?: string | null;
8
+ open: boolean;
9
+ onClose: () => void;
10
+ /** Called with the updated schedule fields after a successful save. */
11
+ onScheduled?: (next: {
12
+ status: string;
13
+ scheduledAt: string | null;
14
+ scheduledUnpublishAt: string | null;
15
+ }) => void;
16
+ }
17
+ export declare function SchedulePublishDialog({ collectionSlug, documentId, scheduledAt, scheduledUnpublishAt, open, onClose, onScheduled, }: SchedulePublishDialogProps): import("react/jsx-runtime").JSX.Element | null;
18
+ //# sourceMappingURL=SchedulePublishDialog.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SchedulePublishDialog.d.ts","sourceRoot":"","sources":["../../src/components/SchedulePublishDialog.tsx"],"names":[],"mappings":"AAOA,MAAM,WAAW,0BAA0B;IACzC,cAAc,EAAE,MAAM,CAAA;IACtB,UAAU,EAAE,MAAM,CAAA;IAClB,+CAA+C;IAC/C,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC3B,iDAAiD;IACjD,oBAAoB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACpC,IAAI,EAAE,OAAO,CAAA;IACb,OAAO,EAAE,MAAM,IAAI,CAAA;IACnB,uEAAuE;IACvE,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE;QACnB,MAAM,EAAE,MAAM,CAAA;QACd,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;QAC1B,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAA;KACpC,KAAK,IAAI,CAAA;CACX;AAsBD,wBAAgB,qBAAqB,CAAC,EACpC,cAAc,EACd,UAAU,EACV,WAAW,EACX,oBAAoB,EACpB,IAAI,EACJ,OAAO,EACP,WAAW,GACZ,EAAE,0BAA0B,kDA4L5B"}
@@ -0,0 +1,106 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useEffect, useState } from 'react';
4
+ import { Calendar, Clock, Loader2, X } from 'lucide-react';
5
+ import { toast } from 'sonner';
6
+ import { cmsApi } from '../lib/api.js';
7
+ /**
8
+ * Convert a Date or ISO string to the `YYYY-MM-DDTHH:mm` shape that the
9
+ * `<input type="datetime-local">` element expects, in the user's local
10
+ * timezone (the input is timezone-naive but we present + parse it as local).
11
+ */
12
+ function toLocalDateTimeInput(value) {
13
+ if (!value)
14
+ return '';
15
+ const d = typeof value === 'string' ? new Date(value) : value;
16
+ if (Number.isNaN(d.getTime()))
17
+ return '';
18
+ const pad = (n) => String(n).padStart(2, '0');
19
+ return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}T${pad(d.getHours())}:${pad(d.getMinutes())}`;
20
+ }
21
+ /** Round "now + 1 hour" to the next quarter-hour for a friendly default. */
22
+ function defaultScheduleTime() {
23
+ const d = new Date(Date.now() + 60 * 60 * 1000);
24
+ d.setMinutes(Math.ceil(d.getMinutes() / 15) * 15, 0, 0);
25
+ return toLocalDateTimeInput(d);
26
+ }
27
+ export function SchedulePublishDialog({ collectionSlug, documentId, scheduledAt, scheduledUnpublishAt, open, onClose, onScheduled, }) {
28
+ const [publishAt, setPublishAt] = useState('');
29
+ const [unpublishAt, setUnpublishAt] = useState('');
30
+ const [includeUnpublish, setIncludeUnpublish] = useState(false);
31
+ const [saving, setSaving] = useState(false);
32
+ const [cancelling, setCancelling] = useState(false);
33
+ const hasExistingSchedule = Boolean(scheduledAt || scheduledUnpublishAt);
34
+ useEffect(() => {
35
+ if (!open)
36
+ return;
37
+ setPublishAt(scheduledAt ? toLocalDateTimeInput(scheduledAt) : defaultScheduleTime());
38
+ setUnpublishAt(scheduledUnpublishAt ? toLocalDateTimeInput(scheduledUnpublishAt) : '');
39
+ setIncludeUnpublish(Boolean(scheduledUnpublishAt));
40
+ }, [open, scheduledAt, scheduledUnpublishAt]);
41
+ async function handleSave() {
42
+ if (!publishAt && !(includeUnpublish && unpublishAt)) {
43
+ toast.error('Pick a publish or unpublish time');
44
+ return;
45
+ }
46
+ // datetime-local is parsed by the browser as local time; new Date() on
47
+ // that string respects the user's timezone and serialises to a UTC
48
+ // ISO string the server can compare against `Date.now()` cleanly.
49
+ const publishDate = publishAt ? new Date(publishAt) : null;
50
+ const unpublishDate = includeUnpublish && unpublishAt ? new Date(unpublishAt) : null;
51
+ if (publishDate && publishDate.getTime() <= Date.now()) {
52
+ toast.error('Publish time must be in the future');
53
+ return;
54
+ }
55
+ if (unpublishDate && unpublishDate.getTime() <= Date.now()) {
56
+ toast.error('Unpublish time must be in the future');
57
+ return;
58
+ }
59
+ if (publishDate && unpublishDate && unpublishDate <= publishDate) {
60
+ toast.error('Unpublish time must be after publish time');
61
+ return;
62
+ }
63
+ setSaving(true);
64
+ const res = await cmsApi(`/collections/${collectionSlug}/${documentId}/schedule`, {
65
+ method: 'POST',
66
+ body: JSON.stringify({
67
+ scheduledAt: publishDate ? publishDate.toISOString() : null,
68
+ scheduledUnpublishAt: unpublishDate ? unpublishDate.toISOString() : null,
69
+ }),
70
+ });
71
+ setSaving(false);
72
+ if (res.error) {
73
+ toast.error(res.error);
74
+ return;
75
+ }
76
+ toast.success(publishDate ? 'Publish scheduled' : 'Unpublish scheduled');
77
+ onScheduled?.({
78
+ status: res.data?.status ?? 'SCHEDULED',
79
+ scheduledAt: res.data?.scheduledAt ?? (publishDate ? publishDate.toISOString() : null),
80
+ scheduledUnpublishAt: res.data?.scheduledUnpublishAt ?? (unpublishDate ? unpublishDate.toISOString() : null),
81
+ });
82
+ onClose();
83
+ }
84
+ async function handleCancelSchedule() {
85
+ setCancelling(true);
86
+ const res = await cmsApi(`/collections/${collectionSlug}/${documentId}/schedule`, {
87
+ method: 'DELETE',
88
+ });
89
+ setCancelling(false);
90
+ if (res.error) {
91
+ toast.error(res.error);
92
+ return;
93
+ }
94
+ toast.success('Schedule cancelled');
95
+ onScheduled?.({
96
+ status: res.data?.status ?? 'DRAFT',
97
+ scheduledAt: null,
98
+ scheduledUnpublishAt: null,
99
+ });
100
+ onClose();
101
+ }
102
+ if (!open)
103
+ return null;
104
+ return (_jsxs("div", { className: "fixed inset-0 z-50 flex items-center justify-center p-4", children: [_jsx("div", { className: "fixed inset-0 bg-black/40", onClick: onClose }), _jsxs("div", { className: "relative w-full max-w-md rounded-lg bg-white shadow-xl", children: [_jsxs("div", { className: "flex items-center justify-between border-b border-gray-200 px-4 py-3", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Calendar, { className: "h-5 w-5 text-gray-600" }), _jsx("h2", { className: "text-lg font-semibold text-gray-900", children: "Schedule publishing" })] }), _jsx("button", { onClick: onClose, className: "rounded-lg p-1.5 transition-colors hover:bg-gray-100", children: _jsx(X, { className: "h-5 w-5 text-gray-500" }) })] }), _jsxs("div", { className: "space-y-4 px-4 py-4", children: [_jsxs("div", { className: "space-y-1.5", children: [_jsx("label", { className: "text-sm font-medium text-gray-700", children: "Publish at" }), _jsxs("div", { className: "relative", children: [_jsx(Clock, { className: "pointer-events-none absolute top-2.5 left-2.5 h-4 w-4 text-gray-400" }), _jsx("input", { type: "datetime-local", value: publishAt, onChange: (e) => setPublishAt(e.target.value), min: toLocalDateTimeInput(new Date(Date.now() + 60 * 1000)), className: "w-full rounded-md border border-gray-300 bg-white py-2 pr-3 pl-9 text-sm focus:border-blue-500 focus:ring-1 focus:ring-blue-500 focus:outline-none" })] }), _jsx("p", { className: "text-xs text-gray-500", children: "The document will move from DRAFT to PUBLISHED at this time (your local timezone)." })] }), _jsxs("label", { className: "flex items-center gap-2 text-sm text-gray-700", children: [_jsx("input", { type: "checkbox", checked: includeUnpublish, onChange: (e) => setIncludeUnpublish(e.target.checked), className: "h-4 w-4 rounded border-gray-300 text-blue-600 focus:ring-blue-500" }), "Also schedule an unpublish"] }), includeUnpublish && (_jsxs("div", { className: "space-y-1.5", children: [_jsx("label", { className: "text-sm font-medium text-gray-700", children: "Unpublish at" }), _jsxs("div", { className: "relative", children: [_jsx(Clock, { className: "pointer-events-none absolute top-2.5 left-2.5 h-4 w-4 text-gray-400" }), _jsx("input", { type: "datetime-local", value: unpublishAt, onChange: (e) => setUnpublishAt(e.target.value), min: publishAt || toLocalDateTimeInput(new Date(Date.now() + 60 * 1000)), className: "w-full rounded-md border border-gray-300 bg-white py-2 pr-3 pl-9 text-sm focus:border-blue-500 focus:ring-1 focus:ring-blue-500 focus:outline-none" })] })] }))] }), _jsxs("div", { className: "flex items-center justify-between gap-2 border-t border-gray-200 px-4 py-3", children: [hasExistingSchedule ? (_jsxs("button", { onClick: handleCancelSchedule, disabled: cancelling || saving, className: "inline-flex items-center gap-1.5 rounded-md px-3 py-1.5 text-sm font-medium text-red-700 hover:bg-red-50 disabled:opacity-50", children: [cancelling ? (_jsx(Loader2, { className: "h-4 w-4 animate-spin" })) : (_jsx(X, { className: "h-4 w-4" })), "Cancel schedule"] })) : (_jsx("span", {})), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx("button", { onClick: onClose, className: "rounded-md px-3 py-1.5 text-sm text-gray-700 hover:bg-gray-100", children: "Close" }), _jsxs("button", { onClick: handleSave, disabled: saving || cancelling, className: "inline-flex items-center gap-1.5 rounded-md bg-blue-600 px-3 py-1.5 text-sm font-medium text-white hover:bg-blue-700 disabled:opacity-50", children: [saving ? (_jsx(Loader2, { className: "h-4 w-4 animate-spin" })) : (_jsx(Calendar, { className: "h-4 w-4" })), hasExistingSchedule ? 'Reschedule' : 'Schedule'] })] })] })] })] }));
105
+ }
106
+ //# sourceMappingURL=SchedulePublishDialog.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SchedulePublishDialog.js","sourceRoot":"","sources":["../../src/components/SchedulePublishDialog.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ export interface SharePreviewLinkDialogProps {
2
+ collectionSlug: string;
3
+ documentId: string;
4
+ /** Document slug, used to build a friendly preview URL. */
5
+ documentSlug?: string | null;
6
+ /**
7
+ * Optional site URL (https://...) to prepend. If omitted we just emit the
8
+ * relative path and ask the admin to share it however they want.
9
+ */
10
+ siteUrl?: string;
11
+ /** Custom URL prefix for this collection (e.g. /blog). Defaults to slug. */
12
+ urlPrefix?: string;
13
+ open: boolean;
14
+ onClose: () => void;
15
+ }
16
+ export declare function SharePreviewLinkDialog({ collectionSlug, documentId, documentSlug, siteUrl, urlPrefix, open, onClose, }: SharePreviewLinkDialogProps): import("react/jsx-runtime").JSX.Element | null;
17
+ //# sourceMappingURL=SharePreviewLinkDialog.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SharePreviewLinkDialog.d.ts","sourceRoot":"","sources":["../../src/components/SharePreviewLinkDialog.tsx"],"names":[],"mappings":"AAOA,MAAM,WAAW,2BAA2B;IAC1C,cAAc,EAAE,MAAM,CAAA;IACtB,UAAU,EAAE,MAAM,CAAA;IAClB,2DAA2D;IAC3D,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC5B;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,4EAA4E;IAC5E,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,IAAI,EAAE,OAAO,CAAA;IACb,OAAO,EAAE,MAAM,IAAI,CAAA;CACpB;AAyCD,wBAAgB,sBAAsB,CAAC,EACrC,cAAc,EACd,UAAU,EACV,YAAY,EACZ,OAAO,EACP,SAAS,EACT,IAAI,EACJ,OAAO,GACR,EAAE,2BAA2B,kDA4J7B"}
@@ -0,0 +1,83 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useState } from 'react';
4
+ import { Check, Copy, Link2, Loader2, Share2, X } from 'lucide-react';
5
+ import { toast } from 'sonner';
6
+ import { cmsApi } from '../lib/api.js';
7
+ const TTL_CHOICES = [
8
+ { label: '1 hour', seconds: 60 * 60, hint: 'Quick review' },
9
+ { label: '1 day', seconds: 24 * 60 * 60, hint: 'Single workday' },
10
+ { label: '7 days', seconds: 7 * 24 * 60 * 60, hint: 'Client review' },
11
+ { label: '30 days', seconds: 30 * 24 * 60 * 60, hint: 'Long-running staging' },
12
+ ];
13
+ function buildPreviewUrl({ siteUrl, urlPrefix, collectionSlug, documentSlug, token, }) {
14
+ const base = (siteUrl ?? '').replace(/\/+$/, '');
15
+ // Build the same path /resolve would match: <urlPrefix>/<slug>, or
16
+ // /<slug> for top-level page collections. If there's no slug yet we
17
+ // fall back to /admin's preview endpoint as a safety net.
18
+ const slug = documentSlug?.toString().trim() ?? '';
19
+ if (!slug) {
20
+ return `${base}/preview/${collectionSlug}/_?token=${encodeURIComponent(token)}`;
21
+ }
22
+ const prefix = (urlPrefix ?? collectionSlug).replace(/^\/+|\/+$/g, '');
23
+ const path = prefix ? `/${prefix}/${slug}` : `/${slug}`;
24
+ return `${base}${path}?preview=${encodeURIComponent(token)}`;
25
+ }
26
+ export function SharePreviewLinkDialog({ collectionSlug, documentId, documentSlug, siteUrl, urlPrefix, open, onClose, }) {
27
+ const [ttl, setTtl] = useState(TTL_CHOICES[2].seconds);
28
+ const [token, setToken] = useState('');
29
+ const [previewUrl, setPreviewUrl] = useState('');
30
+ const [expiresAt, setExpiresAt] = useState('');
31
+ const [generating, setGenerating] = useState(false);
32
+ const [copied, setCopied] = useState(false);
33
+ async function generate() {
34
+ setGenerating(true);
35
+ const res = await cmsApi('/preview/token', {
36
+ method: 'POST',
37
+ body: JSON.stringify({
38
+ collection: collectionSlug,
39
+ documentId,
40
+ ttlSeconds: ttl,
41
+ }),
42
+ });
43
+ setGenerating(false);
44
+ if (res.error || !res.data) {
45
+ toast.error(res.error ?? 'Failed to create preview token');
46
+ return;
47
+ }
48
+ const data = res.data;
49
+ setToken(data.token);
50
+ setExpiresAt(data.expiresAt ?? '');
51
+ const url = buildPreviewUrl({
52
+ siteUrl,
53
+ urlPrefix,
54
+ collectionSlug,
55
+ documentSlug: data.slug ?? documentSlug,
56
+ token: data.token,
57
+ });
58
+ setPreviewUrl(url);
59
+ setCopied(false);
60
+ }
61
+ async function copyToClipboard() {
62
+ if (!previewUrl)
63
+ return;
64
+ try {
65
+ await navigator.clipboard.writeText(previewUrl);
66
+ setCopied(true);
67
+ toast.success('Preview link copied');
68
+ setTimeout(() => setCopied(false), 2000);
69
+ }
70
+ catch {
71
+ toast.error("Couldn't copy to clipboard");
72
+ }
73
+ }
74
+ if (!open)
75
+ return null;
76
+ return (_jsxs("div", { className: "fixed inset-0 z-50 flex items-center justify-center p-4", children: [_jsx("div", { className: "fixed inset-0 bg-black/40", onClick: onClose }), _jsxs("div", { className: "relative w-full max-w-lg rounded-lg bg-white shadow-xl", children: [_jsxs("div", { className: "flex items-center justify-between border-b border-gray-200 px-4 py-3", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Share2, { className: "h-5 w-5 text-gray-600" }), _jsx("h2", { className: "text-lg font-semibold text-gray-900", children: "Share preview link" })] }), _jsx("button", { onClick: onClose, className: "rounded-lg p-1.5 transition-colors hover:bg-gray-100", children: _jsx(X, { className: "h-5 w-5 text-gray-500" }) })] }), _jsxs("div", { className: "space-y-4 px-4 py-4", children: [_jsx("p", { className: "text-sm text-gray-600", children: "Generate a signed URL that lets anyone with the link view the current draft of this document \u2014 even if it's never been published." }), _jsxs("div", { className: "space-y-2", children: [_jsx("label", { className: "text-sm font-medium text-gray-700", children: "Link lifetime" }), _jsx("div", { className: "grid grid-cols-2 gap-2", children: TTL_CHOICES.map((choice) => {
77
+ const selected = ttl === choice.seconds;
78
+ return (_jsxs("button", { onClick: () => setTtl(choice.seconds), className: `rounded-md border px-3 py-2 text-left text-sm transition-colors ${selected
79
+ ? 'border-blue-500 bg-blue-50 text-blue-900'
80
+ : 'border-gray-200 hover:border-gray-300 hover:bg-gray-50'}`, children: [_jsx("div", { className: "font-medium", children: choice.label }), _jsx("div", { className: "text-xs text-gray-500", children: choice.hint })] }, choice.seconds));
81
+ }) }), _jsx("p", { className: "text-xs text-gray-500", children: "Preview tokens can't be revoked individually \u2014 pick the shortest TTL that fits." })] }), previewUrl ? (_jsxs("div", { className: "space-y-2 rounded-lg border border-gray-200 bg-gray-50 p-3", children: [_jsx("label", { className: "text-xs font-medium tracking-wide text-gray-500 uppercase", children: "Preview URL" }), _jsxs("div", { className: "flex items-stretch gap-2", children: [_jsx("input", { readOnly: true, value: previewUrl, onFocus: (e) => e.currentTarget.select(), className: "flex-1 rounded-md border border-gray-300 bg-white px-2 py-1.5 font-mono text-xs" }), _jsxs("button", { onClick: copyToClipboard, className: "inline-flex items-center gap-1.5 rounded-md bg-gray-900 px-3 py-1.5 text-xs font-medium text-white hover:bg-gray-700", children: [copied ? _jsx(Check, { className: "h-3.5 w-3.5" }) : _jsx(Copy, { className: "h-3.5 w-3.5" }), copied ? 'Copied' : 'Copy'] })] }), expiresAt && (_jsxs("p", { className: "text-xs text-gray-500", children: ["Expires ", new Date(expiresAt).toLocaleString()] }))] })) : null] }), _jsxs("div", { className: "flex items-center justify-end gap-2 border-t border-gray-200 px-4 py-3", children: [_jsx("button", { onClick: onClose, className: "rounded-md px-3 py-1.5 text-sm text-gray-700 hover:bg-gray-100", children: "Close" }), _jsxs("button", { onClick: generate, disabled: generating, className: "inline-flex items-center gap-1.5 rounded-md bg-blue-600 px-3 py-1.5 text-sm font-medium text-white hover:bg-blue-700 disabled:opacity-50", children: [generating ? (_jsx(Loader2, { className: "h-4 w-4 animate-spin" })) : (_jsx(Link2, { className: "h-4 w-4" })), previewUrl ? 'Generate new link' : 'Generate link'] })] })] })] }));
82
+ }
83
+ //# sourceMappingURL=SharePreviewLinkDialog.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SharePreviewLinkDialog.js","sourceRoot":"","sources":["../../src/components/SharePreviewLinkDialog.tsx"],"names":[],"mappings":"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"}
@@ -98,12 +98,12 @@ const editorStyles = `
98
98
  }
99
99
  `;
100
100
  function ToolbarButton({ onClick, isActive = false, disabled = false, title, children, }) {
101
- return (_jsx("button", { type: "button", onClick: onClick, disabled: disabled, title: title, className: `p-1.5 rounded transition-colors ${isActive
101
+ return (_jsx("button", { type: "button", onClick: onClick, disabled: disabled, title: title, className: `rounded p-1.5 transition-colors ${isActive
102
102
  ? 'bg-blue-100 text-blue-700'
103
- : 'text-gray-600 hover:bg-gray-100 hover:text-gray-900'} ${disabled ? 'opacity-40 cursor-not-allowed' : ''}`, children: children }));
103
+ : 'text-gray-600 hover:bg-gray-100 hover:text-gray-900'} ${disabled ? 'cursor-not-allowed opacity-40' : ''}`, children: children }));
104
104
  }
105
105
  function Divider() {
106
- return _jsx("div", { className: "w-px h-6 bg-gray-200 mx-1" });
106
+ return _jsx("div", { className: "mx-1 h-6 w-px bg-gray-200" });
107
107
  }
108
108
  function Toolbar({ editor, onOpenMediaPicker }) {
109
109
  const addLink = () => {
@@ -121,7 +121,7 @@ function Toolbar({ editor, onOpenMediaPicker }) {
121
121
  editor.chain().focus().insertTable({ rows: 3, cols: 3, withHeaderRow: true }).run();
122
122
  };
123
123
  const isInTable = editor.isActive('table');
124
- return (_jsxs("div", { className: "border-b border-gray-200 bg-gray-50 p-2 flex items-center gap-0.5 flex-wrap sticky top-0 z-10", children: [_jsx(ToolbarButton, { onClick: () => editor.chain().focus().toggleBold().run(), isActive: editor.isActive('bold'), title: "Bold (Ctrl+B)", children: _jsx(Bold, { className: "w-4 h-4" }) }), _jsx(ToolbarButton, { onClick: () => editor.chain().focus().toggleItalic().run(), isActive: editor.isActive('italic'), title: "Italic (Ctrl+I)", children: _jsx(Italic, { className: "w-4 h-4" }) }), _jsx(ToolbarButton, { onClick: () => editor.chain().focus().toggleUnderline().run(), isActive: editor.isActive('underline'), title: "Underline (Ctrl+U)", children: _jsx(Underline, { className: "w-4 h-4" }) }), _jsx(ToolbarButton, { onClick: () => editor.chain().focus().toggleStrike().run(), isActive: editor.isActive('strike'), title: "Strikethrough", children: _jsx(Strikethrough, { className: "w-4 h-4" }) }), _jsx(ToolbarButton, { onClick: () => editor.chain().focus().toggleCode().run(), isActive: editor.isActive('code'), title: "Inline code", children: _jsx(Code, { className: "w-4 h-4" }) }), _jsx(Divider, {}), _jsx(ToolbarButton, { onClick: () => editor.chain().focus().toggleHeading({ level: 1 }).run(), isActive: editor.isActive('heading', { level: 1 }), title: "Heading 1", children: _jsx(Heading1, { className: "w-4 h-4" }) }), _jsx(ToolbarButton, { onClick: () => editor.chain().focus().toggleHeading({ level: 2 }).run(), isActive: editor.isActive('heading', { level: 2 }), title: "Heading 2", children: _jsx(Heading2, { className: "w-4 h-4" }) }), _jsx(ToolbarButton, { onClick: () => editor.chain().focus().toggleHeading({ level: 3 }).run(), isActive: editor.isActive('heading', { level: 3 }), title: "Heading 3", children: _jsx(Heading3, { className: "w-4 h-4" }) }), _jsx(Divider, {}), _jsx(ToolbarButton, { onClick: () => editor.chain().focus().toggleBulletList().run(), isActive: editor.isActive('bulletList'), title: "Bullet list", children: _jsx(List, { className: "w-4 h-4" }) }), _jsx(ToolbarButton, { onClick: () => editor.chain().focus().toggleOrderedList().run(), isActive: editor.isActive('orderedList'), title: "Ordered list", children: _jsx(ListOrdered, { className: "w-4 h-4" }) }), _jsx(ToolbarButton, { onClick: () => editor.chain().focus().toggleBlockquote().run(), isActive: editor.isActive('blockquote'), title: "Blockquote", children: _jsx(Quote, { className: "w-4 h-4" }) }), _jsx(ToolbarButton, { onClick: () => editor.chain().focus().toggleCodeBlock().run(), isActive: editor.isActive('codeBlock'), title: "Code block", children: _jsx(FileCode, { className: "w-4 h-4" }) }), _jsx(ToolbarButton, { onClick: () => editor.chain().focus().setHorizontalRule().run(), title: "Horizontal rule", children: _jsx(Minus, { className: "w-4 h-4" }) }), _jsx(Divider, {}), _jsx(ToolbarButton, { onClick: () => editor.chain().focus().setTextAlign('left').run(), isActive: editor.isActive({ textAlign: 'left' }), title: "Align left", children: _jsx(AlignLeft, { className: "w-4 h-4" }) }), _jsx(ToolbarButton, { onClick: () => editor.chain().focus().setTextAlign('center').run(), isActive: editor.isActive({ textAlign: 'center' }), title: "Align center", children: _jsx(AlignCenter, { className: "w-4 h-4" }) }), _jsx(ToolbarButton, { onClick: () => editor.chain().focus().setTextAlign('right').run(), isActive: editor.isActive({ textAlign: 'right' }), title: "Align right", children: _jsx(AlignRight, { className: "w-4 h-4" }) }), _jsx(Divider, {}), _jsx(ToolbarButton, { onClick: addLink, isActive: editor.isActive('link'), title: "Insert link", children: _jsx(LinkIcon, { className: "w-4 h-4" }) }), _jsx(ToolbarButton, { onClick: onOpenMediaPicker, title: "Insert image", children: _jsx(ImageIcon, { className: "w-4 h-4" }) }), _jsx(ToolbarButton, { onClick: insertTable, title: "Insert table (3\u00D73)", children: _jsx(TableIcon, { className: "w-4 h-4" }) }), isInTable && (_jsxs(_Fragment, { children: [_jsx(Divider, {}), _jsx(ToolbarButton, { onClick: () => editor.chain().focus().addColumnBefore().run(), title: "Add column before", children: _jsx(Columns, { className: "w-4 h-4" }) }), _jsx(ToolbarButton, { onClick: () => editor.chain().focus().addColumnAfter().run(), title: "Add column after", children: _jsx(Columns, { className: "w-4 h-4" }) }), _jsx(ToolbarButton, { onClick: () => editor.chain().focus().deleteColumn().run(), title: "Delete column", children: _jsx(Columns, { className: "w-4 h-4" }) }), _jsx(ToolbarButton, { onClick: () => editor.chain().focus().addRowBefore().run(), title: "Add row before", children: _jsx(Rows, { className: "w-4 h-4" }) }), _jsx(ToolbarButton, { onClick: () => editor.chain().focus().addRowAfter().run(), title: "Add row after", children: _jsx(Rows, { className: "w-4 h-4" }) }), _jsx(ToolbarButton, { onClick: () => editor.chain().focus().deleteRow().run(), title: "Delete row", children: _jsx(Rows, { className: "w-4 h-4" }) }), _jsx(ToolbarButton, { onClick: () => editor.chain().focus().deleteTable().run(), title: "Delete table", children: _jsx(Trash2, { className: "w-4 h-4" }) })] })), _jsx(Divider, {}), _jsx(ToolbarButton, { onClick: () => editor.chain().focus().undo().run(), disabled: !editor.can().undo(), title: "Undo", children: _jsx(Undo, { className: "w-4 h-4" }) }), _jsx(ToolbarButton, { onClick: () => editor.chain().focus().redo().run(), disabled: !editor.can().redo(), title: "Redo", children: _jsx(Redo, { className: "w-4 h-4" }) })] }));
124
+ return (_jsxs("div", { className: "sticky top-0 z-10 flex flex-wrap items-center gap-0.5 border-b border-gray-200 bg-gray-50 p-2", children: [_jsx(ToolbarButton, { onClick: () => editor.chain().focus().toggleBold().run(), isActive: editor.isActive('bold'), title: "Bold (Ctrl+B)", children: _jsx(Bold, { className: "h-4 w-4" }) }), _jsx(ToolbarButton, { onClick: () => editor.chain().focus().toggleItalic().run(), isActive: editor.isActive('italic'), title: "Italic (Ctrl+I)", children: _jsx(Italic, { className: "h-4 w-4" }) }), _jsx(ToolbarButton, { onClick: () => editor.chain().focus().toggleUnderline().run(), isActive: editor.isActive('underline'), title: "Underline (Ctrl+U)", children: _jsx(Underline, { className: "h-4 w-4" }) }), _jsx(ToolbarButton, { onClick: () => editor.chain().focus().toggleStrike().run(), isActive: editor.isActive('strike'), title: "Strikethrough", children: _jsx(Strikethrough, { className: "h-4 w-4" }) }), _jsx(ToolbarButton, { onClick: () => editor.chain().focus().toggleCode().run(), isActive: editor.isActive('code'), title: "Inline code", children: _jsx(Code, { className: "h-4 w-4" }) }), _jsx(Divider, {}), _jsx(ToolbarButton, { onClick: () => editor.chain().focus().toggleHeading({ level: 1 }).run(), isActive: editor.isActive('heading', { level: 1 }), title: "Heading 1", children: _jsx(Heading1, { className: "h-4 w-4" }) }), _jsx(ToolbarButton, { onClick: () => editor.chain().focus().toggleHeading({ level: 2 }).run(), isActive: editor.isActive('heading', { level: 2 }), title: "Heading 2", children: _jsx(Heading2, { className: "h-4 w-4" }) }), _jsx(ToolbarButton, { onClick: () => editor.chain().focus().toggleHeading({ level: 3 }).run(), isActive: editor.isActive('heading', { level: 3 }), title: "Heading 3", children: _jsx(Heading3, { className: "h-4 w-4" }) }), _jsx(Divider, {}), _jsx(ToolbarButton, { onClick: () => editor.chain().focus().toggleBulletList().run(), isActive: editor.isActive('bulletList'), title: "Bullet list", children: _jsx(List, { className: "h-4 w-4" }) }), _jsx(ToolbarButton, { onClick: () => editor.chain().focus().toggleOrderedList().run(), isActive: editor.isActive('orderedList'), title: "Ordered list", children: _jsx(ListOrdered, { className: "h-4 w-4" }) }), _jsx(ToolbarButton, { onClick: () => editor.chain().focus().toggleBlockquote().run(), isActive: editor.isActive('blockquote'), title: "Blockquote", children: _jsx(Quote, { className: "h-4 w-4" }) }), _jsx(ToolbarButton, { onClick: () => editor.chain().focus().toggleCodeBlock().run(), isActive: editor.isActive('codeBlock'), title: "Code block", children: _jsx(FileCode, { className: "h-4 w-4" }) }), _jsx(ToolbarButton, { onClick: () => editor.chain().focus().setHorizontalRule().run(), title: "Horizontal rule", children: _jsx(Minus, { className: "h-4 w-4" }) }), _jsx(Divider, {}), _jsx(ToolbarButton, { onClick: () => editor.chain().focus().setTextAlign('left').run(), isActive: editor.isActive({ textAlign: 'left' }), title: "Align left", children: _jsx(AlignLeft, { className: "h-4 w-4" }) }), _jsx(ToolbarButton, { onClick: () => editor.chain().focus().setTextAlign('center').run(), isActive: editor.isActive({ textAlign: 'center' }), title: "Align center", children: _jsx(AlignCenter, { className: "h-4 w-4" }) }), _jsx(ToolbarButton, { onClick: () => editor.chain().focus().setTextAlign('right').run(), isActive: editor.isActive({ textAlign: 'right' }), title: "Align right", children: _jsx(AlignRight, { className: "h-4 w-4" }) }), _jsx(Divider, {}), _jsx(ToolbarButton, { onClick: addLink, isActive: editor.isActive('link'), title: "Insert link", children: _jsx(LinkIcon, { className: "h-4 w-4" }) }), _jsx(ToolbarButton, { onClick: onOpenMediaPicker, title: "Insert image", children: _jsx(ImageIcon, { className: "h-4 w-4" }) }), _jsx(ToolbarButton, { onClick: insertTable, title: "Insert table (3\u00D73)", children: _jsx(TableIcon, { className: "h-4 w-4" }) }), isInTable && (_jsxs(_Fragment, { children: [_jsx(Divider, {}), _jsx(ToolbarButton, { onClick: () => editor.chain().focus().addColumnBefore().run(), title: "Add column before", children: _jsx(Columns, { className: "h-4 w-4" }) }), _jsx(ToolbarButton, { onClick: () => editor.chain().focus().addColumnAfter().run(), title: "Add column after", children: _jsx(Columns, { className: "h-4 w-4" }) }), _jsx(ToolbarButton, { onClick: () => editor.chain().focus().deleteColumn().run(), title: "Delete column", children: _jsx(Columns, { className: "h-4 w-4" }) }), _jsx(ToolbarButton, { onClick: () => editor.chain().focus().addRowBefore().run(), title: "Add row before", children: _jsx(Rows, { className: "h-4 w-4" }) }), _jsx(ToolbarButton, { onClick: () => editor.chain().focus().addRowAfter().run(), title: "Add row after", children: _jsx(Rows, { className: "h-4 w-4" }) }), _jsx(ToolbarButton, { onClick: () => editor.chain().focus().deleteRow().run(), title: "Delete row", children: _jsx(Rows, { className: "h-4 w-4" }) }), _jsx(ToolbarButton, { onClick: () => editor.chain().focus().deleteTable().run(), title: "Delete table", children: _jsx(Trash2, { className: "h-4 w-4" }) })] })), _jsx(Divider, {}), _jsx(ToolbarButton, { onClick: () => editor.chain().focus().undo().run(), disabled: !editor.can().undo(), title: "Undo", children: _jsx(Undo, { className: "h-4 w-4" }) }), _jsx(ToolbarButton, { onClick: () => editor.chain().focus().redo().run(), disabled: !editor.can().redo(), title: "Redo", children: _jsx(Redo, { className: "h-4 w-4" }) })] }));
125
125
  }
126
126
  export function TipTapEditor({ content, onChange, placeholder, editable = true, className, }) {
127
127
  const [mediaPickerOpen, setMediaPickerOpen] = useState(false);
@@ -166,6 +166,6 @@ export function TipTapEditor({ content, onChange, placeholder, editable = true,
166
166
  .setImage({ src: url, alt: alt ?? '' })
167
167
  .run();
168
168
  };
169
- return (_jsxs("div", { className: `border border-gray-200 rounded-lg overflow-hidden bg-white ${className ?? ''}`, children: [editable && _jsx(Toolbar, { editor: editor, onOpenMediaPicker: () => setMediaPickerOpen(true) }), _jsx(EditorContent, { editor: editor }), _jsx("style", { dangerouslySetInnerHTML: { __html: editorStyles } }), _jsx(MediaPickerModal, { open: mediaPickerOpen, onClose: () => setMediaPickerOpen(false), onSelect: handleImageSelected, accept: "image/*" })] }));
169
+ return (_jsxs("div", { className: `overflow-hidden rounded-lg border border-gray-200 bg-white ${className ?? ''}`, children: [editable && _jsx(Toolbar, { editor: editor, onOpenMediaPicker: () => setMediaPickerOpen(true) }), _jsx(EditorContent, { editor: editor }), _jsx("style", { dangerouslySetInnerHTML: { __html: editorStyles } }), _jsx(MediaPickerModal, { open: mediaPickerOpen, onClose: () => setMediaPickerOpen(false), onSelect: handleImageSelected, accept: "image/*" })] }));
170
170
  }
171
171
  //# sourceMappingURL=TipTapEditor.js.map
@@ -58,13 +58,13 @@ export function VersionHistory({ collectionSlug, documentId, open, onClose, onRe
58
58
  }
59
59
  if (!open)
60
60
  return null;
61
- return (_jsxs("div", { className: "fixed inset-0 z-50 flex justify-end", children: [_jsx("div", { className: "fixed inset-0 bg-black/30", onClick: onClose }), _jsxs("div", { className: "relative w-full max-w-md bg-white shadow-xl flex flex-col animate-in slide-in-from-right", children: [_jsxs("div", { className: "flex items-center justify-between px-4 py-3 border-b border-gray-200", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Clock, { className: "w-5 h-5 text-gray-600" }), _jsx("h2", { className: "text-lg font-semibold text-gray-900", children: "Version History" })] }), _jsx("button", { onClick: onClose, className: "p-1.5 hover:bg-gray-100 rounded-lg transition-colors", children: _jsx(X, { className: "w-5 h-5 text-gray-500" }) })] }), _jsx("div", { className: "flex-1 overflow-y-auto", children: loading ? (_jsx("div", { className: "flex items-center justify-center py-16", children: _jsx(Loader2, { className: "w-6 h-6 animate-spin text-gray-400" }) })) : versions.length === 0 ? (_jsx("div", { className: "text-center py-16 text-sm text-gray-500", children: "No version history available" })) : (_jsx("div", { className: "divide-y divide-gray-100", children: versions.map((version, index) => {
61
+ return (_jsxs("div", { className: "fixed inset-0 z-50 flex justify-end", children: [_jsx("div", { className: "fixed inset-0 bg-black/30", onClick: onClose }), _jsxs("div", { className: "animate-in slide-in-from-right relative flex w-full max-w-md flex-col bg-white shadow-xl", children: [_jsxs("div", { className: "flex items-center justify-between border-b border-gray-200 px-4 py-3", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Clock, { className: "h-5 w-5 text-gray-600" }), _jsx("h2", { className: "text-lg font-semibold text-gray-900", children: "Version History" })] }), _jsx("button", { onClick: onClose, className: "rounded-lg p-1.5 transition-colors hover:bg-gray-100", children: _jsx(X, { className: "h-5 w-5 text-gray-500" }) })] }), _jsx("div", { className: "flex-1 overflow-y-auto", children: loading ? (_jsx("div", { className: "flex items-center justify-center py-16", children: _jsx(Loader2, { className: "h-6 w-6 animate-spin text-gray-400" }) })) : versions.length === 0 ? (_jsx("div", { className: "py-16 text-center text-sm text-gray-500", children: "No version history available" })) : (_jsx("div", { className: "divide-y divide-gray-100", children: versions.map((version, index) => {
62
62
  const typeInfo = CHANGE_TYPE_LABELS[version.changeType] ?? {
63
63
  label: version.changeType,
64
64
  color: 'bg-gray-100 text-gray-800',
65
65
  };
66
66
  const isLatest = index === 0;
67
- return (_jsx("div", { className: "px-4 py-3 hover:bg-gray-50 transition-colors", children: _jsxs("div", { className: "flex items-start justify-between gap-3", children: [_jsxs("div", { className: "flex-1 min-w-0", children: [_jsxs("div", { className: "flex items-center gap-2 mb-1", children: [_jsx("span", { className: `inline-flex px-2 py-0.5 rounded-full text-xs font-medium ${typeInfo.color}`, children: typeInfo.label }), isLatest && (_jsx("span", { className: "text-xs text-gray-400 font-medium", children: "Current" }))] }), _jsxs("div", { className: "flex items-center gap-3 text-xs text-gray-500", children: [version.changedBy && (_jsxs("span", { className: "flex items-center gap-1", children: [_jsx(User, { className: "w-3 h-3" }), version.changedBy.name ?? version.changedBy.email ?? 'Unknown'] })), _jsx("span", { title: new Date(version.createdAt).toLocaleString(), children: timeAgo(version.createdAt) })] })] }), !isLatest && (_jsxs("button", { onClick: () => handleRestore(version), disabled: restoring === version.id, className: "flex items-center gap-1.5 px-2.5 py-1.5 text-xs font-medium text-blue-700 bg-blue-50 rounded-lg hover:bg-blue-100 transition-colors disabled:opacity-50", children: [restoring === version.id ? (_jsx(Loader2, { className: "w-3.5 h-3.5 animate-spin" })) : (_jsx(RotateCcw, { className: "w-3.5 h-3.5" })), "Restore"] }))] }) }, version.id));
67
+ return (_jsx("div", { className: "px-4 py-3 transition-colors hover:bg-gray-50", children: _jsxs("div", { className: "flex items-start justify-between gap-3", children: [_jsxs("div", { className: "min-w-0 flex-1", children: [_jsxs("div", { className: "mb-1 flex items-center gap-2", children: [_jsx("span", { className: `inline-flex rounded-full px-2 py-0.5 text-xs font-medium ${typeInfo.color}`, children: typeInfo.label }), isLatest && (_jsx("span", { className: "text-xs font-medium text-gray-400", children: "Current" }))] }), _jsxs("div", { className: "flex items-center gap-3 text-xs text-gray-500", children: [version.changedBy && (_jsxs("span", { className: "flex items-center gap-1", children: [_jsx(User, { className: "h-3 w-3" }), version.changedBy.name ?? version.changedBy.email ?? 'Unknown'] })), _jsx("span", { title: new Date(version.createdAt).toLocaleString(), children: timeAgo(version.createdAt) })] })] }), !isLatest && (_jsxs("button", { onClick: () => handleRestore(version), disabled: restoring === version.id, className: "flex items-center gap-1.5 rounded-lg bg-blue-50 px-2.5 py-1.5 text-xs font-medium text-blue-700 transition-colors hover:bg-blue-100 disabled:opacity-50", children: [restoring === version.id ? (_jsx(Loader2, { className: "h-3.5 w-3.5 animate-spin" })) : (_jsx(RotateCcw, { className: "h-3.5 w-3.5" })), "Restore"] }))] }) }, version.id));
68
68
  }) })) })] })] }));
69
69
  }
70
70
  //# sourceMappingURL=VersionHistory.js.map
@@ -1,5 +1,35 @@
1
- export interface BadgeProps {
2
- status: 'published' | 'draft' | 'archived' | 'scheduled';
1
+ import type { HTMLAttributes, ReactNode } from 'react';
2
+ import { type VariantProps } from '../../lib/cv.js';
3
+ declare const badge: (props?: ({
4
+ tone?: "primary" | "danger" | "neutral" | "success" | "warning" | "info" | undefined;
5
+ size?: "sm" | "md" | "lg" | undefined;
6
+ } & {
7
+ class?: string | false | null | undefined;
8
+ className?: string | false | null | undefined;
9
+ }) | undefined) => string;
10
+ export type BadgeVariants = VariantProps<typeof badge>;
11
+ /**
12
+ * Map document statuses to badge tones. Exposed so callers can reuse the
13
+ * mapping (e.g. for the same status rendered as a dot indicator).
14
+ */
15
+ export declare const STATUS_TONE: Record<DocumentStatus, BadgeVariants['tone']>;
16
+ export declare const STATUS_LABEL: Record<DocumentStatus, string>;
17
+ export type DocumentStatus = 'published' | 'draft' | 'archived' | 'scheduled';
18
+ export interface BadgeProps extends HTMLAttributes<HTMLSpanElement>, BadgeVariants {
19
+ /**
20
+ * Shorthand for the canonical document status badge. When set, takes
21
+ * precedence over `tone` and uses the matching label.
22
+ */
23
+ status?: DocumentStatus;
24
+ /** Render as outlined (border + transparent background). */
25
+ outline?: boolean;
26
+ children?: ReactNode;
3
27
  }
4
- export declare function Badge({ status }: BadgeProps): import("react/jsx-runtime").JSX.Element;
28
+ /**
29
+ * Generic typed badge. Pass `status` for the canonical document-status
30
+ * variants (preserves the original Badge API), or `tone` / `outline` /
31
+ * `size` for everything else.
32
+ */
33
+ export declare function Badge({ status, tone, outline, size, className, children, ...rest }: BadgeProps): import("react/jsx-runtime").JSX.Element;
34
+ export { badge as badgeVariants };
5
35
  //# sourceMappingURL=Badge.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Badge.d.ts","sourceRoot":"","sources":["../../../src/components/ui/Badge.tsx"],"names":[],"mappings":"AAAA,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,WAAW,GAAG,OAAO,GAAG,UAAU,GAAG,WAAW,CAAA;CACzD;AAgBD,wBAAgB,KAAK,CAAC,EAAE,MAAM,EAAE,EAAE,UAAU,2CAQ3C"}
1
+ {"version":3,"file":"Badge.d.ts","sourceRoot":"","sources":["../../../src/components/ui/Badge.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AACtD,OAAO,EAAM,KAAK,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAEvD,QAAA,MAAM,KAAK;;;;;;yBAiBT,CAAA;AAEF,MAAM,MAAM,aAAa,GAAG,YAAY,CAAC,OAAO,KAAK,CAAC,CAAA;AAEtD;;;GAGG;AACH,eAAO,MAAM,WAAW,EAAE,MAAM,CAAC,cAAc,EAAE,aAAa,CAAC,MAAM,CAAC,CAKrE,CAAA;AAED,eAAO,MAAM,YAAY,EAAE,MAAM,CAAC,cAAc,EAAE,MAAM,CAKvD,CAAA;AAED,MAAM,MAAM,cAAc,GAAG,WAAW,GAAG,OAAO,GAAG,UAAU,GAAG,WAAW,CAAA;AAE7E,MAAM,WAAW,UAAW,SAAQ,cAAc,CAAC,eAAe,CAAC,EAAE,aAAa;IAChF;;;OAGG;IACH,MAAM,CAAC,EAAE,cAAc,CAAA;IACvB,4DAA4D;IAC5D,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,QAAQ,CAAC,EAAE,SAAS,CAAA;CACrB;AAID;;;;GAIG;AACH,wBAAgB,KAAK,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,GAAG,IAAI,EAAE,EAAE,UAAU,2CAc9F;AAED,OAAO,EAAE,KAAK,IAAI,aAAa,EAAE,CAAA"}
@@ -1,17 +1,51 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
- const statusClasses = {
3
- published: 'bg-emerald-100 text-emerald-800 dark:bg-emerald-900/30 dark:text-emerald-400',
4
- draft: 'bg-gray-100 text-gray-800 dark:bg-gray-800 dark:text-gray-300',
5
- archived: 'bg-amber-100 text-amber-800 dark:bg-amber-900/30 dark:text-amber-400',
6
- scheduled: 'bg-blue-100 text-blue-800 dark:bg-blue-900/30 dark:text-blue-400',
2
+ import { cv } from '../../lib/cv.js';
3
+ const badge = cv('inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-medium', {
4
+ variants: {
5
+ tone: {
6
+ neutral: 'bg-gray-100 text-gray-800 dark:bg-gray-800 dark:text-gray-300',
7
+ success: 'bg-emerald-100 text-emerald-800 dark:bg-emerald-900/30 dark:text-emerald-400',
8
+ warning: 'bg-amber-100 text-amber-800 dark:bg-amber-900/30 dark:text-amber-400',
9
+ danger: 'bg-red-100 text-red-800 dark:bg-red-900/30 dark:text-red-400',
10
+ info: 'bg-blue-100 text-blue-800 dark:bg-blue-900/30 dark:text-blue-400',
11
+ primary: 'bg-[var(--primary)]/15 text-[var(--primary)] dark:bg-[var(--primary)]/25',
12
+ },
13
+ size: {
14
+ sm: 'px-2 py-0.5 text-[10px]',
15
+ md: 'px-2.5 py-0.5 text-xs',
16
+ lg: 'px-3 py-1 text-sm',
17
+ },
18
+ },
19
+ defaultVariants: { tone: 'neutral', size: 'md' },
20
+ });
21
+ /**
22
+ * Map document statuses to badge tones. Exposed so callers can reuse the
23
+ * mapping (e.g. for the same status rendered as a dot indicator).
24
+ */
25
+ export const STATUS_TONE = {
26
+ published: 'success',
27
+ draft: 'neutral',
28
+ archived: 'warning',
29
+ scheduled: 'info',
7
30
  };
8
- const statusLabels = {
31
+ export const STATUS_LABEL = {
9
32
  published: 'Published',
10
33
  draft: 'Draft',
11
34
  archived: 'Archived',
12
35
  scheduled: 'Scheduled',
13
36
  };
14
- export function Badge({ status }) {
15
- return (_jsx("span", { className: `inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-medium ${statusClasses[status]}`, children: statusLabels[status] }));
37
+ const OUTLINE_CLASS = 'border border-current bg-transparent';
38
+ /**
39
+ * Generic typed badge. Pass `status` for the canonical document-status
40
+ * variants (preserves the original Badge API), or `tone` / `outline` /
41
+ * `size` for everything else.
42
+ */
43
+ export function Badge({ status, tone, outline, size, className, children, ...rest }) {
44
+ const extras = [outline ? OUTLINE_CLASS : '', className].filter(Boolean).join(' ');
45
+ if (status) {
46
+ return (_jsx("span", { className: badge({ tone: STATUS_TONE[status], size, class: extras }), ...rest, children: children ?? STATUS_LABEL[status] }));
47
+ }
48
+ return (_jsx("span", { className: badge({ tone, size, class: extras }), ...rest, children: children }));
16
49
  }
50
+ export { badge as badgeVariants };
17
51
  //# sourceMappingURL=Badge.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Badge.js","sourceRoot":"","sources":["../../../src/components/ui/Badge.tsx"],"names":[],"mappings":";AAIA,MAAM,aAAa,GAAyC;IAC1D,SAAS,EAAE,8EAA8E;IACzF,KAAK,EAAE,+DAA+D;IACtE,QAAQ,EAAE,sEAAsE;IAChF,SAAS,EAAE,kEAAkE;CAC9E,CAAA;AAED,MAAM,YAAY,GAAyC;IACzD,SAAS,EAAE,WAAW;IACtB,KAAK,EAAE,OAAO;IACd,QAAQ,EAAE,UAAU;IACpB,SAAS,EAAE,WAAW;CACvB,CAAA;AAED,MAAM,UAAU,KAAK,CAAC,EAAE,MAAM,EAAc;IAC1C,OAAO,CACL,eACE,SAAS,EAAE,2EAA2E,aAAa,CAAC,MAAM,CAAC,EAAE,YAE5G,YAAY,CAAC,MAAM,CAAC,GAChB,CACR,CAAA;AACH,CAAC"}
1
+ {"version":3,"file":"Badge.js","sourceRoot":"","sources":["../../../src/components/ui/Badge.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,EAAE,EAAqB,MAAM,iBAAiB,CAAA;AAEvD,MAAM,KAAK,GAAG,EAAE,CAAC,yEAAyE,EAAE;IAC1F,QAAQ,EAAE;QACR,IAAI,EAAE;YACJ,OAAO,EAAE,+DAA+D;YACxE,OAAO,EAAE,8EAA8E;YACvF,OAAO,EAAE,sEAAsE;YAC/E,MAAM,EAAE,8DAA8D;YACtE,IAAI,EAAE,kEAAkE;YACxE,OAAO,EAAE,0EAA0E;SACpF;QACD,IAAI,EAAE;YACJ,EAAE,EAAE,yBAAyB;YAC7B,EAAE,EAAE,uBAAuB;YAC3B,EAAE,EAAE,mBAAmB;SACxB;KACF;IACD,eAAe,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE;CACjD,CAAC,CAAA;AAIF;;;GAGG;AACH,MAAM,CAAC,MAAM,WAAW,GAAkD;IACxE,SAAS,EAAE,SAAS;IACpB,KAAK,EAAE,SAAS;IAChB,QAAQ,EAAE,SAAS;IACnB,SAAS,EAAE,MAAM;CAClB,CAAA;AAED,MAAM,CAAC,MAAM,YAAY,GAAmC;IAC1D,SAAS,EAAE,WAAW;IACtB,KAAK,EAAE,OAAO;IACd,QAAQ,EAAE,UAAU;IACpB,SAAS,EAAE,WAAW;CACvB,CAAA;AAeD,MAAM,aAAa,GAAG,sCAAsC,CAAA;AAE5D;;;;GAIG;AACH,MAAM,UAAU,KAAK,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,GAAG,IAAI,EAAc;IAC7F,MAAM,MAAM,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,EAAE,SAAS,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IAClF,IAAI,MAAM,EAAE,CAAC;QACX,OAAO,CACL,eAAM,SAAS,EAAE,KAAK,CAAC,EAAE,IAAI,EAAE,WAAW,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,KAAM,IAAI,YACjF,QAAQ,IAAI,YAAY,CAAC,MAAM,CAAC,GAC5B,CACR,CAAA;IACH,CAAC;IACD,OAAO,CACL,eAAM,SAAS,EAAE,KAAK,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,KAAM,IAAI,YAC5D,QAAQ,GACJ,CACR,CAAA;AACH,CAAC;AAED,OAAO,EAAE,KAAK,IAAI,aAAa,EAAE,CAAA"}
@@ -1,12 +1,23 @@
1
1
  import { type ButtonHTMLAttributes, type ReactNode } from 'react';
2
- type ButtonVariant = 'primary' | 'secondary' | 'danger' | 'ghost';
3
- type ButtonSize = 'sm' | 'md' | 'lg';
4
- export interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
5
- variant?: ButtonVariant;
6
- size?: ButtonSize;
2
+ import { type VariantProps } from '../../lib/cv.js';
3
+ declare const button: (props?: ({
4
+ variant?: "link" | "primary" | "secondary" | "danger" | "ghost" | "outline" | undefined;
5
+ size?: "icon" | "xs" | "sm" | "md" | "lg" | undefined;
6
+ } & {
7
+ class?: string | false | null | undefined;
8
+ className?: string | false | null | undefined;
9
+ }) | undefined) => string;
10
+ export type ButtonVariants = VariantProps<typeof button>;
11
+ export interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement>, ButtonVariants {
7
12
  loading?: boolean;
8
- children: ReactNode;
13
+ /** Stretch the button to fill its container width. */
14
+ full?: boolean;
15
+ /** Icon rendered before the children. Use with `size="icon"` for icon-only buttons. */
16
+ leftIcon?: ReactNode;
17
+ /** Icon rendered after the children. */
18
+ rightIcon?: ReactNode;
19
+ children?: ReactNode;
9
20
  }
10
- export declare function Button({ variant, size, loading, disabled, children, className, ...rest }: ButtonProps): import("react/jsx-runtime").JSX.Element;
11
- export {};
21
+ export declare const Button: import("react").ForwardRefExoticComponent<ButtonProps & import("react").RefAttributes<HTMLButtonElement>>;
22
+ export { button as buttonVariants };
12
23
  //# sourceMappingURL=Button.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Button.d.ts","sourceRoot":"","sources":["../../../src/components/ui/Button.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,oBAAoB,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAA;AAEjE,KAAK,aAAa,GAAG,SAAS,GAAG,WAAW,GAAG,QAAQ,GAAG,OAAO,CAAA;AACjE,KAAK,UAAU,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAA;AAEpC,MAAM,WAAW,WAAY,SAAQ,oBAAoB,CAAC,iBAAiB,CAAC;IAC1E,OAAO,CAAC,EAAE,aAAa,CAAA;IACvB,IAAI,CAAC,EAAE,UAAU,CAAA;IACjB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,QAAQ,EAAE,SAAS,CAAA;CACpB;AAeD,wBAAgB,MAAM,CAAC,EACrB,OAAmB,EACnB,IAAW,EACX,OAAe,EACf,QAAQ,EACR,QAAQ,EACR,SAAc,EACd,GAAG,IAAI,EACR,EAAE,WAAW,2CA2Bb"}
1
+ {"version":3,"file":"Button.d.ts","sourceRoot":"","sources":["../../../src/components/ui/Button.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAc,KAAK,oBAAoB,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAA;AAC7E,OAAO,EAAM,KAAK,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAEvD,QAAA,MAAM,MAAM;;;;;;yBA2BX,CAAA;AAED,MAAM,MAAM,cAAc,GAAG,YAAY,CAAC,OAAO,MAAM,CAAC,CAAA;AAExD,MAAM,WAAW,WAAY,SAAQ,oBAAoB,CAAC,iBAAiB,CAAC,EAAE,cAAc;IAC1F,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,sDAAsD;IACtD,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,uFAAuF;IACvF,QAAQ,CAAC,EAAE,SAAS,CAAA;IACpB,wCAAwC;IACxC,SAAS,CAAC,EAAE,SAAS,CAAA;IACrB,QAAQ,CAAC,EAAE,SAAS,CAAA;CACrB;AAED,eAAO,MAAM,MAAM,2GAkDjB,CAAA;AAEF,OAAO,EAAE,MAAM,IAAI,cAAc,EAAE,CAAA"}