@actuate-media/cms-admin 0.18.0 → 0.20.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 (167) hide show
  1. package/dist/AdminRoot.d.ts.map +1 -1
  2. package/dist/AdminRoot.js +9 -5
  3. package/dist/AdminRoot.js.map +1 -1
  4. package/dist/__tests__/lib/post-editor-service.test.js +75 -23
  5. package/dist/__tests__/lib/post-editor-service.test.js.map +1 -1
  6. package/dist/__tests__/lib/posts-service.test.js +132 -142
  7. package/dist/__tests__/lib/posts-service.test.js.map +1 -1
  8. package/dist/__tests__/views/posts-list-view.render.test.d.ts +2 -0
  9. package/dist/__tests__/views/posts-list-view.render.test.d.ts.map +1 -0
  10. package/dist/__tests__/views/posts-list-view.render.test.js +73 -0
  11. package/dist/__tests__/views/posts-list-view.render.test.js.map +1 -0
  12. package/dist/actuate-admin.css +1 -1
  13. package/dist/components/seo/Drawer.d.ts +11 -0
  14. package/dist/components/seo/Drawer.d.ts.map +1 -0
  15. package/dist/components/seo/Drawer.js +13 -0
  16. package/dist/components/seo/Drawer.js.map +1 -0
  17. package/dist/components/seo/RedirectEditorDrawer.d.ts +9 -0
  18. package/dist/components/seo/RedirectEditorDrawer.d.ts.map +1 -0
  19. package/dist/components/seo/RedirectEditorDrawer.js +94 -0
  20. package/dist/components/seo/RedirectEditorDrawer.js.map +1 -0
  21. package/dist/components/seo/SeoCopilotDrawer.d.ts +10 -0
  22. package/dist/components/seo/SeoCopilotDrawer.d.ts.map +1 -0
  23. package/dist/components/seo/SeoCopilotDrawer.js +34 -0
  24. package/dist/components/seo/SeoCopilotDrawer.js.map +1 -0
  25. package/dist/components/seo/SeoEditorDrawer.d.ts +8 -0
  26. package/dist/components/seo/SeoEditorDrawer.d.ts.map +1 -0
  27. package/dist/components/seo/SeoEditorDrawer.js +111 -0
  28. package/dist/components/seo/SeoEditorDrawer.js.map +1 -0
  29. package/dist/components/seo/SeoIssueFixDrawer.d.ts +8 -0
  30. package/dist/components/seo/SeoIssueFixDrawer.d.ts.map +1 -0
  31. package/dist/components/seo/SeoIssueFixDrawer.js +111 -0
  32. package/dist/components/seo/SeoIssueFixDrawer.js.map +1 -0
  33. package/dist/components/seo/primitives.d.ts +53 -0
  34. package/dist/components/seo/primitives.d.ts.map +1 -0
  35. package/dist/components/seo/primitives.js +100 -0
  36. package/dist/components/seo/primitives.js.map +1 -0
  37. package/dist/index.d.ts +0 -2
  38. package/dist/index.d.ts.map +1 -1
  39. package/dist/index.js +0 -2
  40. package/dist/index.js.map +1 -1
  41. package/dist/layout/Sidebar.d.ts.map +1 -1
  42. package/dist/layout/Sidebar.js +3 -0
  43. package/dist/layout/Sidebar.js.map +1 -1
  44. package/dist/lib/post-editor-service.d.ts +6 -4
  45. package/dist/lib/post-editor-service.d.ts.map +1 -1
  46. package/dist/lib/post-editor-service.js +32 -37
  47. package/dist/lib/post-editor-service.js.map +1 -1
  48. package/dist/lib/posts-service.d.ts.map +1 -1
  49. package/dist/lib/posts-service.js +91 -160
  50. package/dist/lib/posts-service.js.map +1 -1
  51. package/dist/lib/seo-service.d.ts +322 -0
  52. package/dist/lib/seo-service.d.ts.map +1 -0
  53. package/dist/lib/seo-service.js +295 -0
  54. package/dist/lib/seo-service.js.map +1 -0
  55. package/dist/router/index.d.ts.map +1 -1
  56. package/dist/router/index.js +4 -1
  57. package/dist/router/index.js.map +1 -1
  58. package/dist/views/MediaBrowser.d.ts.map +1 -1
  59. package/dist/views/MediaBrowser.js +36 -25
  60. package/dist/views/MediaBrowser.js.map +1 -1
  61. package/dist/views/Posts/NewPostPicker.d.ts +5 -4
  62. package/dist/views/Posts/NewPostPicker.d.ts.map +1 -1
  63. package/dist/views/Posts/NewPostPicker.js +5 -4
  64. package/dist/views/Posts/NewPostPicker.js.map +1 -1
  65. package/dist/views/Posts/NewPostTypeInstructions.js +2 -2
  66. package/dist/views/Posts/PostTypesView.d.ts +5 -4
  67. package/dist/views/Posts/PostTypesView.d.ts.map +1 -1
  68. package/dist/views/Posts/PostTypesView.js.map +1 -1
  69. package/dist/views/Posts/PostsListView.d.ts.map +1 -1
  70. package/dist/views/Posts/PostsListView.js +8 -0
  71. package/dist/views/Posts/PostsListView.js.map +1 -1
  72. package/dist/views/Posts/post-type-presets.d.ts +5 -0
  73. package/dist/views/Posts/post-type-presets.d.ts.map +1 -1
  74. package/dist/views/Posts/post-type-presets.js +10 -64
  75. package/dist/views/Posts/post-type-presets.js.map +1 -1
  76. package/dist/views/SEO.d.ts.map +1 -1
  77. package/dist/views/SEO.js +89 -132
  78. package/dist/views/SEO.js.map +1 -1
  79. package/dist/views/page-editor/sections/ArticleBodySection.d.ts +6 -2
  80. package/dist/views/page-editor/sections/ArticleBodySection.d.ts.map +1 -1
  81. package/dist/views/page-editor/sections/ArticleBodySection.js +8 -8
  82. package/dist/views/page-editor/sections/ArticleBodySection.js.map +1 -1
  83. package/dist/views/post-editor/PostEditorCanvas.js +7 -1
  84. package/dist/views/post-editor/PostEditorCanvas.js.map +1 -1
  85. package/dist/views/post-editor/PostFieldsModal.d.ts.map +1 -1
  86. package/dist/views/post-editor/PostFieldsModal.js +10 -4
  87. package/dist/views/post-editor/PostFieldsModal.js.map +1 -1
  88. package/dist/views/post-editor/PostHeader.d.ts.map +1 -1
  89. package/dist/views/post-editor/PostHeader.js +4 -3
  90. package/dist/views/post-editor/PostHeader.js.map +1 -1
  91. package/dist/views/post-editor/PostPreview.d.ts.map +1 -1
  92. package/dist/views/post-editor/PostPreview.js +11 -1
  93. package/dist/views/post-editor/PostPreview.js.map +1 -1
  94. package/dist/views/post-editor/PostSectionEditor.d.ts +22 -2
  95. package/dist/views/post-editor/PostSectionEditor.d.ts.map +1 -1
  96. package/dist/views/post-editor/PostSectionEditor.js +4 -1
  97. package/dist/views/post-editor/PostSectionEditor.js.map +1 -1
  98. package/dist/views/seo/AuditTab.d.ts +6 -0
  99. package/dist/views/seo/AuditTab.d.ts.map +1 -0
  100. package/dist/views/seo/AuditTab.js +57 -0
  101. package/dist/views/seo/AuditTab.js.map +1 -0
  102. package/dist/views/seo/ContentTab.d.ts +5 -0
  103. package/dist/views/seo/ContentTab.d.ts.map +1 -0
  104. package/dist/views/seo/ContentTab.js +27 -0
  105. package/dist/views/seo/ContentTab.js.map +1 -0
  106. package/dist/views/seo/OverviewTab.d.ts +8 -0
  107. package/dist/views/seo/OverviewTab.d.ts.map +1 -0
  108. package/dist/views/seo/OverviewTab.js +35 -0
  109. package/dist/views/seo/OverviewTab.js.map +1 -0
  110. package/dist/views/seo/RedirectsTab.d.ts +2 -0
  111. package/dist/views/seo/RedirectsTab.d.ts.map +1 -0
  112. package/dist/views/seo/RedirectsTab.js +124 -0
  113. package/dist/views/seo/RedirectsTab.js.map +1 -0
  114. package/dist/views/seo/TechnicalTab.d.ts +2 -0
  115. package/dist/views/seo/TechnicalTab.d.ts.map +1 -0
  116. package/dist/views/seo/TechnicalTab.js +102 -0
  117. package/dist/views/seo/TechnicalTab.js.map +1 -0
  118. package/dist/views/seo/useSeoResource.d.ts +8 -0
  119. package/dist/views/seo/useSeoResource.d.ts.map +1 -0
  120. package/dist/views/seo/useSeoResource.js +42 -0
  121. package/dist/views/seo/useSeoResource.js.map +1 -0
  122. package/package.json +2 -2
  123. package/src/AdminRoot.tsx +9 -5
  124. package/src/__tests__/lib/post-editor-service.test.ts +78 -23
  125. package/src/__tests__/lib/posts-service.test.ts +134 -163
  126. package/src/__tests__/views/posts-list-view.render.test.tsx +84 -0
  127. package/src/components/seo/Drawer.tsx +61 -0
  128. package/src/components/seo/RedirectEditorDrawer.tsx +235 -0
  129. package/src/components/seo/SeoCopilotDrawer.tsx +76 -0
  130. package/src/components/seo/SeoEditorDrawer.tsx +347 -0
  131. package/src/components/seo/SeoIssueFixDrawer.tsx +244 -0
  132. package/src/components/seo/primitives.tsx +237 -0
  133. package/src/index.ts +0 -2
  134. package/src/layout/Sidebar.tsx +3 -0
  135. package/src/lib/post-editor-service.ts +41 -40
  136. package/src/lib/posts-service.ts +109 -180
  137. package/src/lib/seo-service.ts +623 -0
  138. package/src/router/index.ts +4 -1
  139. package/src/views/MediaBrowser.tsx +89 -67
  140. package/src/views/Posts/NewPostPicker.tsx +5 -4
  141. package/src/views/Posts/NewPostTypeInstructions.tsx +2 -2
  142. package/src/views/Posts/PostTypesView.tsx +5 -4
  143. package/src/views/Posts/PostsListView.tsx +9 -0
  144. package/src/views/Posts/post-type-presets.ts +15 -64
  145. package/src/views/SEO.tsx +186 -863
  146. package/src/views/page-editor/sections/ArticleBodySection.tsx +12 -16
  147. package/src/views/post-editor/PostEditorCanvas.tsx +7 -1
  148. package/src/views/post-editor/PostFieldsModal.tsx +36 -21
  149. package/src/views/post-editor/PostHeader.tsx +4 -4
  150. package/src/views/post-editor/PostPreview.tsx +12 -1
  151. package/src/views/post-editor/PostSectionEditor.tsx +22 -5
  152. package/src/views/seo/AuditTab.tsx +229 -0
  153. package/src/views/seo/ContentTab.tsx +164 -0
  154. package/src/views/seo/OverviewTab.tsx +257 -0
  155. package/src/views/seo/RedirectsTab.tsx +392 -0
  156. package/src/views/seo/TechnicalTab.tsx +303 -0
  157. package/src/views/seo/useSeoResource.ts +52 -0
  158. package/dist/views/PostEditor.d.ts +0 -6
  159. package/dist/views/PostEditor.d.ts.map +0 -1
  160. package/dist/views/PostEditor.js +0 -79
  161. package/dist/views/PostEditor.js.map +0 -1
  162. package/dist/views/Posts.d.ts +0 -5
  163. package/dist/views/Posts.d.ts.map +0 -1
  164. package/dist/views/Posts.js +0 -73
  165. package/dist/views/Posts.js.map +0 -1
  166. package/src/views/PostEditor.tsx +0 -257
  167. package/src/views/Posts.tsx +0 -375
@@ -0,0 +1,94 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
+ import { useEffect, useState } from 'react';
4
+ import { toast } from 'sonner';
5
+ import { createRedirectRule, updateRedirectRule, } from '../../lib/seo-service.js';
6
+ import { Drawer } from './Drawer.js';
7
+ import { btnPrimary, btnSecondary } from './primitives.js';
8
+ const STATUS_CODES = [
9
+ { value: 301, label: '301 — Permanent' },
10
+ { value: 302, label: '302 — Temporary' },
11
+ { value: 307, label: '307 — Temporary (preserve method)' },
12
+ { value: 308, label: '308 — Permanent (preserve method)' },
13
+ { value: 410, label: '410 — Gone (no destination)' },
14
+ ];
15
+ const inputCls = 'w-full rounded-md border border-border bg-input-background px-3 py-2 text-base text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring';
16
+ function normalizePath(p) {
17
+ const t = p.trim();
18
+ if (!t)
19
+ return '';
20
+ if (/^https?:\/\//i.test(t))
21
+ return t;
22
+ return t.startsWith('/') ? t : `/${t}`;
23
+ }
24
+ export function RedirectEditorDrawer({ open, onOpenChange, rule, onSaved, }) {
25
+ const [form, setForm] = useState({
26
+ type: 301,
27
+ fromPath: '',
28
+ toPath: '',
29
+ enabled: true,
30
+ preserveQuery: false,
31
+ notes: '',
32
+ });
33
+ const [saving, setSaving] = useState(false);
34
+ const [clientError, setClientError] = useState(null);
35
+ useEffect(() => {
36
+ if (!open)
37
+ return;
38
+ if (rule) {
39
+ setForm({
40
+ type: rule.type,
41
+ fromPath: rule.fromPath,
42
+ toPath: rule.toPath,
43
+ enabled: rule.enabled,
44
+ preserveQuery: rule.preserveQuery,
45
+ notes: rule.notes ?? '',
46
+ });
47
+ }
48
+ else {
49
+ setForm({
50
+ type: 301,
51
+ fromPath: '',
52
+ toPath: '',
53
+ enabled: true,
54
+ preserveQuery: false,
55
+ notes: '',
56
+ });
57
+ }
58
+ setClientError(null);
59
+ }, [open, rule]);
60
+ const isGone = form.type === 410;
61
+ const update = (patch) => setForm((f) => ({ ...f, ...patch }));
62
+ async function handleSave() {
63
+ const fromPath = normalizePath(form.fromPath);
64
+ const toPath = isGone ? '' : normalizePath(form.toPath);
65
+ if (!fromPath) {
66
+ setClientError('Source path is required.');
67
+ return;
68
+ }
69
+ if (!isGone && !toPath) {
70
+ setClientError('Destination is required for redirect status codes.');
71
+ return;
72
+ }
73
+ if (!isGone && fromPath === toPath) {
74
+ setClientError('Source and destination cannot be identical (would create a loop).');
75
+ return;
76
+ }
77
+ setClientError(null);
78
+ setSaving(true);
79
+ const payload = { ...form, fromPath, toPath };
80
+ const res = rule
81
+ ? await updateRedirectRule(rule.id, payload)
82
+ : await createRedirectRule(payload);
83
+ setSaving(false);
84
+ if (res.error) {
85
+ toast.error(res.error);
86
+ return;
87
+ }
88
+ toast.success(rule ? 'Redirect updated.' : 'Redirect created.');
89
+ onOpenChange(false);
90
+ onSaved?.();
91
+ }
92
+ return (_jsx(Drawer, { open: open, onOpenChange: onOpenChange, title: rule ? 'Edit redirect' : 'New redirect', width: "max-w-lg", footer: _jsxs(_Fragment, { children: [_jsx("button", { className: btnSecondary, onClick: () => onOpenChange(false), disabled: saving, children: "Cancel" }), _jsx("button", { className: btnPrimary, onClick: handleSave, disabled: saving, children: saving ? 'Saving…' : rule ? 'Save changes' : 'Create redirect' })] }), children: _jsxs("div", { className: "space-y-4", children: [clientError && (_jsx("p", { className: "text-destructive bg-destructive/10 rounded-md px-3 py-2 text-sm", role: "alert", children: clientError })), _jsxs("div", { className: "space-y-1.5", children: [_jsx("label", { className: "text-foreground text-sm font-medium", htmlFor: "redir-type", children: "Status code" }), _jsx("select", { id: "redir-type", className: inputCls, value: form.type, onChange: (e) => update({ type: Number(e.target.value) }), children: STATUS_CODES.map((s) => (_jsx("option", { value: s.value, children: s.label }, s.value))) })] }), _jsxs("div", { className: "space-y-1.5", children: [_jsx("label", { className: "text-foreground text-sm font-medium", htmlFor: "redir-from", children: "Source path" }), _jsx("input", { id: "redir-from", className: inputCls, value: form.fromPath, onChange: (e) => update({ fromPath: e.target.value }), placeholder: "/old-path" })] }), !isGone && (_jsxs("div", { className: "space-y-1.5", children: [_jsx("label", { className: "text-foreground text-sm font-medium", htmlFor: "redir-to", children: "Destination" }), _jsx("input", { id: "redir-to", className: inputCls, value: form.toPath, onChange: (e) => update({ toPath: e.target.value }), placeholder: "/new-path or https://example.com/page" })] })), _jsxs("div", { className: "space-y-1.5", children: [_jsxs("label", { className: "text-foreground text-sm font-medium", htmlFor: "redir-notes", children: ["Notes ", _jsx("span", { className: "text-muted-foreground font-normal", children: "(optional)" })] }), _jsx("input", { id: "redir-notes", className: inputCls, value: form.notes ?? '', onChange: (e) => update({ notes: e.target.value }), placeholder: "Why this redirect exists" })] }), _jsxs("div", { className: "border-border space-y-3 rounded-lg border p-4", children: [_jsxs("label", { className: "flex items-center justify-between gap-3", children: [_jsx("span", { className: "text-foreground text-sm font-medium", children: "Enabled" }), _jsx("input", { type: "checkbox", role: "switch", "aria-checked": !!form.enabled, checked: !!form.enabled, onChange: (e) => update({ enabled: e.target.checked }), className: "accent-primary h-4 w-4" })] }), !isGone && (_jsxs("label", { className: "flex items-center justify-between gap-3", children: [_jsxs("span", { className: "min-w-0", children: [_jsx("span", { className: "text-foreground block text-sm font-medium", children: "Preserve query string" }), _jsx("span", { className: "text-muted-foreground block text-sm", children: "Append the original query params to the destination." })] }), _jsx("input", { type: "checkbox", role: "switch", "aria-checked": !!form.preserveQuery, checked: !!form.preserveQuery, onChange: (e) => update({ preserveQuery: e.target.checked }), className: "accent-primary h-4 w-4 shrink-0" })] }))] })] }) }));
93
+ }
94
+ //# sourceMappingURL=RedirectEditorDrawer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RedirectEditorDrawer.js","sourceRoot":"","sources":["../../../src/components/seo/RedirectEditorDrawer.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAA;;AAEZ,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAC3C,OAAO,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAA;AAC9B,OAAO,EACL,kBAAkB,EAClB,kBAAkB,GAInB,MAAM,0BAA0B,CAAA;AACjC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACpC,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAE1D,MAAM,YAAY,GAAmD;IACnE,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,iBAAiB,EAAE;IACxC,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,iBAAiB,EAAE;IACxC,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,mCAAmC,EAAE;IAC1D,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,mCAAmC,EAAE;IAC1D,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,6BAA6B,EAAE;CACrD,CAAA;AAED,MAAM,QAAQ,GACZ,0MAA0M,CAAA;AAE5M,SAAS,aAAa,CAAC,CAAS;IAC9B,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAA;IAClB,IAAI,CAAC,CAAC;QAAE,OAAO,EAAE,CAAA;IACjB,IAAI,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC;QAAE,OAAO,CAAC,CAAA;IACrC,OAAO,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAA;AACxC,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,EACnC,IAAI,EACJ,YAAY,EACZ,IAAI,EACJ,OAAO,GAOR;IACC,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,QAAQ,CAAsB;QACpD,IAAI,EAAE,GAAG;QACT,QAAQ,EAAE,EAAE;QACZ,MAAM,EAAE,EAAE;QACV,OAAO,EAAE,IAAI;QACb,aAAa,EAAE,KAAK;QACpB,KAAK,EAAE,EAAE;KACV,CAAC,CAAA;IACF,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAA;IAC3C,MAAM,CAAC,WAAW,EAAE,cAAc,CAAC,GAAG,QAAQ,CAAgB,IAAI,CAAC,CAAA;IAEnE,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,IAAI;YAAE,OAAM;QACjB,IAAI,IAAI,EAAE,CAAC;YACT,OAAO,CAAC;gBACN,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,QAAQ,EAAE,IAAI,CAAC,QAAQ;gBACvB,MAAM,EAAE,IAAI,CAAC,MAAM;gBACnB,OAAO,EAAE,IAAI,CAAC,OAAO;gBACrB,aAAa,EAAE,IAAI,CAAC,aAAa;gBACjC,KAAK,EAAE,IAAI,CAAC,KAAK,IAAI,EAAE;aACxB,CAAC,CAAA;QACJ,CAAC;aAAM,CAAC;YACN,OAAO,CAAC;gBACN,IAAI,EAAE,GAAG;gBACT,QAAQ,EAAE,EAAE;gBACZ,MAAM,EAAE,EAAE;gBACV,OAAO,EAAE,IAAI;gBACb,aAAa,EAAE,KAAK;gBACpB,KAAK,EAAE,EAAE;aACV,CAAC,CAAA;QACJ,CAAC;QACD,cAAc,CAAC,IAAI,CAAC,CAAA;IACtB,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAA;IAEhB,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,KAAK,GAAG,CAAA;IAChC,MAAM,MAAM,GAAG,CAAC,KAAmC,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,GAAG,KAAK,EAAE,CAAC,CAAC,CAAA;IAE5F,KAAK,UAAU,UAAU;QACvB,MAAM,QAAQ,GAAG,aAAa,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;QAC7C,MAAM,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;QACvD,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,cAAc,CAAC,0BAA0B,CAAC,CAAA;YAC1C,OAAM;QACR,CAAC;QACD,IAAI,CAAC,MAAM,IAAI,CAAC,MAAM,EAAE,CAAC;YACvB,cAAc,CAAC,oDAAoD,CAAC,CAAA;YACpE,OAAM;QACR,CAAC;QACD,IAAI,CAAC,MAAM,IAAI,QAAQ,KAAK,MAAM,EAAE,CAAC;YACnC,cAAc,CAAC,mEAAmE,CAAC,CAAA;YACnF,OAAM;QACR,CAAC;QACD,cAAc,CAAC,IAAI,CAAC,CAAA;QACpB,SAAS,CAAC,IAAI,CAAC,CAAA;QACf,MAAM,OAAO,GAAwB,EAAE,GAAG,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAA;QAClE,MAAM,GAAG,GAAG,IAAI;YACd,CAAC,CAAC,MAAM,kBAAkB,CAAC,IAAI,CAAC,EAAE,EAAE,OAAO,CAAC;YAC5C,CAAC,CAAC,MAAM,kBAAkB,CAAC,OAAO,CAAC,CAAA;QACrC,SAAS,CAAC,KAAK,CAAC,CAAA;QAChB,IAAI,GAAG,CAAC,KAAK,EAAE,CAAC;YACd,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;YACtB,OAAM;QACR,CAAC;QACD,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAA;QAC/D,YAAY,CAAC,KAAK,CAAC,CAAA;QACnB,OAAO,EAAE,EAAE,CAAA;IACb,CAAC;IAED,OAAO,CACL,KAAC,MAAM,IACL,IAAI,EAAE,IAAI,EACV,YAAY,EAAE,YAAY,EAC1B,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,cAAc,EAC9C,KAAK,EAAC,UAAU,EAChB,MAAM,EACJ,8BACE,iBAAQ,SAAS,EAAE,YAAY,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,YAAY,CAAC,KAAK,CAAC,EAAE,QAAQ,EAAE,MAAM,uBAE5E,EACT,iBAAQ,SAAS,EAAE,UAAU,EAAE,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,YACjE,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,iBAAiB,GACxD,IACR,YAGL,eAAK,SAAS,EAAC,WAAW,aACvB,WAAW,IAAI,CACd,YACE,SAAS,EAAC,iEAAiE,EAC3E,IAAI,EAAC,OAAO,YAEX,WAAW,GACV,CACL,EACD,eAAK,SAAS,EAAC,aAAa,aAC1B,gBAAO,SAAS,EAAC,qCAAqC,EAAC,OAAO,EAAC,YAAY,4BAEnE,EACR,iBACE,EAAE,EAAC,YAAY,EACf,SAAS,EAAE,QAAQ,EACnB,KAAK,EAAE,IAAI,CAAC,IAAI,EAChB,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAuB,EAAE,CAAC,YAE9E,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CACvB,iBAAsB,KAAK,EAAE,CAAC,CAAC,KAAK,YACjC,CAAC,CAAC,KAAK,IADG,CAAC,CAAC,KAAK,CAEX,CACV,CAAC,GACK,IACL,EAEN,eAAK,SAAS,EAAC,aAAa,aAC1B,gBAAO,SAAS,EAAC,qCAAqC,EAAC,OAAO,EAAC,YAAY,4BAEnE,EACR,gBACE,EAAE,EAAC,YAAY,EACf,SAAS,EAAE,QAAQ,EACnB,KAAK,EAAE,IAAI,CAAC,QAAQ,EACpB,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,EACrD,WAAW,EAAC,WAAW,GACvB,IACE,EAEL,CAAC,MAAM,IAAI,CACV,eAAK,SAAS,EAAC,aAAa,aAC1B,gBAAO,SAAS,EAAC,qCAAqC,EAAC,OAAO,EAAC,UAAU,4BAEjE,EACR,gBACE,EAAE,EAAC,UAAU,EACb,SAAS,EAAE,QAAQ,EACnB,KAAK,EAAE,IAAI,CAAC,MAAM,EAClB,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,EACnD,WAAW,EAAC,uCAAuC,GACnD,IACE,CACP,EAED,eAAK,SAAS,EAAC,aAAa,aAC1B,iBAAO,SAAS,EAAC,qCAAqC,EAAC,OAAO,EAAC,aAAa,uBACpE,eAAM,SAAS,EAAC,mCAAmC,2BAAkB,IACrE,EACR,gBACE,EAAE,EAAC,aAAa,EAChB,SAAS,EAAE,QAAQ,EACnB,KAAK,EAAE,IAAI,CAAC,KAAK,IAAI,EAAE,EACvB,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,EAClD,WAAW,EAAC,0BAA0B,GACtC,IACE,EAEN,eAAK,SAAS,EAAC,+CAA+C,aAC5D,iBAAO,SAAS,EAAC,yCAAyC,aACxD,eAAM,SAAS,EAAC,qCAAqC,wBAAe,EACpE,gBACE,IAAI,EAAC,UAAU,EACf,IAAI,EAAC,QAAQ,kBACC,CAAC,CAAC,IAAI,CAAC,OAAO,EAC5B,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,OAAO,EACvB,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,EACtD,SAAS,EAAC,wBAAwB,GAClC,IACI,EACP,CAAC,MAAM,IAAI,CACV,iBAAO,SAAS,EAAC,yCAAyC,aACxD,gBAAM,SAAS,EAAC,SAAS,aACvB,eAAM,SAAS,EAAC,2CAA2C,sCAEpD,EACP,eAAM,SAAS,EAAC,qCAAqC,qEAE9C,IACF,EACP,gBACE,IAAI,EAAC,UAAU,EACf,IAAI,EAAC,QAAQ,kBACC,CAAC,CAAC,IAAI,CAAC,aAAa,EAClC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,aAAa,EAC7B,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,EAAE,aAAa,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,EAC5D,SAAS,EAAC,iCAAiC,GAC3C,IACI,CACT,IACG,IACF,GACC,CACV,CAAA;AACH,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * AI Copilot drawer — summarizes the current SEO state and surfaces the top
3
+ * priorities. Degrades gracefully when AI is unconfigured. All AI text is
4
+ * advisory; the editor takes action via the tabs/drawers.
5
+ */
6
+ export declare function SeoCopilotDrawer({ open, onOpenChange, }: {
7
+ open: boolean;
8
+ onOpenChange: (open: boolean) => void;
9
+ }): import("react/jsx-runtime").JSX.Element;
10
+ //# sourceMappingURL=SeoCopilotDrawer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SeoCopilotDrawer.d.ts","sourceRoot":"","sources":["../../../src/components/seo/SeoCopilotDrawer.tsx"],"names":[],"mappings":"AASA;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,EAC/B,IAAI,EACJ,YAAY,GACb,EAAE;IACD,IAAI,EAAE,OAAO,CAAA;IACb,YAAY,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;CACtC,2CAuDA"}
@@ -0,0 +1,34 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useState } from 'react';
4
+ import { Sparkles, Bot } from 'lucide-react';
5
+ import { toast } from 'sonner';
6
+ import { summarizeSeoAudit } from '../../lib/seo-service.js';
7
+ import { Drawer } from './Drawer.js';
8
+ import { SeoLoading, SeoEmptyState, btnPrimary } from './primitives.js';
9
+ /**
10
+ * AI Copilot drawer — summarizes the current SEO state and surfaces the top
11
+ * priorities. Degrades gracefully when AI is unconfigured. All AI text is
12
+ * advisory; the editor takes action via the tabs/drawers.
13
+ */
14
+ export function SeoCopilotDrawer({ open, onOpenChange, }) {
15
+ const [loading, setLoading] = useState(false);
16
+ const [summary, setSummary] = useState(null);
17
+ const [unavailable, setUnavailable] = useState(false);
18
+ async function handleSummarize() {
19
+ setLoading(true);
20
+ setUnavailable(false);
21
+ const res = await summarizeSeoAudit();
22
+ setLoading(false);
23
+ if (res.unavailable) {
24
+ setUnavailable(true);
25
+ return;
26
+ }
27
+ if (res.text)
28
+ setSummary(res.text);
29
+ else
30
+ toast.error('No summary was returned.');
31
+ }
32
+ return (_jsx(Drawer, { open: open, onOpenChange: onOpenChange, title: "SEO Copilot", description: "AI-assisted analysis of your site's SEO health", width: "max-w-md", footer: _jsxs("button", { className: btnPrimary, onClick: handleSummarize, disabled: loading, children: [_jsx(Sparkles, { className: `h-4 w-4 ${loading ? 'animate-pulse' : ''}`, "aria-hidden": true }), loading ? 'Analyzing…' : summary ? 'Re-analyze' : 'Analyze my SEO'] }), children: loading ? (_jsx(SeoLoading, { label: "Analyzing your SEO\u2026" })) : unavailable ? (_jsx(SeoEmptyState, { icon: _jsx(Bot, { size: 24 }), title: "AI is not configured", description: "Install and configure an AI provider (plugin-ai) to enable the SEO Copilot." })) : summary ? (_jsx("div", { className: "text-foreground space-y-3 text-sm leading-relaxed", children: summary.split(/\n+/).map((para, i) => (_jsx("p", { children: para }, i))) })) : (_jsx(SeoEmptyState, { icon: _jsx(Bot, { size: 24 }), title: "Ask the Copilot", description: "Get an AI summary of your open issues and the top priorities to fix first." })) }));
33
+ }
34
+ //# sourceMappingURL=SeoCopilotDrawer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SeoCopilotDrawer.js","sourceRoot":"","sources":["../../../src/components/seo/SeoCopilotDrawer.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAA;;AAEZ,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAChC,OAAO,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,cAAc,CAAA;AAC5C,OAAO,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAA;AAC9B,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAA;AAC5D,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACpC,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAEvE;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,EAC/B,IAAI,EACJ,YAAY,GAIb;IACC,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAA;IAC7C,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAgB,IAAI,CAAC,CAAA;IAC3D,MAAM,CAAC,WAAW,EAAE,cAAc,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAA;IAErD,KAAK,UAAU,eAAe;QAC5B,UAAU,CAAC,IAAI,CAAC,CAAA;QAChB,cAAc,CAAC,KAAK,CAAC,CAAA;QACrB,MAAM,GAAG,GAAG,MAAM,iBAAiB,EAAE,CAAA;QACrC,UAAU,CAAC,KAAK,CAAC,CAAA;QACjB,IAAI,GAAG,CAAC,WAAW,EAAE,CAAC;YACpB,cAAc,CAAC,IAAI,CAAC,CAAA;YACpB,OAAM;QACR,CAAC;QACD,IAAI,GAAG,CAAC,IAAI;YAAE,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;;YAC7B,KAAK,CAAC,KAAK,CAAC,0BAA0B,CAAC,CAAA;IAC9C,CAAC;IAED,OAAO,CACL,KAAC,MAAM,IACL,IAAI,EAAE,IAAI,EACV,YAAY,EAAE,YAAY,EAC1B,KAAK,EAAC,aAAa,EACnB,WAAW,EAAC,gDAAgD,EAC5D,KAAK,EAAC,UAAU,EAChB,MAAM,EACJ,kBAAQ,SAAS,EAAE,UAAU,EAAE,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,OAAO,aACxE,KAAC,QAAQ,IAAC,SAAS,EAAE,WAAW,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE,EAAE,wBAAgB,EAC/E,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,gBAAgB,IAC5D,YAGV,OAAO,CAAC,CAAC,CAAC,CACT,KAAC,UAAU,IAAC,KAAK,EAAC,0BAAqB,GAAG,CAC3C,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAChB,KAAC,aAAa,IACZ,IAAI,EAAE,KAAC,GAAG,IAAC,IAAI,EAAE,EAAE,GAAI,EACvB,KAAK,EAAC,sBAAsB,EAC5B,WAAW,EAAC,6EAA6E,GACzF,CACH,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CACZ,cAAK,SAAS,EAAC,mDAAmD,YAC/D,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC,CACrC,sBAAY,IAAI,IAAR,CAAC,CAAY,CACtB,CAAC,GACE,CACP,CAAC,CAAC,CAAC,CACF,KAAC,aAAa,IACZ,IAAI,EAAE,KAAC,GAAG,IAAC,IAAI,EAAE,EAAE,GAAI,EACvB,KAAK,EAAC,iBAAiB,EACvB,WAAW,EAAC,4EAA4E,GACxF,CACH,GACM,CACV,CAAA;AACH,CAAC"}
@@ -0,0 +1,8 @@
1
+ export declare function SeoEditorDrawer({ open, onOpenChange, entityType, entityId, onSaved, }: {
2
+ open: boolean;
3
+ onOpenChange: (open: boolean) => void;
4
+ entityType: string | null;
5
+ entityId: string | null;
6
+ onSaved?: () => void;
7
+ }): import("react/jsx-runtime").JSX.Element;
8
+ //# sourceMappingURL=SeoEditorDrawer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SeoEditorDrawer.d.ts","sourceRoot":"","sources":["../../../src/components/seo/SeoEditorDrawer.tsx"],"names":[],"mappings":"AAoDA,wBAAgB,eAAe,CAAC,EAC9B,IAAI,EACJ,YAAY,EACZ,UAAU,EACV,QAAQ,EACR,OAAO,GACR,EAAE;IACD,IAAI,EAAE,OAAO,CAAA;IACb,YAAY,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;IACrC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;IACvB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;CACrB,2CA0RA"}
@@ -0,0 +1,111 @@
1
+ 'use client';
2
+ import { jsxs as _jsxs, jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
3
+ import { useEffect, useState } from 'react';
4
+ import { Sparkles, Check } from 'lucide-react';
5
+ import { toast } from 'sonner';
6
+ import { fetchSeoContentRecord, updateSeoFields, generateSeoField, } from '../../lib/seo-service.js';
7
+ import { Drawer } from './Drawer.js';
8
+ import { SeoLoading, SeoErrorState, btnPrimary, btnSecondary, gradeMeta } from './primitives.js';
9
+ const META_TITLE_MAX = 60;
10
+ const META_DESC_MAX = 160;
11
+ function CharCount({ value, max }) {
12
+ const over = value.length > max;
13
+ return (_jsxs("span", { className: `text-xs ${over ? 'text-destructive' : 'text-muted-foreground'}`, children: [value.length, "/", max] }));
14
+ }
15
+ function Field({ label, children, hint, }) {
16
+ return (_jsxs("div", { className: "space-y-1.5", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsx("label", { className: "text-foreground text-sm font-medium", children: label }), hint] }), children] }));
17
+ }
18
+ const inputCls = 'w-full rounded-md border border-border bg-input-background px-3 py-2 text-base text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring';
19
+ export function SeoEditorDrawer({ open, onOpenChange, entityType, entityId, onSaved, }) {
20
+ const [record, setRecord] = useState(null);
21
+ const [loading, setLoading] = useState(false);
22
+ const [error, setError] = useState(null);
23
+ const [saving, setSaving] = useState(false);
24
+ const [aiBusy, setAiBusy] = useState(null);
25
+ const [form, setForm] = useState({});
26
+ useEffect(() => {
27
+ if (!open || !entityType || !entityId)
28
+ return;
29
+ let alive = true;
30
+ setLoading(true);
31
+ setError(null);
32
+ fetchSeoContentRecord(entityType, entityId)
33
+ .then((rec) => {
34
+ if (!alive)
35
+ return;
36
+ if (!rec) {
37
+ setError('Could not load this record.');
38
+ return;
39
+ }
40
+ setRecord(rec);
41
+ setForm({
42
+ metaTitle: rec.metaTitle ?? '',
43
+ metaDescription: rec.metaDescription ?? '',
44
+ canonicalUrl: rec.canonicalUrl ?? '',
45
+ focusKeyword: rec.focusKeyword ?? '',
46
+ ogTitle: rec.ogTitle ?? '',
47
+ ogDescription: rec.ogDescription ?? '',
48
+ noindex: rec.noindex,
49
+ nofollow: rec.nofollow,
50
+ });
51
+ })
52
+ .catch((e) => alive && setError(e instanceof Error ? e.message : 'Failed to load'))
53
+ .finally(() => alive && setLoading(false));
54
+ return () => {
55
+ alive = false;
56
+ };
57
+ }, [open, entityType, entityId]);
58
+ const update = (patch) => setForm((f) => ({ ...f, ...patch }));
59
+ async function handleAiGenerate(field) {
60
+ if (!entityType || !entityId)
61
+ return;
62
+ setAiBusy(field);
63
+ try {
64
+ const result = await generateSeoField(field, { entityType, entityId });
65
+ if (result.unavailable) {
66
+ toast.error('AI is not configured. Add an AI provider to enable suggestions.');
67
+ return;
68
+ }
69
+ if (result.text) {
70
+ update({ [field]: result.text });
71
+ toast.success('AI suggestion applied — review before saving.');
72
+ }
73
+ else {
74
+ toast.error('No suggestion was returned.');
75
+ }
76
+ }
77
+ catch {
78
+ toast.error('AI request failed.');
79
+ }
80
+ finally {
81
+ setAiBusy(null);
82
+ }
83
+ }
84
+ async function handleSave() {
85
+ if (!entityType || !entityId)
86
+ return;
87
+ setSaving(true);
88
+ const res = await updateSeoFields(entityType, entityId, form);
89
+ setSaving(false);
90
+ if (res.error) {
91
+ toast.error(res.error);
92
+ return;
93
+ }
94
+ toast.success('SEO fields saved.');
95
+ onOpenChange(false);
96
+ onSaved?.();
97
+ }
98
+ const title = form.metaTitle || record?.title || 'Untitled';
99
+ const desc = form.metaDescription || 'No meta description set. Search engines may generate one.';
100
+ const url = record?.url ?? '';
101
+ function aiButton(field) {
102
+ return (_jsxs("button", { type: "button", onClick: () => handleAiGenerate(field), disabled: aiBusy !== null, className: "text-primary hover:bg-accent focus-visible:ring-ring inline-flex items-center gap-1 rounded-md px-2 py-0.5 text-xs font-medium focus-visible:ring-2 focus-visible:outline-none disabled:opacity-60", children: [_jsx(Sparkles, { className: `h-3.5 w-3.5 ${aiBusy === field ? 'animate-pulse' : ''}`, "aria-hidden": true }), aiBusy === field ? 'Generating…' : 'AI Generate'] }));
103
+ }
104
+ return (_jsx(Drawer, { open: open, onOpenChange: onOpenChange, title: "Edit SEO", description: record?.title, footer: _jsxs(_Fragment, { children: [_jsx("button", { className: btnSecondary, onClick: () => onOpenChange(false), disabled: saving, children: "Cancel" }), _jsx("button", { className: btnPrimary, onClick: handleSave, disabled: saving || loading, children: saving ? 'Saving…' : 'Save changes' })] }), children: loading ? (_jsx(SeoLoading, {})) : error ? (_jsx(SeoErrorState, { message: error })) : record ? (_jsxs("div", { className: "space-y-6", children: [_jsxs("div", { className: "border-border rounded-lg border p-4", children: [_jsx("p", { className: "text-muted-foreground mb-2 text-xs font-medium tracking-wide uppercase", children: "Google preview" }), _jsx("p", { className: "text-success truncate text-sm", children: url }), _jsx("p", { className: "text-primary text-lg leading-snug", children: title }), _jsx("p", { className: "text-muted-foreground line-clamp-2 text-sm", children: desc })] }), _jsx(Field, { label: "Meta title", hint: _jsxs("span", { className: "flex items-center gap-2", children: [_jsx(CharCount, { value: form.metaTitle ?? '', max: META_TITLE_MAX }), aiButton('metaTitle')] }), children: _jsx("input", { className: inputCls, value: form.metaTitle ?? '', onChange: (e) => update({ metaTitle: e.target.value }), placeholder: "Page title for search results" }) }), _jsx(Field, { label: "Meta description", hint: _jsxs("span", { className: "flex items-center gap-2", children: [_jsx(CharCount, { value: form.metaDescription ?? '', max: META_DESC_MAX }), aiButton('metaDescription')] }), children: _jsx("textarea", { className: `${inputCls} min-h-20 resize-y`, value: form.metaDescription ?? '', onChange: (e) => update({ metaDescription: e.target.value }), placeholder: "Short summary shown under the title in search results" }) }), _jsx(Field, { label: "Focus keyword", hint: aiButton('focusKeyword'), children: _jsx("input", { className: inputCls, value: form.focusKeyword ?? '', onChange: (e) => update({ focusKeyword: e.target.value }), placeholder: "Primary keyword this page targets" }) }), _jsx(Field, { label: "Canonical URL", children: _jsx("input", { className: inputCls, value: form.canonicalUrl ?? '', onChange: (e) => update({ canonicalUrl: e.target.value }), placeholder: url || 'https://example.com/page' }) }), _jsxs("div", { className: "space-y-4", children: [_jsx("p", { className: "text-foreground text-sm font-medium", children: "Social sharing" }), _jsx(Field, { label: "Open Graph title", hint: aiButton('ogTitle'), children: _jsx("input", { className: inputCls, value: form.ogTitle ?? '', onChange: (e) => update({ ogTitle: e.target.value }), placeholder: form.metaTitle || 'Title when shared on social media' }) }), _jsx(Field, { label: "Open Graph description", hint: aiButton('ogDescription'), children: _jsx("textarea", { className: `${inputCls} min-h-16 resize-y`, value: form.ogDescription ?? '', onChange: (e) => update({ ogDescription: e.target.value }), placeholder: form.metaDescription || 'Description when shared on social media' }) }), _jsxs("div", { className: "border-border overflow-hidden rounded-lg border", children: [record.ogImage ? (
105
+ // eslint-disable-next-line @next/next/no-img-element
106
+ _jsx("img", { src: record.ogImage, alt: `Social preview for ${record.title}`, className: "bg-muted aspect-[1200/630] w-full object-cover" })) : (_jsx("div", { className: "bg-muted text-muted-foreground flex aspect-[1200/630] w-full items-center justify-center text-sm", children: "No OG image set" })), _jsxs("div", { className: "p-3", children: [_jsx("p", { className: "text-muted-foreground truncate text-xs uppercase", children: url.replace(/^https?:\/\//, '').split('/')[0] }), _jsx("p", { className: "text-foreground truncate text-sm font-medium", children: form.ogTitle || title }), _jsx("p", { className: "text-muted-foreground line-clamp-1 text-sm", children: form.ogDescription || desc })] })] })] }), _jsxs("div", { className: "border-border space-y-3 rounded-lg border p-4", children: [_jsxs("label", { className: "flex items-center justify-between gap-3", children: [_jsxs("span", { className: "min-w-0", children: [_jsx("span", { className: "text-foreground block text-sm font-medium", children: "No-index" }), _jsx("span", { className: "text-muted-foreground block text-sm", children: "Hide this page from search engines." })] }), _jsx("input", { type: "checkbox", role: "switch", "aria-checked": !!form.noindex, checked: !!form.noindex, onChange: (e) => update({ noindex: e.target.checked }), className: "accent-primary h-4 w-4" })] }), _jsxs("label", { className: "flex items-center justify-between gap-3", children: [_jsxs("span", { className: "min-w-0", children: [_jsx("span", { className: "text-foreground block text-sm font-medium", children: "No-follow" }), _jsx("span", { className: "text-muted-foreground block text-sm", children: "Tell crawlers not to follow links on this page." })] }), _jsx("input", { type: "checkbox", role: "switch", "aria-checked": !!form.nofollow, checked: !!form.nofollow, onChange: (e) => update({ nofollow: e.target.checked }), className: "accent-primary h-4 w-4" })] })] }), (() => {
107
+ const meta = gradeMeta(record.seoGrade);
108
+ return (_jsxs("div", { className: `flex items-center gap-2 rounded-lg px-3 py-2 text-sm ${meta.bg} ${meta.text}`, children: [_jsx(Check, { className: "h-4 w-4", "aria-hidden": true }), "Current SEO score: ", _jsx("span", { className: "font-medium", children: record.seoScore }), " (", meta.label, ")"] }));
109
+ })()] })) : null }));
110
+ }
111
+ //# sourceMappingURL=SeoEditorDrawer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SeoEditorDrawer.js","sourceRoot":"","sources":["../../../src/components/seo/SeoEditorDrawer.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ export declare function SeoIssueFixDrawer({ open, onOpenChange, issueId, onChanged, onNavigate, }: {
2
+ open: boolean;
3
+ onOpenChange: (open: boolean) => void;
4
+ issueId: string | null;
5
+ onChanged?: () => void;
6
+ onNavigate?: (path: string) => void;
7
+ }): import("react/jsx-runtime").JSX.Element;
8
+ //# sourceMappingURL=SeoIssueFixDrawer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SeoIssueFixDrawer.d.ts","sourceRoot":"","sources":["../../../src/components/seo/SeoIssueFixDrawer.tsx"],"names":[],"mappings":"AAyDA,wBAAgB,iBAAiB,CAAC,EAChC,IAAI,EACJ,YAAY,EACZ,OAAO,EACP,SAAS,EACT,UAAU,GACX,EAAE;IACD,IAAI,EAAE,OAAO,CAAA;IACb,YAAY,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;IACrC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;IACtB,SAAS,CAAC,EAAE,MAAM,IAAI,CAAA;IACtB,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;CACpC,2CA8KA"}
@@ -0,0 +1,111 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
+ import { useEffect, useState } from 'react';
4
+ import { Sparkles, ArrowRight, ExternalLink, Image as ImageIcon, Gauge } from 'lucide-react';
5
+ import { toast } from 'sonner';
6
+ import { fetchSeoIssue, resolveSeoIssue, ignoreSeoIssue, reopenSeoIssue, explainSeoIssue, } from '../../lib/seo-service.js';
7
+ import { Drawer } from './Drawer.js';
8
+ import { SeoLoading, SeoErrorState, severityMeta, btnPrimary, btnSecondary } from './primitives.js';
9
+ /** Map a fix action to a destination route within the admin. */
10
+ function fixRoute(issue) {
11
+ const ent = issue.entityType;
12
+ const id = issue.entityId;
13
+ switch (issue.fixActionType) {
14
+ case 'edit-metadata':
15
+ case 'edit-canonical':
16
+ case 'edit-og':
17
+ case 'edit-schema':
18
+ if (ent && id) {
19
+ return {
20
+ label: 'Edit content SEO',
21
+ path: `/seo?tab=content&entityType=${ent}&entityId=${encodeURIComponent(id)}`,
22
+ icon: _jsx(ArrowRight, { className: "h-4 w-4", "aria-hidden": true }),
23
+ };
24
+ }
25
+ return null;
26
+ case 'fix-broken-link':
27
+ case 'create-redirect':
28
+ return {
29
+ label: 'Open redirects',
30
+ path: '/seo?tab=redirects',
31
+ icon: _jsx(ArrowRight, { className: "h-4 w-4", "aria-hidden": true }),
32
+ };
33
+ case 'optimize-media':
34
+ return {
35
+ label: 'Open Media Center',
36
+ path: '/media',
37
+ icon: _jsx(ImageIcon, { className: "h-4 w-4", "aria-hidden": true }),
38
+ };
39
+ case 'improve-speed':
40
+ return {
41
+ label: 'Technical settings',
42
+ path: '/seo?tab=technical',
43
+ icon: _jsx(Gauge, { className: "h-4 w-4", "aria-hidden": true }),
44
+ };
45
+ default:
46
+ return null;
47
+ }
48
+ }
49
+ export function SeoIssueFixDrawer({ open, onOpenChange, issueId, onChanged, onNavigate, }) {
50
+ const [issue, setIssue] = useState(null);
51
+ const [loading, setLoading] = useState(false);
52
+ const [error, setError] = useState(null);
53
+ const [busy, setBusy] = useState(false);
54
+ const [explanation, setExplanation] = useState(null);
55
+ const [explaining, setExplaining] = useState(false);
56
+ useEffect(() => {
57
+ if (!open || !issueId)
58
+ return;
59
+ let alive = true;
60
+ setLoading(true);
61
+ setError(null);
62
+ setExplanation(null);
63
+ fetchSeoIssue(issueId)
64
+ .then((i) => {
65
+ if (!alive)
66
+ return;
67
+ if (!i)
68
+ setError('Issue not found.');
69
+ else
70
+ setIssue(i);
71
+ })
72
+ .catch((e) => alive && setError(e instanceof Error ? e.message : 'Failed to load'))
73
+ .finally(() => alive && setLoading(false));
74
+ return () => {
75
+ alive = false;
76
+ };
77
+ }, [open, issueId]);
78
+ async function mutate(fn, successMsg) {
79
+ if (!issue)
80
+ return;
81
+ setBusy(true);
82
+ const res = await fn(issue.id);
83
+ setBusy(false);
84
+ if (res.error)
85
+ return toast.error(res.error);
86
+ toast.success(successMsg);
87
+ onOpenChange(false);
88
+ onChanged?.();
89
+ }
90
+ async function handleExplain() {
91
+ if (!issue)
92
+ return;
93
+ setExplaining(true);
94
+ const res = await explainSeoIssue(issue.id);
95
+ setExplaining(false);
96
+ if (res.unavailable) {
97
+ toast.error('AI is not configured.');
98
+ return;
99
+ }
100
+ setExplanation(res.text ?? 'No explanation available.');
101
+ }
102
+ const route = issue ? fixRoute(issue) : null;
103
+ return (_jsx(Drawer, { open: open, onOpenChange: onOpenChange, title: "Issue detail", width: "max-w-lg", footer: issue ? (_jsxs(_Fragment, { children: [issue.status === 'ignored' ? (_jsx("button", { className: btnSecondary, onClick: () => mutate(reopenSeoIssue, 'Issue reopened.'), disabled: busy, children: "Reopen" })) : (_jsx("button", { className: btnSecondary, onClick: () => mutate(ignoreSeoIssue, 'Issue ignored.'), disabled: busy, children: "Ignore" })), route && onNavigate ? (_jsxs("button", { className: btnPrimary, onClick: () => {
104
+ onNavigate(route.path);
105
+ onOpenChange(false);
106
+ }, children: [route.icon, route.label] })) : (_jsx("button", { className: btnPrimary, onClick: () => mutate(resolveSeoIssue, 'Issue resolved.'), disabled: busy, children: "Mark resolved" }))] })) : null, children: loading ? (_jsx(SeoLoading, {})) : error ? (_jsx(SeoErrorState, { message: error })) : issue ? (_jsxs("div", { className: "space-y-4", children: [(() => {
107
+ const meta = severityMeta(issue.severity);
108
+ return (_jsxs("span", { className: `inline-flex items-center gap-1.5 rounded-full px-2.5 py-0.5 text-xs font-medium ${meta.bg} ${meta.text}`, children: [_jsx("span", { className: `h-1.5 w-1.5 rounded-full ${meta.dot}`, "aria-hidden": true }), meta.label, " \u00B7 ", issue.category] }));
109
+ })(), _jsxs("div", { children: [_jsx("h3", { className: "text-foreground text-base font-medium", children: issue.title }), issue.entityTitle && (_jsx("p", { className: "text-muted-foreground mt-0.5 text-sm", children: issue.entityTitle }))] }), issue.url && (_jsxs("a", { href: issue.url, target: "_blank", rel: "noopener noreferrer", className: "text-primary inline-flex items-center gap-1 text-sm hover:underline", children: [issue.url, _jsx(ExternalLink, { className: "h-3.5 w-3.5", "aria-hidden": true })] })), issue.description && _jsx("p", { className: "text-foreground text-sm", children: issue.description }), issue.impact && (_jsxs("div", { className: "border-border rounded-md border p-3", children: [_jsx("p", { className: "text-muted-foreground text-xs font-medium tracking-wide uppercase", children: "Impact" }), _jsx("p", { className: "text-foreground mt-1 text-sm", children: issue.impact })] })), issue.recommendation && (_jsxs("div", { className: "border-border rounded-md border p-3", children: [_jsx("p", { className: "text-muted-foreground text-xs font-medium tracking-wide uppercase", children: "Recommendation" }), _jsx("p", { className: "text-foreground mt-1 text-sm", children: issue.recommendation })] })), _jsxs("div", { className: "border-border rounded-md border p-3", children: [_jsxs("button", { onClick: handleExplain, disabled: explaining, className: "text-primary focus-visible:ring-ring inline-flex items-center gap-1.5 text-sm font-medium focus-visible:ring-2 focus-visible:outline-none disabled:opacity-60", children: [_jsx(Sparkles, { className: `h-4 w-4 ${explaining ? 'animate-pulse' : ''}`, "aria-hidden": true }), explaining ? 'Asking AI…' : 'Explain with AI'] }), explanation && _jsx("p", { className: "text-foreground mt-2 text-sm", children: explanation })] })] })) : null }));
110
+ }
111
+ //# sourceMappingURL=SeoIssueFixDrawer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SeoIssueFixDrawer.js","sourceRoot":"","sources":["../../../src/components/seo/SeoIssueFixDrawer.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Shared SEO UI primitives — token-only, accessible building blocks used across
3
+ * the five SEO tabs. No raw palette colours: status uses the theme's
4
+ * success / warning / destructive / muted tokens.
5
+ */
6
+ import type { ReactNode } from 'react';
7
+ import type { SeoGrade, SeoSeverity } from '../../lib/seo-service.js';
8
+ export interface GradeMeta {
9
+ label: string;
10
+ text: string;
11
+ bg: string;
12
+ dot: string;
13
+ }
14
+ export declare function gradeMeta(grade: SeoGrade): GradeMeta;
15
+ /** Grade band from a numeric 0-100 score. */
16
+ export declare function gradeFromScore(score: number): SeoGrade;
17
+ export declare function severityMeta(severity: SeoSeverity): GradeMeta;
18
+ export declare function SeoStatusBadge({ label, tone, }: {
19
+ label: string;
20
+ tone: 'good' | 'fair' | 'poor' | 'critical' | 'neutral';
21
+ }): import("react/jsx-runtime").JSX.Element;
22
+ /** A horizontal score bar (0-100), coloured by grade. */
23
+ export declare function SeoScoreBar({ score, className }: {
24
+ score: number;
25
+ className?: string;
26
+ }): import("react/jsx-runtime").JSX.Element;
27
+ export declare function ScorePill({ score }: {
28
+ score: number;
29
+ }): import("react/jsx-runtime").JSX.Element;
30
+ export declare function SectionCard({ title, description, action, children, className, }: {
31
+ title?: string;
32
+ description?: string;
33
+ action?: ReactNode;
34
+ children: ReactNode;
35
+ className?: string;
36
+ }): import("react/jsx-runtime").JSX.Element;
37
+ export declare function SeoLoading({ label }: {
38
+ label?: string;
39
+ }): import("react/jsx-runtime").JSX.Element;
40
+ export declare function SeoEmptyState({ icon, title, description, action, }: {
41
+ icon?: ReactNode;
42
+ title: string;
43
+ description?: string;
44
+ action?: ReactNode;
45
+ }): import("react/jsx-runtime").JSX.Element;
46
+ export declare function SeoErrorState({ message, onRetry }: {
47
+ message: string;
48
+ onRetry?: () => void;
49
+ }): import("react/jsx-runtime").JSX.Element;
50
+ export declare const btnPrimary = "inline-flex items-center justify-center gap-2 rounded-md bg-primary px-4 py-2 text-base font-medium text-primary-foreground transition-colors hover:bg-primary/90 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:opacity-60";
51
+ export declare const btnSecondary = "inline-flex items-center justify-center gap-2 rounded-md border border-border bg-card px-4 py-2 text-base font-medium text-foreground transition-colors hover:bg-accent focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:opacity-60";
52
+ export declare const btnGhostIcon = "inline-flex items-center justify-center rounded-md p-2 text-muted-foreground transition-colors hover:bg-accent hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring";
53
+ //# sourceMappingURL=primitives.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"primitives.d.ts","sourceRoot":"","sources":["../../../src/components/seo/primitives.tsx"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAEtC,OAAO,KAAK,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAA;AAIrE,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;IACZ,EAAE,EAAE,MAAM,CAAA;IACV,GAAG,EAAE,MAAM,CAAA;CACZ;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,QAAQ,GAAG,SAAS,CAqBpD;AAED,6CAA6C;AAC7C,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,QAAQ,CAKtD;AAED,wBAAgB,YAAY,CAAC,QAAQ,EAAE,WAAW,GAAG,SAAS,CAmB7D;AAID,wBAAgB,cAAc,CAAC,EAC7B,KAAK,EACL,IAAI,GACL,EAAE;IACD,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,UAAU,GAAG,SAAS,CAAA;CACxD,2CA4BA;AAED,yDAAyD;AACzD,wBAAgB,WAAW,CAAC,EAAE,KAAK,EAAE,SAAc,EAAE,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,2CAiB3F;AAED,wBAAgB,SAAS,CAAC,EAAE,KAAK,EAAE,EAAE;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,2CAUrD;AAID,wBAAgB,WAAW,CAAC,EAC1B,KAAK,EACL,WAAW,EACX,MAAM,EACN,QAAQ,EACR,SAAc,GACf,EAAE;IACD,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,MAAM,CAAC,EAAE,SAAS,CAAA;IAClB,QAAQ,EAAE,SAAS,CAAA;IACnB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,2CAeA;AAED,wBAAgB,UAAU,CAAC,EAAE,KAAkB,EAAE,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,2CAOpE;AAED,wBAAgB,aAAa,CAAC,EAC5B,IAAI,EACJ,KAAK,EACL,WAAW,EACX,MAAM,GACP,EAAE;IACD,IAAI,CAAC,EAAE,SAAS,CAAA;IAChB,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,MAAM,CAAC,EAAE,SAAS,CAAA;CACnB,2CAaA;AAED,wBAAgB,aAAa,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;CAAE,2CAkB5F;AAID,eAAO,MAAM,UAAU,kQAC0O,CAAA;AAEjQ,eAAO,MAAM,YAAY,wQAC8O,CAAA;AAEvQ,eAAO,MAAM,YAAY,iNACuL,CAAA"}