@actuate-media/cms-admin 0.19.0 → 0.21.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.
- package/dist/AdminRoot.d.ts.map +1 -1
- package/dist/AdminRoot.js +13 -9
- package/dist/AdminRoot.js.map +1 -1
- package/dist/__tests__/layout/sidebar-posts.test.js +6 -4
- package/dist/__tests__/layout/sidebar-posts.test.js.map +1 -1
- package/dist/__tests__/lib/seo-service-errors.test.d.ts +2 -0
- package/dist/__tests__/lib/seo-service-errors.test.d.ts.map +1 -0
- package/dist/__tests__/lib/seo-service-errors.test.js +46 -0
- package/dist/__tests__/lib/seo-service-errors.test.js.map +1 -0
- package/dist/__tests__/views/use-seo-resource.test.d.ts +2 -0
- package/dist/__tests__/views/use-seo-resource.test.d.ts.map +1 -0
- package/dist/__tests__/views/use-seo-resource.test.js +56 -0
- package/dist/__tests__/views/use-seo-resource.test.js.map +1 -0
- package/dist/actuate-admin.css +1 -1
- package/dist/components/Breadcrumbs.d.ts.map +1 -1
- package/dist/components/Breadcrumbs.js +4 -1
- package/dist/components/Breadcrumbs.js.map +1 -1
- package/dist/components/seo/Drawer.d.ts +11 -0
- package/dist/components/seo/Drawer.d.ts.map +1 -0
- package/dist/components/seo/Drawer.js +17 -0
- package/dist/components/seo/Drawer.js.map +1 -0
- package/dist/components/seo/RedirectEditorDrawer.d.ts +9 -0
- package/dist/components/seo/RedirectEditorDrawer.d.ts.map +1 -0
- package/dist/components/seo/RedirectEditorDrawer.js +94 -0
- package/dist/components/seo/RedirectEditorDrawer.js.map +1 -0
- package/dist/components/seo/SeoCopilotDrawer.d.ts +10 -0
- package/dist/components/seo/SeoCopilotDrawer.d.ts.map +1 -0
- package/dist/components/seo/SeoCopilotDrawer.js +34 -0
- package/dist/components/seo/SeoCopilotDrawer.js.map +1 -0
- package/dist/components/seo/SeoEditorDrawer.d.ts +8 -0
- package/dist/components/seo/SeoEditorDrawer.d.ts.map +1 -0
- package/dist/components/seo/SeoEditorDrawer.js +120 -0
- package/dist/components/seo/SeoEditorDrawer.js.map +1 -0
- package/dist/components/seo/SeoIssueFixDrawer.d.ts +8 -0
- package/dist/components/seo/SeoIssueFixDrawer.d.ts.map +1 -0
- package/dist/components/seo/SeoIssueFixDrawer.js +111 -0
- package/dist/components/seo/SeoIssueFixDrawer.js.map +1 -0
- package/dist/components/seo/primitives.d.ts +53 -0
- package/dist/components/seo/primitives.d.ts.map +1 -0
- package/dist/components/seo/primitives.js +101 -0
- package/dist/components/seo/primitives.js.map +1 -0
- package/dist/layout/Sidebar.d.ts.map +1 -1
- package/dist/layout/Sidebar.js +8 -5
- package/dist/layout/Sidebar.js.map +1 -1
- package/dist/lib/seo-service.d.ts +322 -0
- package/dist/lib/seo-service.d.ts.map +1 -0
- package/dist/lib/seo-service.js +331 -0
- package/dist/lib/seo-service.js.map +1 -0
- package/dist/router/index.d.ts.map +1 -1
- package/dist/router/index.js +4 -1
- package/dist/router/index.js.map +1 -1
- package/dist/views/ApiKeys.d.ts +4 -1
- package/dist/views/ApiKeys.d.ts.map +1 -1
- package/dist/views/ApiKeys.js +5 -3
- package/dist/views/ApiKeys.js.map +1 -1
- package/dist/views/Dashboard.js +2 -2
- package/dist/views/Dashboard.js.map +1 -1
- package/dist/views/MediaBrowser.d.ts.map +1 -1
- package/dist/views/MediaBrowser.js +36 -25
- package/dist/views/MediaBrowser.js.map +1 -1
- package/dist/views/Posts/NewPostTypeInstructions.js +2 -2
- package/dist/views/Posts/post-type-presets.d.ts +5 -0
- package/dist/views/Posts/post-type-presets.d.ts.map +1 -1
- package/dist/views/Posts/post-type-presets.js +10 -64
- package/dist/views/Posts/post-type-presets.js.map +1 -1
- package/dist/views/SEO.d.ts.map +1 -1
- package/dist/views/SEO.js +89 -132
- package/dist/views/SEO.js.map +1 -1
- package/dist/views/Settings.d.ts +4 -1
- package/dist/views/Settings.d.ts.map +1 -1
- package/dist/views/Settings.js +45 -6
- package/dist/views/Settings.js.map +1 -1
- package/dist/views/Users.d.ts +4 -1
- package/dist/views/Users.d.ts.map +1 -1
- package/dist/views/Users.js +5 -3
- package/dist/views/Users.js.map +1 -1
- package/dist/views/seo/AuditTab.d.ts +6 -0
- package/dist/views/seo/AuditTab.d.ts.map +1 -0
- package/dist/views/seo/AuditTab.js +57 -0
- package/dist/views/seo/AuditTab.js.map +1 -0
- package/dist/views/seo/ContentTab.d.ts +5 -0
- package/dist/views/seo/ContentTab.d.ts.map +1 -0
- package/dist/views/seo/ContentTab.js +27 -0
- package/dist/views/seo/ContentTab.js.map +1 -0
- package/dist/views/seo/OverviewTab.d.ts +8 -0
- package/dist/views/seo/OverviewTab.d.ts.map +1 -0
- package/dist/views/seo/OverviewTab.js +35 -0
- package/dist/views/seo/OverviewTab.js.map +1 -0
- package/dist/views/seo/RedirectsTab.d.ts +2 -0
- package/dist/views/seo/RedirectsTab.d.ts.map +1 -0
- package/dist/views/seo/RedirectsTab.js +130 -0
- package/dist/views/seo/RedirectsTab.js.map +1 -0
- package/dist/views/seo/TechnicalTab.d.ts +2 -0
- package/dist/views/seo/TechnicalTab.d.ts.map +1 -0
- package/dist/views/seo/TechnicalTab.js +105 -0
- package/dist/views/seo/TechnicalTab.js.map +1 -0
- package/dist/views/seo/useSeoResource.d.ts +8 -0
- package/dist/views/seo/useSeoResource.d.ts.map +1 -0
- package/dist/views/seo/useSeoResource.js +55 -0
- package/dist/views/seo/useSeoResource.js.map +1 -0
- package/package.json +2 -2
- package/src/AdminRoot.tsx +13 -9
- package/src/__tests__/layout/sidebar-posts.test.ts +6 -4
- package/src/__tests__/lib/seo-service-errors.test.ts +60 -0
- package/src/__tests__/views/use-seo-resource.test.tsx +68 -0
- package/src/components/Breadcrumbs.tsx +4 -1
- package/src/components/seo/Drawer.tsx +65 -0
- package/src/components/seo/RedirectEditorDrawer.tsx +235 -0
- package/src/components/seo/SeoCopilotDrawer.tsx +76 -0
- package/src/components/seo/SeoEditorDrawer.tsx +359 -0
- package/src/components/seo/SeoIssueFixDrawer.tsx +244 -0
- package/src/components/seo/primitives.tsx +240 -0
- package/src/layout/Sidebar.tsx +7 -10
- package/src/lib/seo-service.ts +660 -0
- package/src/router/index.ts +4 -1
- package/src/views/ApiKeys.tsx +10 -5
- package/src/views/Dashboard.tsx +2 -2
- package/src/views/MediaBrowser.tsx +89 -67
- package/src/views/Posts/NewPostTypeInstructions.tsx +2 -2
- package/src/views/Posts/post-type-presets.ts +15 -64
- package/src/views/SEO.tsx +186 -863
- package/src/views/Settings.tsx +93 -40
- package/src/views/Users.tsx +10 -4
- package/src/views/seo/AuditTab.tsx +229 -0
- package/src/views/seo/ContentTab.tsx +164 -0
- package/src/views/seo/OverviewTab.tsx +257 -0
- package/src/views/seo/RedirectsTab.tsx +398 -0
- package/src/views/seo/TechnicalTab.tsx +315 -0
- package/src/views/seo/useSeoResource.ts +66 -0
package/dist/views/SEO.js
CHANGED
|
@@ -1,143 +1,100 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
/**
|
|
4
|
+
* SEO Operations Center — five-tab workflow surface (Overview / Content /
|
|
5
|
+
* Technical / Redirects / Audit). Tab + deep-link state is driven by the
|
|
6
|
+
* `?tab=` query string so audits, issues, redirects, and content editors are
|
|
7
|
+
* all linkable. All data flows through `lib/seo-service.ts`.
|
|
8
|
+
*/
|
|
3
9
|
import * as Tabs from '@radix-ui/react-tabs';
|
|
4
|
-
import {
|
|
5
|
-
import { useState } from 'react';
|
|
10
|
+
import { LayoutDashboard, FileText, Settings2, ArrowRightLeft, ClipboardCheck, RefreshCw, Bot, } from 'lucide-react';
|
|
11
|
+
import { useCallback, useEffect, useMemo, useState } from 'react';
|
|
6
12
|
import { toast } from 'sonner';
|
|
7
|
-
import
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
.
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
(filterScore === 'good' && page.score >= 80) ||
|
|
40
|
-
(filterScore === 'warning' && page.score >= 50 && page.score < 80) ||
|
|
41
|
-
(filterScore === 'critical' && page.score < 50);
|
|
42
|
-
return matchesSearch && matchesScore;
|
|
43
|
-
})
|
|
44
|
-
.sort((a, b) => (!searchQuery ? b.issues - a.issues : 0));
|
|
45
|
-
const totalIssues = seoPages.reduce((sum, p) => sum + p.issues, 0);
|
|
46
|
-
const avgScore = seoPages.length > 0
|
|
47
|
-
? Math.round(seoPages.reduce((sum, p) => sum + p.score, 0) / seoPages.length)
|
|
48
|
-
: 0;
|
|
49
|
-
const missingMeta = seoPages.filter((p) => !p.metaTitle || !p.metaDescription).length;
|
|
50
|
-
const missingSchema = seoPages.filter((p) => !p.schemaType).length;
|
|
51
|
-
// --- Canonical data ---
|
|
52
|
-
const missingCanonical = seoPages.filter((p) => !p.canonical);
|
|
53
|
-
const allCanonicals = seoPages.filter((p) => p.canonical);
|
|
54
|
-
const canonicalDomains = [
|
|
55
|
-
...new Set(allCanonicals
|
|
56
|
-
.map((p) => {
|
|
57
|
-
try {
|
|
58
|
-
return new URL(p.canonical).hostname;
|
|
59
|
-
}
|
|
60
|
-
catch {
|
|
61
|
-
return '';
|
|
62
|
-
}
|
|
63
|
-
})
|
|
64
|
-
.filter(Boolean)),
|
|
65
|
-
];
|
|
66
|
-
// --- Redirects data ---
|
|
67
|
-
const filteredRedirects = redirects.filter((r) => (r.from ?? '').toLowerCase().includes(redirectSearch.toLowerCase()) ||
|
|
68
|
-
(r.to ?? '').toLowerCase().includes(redirectSearch.toLowerCase()));
|
|
69
|
-
const handleScan = async () => {
|
|
70
|
-
setScanning(true);
|
|
71
|
-
try {
|
|
72
|
-
const res = await cmsApi('/seo/scan', { method: 'POST' });
|
|
73
|
-
if (res.error) {
|
|
74
|
-
toast.error(res.error);
|
|
75
|
-
}
|
|
76
|
-
else {
|
|
77
|
-
const d = res.data;
|
|
78
|
-
toast.success(`SEO scan complete — ${d.totalProblems} issues found across ${d.pagesWithIssues} of ${d.total} pages`);
|
|
79
|
-
seoRefetch();
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
catch {
|
|
83
|
-
toast.error('SEO scan failed');
|
|
84
|
-
}
|
|
85
|
-
finally {
|
|
86
|
-
setScanning(false);
|
|
87
|
-
}
|
|
13
|
+
import { ErrorBoundary } from '../components/ErrorBoundary.js';
|
|
14
|
+
import { fetchSeoOverview, runSeoAudit } from '../lib/seo-service.js';
|
|
15
|
+
import { ScorePill, btnPrimary, btnSecondary } from '../components/seo/primitives.js';
|
|
16
|
+
import { SeoCopilotDrawer } from '../components/seo/SeoCopilotDrawer.js';
|
|
17
|
+
import { useSeoResource } from './seo/useSeoResource.js';
|
|
18
|
+
import { OverviewTab } from './seo/OverviewTab.js';
|
|
19
|
+
import { ContentTab } from './seo/ContentTab.js';
|
|
20
|
+
import { TechnicalTab } from './seo/TechnicalTab.js';
|
|
21
|
+
import { RedirectsTab } from './seo/RedirectsTab.js';
|
|
22
|
+
import { AuditTab } from './seo/AuditTab.js';
|
|
23
|
+
const TABS = [
|
|
24
|
+
{ id: 'overview', label: 'Overview', icon: LayoutDashboard },
|
|
25
|
+
{ id: 'content', label: 'Content SEO', icon: FileText },
|
|
26
|
+
{ id: 'technical', label: 'Technical', icon: Settings2 },
|
|
27
|
+
{ id: 'redirects', label: 'Redirects', icon: ArrowRightLeft },
|
|
28
|
+
{ id: 'audit', label: 'Audit', icon: ClipboardCheck },
|
|
29
|
+
];
|
|
30
|
+
function normalizeTab(tab) {
|
|
31
|
+
const valid = TABS.map((t) => t.id);
|
|
32
|
+
return (valid.includes(tab ?? '') ? tab : 'overview');
|
|
33
|
+
}
|
|
34
|
+
/** Read tab + deep-link query params from the current URL. */
|
|
35
|
+
function readUrlState() {
|
|
36
|
+
if (typeof window === 'undefined') {
|
|
37
|
+
return { tab: null, entityType: null, entityId: null, issueId: null };
|
|
38
|
+
}
|
|
39
|
+
const params = new URLSearchParams(window.location.search);
|
|
40
|
+
return {
|
|
41
|
+
tab: params.get('tab'),
|
|
42
|
+
entityType: params.get('entityType'),
|
|
43
|
+
entityId: params.get('entityId'),
|
|
44
|
+
issueId: params.get('issueId'),
|
|
88
45
|
};
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
46
|
+
}
|
|
47
|
+
export function SEO({ onNavigate, initialTab = 'overview' }) {
|
|
48
|
+
const initialUrl = readUrlState();
|
|
49
|
+
const [activeTab, setActiveTab] = useState(normalizeTab(initialUrl.tab ?? initialTab));
|
|
50
|
+
const [refetchKey, setRefetchKey] = useState(0);
|
|
51
|
+
const [auditing, setAuditing] = useState(false);
|
|
52
|
+
const [copilotOpen, setCopilotOpen] = useState(false);
|
|
53
|
+
const [deepLink, setDeepLink] = useState(initialUrl);
|
|
54
|
+
// Overview resource is owned here so the header score pill and the Overview
|
|
55
|
+
// tab share a single request; `refetchKey` re-runs it after an audit.
|
|
56
|
+
const overviewResource = useSeoResource(fetchSeoOverview, [refetchKey]);
|
|
57
|
+
// Keep tab + deep links in sync with browser back/forward navigation.
|
|
58
|
+
useEffect(() => {
|
|
59
|
+
function sync() {
|
|
60
|
+
const url = readUrlState();
|
|
61
|
+
setActiveTab(normalizeTab(url.tab ?? initialTab));
|
|
62
|
+
setDeepLink(url);
|
|
105
63
|
}
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
};
|
|
109
|
-
|
|
110
|
-
const
|
|
64
|
+
window.addEventListener('popstate', sync);
|
|
65
|
+
return () => window.removeEventListener('popstate', sync);
|
|
66
|
+
}, [initialTab]);
|
|
67
|
+
useEffect(() => {
|
|
68
|
+
const url = readUrlState();
|
|
69
|
+
setActiveTab(normalizeTab(url.tab ?? initialTab));
|
|
70
|
+
setDeepLink(url);
|
|
71
|
+
}, [initialTab]);
|
|
72
|
+
const changeTab = useCallback((tab) => {
|
|
73
|
+
const next = normalizeTab(tab);
|
|
74
|
+
setActiveTab(next);
|
|
75
|
+
setDeepLink({ tab: next, entityType: null, entityId: null, issueId: null });
|
|
76
|
+
onNavigate?.(`/seo?tab=${next}`);
|
|
77
|
+
}, [onNavigate]);
|
|
78
|
+
const handleRunAudit = useCallback(async () => {
|
|
79
|
+
setAuditing(true);
|
|
80
|
+
const res = await runSeoAudit('full');
|
|
81
|
+
setAuditing(false);
|
|
111
82
|
if (res.error) {
|
|
112
83
|
toast.error(res.error);
|
|
84
|
+
return;
|
|
113
85
|
}
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
if (score >= 80)
|
|
128
|
-
return _jsx(CheckCircle2, { className: "h-4 w-4 text-green-600" });
|
|
129
|
-
if (score >= 50)
|
|
130
|
-
return _jsx(AlertTriangle, { className: "h-4 w-4 text-yellow-600" });
|
|
131
|
-
return _jsx(XCircle, { className: "h-4 w-4 text-red-600" });
|
|
132
|
-
}
|
|
133
|
-
const tabClass = 'px-4 py-2 text-sm font-medium text-gray-600 transition-colors hover:text-gray-900 data-[state=active]:border-b-2 data-[state=active]:border-blue-600 data-[state=active]:text-blue-600 shrink-0';
|
|
134
|
-
const isLoading = seoLoading || redirectsLoading || linkHealthLoading;
|
|
135
|
-
if (isLoading) {
|
|
136
|
-
return (_jsx("div", { className: "flex h-64 items-center justify-center p-3 pr-6 sm:p-4 sm:pr-8", children: _jsx(Loader2, { className: "h-6 w-6 animate-spin text-blue-600" }) }));
|
|
137
|
-
}
|
|
138
|
-
return (_jsxs("div", { className: "flex h-full flex-col p-3 pr-6 sm:p-4 sm:pr-8", children: [(seoError || redirectsError) && (_jsxs("div", { className: "mb-4 flex items-center gap-3 rounded-lg border border-red-200 bg-red-50 p-3", children: [_jsx(AlertTriangle, { className: "h-5 w-5 shrink-0 text-red-600" }), _jsx("span", { className: "flex-1 text-sm text-red-800", children: seoError || redirectsError }), _jsx("button", { onClick: () => {
|
|
139
|
-
seoRefetch();
|
|
140
|
-
redirectsRefetch();
|
|
141
|
-
}, className: "rounded-lg border border-red-300 px-3 py-1 text-sm text-red-700 transition-colors hover:bg-red-100", children: "Retry" })] })), _jsxs("div", { className: "mb-4 flex flex-col justify-between gap-3 sm:flex-row sm:items-center", children: [_jsxs("div", { children: [_jsx("h1", { className: "mb-1 text-xl font-semibold text-gray-900 sm:text-2xl", children: "SEO & Redirects" }), _jsx("p", { className: "text-sm text-gray-600", children: "Search optimization, redirects, canonicalization, and link health" })] }), _jsxs("button", { onClick: handleScan, disabled: scanning, className: "flex items-center justify-center gap-2 rounded-lg bg-blue-600 px-4 py-2 text-sm text-white transition-colors hover:bg-blue-700 disabled:opacity-60", children: [_jsx(RefreshCw, { className: `h-4 w-4 ${scanning ? 'animate-spin' : ''}` }), scanning ? 'Scanning...' : 'Run SEO Scan'] })] }), _jsxs(Tabs.Root, { value: activeTab, onValueChange: handleTabChange, children: [_jsxs(Tabs.List, { className: "mb-4 flex gap-1 overflow-x-auto border-b border-gray-200", children: [_jsx(Tabs.Trigger, { value: "pages", className: tabClass, children: _jsxs("span", { className: "flex items-center gap-1.5", children: [_jsx(BarChart3, { className: "h-4 w-4" }), "Pages"] }) }), _jsx(Tabs.Trigger, { value: "redirects", className: tabClass, children: _jsxs("span", { className: "flex items-center gap-1.5", children: [_jsx(ArrowRightLeft, { className: "h-4 w-4" }), "Redirects"] }) }), _jsx(Tabs.Trigger, { value: "canonicals", className: tabClass, children: _jsxs("span", { className: "flex items-center gap-1.5", children: [_jsx(Copy, { className: "h-4 w-4" }), "Canonicalization"] }) }), _jsx(Tabs.Trigger, { value: "links", className: tabClass, children: _jsxs("span", { className: "flex items-center gap-1.5", children: [_jsx(Link2, { className: "h-4 w-4" }), "Link Health"] }) })] }), _jsxs(Tabs.Content, { value: "pages", className: "flex min-h-0 flex-1 flex-col", children: [_jsxs("div", { className: "mb-4 grid grid-cols-2 gap-3 lg:grid-cols-4", children: [_jsxs("div", { className: "rounded-lg border border-gray-200 bg-white p-4", children: [_jsxs("div", { className: "mb-2 flex items-center gap-2", children: [_jsx(BarChart3, { className: "h-4 w-4 text-blue-600" }), _jsx("span", { className: "text-xs font-medium text-gray-600", children: "Avg SEO Score" })] }), _jsx("div", { className: "text-2xl font-semibold text-gray-900", children: avgScore }), _jsx("div", { className: `mt-1 text-xs ${avgScore >= 80 ? 'text-green-600' : avgScore >= 50 ? 'text-yellow-600' : 'text-red-600'}`, children: avgScore >= 80 ? 'Good' : avgScore >= 50 ? 'Needs improvement' : 'Critical' })] }), _jsxs("div", { className: "rounded-lg border border-gray-200 bg-white p-4", children: [_jsxs("div", { className: "mb-2 flex items-center gap-2", children: [_jsx(AlertTriangle, { className: "h-4 w-4 text-yellow-600" }), _jsx("span", { className: "text-xs font-medium text-gray-600", children: "Total Issues" })] }), _jsx("div", { className: "text-2xl font-semibold text-gray-900", children: totalIssues }), _jsxs("div", { className: "mt-1 text-xs text-gray-500", children: ["Across ", seoPages.filter((p) => p.issues > 0).length, " pages"] })] }), _jsxs("div", { className: "rounded-lg border border-gray-200 bg-white p-4", children: [_jsxs("div", { className: "mb-2 flex items-center gap-2", children: [_jsx(FileCode2, { className: "h-4 w-4 text-purple-600" }), _jsx("span", { className: "text-xs font-medium text-gray-600", children: "Missing Meta" })] }), _jsx("div", { className: "text-2xl font-semibold text-gray-900", children: missingMeta }), _jsx("div", { className: "mt-1 text-xs text-gray-500", children: "Title or description" })] }), _jsxs("div", { className: "rounded-lg border border-gray-200 bg-white p-4", children: [_jsxs("div", { className: "mb-2 flex items-center gap-2", children: [_jsx(Globe, { className: "h-4 w-4 text-green-600" }), _jsx("span", { className: "text-xs font-medium text-gray-600", children: "Missing Schema" })] }), _jsx("div", { className: "text-2xl font-semibold text-gray-900", children: missingSchema }), _jsx("div", { className: "mt-1 text-xs text-gray-500", children: "No Schema.org markup" })] })] }), _jsx("div", { className: "mb-4 rounded-lg border border-indigo-200 bg-linear-to-r from-indigo-50 to-purple-50 p-4", children: _jsxs("div", { className: "flex items-start gap-3", children: [_jsx(Bot, { className: "mt-0.5 h-5 w-5 shrink-0 text-indigo-600" }), _jsxs("div", { className: "flex-1", children: [_jsx("h3", { className: "mb-1 text-sm font-semibold text-indigo-900", children: "AI SEO Recommendations" }), _jsxs("p", { className: "mb-2 text-sm text-indigo-700", children: [missingMeta, " pages missing meta descriptions. ", missingCanonical.length, " pages without canonical URLs. AI can auto-generate these from page content."] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx("button", { onClick: () => onNavigate?.('/settings'), className: "rounded-lg bg-indigo-600 px-3 py-1.5 text-xs text-white transition-colors hover:bg-indigo-700", children: "Configure AI" }), _jsx("button", { className: "rounded-lg border border-indigo-300 px-3 py-1.5 text-xs text-indigo-700 transition-colors hover:bg-indigo-50", children: "Auto-fix All" })] })] })] }) }), _jsx("div", { className: "mb-4 rounded-lg border border-gray-200 bg-white", children: _jsxs("div", { className: "flex flex-col gap-3 p-3 sm:flex-row", children: [_jsxs("div", { className: "relative flex-1", children: [_jsx(Search, { className: "absolute top-1/2 left-3 h-4 w-4 -translate-y-1/2 text-gray-400" }), _jsx("input", { type: "text", placeholder: "Search pages by URL or title...", value: searchQuery, onChange: (e) => setSearchQuery(e.target.value), className: "w-full rounded-lg border border-gray-300 py-2 pr-3 pl-9 text-sm focus:ring-2 focus:ring-blue-500 focus:outline-none" })] }), _jsxs("select", { value: filterScore, onChange: (e) => setFilterScore(e.target.value), className: "rounded-lg border border-gray-300 px-3 py-2 text-sm focus:ring-2 focus:ring-blue-500 focus:outline-none", children: [_jsx("option", { value: "all", children: "All Scores" }), _jsx("option", { value: "good", children: "Good (80+)" }), _jsx("option", { value: "warning", children: "Needs Work (50-79)" }), _jsx("option", { value: "critical", children: "Critical (<50)" })] })] }) }), _jsx("div", { className: "flex-1 overflow-hidden rounded-lg border border-gray-200 bg-white", children: _jsx("div", { className: "h-full overflow-x-auto", children: _jsxs("table", { className: "w-full", children: [_jsx("thead", { className: "sticky top-0 border-b border-gray-200 bg-gray-50", children: _jsxs("tr", { children: [_jsx("th", { className: "px-4 py-2 text-left text-xs font-medium text-gray-700", children: "Page" }), _jsx("th", { className: "px-4 py-2 text-left text-xs font-medium text-gray-700", children: "Score" }), _jsx("th", { className: "px-4 py-2 text-left text-xs font-medium text-gray-700", children: "Readability" }), _jsx("th", { className: "px-4 py-2 text-left text-xs font-medium text-gray-700", children: "Schema" }), _jsx("th", { className: "px-4 py-2 text-left text-xs font-medium text-gray-700", children: "Meta" }), _jsx("th", { className: "px-4 py-2 text-left text-xs font-medium text-gray-700", children: "Issues" }), _jsx("th", { className: "px-4 py-2 text-left text-xs font-medium text-gray-700", children: "Actions" })] }) }), _jsx("tbody", { className: "divide-y divide-gray-200", children: filtered.map((page) => (_jsxs("tr", { className: "transition-colors hover:bg-gray-50", children: [_jsxs("td", { className: "px-4 py-3", children: [_jsx("div", { className: "text-sm font-medium text-gray-900", children: page.title }), _jsx("div", { className: "text-xs text-gray-500", children: page.url })] }), _jsx("td", { className: "px-4 py-3", children: _jsxs("div", { className: "flex items-center gap-2", children: [scoreIcon(page.score), _jsx("span", { className: `rounded-full px-2 py-0.5 text-xs font-medium ${scoreBadge(page.score)}`, children: page.score })] }) }), _jsx("td", { className: "px-4 py-3", children: page.readability > 0 ? (_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(BookOpen, { className: "h-3.5 w-3.5 text-gray-400" }), _jsx("span", { className: `text-sm ${page.readability >= 80 ? 'text-green-700' : page.readability >= 60 ? 'text-yellow-700' : 'text-red-700'}`, children: page.readability })] })) : (_jsx("span", { className: "text-xs text-gray-400", children: "\u2014" })) }), _jsx("td", { className: "px-4 py-3", children: page.schemaType ? (_jsx("span", { className: "rounded-full bg-purple-100 px-2 py-0.5 text-xs font-medium text-purple-800", children: page.schemaType })) : (_jsx("span", { className: "rounded-full bg-red-100 px-2 py-0.5 text-xs font-medium text-red-800", children: "Missing" })) }), _jsx("td", { className: "px-4 py-3", children: _jsxs("div", { className: "flex flex-col gap-0.5", children: [_jsx("span", { className: `text-xs ${page.metaTitle ? 'text-green-700' : 'text-red-600'}`, children: page.metaTitle ? '✓ Title' : '✗ Title' }), _jsx("span", { className: `text-xs ${page.metaDescription ? 'text-green-700' : 'text-red-600'}`, children: page.metaDescription ? '✓ Desc' : '✗ Desc' })] }) }), _jsx("td", { className: "px-4 py-3", children: page.issues > 0 ? (_jsx("span", { className: "rounded-full bg-yellow-100 px-2 py-0.5 text-xs font-medium text-yellow-800", children: page.issues })) : (_jsx("span", { className: "rounded-full bg-green-100 px-2 py-0.5 text-xs font-medium text-green-800", children: "\u2713" })) }), _jsx("td", { className: "px-4 py-3", children: _jsxs("div", { className: "flex items-center gap-1", children: [_jsx("button", { onClick: () => onNavigate?.(`/pages/${page.id}`), className: "rounded p-1.5 transition-colors hover:bg-gray-100", title: "Edit", children: _jsx(ArrowUpRight, { className: "h-4 w-4 text-gray-600" }) }), _jsx("button", { className: "rounded p-1.5 transition-colors hover:bg-gray-100", title: "AI analyze", children: _jsx(Bot, { className: "h-4 w-4 text-indigo-600" }) })] }) })] }, page.id))) })] }) }) })] }), _jsxs(Tabs.Content, { value: "redirects", className: "flex min-h-0 flex-1 flex-col", children: [_jsxs("div", { className: "mb-4 grid grid-cols-2 gap-3 lg:grid-cols-4", children: [_jsxs("div", { className: "rounded-lg border border-gray-200 bg-white p-4", children: [_jsx("div", { className: "mb-1 text-xs text-gray-600", children: "Total Redirects" }), _jsx("div", { className: "text-2xl font-semibold text-gray-900", children: redirects.length })] }), _jsxs("div", { className: "rounded-lg border border-gray-200 bg-white p-4", children: [_jsx("div", { className: "mb-1 text-xs text-gray-600", children: "Active" }), _jsx("div", { className: "text-2xl font-semibold text-green-600", children: redirects.filter((r) => r.active).length })] }), _jsxs("div", { className: "rounded-lg border border-gray-200 bg-white p-4", children: [_jsx("div", { className: "mb-1 text-xs text-gray-600", children: "Total Hits" }), _jsx("div", { className: "text-2xl font-semibold text-blue-600", children: redirects.reduce((s, r) => s + r.hits, 0).toLocaleString() })] }), _jsxs("div", { className: "rounded-lg border border-gray-200 bg-white p-4", children: [_jsx("div", { className: "mb-1 text-xs text-gray-600", children: "301 Permanent" }), _jsx("div", { className: "text-2xl font-semibold text-gray-900", children: redirects.filter((r) => r.type === '301').length })] })] }), _jsxs("div", { className: "mb-4 flex items-center gap-3", children: [_jsxs("div", { className: "relative max-w-md flex-1", children: [_jsx(Search, { className: "absolute top-1/2 left-3 h-4 w-4 -translate-y-1/2 text-gray-400" }), _jsx("input", { type: "text", placeholder: "Search redirects...", value: redirectSearch, onChange: (e) => setRedirectSearch(e.target.value), className: "w-full rounded-lg border border-gray-300 bg-white py-2 pr-3 pl-9 text-sm focus:ring-2 focus:ring-blue-500 focus:outline-none" })] }), _jsxs("button", { onClick: () => setShowAddRedirect(true), className: "flex shrink-0 items-center gap-2 rounded-lg bg-blue-600 px-4 py-2 text-sm text-white transition-colors hover:bg-blue-700", children: [_jsx(Plus, { className: "h-4 w-4" }), "Add Redirect"] })] }), _jsx("div", { className: "flex-1 overflow-hidden rounded-lg border border-gray-200 bg-white", children: _jsx("div", { className: "h-full overflow-x-auto", children: _jsxs("table", { className: "w-full", children: [_jsx("thead", { className: "sticky top-0 border-b border-gray-200 bg-gray-50", children: _jsxs("tr", { children: [_jsx("th", { className: "px-4 py-2 text-left text-xs font-medium text-gray-700", children: "Source" }), _jsx("th", { className: "px-4 py-2 text-left text-xs font-medium text-gray-700", children: "Destination" }), _jsx("th", { className: "px-4 py-2 text-left text-xs font-medium text-gray-700", children: "Type" }), _jsx("th", { className: "px-4 py-2 text-left text-xs font-medium text-gray-700", children: "Hits" }), _jsx("th", { className: "px-4 py-2 text-left text-xs font-medium text-gray-700", children: "Status" }), _jsx("th", { className: "px-4 py-2 text-left text-xs font-medium text-gray-700", children: "Actions" })] }) }), _jsx("tbody", { className: "divide-y divide-gray-200", children: filteredRedirects.map((r) => (_jsxs("tr", { className: "transition-colors hover:bg-gray-50", children: [_jsx("td", { className: "px-4 py-3", children: _jsx("code", { className: "rounded bg-gray-100 px-2 py-1 text-xs text-gray-900", children: r.from }) }), _jsx("td", { className: "px-4 py-3", children: _jsx("code", { className: "rounded bg-gray-100 px-2 py-1 text-xs text-gray-900", children: r.to }) }), _jsx("td", { className: "px-4 py-3", children: _jsx("span", { className: `rounded-full px-2 py-0.5 text-xs font-medium ${r.type === '301' ? 'bg-blue-100 text-blue-800' : 'bg-purple-100 text-purple-800'}`, children: r.type }) }), _jsx("td", { className: "px-4 py-3 text-sm text-gray-600", children: r.hits.toLocaleString() }), _jsx("td", { className: "px-4 py-3", children: _jsx("span", { className: `rounded-full px-2 py-0.5 text-xs font-medium ${r.active ? 'bg-green-100 text-green-800' : 'bg-gray-100 text-gray-800'}`, children: r.active ? 'Active' : 'Inactive' }) }), _jsx("td", { className: "px-4 py-3", children: _jsxs("div", { className: "flex items-center gap-2", children: [_jsx("button", { className: "rounded p-1.5 transition-colors hover:bg-gray-100", children: _jsx(Pencil, { className: "h-4 w-4 text-gray-600" }) }), _jsx("button", { onClick: () => handleDeleteRedirect(r.id), className: "rounded p-1.5 transition-colors hover:bg-gray-100", children: _jsx(Trash2, { className: "h-4 w-4 text-red-600" }) })] }) })] }, r.id))) })] }) }) }), _jsx(Dialog.Root, { open: showAddRedirect, onOpenChange: setShowAddRedirect, children: _jsxs(Dialog.Portal, { children: [_jsx(Dialog.Overlay, { className: "fixed inset-0 z-50 bg-black/50" }), _jsxs(Dialog.Content, { className: "fixed top-1/2 left-1/2 z-50 w-full max-w-md -translate-x-1/2 -translate-y-1/2 rounded-lg bg-white p-6 shadow-lg", children: [_jsx(Dialog.Title, { className: "mb-4 text-lg font-semibold text-gray-900", children: "Add Redirect" }), _jsxs("form", { onSubmit: handleAddRedirect, className: "space-y-4", children: [_jsxs("div", { children: [_jsx("label", { className: "mb-1 block text-sm font-medium text-gray-700", children: "Source URL" }), _jsx("input", { type: "text", value: newRedirect.source, onChange: (e) => setNewRedirect({ ...newRedirect, source: e.target.value }), placeholder: "/old-page", className: "w-full rounded-lg border border-gray-300 px-3 py-2 text-sm focus:ring-2 focus:ring-blue-500 focus:outline-none", required: true })] }), _jsxs("div", { children: [_jsx("label", { className: "mb-1 block text-sm font-medium text-gray-700", children: "Destination URL" }), _jsx("input", { type: "text", value: newRedirect.destination, onChange: (e) => setNewRedirect({ ...newRedirect, destination: e.target.value }), placeholder: "/new-page", className: "w-full rounded-lg border border-gray-300 px-3 py-2 text-sm focus:ring-2 focus:ring-blue-500 focus:outline-none", required: true })] }), _jsxs("div", { children: [_jsx("label", { className: "mb-1 block text-sm font-medium text-gray-700", children: "Type" }), _jsxs("select", { value: newRedirect.type, onChange: (e) => setNewRedirect({ ...newRedirect, type: e.target.value }), className: "w-full rounded-lg border border-gray-300 px-3 py-2 text-sm focus:ring-2 focus:ring-blue-500 focus:outline-none", children: [_jsx("option", { value: "301", children: "301 (Permanent)" }), _jsx("option", { value: "302", children: "302 (Temporary)" })] })] }), _jsxs("div", { className: "flex justify-end gap-3 pt-4", children: [_jsx(Dialog.Close, { asChild: true, children: _jsx("button", { type: "button", className: "rounded-lg border border-gray-300 px-4 py-2 text-sm hover:bg-gray-50", children: "Cancel" }) }), _jsx("button", { type: "submit", className: "rounded-lg bg-blue-600 px-4 py-2 text-sm text-white hover:bg-blue-700", children: "Add Redirect" })] })] })] })] }) })] }), _jsxs(Tabs.Content, { value: "canonicals", className: "flex min-h-0 flex-1 flex-col space-y-4", children: [_jsxs("div", { className: "grid grid-cols-2 gap-3 lg:grid-cols-4", children: [_jsxs("div", { className: "rounded-lg border border-gray-200 bg-white p-4", children: [_jsxs("div", { className: "mb-2 flex items-center gap-2", children: [_jsx(ShieldCheck, { className: "h-4 w-4 text-green-600" }), _jsx("span", { className: "text-xs font-medium text-gray-600", children: "With Canonical" })] }), _jsx("div", { className: "text-2xl font-semibold text-green-700", children: allCanonicals.length })] }), _jsxs("div", { className: "rounded-lg border border-gray-200 bg-white p-4", children: [_jsxs("div", { className: "mb-2 flex items-center gap-2", children: [_jsx(AlertTriangle, { className: "h-4 w-4 text-red-600" }), _jsx("span", { className: "text-xs font-medium text-gray-600", children: "Missing Canonical" })] }), _jsx("div", { className: "text-2xl font-semibold text-red-700", children: missingCanonical.length })] }), _jsxs("div", { className: "rounded-lg border border-gray-200 bg-white p-4", children: [_jsxs("div", { className: "mb-2 flex items-center gap-2", children: [_jsx(Globe, { className: "h-4 w-4 text-blue-600" }), _jsx("span", { className: "text-xs font-medium text-gray-600", children: "Canonical Domains" })] }), _jsx("div", { className: "text-2xl font-semibold text-gray-900", children: canonicalDomains.length })] }), _jsxs("div", { className: "rounded-lg border border-gray-200 bg-white p-4", children: [_jsxs("div", { className: "mb-2 flex items-center gap-2", children: [_jsx(CheckCircle2, { className: "h-4 w-4 text-green-600" }), _jsx("span", { className: "text-xs font-medium text-gray-600", children: "Self-Referencing" })] }), _jsx("div", { className: "text-2xl font-semibold text-green-700", children: allCanonicals.length }), _jsx("div", { className: "mt-1 text-xs text-gray-500", children: "Correct pattern" })] })] }), missingCanonical.length > 0 && (_jsx("div", { className: "rounded-lg border border-yellow-200 bg-yellow-50 p-4", children: _jsxs("div", { className: "flex items-start gap-3", children: [_jsx(AlertTriangle, { className: "mt-0.5 h-5 w-5 shrink-0 text-yellow-600" }), _jsxs("div", { className: "flex-1", children: [_jsxs("h3", { className: "mb-1 text-sm font-semibold text-yellow-900", children: [missingCanonical.length, " page", missingCanonical.length !== 1 ? 's' : '', " missing canonical URLs"] }), _jsx("p", { className: "mb-2 text-sm text-yellow-700", children: "Without canonical tags, search engines may index duplicate versions of these pages, diluting your ranking signals." }), _jsx("div", { className: "flex flex-wrap gap-2", children: missingCanonical.map((p) => (_jsxs("button", { onClick: () => onNavigate?.(`/pages/${p.id}`), className: "rounded-lg bg-yellow-100 px-2.5 py-1 text-xs text-yellow-900 transition-colors hover:bg-yellow-200", children: [p.title, " (", p.url, ")"] }, p.id))) })] })] }) })), _jsx("div", { className: "flex-1 overflow-hidden rounded-lg border border-gray-200 bg-white", children: _jsx("div", { className: "h-full overflow-x-auto", children: _jsxs("table", { className: "w-full", children: [_jsx("thead", { className: "sticky top-0 border-b border-gray-200 bg-gray-50", children: _jsxs("tr", { children: [_jsx("th", { className: "px-4 py-2 text-left text-xs font-medium text-gray-700", children: "Page" }), _jsx("th", { className: "px-4 py-2 text-left text-xs font-medium text-gray-700", children: "URL" }), _jsx("th", { className: "px-4 py-2 text-left text-xs font-medium text-gray-700", children: "Canonical URL" }), _jsx("th", { className: "px-4 py-2 text-left text-xs font-medium text-gray-700", children: "Status" }), _jsx("th", { className: "px-4 py-2 text-left text-xs font-medium text-gray-700", children: "Actions" })] }) }), _jsx("tbody", { className: "divide-y divide-gray-200", children: seoPages.map((page) => (_jsxs("tr", { className: "transition-colors hover:bg-gray-50", children: [_jsx("td", { className: "px-4 py-3 text-sm font-medium text-gray-900", children: page.title }), _jsx("td", { className: "px-4 py-3", children: _jsx("code", { className: "rounded bg-gray-100 px-2 py-1 text-xs text-gray-700", children: page.url }) }), _jsx("td", { className: "px-4 py-3", children: page.canonical ? (_jsx("code", { className: "block max-w-[200px] truncate rounded bg-gray-100 px-2 py-1 text-xs text-gray-700", children: page.canonical })) : (_jsx("span", { className: "text-xs font-medium text-red-600", children: "Not set" })) }), _jsx("td", { className: "px-4 py-3", children: page.canonical ? (_jsx("span", { className: "rounded-full bg-green-100 px-2 py-0.5 text-xs font-medium text-green-800", children: "\u2713 Set" })) : (_jsx("span", { className: "rounded-full bg-red-100 px-2 py-0.5 text-xs font-medium text-red-800", children: "Missing" })) }), _jsx("td", { className: "px-4 py-3", children: _jsx("button", { onClick: () => onNavigate?.(`/pages/${page.id}`), className: "rounded p-1.5 transition-colors hover:bg-gray-100", title: "Edit", children: _jsx(Pencil, { className: "h-4 w-4 text-gray-600" }) }) })] }, page.id))) })] }) }) })] }), _jsxs(Tabs.Content, { value: "links", className: "flex min-h-0 flex-1 flex-col space-y-4", children: [_jsxs("div", { className: "grid grid-cols-2 gap-3 lg:grid-cols-4", children: [_jsxs("div", { className: "rounded-lg border border-gray-200 bg-white p-4", children: [_jsx("div", { className: "mb-1 text-xs text-gray-600", children: "Broken Links" }), _jsx("div", { className: "text-2xl font-semibold text-red-600", children: linkHealth.filter((l) => l.status === 404).length })] }), _jsxs("div", { className: "rounded-lg border border-gray-200 bg-white p-4", children: [_jsx("div", { className: "mb-1 text-xs text-gray-600", children: "Redirect Chains" }), _jsx("div", { className: "text-2xl font-semibold text-yellow-600", children: linkHealth.filter((l) => l.status === 301).length })] }), _jsxs("div", { className: "rounded-lg border border-gray-200 bg-white p-4", children: [_jsx("div", { className: "mb-1 text-xs text-gray-600", children: "Internal Issues" }), _jsx("div", { className: "text-2xl font-semibold text-gray-900", children: linkHealth.filter((l) => l.type === 'internal').length })] }), _jsxs("div", { className: "rounded-lg border border-gray-200 bg-white p-4", children: [_jsx("div", { className: "mb-1 text-xs text-gray-600", children: "External Issues" }), _jsx("div", { className: "text-2xl font-semibold text-gray-900", children: linkHealth.filter((l) => l.type === 'external').length })] })] }), _jsx("div", { className: "flex-1 overflow-hidden rounded-lg border border-gray-200 bg-white", children: _jsx("div", { className: "h-full overflow-x-auto", children: _jsxs("table", { className: "w-full", children: [_jsx("thead", { className: "sticky top-0 border-b border-gray-200 bg-gray-50", children: _jsxs("tr", { children: [_jsx("th", { className: "px-4 py-2 text-left text-xs font-medium text-gray-700", children: "Found On" }), _jsx("th", { className: "px-4 py-2 text-left text-xs font-medium text-gray-700", children: "Broken URL" }), _jsx("th", { className: "px-4 py-2 text-left text-xs font-medium text-gray-700", children: "Status" }), _jsx("th", { className: "px-4 py-2 text-left text-xs font-medium text-gray-700", children: "Type" }), _jsx("th", { className: "px-4 py-2 text-left text-xs font-medium text-gray-700", children: "Last Checked" }), _jsx("th", { className: "px-4 py-2 text-left text-xs font-medium text-gray-700", children: "Actions" })] }) }), _jsx("tbody", { className: "divide-y divide-gray-200", children: linkHealth.map((link) => (_jsxs("tr", { className: "transition-colors hover:bg-gray-50", children: [_jsx("td", { className: "px-4 py-3", children: _jsx("code", { className: "rounded bg-gray-100 px-2 py-1 text-xs text-gray-700", children: link.page }) }), _jsx("td", { className: "px-4 py-3", children: _jsx("code", { className: "block max-w-[200px] truncate rounded bg-red-50 px-2 py-1 text-xs text-red-800", children: link.url }) }), _jsx("td", { className: "px-4 py-3", children: _jsx("span", { className: `rounded-full px-2 py-0.5 text-xs font-medium ${link.status === 404 ? 'bg-red-100 text-red-800' : 'bg-yellow-100 text-yellow-800'}`, children: link.status }) }), _jsx("td", { className: "px-4 py-3", children: _jsx("span", { className: `rounded-full px-2 py-0.5 text-xs font-medium ${link.type === 'internal' ? 'bg-blue-100 text-blue-800' : 'bg-gray-100 text-gray-800'}`, children: link.type }) }), _jsx("td", { className: "px-4 py-3 text-sm text-gray-600", children: link.lastChecked }), _jsx("td", { className: "px-4 py-3", children: _jsxs("div", { className: "flex items-center gap-1", children: [_jsx("button", { className: "rounded p-1.5 transition-colors hover:bg-gray-100", title: "Create redirect", children: _jsx(ArrowRightLeft, { className: "h-4 w-4 text-gray-600" }) }), _jsx("button", { className: "rounded p-1.5 transition-colors hover:bg-gray-100", title: "Open URL", children: _jsx(ExternalLink, { className: "h-4 w-4 text-gray-600" }) })] }) })] }, link.id))) })] }) }) })] })] })] }));
|
|
86
|
+
toast.success('Audit complete.');
|
|
87
|
+
setRefetchKey((k) => k + 1);
|
|
88
|
+
}, []);
|
|
89
|
+
const score = overviewResource.data?.siteScore.score;
|
|
90
|
+
const badgeCounts = useMemo(() => {
|
|
91
|
+
const summary = overviewResource.data?.issuesSummary;
|
|
92
|
+
return { audit: summary ? summary.critical + summary.warning : 0 };
|
|
93
|
+
}, [overviewResource.data]);
|
|
94
|
+
return (_jsxs("div", { className: "space-y-6 p-6", children: [_jsxs("header", { className: "flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between", children: [_jsxs("div", { children: [_jsx("h1", { className: "text-foreground text-2xl font-medium", children: "SEO Operations Center" }), _jsx("p", { className: "text-muted-foreground mt-1 text-sm", children: "Monitor, fix, and automate SEO across your content, redirects, and technical setup." })] }), _jsxs("div", { className: "flex items-center gap-3", children: [typeof score === 'number' && (_jsxs("span", { className: "text-muted-foreground flex items-center gap-2 text-sm", children: ["Site score ", _jsx(ScorePill, { score: score })] })), _jsxs("button", { className: btnSecondary, onClick: () => setCopilotOpen(true), children: [_jsx(Bot, { className: "h-4 w-4", "aria-hidden": true }), "AI Copilot"] }), _jsxs("button", { className: btnPrimary, onClick: handleRunAudit, disabled: auditing, children: [_jsx(RefreshCw, { className: `h-4 w-4 ${auditing ? 'animate-spin' : ''}`, "aria-hidden": true }), auditing ? 'Running audit…' : 'Run audit'] })] })] }), _jsx(SeoCopilotDrawer, { open: copilotOpen, onOpenChange: setCopilotOpen }), _jsxs(Tabs.Root, { value: activeTab, onValueChange: changeTab, children: [_jsx(Tabs.List, { className: "border-border flex gap-1 overflow-x-auto border-b", "aria-label": "SEO sections", children: TABS.map((t) => {
|
|
95
|
+
const Icon = t.icon;
|
|
96
|
+
const badge = t.id === 'audit' ? badgeCounts.audit : 0;
|
|
97
|
+
return (_jsxs(Tabs.Trigger, { value: t.id, className: "text-muted-foreground hover:text-foreground data-[state=active]:text-foreground data-[state=active]:border-primary focus-visible:ring-ring -mb-px flex items-center gap-2 border-b-2 border-transparent px-3 py-2.5 text-sm font-medium transition-colors focus-visible:ring-2 focus-visible:outline-none", children: [_jsx(Icon, { className: "h-4 w-4", "aria-hidden": true }), t.label, badge > 0 && (_jsx("span", { className: "bg-destructive/10 text-destructive ml-1 rounded-full px-1.5 py-0.5 text-xs font-medium tabular-nums", children: badge }))] }, t.id));
|
|
98
|
+
}) }), _jsx("div", { className: "pt-6", children: _jsxs(ErrorBoundary, { children: [_jsx(Tabs.Content, { value: "overview", tabIndex: -1, children: activeTab === 'overview' && (_jsx(OverviewTab, { resource: overviewResource, onOpenIssue: (issueId) => onNavigate?.(`/seo?tab=audit&issueId=${issueId}`), onConnectSearchConsole: () => toast.info('Google Search Console integration is coming soon. Demo performance data is available in local development.') })) }), _jsx(Tabs.Content, { value: "content", tabIndex: -1, children: activeTab === 'content' && (_jsx(ContentTab, { initialEntityType: deepLink.entityType, initialEntityId: deepLink.entityId })) }), _jsx(Tabs.Content, { value: "technical", tabIndex: -1, children: activeTab === 'technical' && _jsx(TechnicalTab, {}) }), _jsx(Tabs.Content, { value: "redirects", tabIndex: -1, children: activeTab === 'redirects' && _jsx(RedirectsTab, {}) }), _jsx(Tabs.Content, { value: "audit", tabIndex: -1, children: activeTab === 'audit' && (_jsx(AuditTab, { refetchKey: refetchKey, initialIssueId: deepLink.issueId, onNavigate: onNavigate })) })] }) })] })] }));
|
|
142
99
|
}
|
|
143
100
|
//# sourceMappingURL=SEO.js.map
|
package/dist/views/SEO.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SEO.js","sourceRoot":"","sources":["../../src/views/SEO.tsx"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"SEO.js","sourceRoot":"","sources":["../../src/views/SEO.tsx"],"names":[],"mappings":"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"}
|
package/dist/views/Settings.d.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
export interface SettingsProps {
|
|
2
2
|
onNavigate?: (path: string) => void;
|
|
3
3
|
config?: any;
|
|
4
|
+
/** Initial tab when arriving without a `?tab=` query param (e.g. via the
|
|
5
|
+
* legacy `/users` or `/api-keys` routes). */
|
|
6
|
+
initialTab?: string;
|
|
4
7
|
}
|
|
5
|
-
export declare function Settings({ config,
|
|
8
|
+
export declare function Settings({ config, onNavigate, initialTab }?: SettingsProps): import("react/jsx-runtime").JSX.Element;
|
|
6
9
|
//# sourceMappingURL=Settings.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Settings.d.ts","sourceRoot":"","sources":["../../src/views/Settings.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Settings.d.ts","sourceRoot":"","sources":["../../src/views/Settings.tsx"],"names":[],"mappings":"AAmCA,MAAM,WAAW,aAAa;IAC5B,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IACnC,MAAM,CAAC,EAAE,GAAG,CAAA;IACZ;iDAC6C;IAC7C,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAUD,wBAAgB,QAAQ,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE,UAAsB,EAAE,GAAE,aAAkB,2CAkqB1F"}
|
package/dist/views/Settings.js
CHANGED
|
@@ -1,15 +1,24 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
3
|
import * as Tabs from '@radix-ui/react-tabs';
|
|
4
|
-
import { Bot, Eye, EyeOff, Image, FileCode2, BookOpen, Sparkles, MessageSquare, Loader2, AlertTriangle, Download, CheckCircle2, ArrowUpCircle, ExternalLink, RefreshCw, GitPullRequest, Layers, } from 'lucide-react';
|
|
5
|
-
import { useState, useEffect } from 'react';
|
|
4
|
+
import { Bot, Eye, EyeOff, Image, FileCode2, BookOpen, Sparkles, MessageSquare, Loader2, AlertTriangle, Download, CheckCircle2, ArrowUpCircle, ExternalLink, RefreshCw, GitPullRequest, Layers, Users as UsersIcon, KeyRound, } from 'lucide-react';
|
|
5
|
+
import { useState, useEffect, useCallback, useMemo } from 'react';
|
|
6
6
|
import { toast } from 'sonner';
|
|
7
7
|
import { useApiData } from '../lib/useApiData.js';
|
|
8
8
|
import { cmsApi } from '../lib/api.js';
|
|
9
9
|
import { useTheme } from '../components/ThemeProvider.js';
|
|
10
10
|
import { RelationshipField } from '../fields/RelationshipField.js';
|
|
11
11
|
import { SEOConfigPanel } from '../components/SEOConfigPanel.js';
|
|
12
|
-
|
|
12
|
+
import { Users as UsersView } from './Users.js';
|
|
13
|
+
import { ApiKeys as ApiKeysView } from './ApiKeys.js';
|
|
14
|
+
/** Tabs that drive their own persistence (no global "Save Changes" footer). */
|
|
15
|
+
const SELF_MANAGED_TABS = new Set(['users', 'api-keys']);
|
|
16
|
+
function readSettingsTabFromUrl() {
|
|
17
|
+
if (typeof window === 'undefined')
|
|
18
|
+
return null;
|
|
19
|
+
return new URLSearchParams(window.location.search).get('tab');
|
|
20
|
+
}
|
|
21
|
+
export function Settings({ config, onNavigate, initialTab = 'general' } = {}) {
|
|
13
22
|
const { data, loading, error, refetch } = useApiData('/globals/settings');
|
|
14
23
|
const [siteTitle, setSiteTitle] = useState('My CMS');
|
|
15
24
|
const [tagline, setTagline] = useState('A lightweight content management system');
|
|
@@ -22,7 +31,7 @@ export function Settings({ config, ..._props } = {}) {
|
|
|
22
31
|
const [twoFactorEnabled, setTwoFactorEnabled] = useState(false);
|
|
23
32
|
const [sessionTimeout, setSessionTimeout] = useState(false);
|
|
24
33
|
const [ipWhitelist, setIpWhitelist] = useState(false);
|
|
25
|
-
const [activeTab, setActiveTab] = useState(
|
|
34
|
+
const [activeTab, setActiveTab] = useState(() => readSettingsTabFromUrl() ?? initialTab);
|
|
26
35
|
const [saving, setSaving] = useState(false);
|
|
27
36
|
// Layout defaults
|
|
28
37
|
const [defaultLayout, setDefaultLayout] = useState({});
|
|
@@ -35,6 +44,36 @@ export function Settings({ config, ..._props } = {}) {
|
|
|
35
44
|
}))
|
|
36
45
|
: [];
|
|
37
46
|
const hasLayoutRegions = layoutRegions.length > 0;
|
|
47
|
+
// Valid tab ids, with `layout` only available when the project configures
|
|
48
|
+
// layout regions. Used to normalise deep links and keep the URL honest.
|
|
49
|
+
const availableTabs = useMemo(() => [
|
|
50
|
+
'general',
|
|
51
|
+
'appearance',
|
|
52
|
+
...(hasLayoutRegions ? ['layout'] : []),
|
|
53
|
+
'security',
|
|
54
|
+
'users',
|
|
55
|
+
'api-keys',
|
|
56
|
+
'seo',
|
|
57
|
+
'ai',
|
|
58
|
+
'updates',
|
|
59
|
+
], [hasLayoutRegions]);
|
|
60
|
+
const normalizeTab = useCallback((tab) => tab && availableTabs.includes(tab) ? tab : 'general', [availableTabs]);
|
|
61
|
+
// Drive the active tab from the `?tab=` query param so tabs are deep-linkable
|
|
62
|
+
// and survive browser back/forward (the legacy /users and /api-keys routes
|
|
63
|
+
// land here via `initialTab`).
|
|
64
|
+
useEffect(() => {
|
|
65
|
+
function sync() {
|
|
66
|
+
setActiveTab(normalizeTab(readSettingsTabFromUrl() ?? initialTab));
|
|
67
|
+
}
|
|
68
|
+
sync();
|
|
69
|
+
window.addEventListener('popstate', sync);
|
|
70
|
+
return () => window.removeEventListener('popstate', sync);
|
|
71
|
+
}, [normalizeTab, initialTab]);
|
|
72
|
+
const changeTab = useCallback((tab) => {
|
|
73
|
+
const next = normalizeTab(tab);
|
|
74
|
+
setActiveTab(next);
|
|
75
|
+
onNavigate?.(`/settings?tab=${next}`);
|
|
76
|
+
}, [normalizeTab, onNavigate]);
|
|
38
77
|
// AI settings
|
|
39
78
|
const [aiProvider, setAiProvider] = useState('anthropic');
|
|
40
79
|
const [aiApiKey, setAiApiKey] = useState('');
|
|
@@ -118,7 +157,7 @@ export function Settings({ config, ..._props } = {}) {
|
|
|
118
157
|
if (loading) {
|
|
119
158
|
return (_jsx("div", { className: "flex h-64 items-center justify-center p-3 pr-6 sm:p-4 sm:pr-8", children: _jsx(Loader2, { className: "h-6 w-6 animate-spin text-blue-600" }) }));
|
|
120
159
|
}
|
|
121
|
-
return (_jsxs("div", { className: "p-3 pr-6 sm:p-4 sm:pr-8", children: [error && (_jsxs("div", { className: "mb-4 flex items-center gap-3 rounded-lg border border-red-200 bg-red-50 p-3", children: [_jsx(AlertTriangle, { className: "h-5 w-5 shrink-0 text-red-600" }), _jsx("span", { className: "flex-1 text-sm text-red-800", children: error }), _jsx("button", { onClick: refetch, className: "rounded-lg border border-red-300 px-3 py-1 text-sm text-red-700 transition-colors hover:bg-red-100", children: "Retry" })] })), _jsxs("div", { className: "mb-4", children: [_jsx("h1", { className: "mb-1 text-2xl font-semibold text-gray-900", children: "Settings" }), _jsx("p", { className: "text-sm text-gray-600", children: "Manage your CMS configuration" })] }), _jsxs(Tabs.Root, { value: activeTab, onValueChange:
|
|
160
|
+
return (_jsxs("div", { className: "p-3 pr-6 sm:p-4 sm:pr-8", children: [error && (_jsxs("div", { className: "mb-4 flex items-center gap-3 rounded-lg border border-red-200 bg-red-50 p-3", children: [_jsx(AlertTriangle, { className: "h-5 w-5 shrink-0 text-red-600" }), _jsx("span", { className: "flex-1 text-sm text-red-800", children: error }), _jsx("button", { onClick: refetch, className: "rounded-lg border border-red-300 px-3 py-1 text-sm text-red-700 transition-colors hover:bg-red-100", children: "Retry" })] })), _jsxs("div", { className: "mb-4", children: [_jsx("h1", { className: "mb-1 text-2xl font-semibold text-gray-900", children: "Settings" }), _jsx("p", { className: "text-sm text-gray-600", children: "Manage your CMS configuration" })] }), _jsxs(Tabs.Root, { value: activeTab, onValueChange: changeTab, children: [_jsxs(Tabs.List, { className: "mb-4 flex gap-1 overflow-x-auto border-b border-gray-200", children: [_jsx(Tabs.Trigger, { value: "general", className: tabTriggerClass, children: "General" }), _jsx(Tabs.Trigger, { value: "appearance", className: tabTriggerClass, children: "Appearance" }), hasLayoutRegions && (_jsx(Tabs.Trigger, { value: "layout", className: tabTriggerClass, children: _jsxs("span", { className: "flex items-center gap-1.5", children: [_jsx(Layers, { className: "h-4 w-4" }), "Layout"] }) })), _jsx(Tabs.Trigger, { value: "security", className: tabTriggerClass, children: "Security" }), _jsx(Tabs.Trigger, { value: "users", className: tabTriggerClass, children: _jsxs("span", { className: "flex items-center gap-1.5", children: [_jsx(UsersIcon, { className: "h-4 w-4" }), "Users"] }) }), _jsx(Tabs.Trigger, { value: "api-keys", className: tabTriggerClass, children: _jsxs("span", { className: "flex items-center gap-1.5", children: [_jsx(KeyRound, { className: "h-4 w-4" }), "API Keys"] }) }), _jsx(Tabs.Trigger, { value: "seo", className: tabTriggerClass, children: "SEO" }), _jsx(Tabs.Trigger, { value: "ai", className: tabTriggerClass, children: _jsxs("span", { className: "flex items-center gap-1.5", children: [_jsx(Bot, { className: "h-4 w-4" }), "AI"] }) }), _jsx(Tabs.Trigger, { value: "updates", className: tabTriggerClass, children: _jsxs("span", { className: "flex items-center gap-1.5", children: [_jsx(Download, { className: "h-4 w-4" }), "Updates"] }) })] }), _jsxs(Tabs.Content, { value: "general", className: "space-y-4", children: [_jsxs("div", { className: "rounded-lg border border-gray-200 bg-white p-4", children: [_jsx("h3", { className: "mb-4 text-sm font-semibold text-gray-900", children: "Site Information" }), _jsxs("div", { className: "space-y-4", children: [_jsxs("div", { children: [_jsx("label", { className: "mb-1 block text-sm font-medium text-gray-700", children: "Site Title" }), _jsx("input", { type: "text", value: siteTitle, onChange: (e) => setSiteTitle(e.target.value), className: "w-full rounded-lg border border-gray-300 px-3 py-2 text-sm focus:ring-2 focus:ring-blue-500 focus:outline-none" })] }), _jsxs("div", { children: [_jsx("label", { className: "mb-1 block text-sm font-medium text-gray-700", children: "Tagline" }), _jsx("input", { type: "text", value: tagline, onChange: (e) => setTagline(e.target.value), className: "w-full rounded-lg border border-gray-300 px-3 py-2 text-sm focus:ring-2 focus:ring-blue-500 focus:outline-none" })] }), _jsxs("div", { children: [_jsx("label", { className: "mb-1 block text-sm font-medium text-gray-700", children: "Site URL" }), _jsx("input", { type: "url", value: siteUrl, onChange: (e) => setSiteUrl(e.target.value), className: "w-full rounded-lg border border-gray-300 px-3 py-2 text-sm focus:ring-2 focus:ring-blue-500 focus:outline-none" })] })] })] }), _jsxs("div", { className: "rounded-lg border border-gray-200 bg-white p-4", children: [_jsx("h3", { className: "mb-4 text-sm font-semibold text-gray-900", children: "Language & Region" }), _jsxs("div", { className: "space-y-4", children: [_jsxs("div", { children: [_jsx("label", { className: "mb-1 block text-sm font-medium text-gray-700", children: "Language" }), _jsxs("select", { value: language, onChange: (e) => setLanguage(e.target.value), className: "w-full rounded-lg border border-gray-300 px-3 py-2 text-sm focus:ring-2 focus:ring-blue-500 focus:outline-none", children: [_jsx("option", { value: "en", children: "English" }), _jsx("option", { value: "es", children: "Spanish" }), _jsx("option", { value: "fr", children: "French" }), _jsx("option", { value: "de", children: "German" })] })] }), _jsxs("div", { children: [_jsx("label", { className: "mb-1 block text-sm font-medium text-gray-700", children: "Timezone" }), _jsxs("select", { value: timezone, onChange: (e) => setTimezone(e.target.value), className: "w-full rounded-lg border border-gray-300 px-3 py-2 text-sm focus:ring-2 focus:ring-blue-500 focus:outline-none", children: [_jsx("option", { value: "UTC", children: "UTC" }), _jsx("option", { value: "America/New_York", children: "Eastern Time" }), _jsx("option", { value: "America/Chicago", children: "Central Time" }), _jsx("option", { value: "America/Denver", children: "Mountain Time" }), _jsx("option", { value: "America/Los_Angeles", children: "Pacific Time" })] })] })] })] }), _jsxs("div", { className: "border-border bg-card rounded-lg border p-4", children: [_jsx("h3", { className: "text-foreground mb-1 text-sm font-medium", children: "SEO & Robots Defaults" }), _jsx("p", { className: "text-muted-foreground mb-4 text-xs", children: "Set the site-wide default for search engine indexing. Individual pages can inherit or override these rules in their SEO panel." }), _jsxs("div", { className: "space-y-4", children: [_jsx(ToggleSetting, { label: "Default No Index", description: "Ask search engines not to index pages unless a page explicitly allows indexing", checked: defaultNoIndex, onChange: setDefaultNoIndex }), _jsx(ToggleSetting, { label: "Default No Follow", description: "Ask search engines not to follow page links unless a page explicitly allows following", checked: defaultNoFollow, onChange: setDefaultNoFollow }), _jsx(ToggleSetting, { label: "Noindex Non-Production Environments", description: "Force noindex when the deployed environment is not production", checked: noIndexNonProduction, onChange: setNoIndexNonProduction })] })] })] }), _jsx(Tabs.Content, { value: "appearance", className: "space-y-4", children: _jsxs("div", { className: "rounded-lg border border-gray-200 bg-white p-4", children: [_jsx("h3", { className: "mb-4 text-sm font-semibold text-gray-900", children: "Theme" }), _jsxs("div", { className: "space-y-4", children: [_jsxs("div", { children: [_jsx("label", { className: "mb-1 block text-sm font-medium text-gray-700", children: "Color Scheme" }), _jsx(ThemeSelect, {})] }), _jsxs("div", { children: [_jsx("label", { className: "mb-1 block text-sm font-medium text-gray-700", children: "Primary Color" }), _jsx("input", { type: "color", defaultValue: "#3b82f6", className: "h-10 w-full rounded-lg border border-gray-300 px-3 py-2" })] })] })] }) }), hasLayoutRegions && (_jsxs(Tabs.Content, { value: "layout", className: "space-y-4", children: [_jsxs("div", { className: "rounded-lg border border-gray-200 bg-white p-4", children: [_jsx("h3", { className: "mb-1 text-sm font-semibold text-gray-900", children: "Default Layout Variants" }), _jsx("p", { className: "mb-4 text-xs text-gray-500", children: "Select the default header, footer, and other layout variants used site-wide. Pages can override these individually or inherit from parent pages." }), _jsx("div", { className: "space-y-4", children: layoutRegions.map((region) => (_jsx(RelationshipField, { label: `Default ${region.label}`, value: defaultLayout[region.name] ?? '', onChange: (val) => {
|
|
122
161
|
setDefaultLayout((prev) => {
|
|
123
162
|
const next = { ...prev };
|
|
124
163
|
if (val && typeof val === 'string') {
|
|
@@ -141,7 +180,7 @@ export function Settings({ config, ..._props } = {}) {
|
|
|
141
180
|
toast.success('API key verified successfully');
|
|
142
181
|
else
|
|
143
182
|
toast.error('Please enter an API key first');
|
|
144
|
-
}, className: "rounded-lg border border-gray-300 px-4 py-2 text-sm transition-colors hover:bg-gray-50", children: "Verify" })] }), _jsx("p", { className: "mt-1 text-xs text-gray-500", children: "Your key is encrypted at rest (AES-256-GCM) and never exposed to the client" })] })] })] }), _jsxs("div", { className: "rounded-lg border border-gray-200 bg-white p-4", children: [_jsxs("div", { className: "mb-1 flex items-center gap-2", children: [_jsx(Image, { className: "h-4 w-4 text-blue-600" }), _jsx("h3", { className: "text-sm font-semibold text-gray-900", children: "Media Intelligence" })] }), _jsx("p", { className: "mb-4 text-xs text-gray-500", children: "AI-powered image and media analysis" }), _jsxs("div", { className: "space-y-4", children: [_jsx(ToggleSetting, { label: "Auto Alt-Tag Generation", description: "Scan uploaded images and automatically generate descriptive alt text for accessibility and SEO", checked: aiAltTags, onChange: setAiAltTags }), _jsx(ToggleSetting, { label: "Media Auto-Categorization", description: "Automatically tag and categorize uploaded media based on visual content analysis", checked: aiMediaCategorize, onChange: setAiMediaCategorize })] })] }), _jsxs("div", { className: "rounded-lg border border-gray-200 bg-white p-4", children: [_jsxs("div", { className: "mb-1 flex items-center gap-2", children: [_jsx(FileCode2, { className: "h-4 w-4 text-purple-600" }), _jsx("h3", { className: "text-sm font-semibold text-gray-900", children: "Content SEO" })] }), _jsx("p", { className: "mb-4 text-xs text-gray-500", children: "AI-driven SEO optimization for your content" }), _jsxs("div", { className: "space-y-4", children: [_jsx(ToggleSetting, { label: "Meta Description Generation", description: "Auto-generate optimized meta descriptions by digesting page content", checked: aiMetaDescriptions, onChange: setAiMetaDescriptions }), _jsx(ToggleSetting, { label: "Readability Analysis", description: "Score content readability (Flesch-Kincaid, Gunning Fog) with improvement suggestions", checked: aiReadability, onChange: setAiReadability }), _jsx(ToggleSetting, { label: "Schema.org Enrichment", description: "Automatically detect content types and generate appropriate Schema.org JSON-LD markup", checked: aiSchema, onChange: setAiSchema })] })] }), _jsxs("div", { className: "rounded-lg border border-gray-200 bg-white p-4", children: [_jsxs("div", { className: "mb-1 flex items-center gap-2", children: [_jsx(MessageSquare, { className: "h-4 w-4 text-green-600" }), _jsx("h3", { className: "text-sm font-semibold text-gray-900", children: "Brand Voice & Writing" })] }), _jsx("p", { className: "mb-4 text-xs text-gray-500", children: "AI that understands and writes in your brand's voice" }), _jsxs("div", { className: "space-y-4", children: [_jsx(ToggleSetting, { label: "Brand Voice Training", description: "Analyze existing content to learn your brand's tone, style, and vocabulary", checked: aiBrandVoice, onChange: setAiBrandVoice }), _jsx(ToggleSetting, { label: "AI Writing Assistant", description: "In-editor AI helper for drafting, rewriting, and expanding content in your brand voice", checked: aiWritingAssistant, onChange: setAiWritingAssistant })] })] }), _jsxs("div", { className: "rounded-lg border border-gray-200 bg-white p-4", children: [_jsxs("div", { className: "mb-1 flex items-center gap-2", children: [_jsx(Sparkles, { className: "h-4 w-4 text-yellow-600" }), _jsx("h3", { className: "text-sm font-semibold text-gray-900", children: "Content Quality" })] }), _jsx("p", { className: "mb-4 text-xs text-gray-500", children: "Automated quality scoring and content intelligence" }), _jsxs("div", { className: "space-y-4", children: [_jsx(ToggleSetting, { label: "Content Scoring", description: "Automatically score content quality based on structure, readability, SEO, and completeness", checked: aiContentScoring, onChange: setAiContentScoring }), _jsx(ToggleSetting, { label: "AI-Powered Translation", description: "Translate content into target languages while preserving tone and meaning", checked: aiTranslation, onChange: setAiTranslation })] })] }), _jsxs("div", { className: "rounded-lg border border-indigo-200 bg-indigo-50 p-4", children: [_jsxs("div", { className: "mb-1 flex items-center gap-2", children: [_jsx(BookOpen, { className: "h-4 w-4 text-indigo-600" }), _jsx("h3", { className: "text-sm font-semibold text-indigo-900", children: "AI Usage This Month" })] }), _jsxs("div", { className: "mt-3 grid grid-cols-3 gap-4", children: [_jsxs("div", { children: [_jsx("div", { className: "text-lg font-semibold text-indigo-900", children: "0" }), _jsx("div", { className: "text-xs text-indigo-700", children: "API Calls" })] }), _jsxs("div", { children: [_jsx("div", { className: "text-lg font-semibold text-indigo-900", children: "0" }), _jsx("div", { className: "text-xs text-indigo-700", children: "Tokens Used" })] }), _jsxs("div", { children: [_jsx("div", { className: "text-lg font-semibold text-indigo-900", children: "$0.00" }), _jsx("div", { className: "text-xs text-indigo-700", children: "Estimated Cost" })] })] }), _jsx("p", { className: "mt-2 text-xs text-indigo-600", children: "Add an API key above to start using AI features" })] })] }), _jsx(Tabs.Content, { value: "
|
|
183
|
+
}, className: "rounded-lg border border-gray-300 px-4 py-2 text-sm transition-colors hover:bg-gray-50", children: "Verify" })] }), _jsx("p", { className: "mt-1 text-xs text-gray-500", children: "Your key is encrypted at rest (AES-256-GCM) and never exposed to the client" })] })] })] }), _jsxs("div", { className: "rounded-lg border border-gray-200 bg-white p-4", children: [_jsxs("div", { className: "mb-1 flex items-center gap-2", children: [_jsx(Image, { className: "h-4 w-4 text-blue-600" }), _jsx("h3", { className: "text-sm font-semibold text-gray-900", children: "Media Intelligence" })] }), _jsx("p", { className: "mb-4 text-xs text-gray-500", children: "AI-powered image and media analysis" }), _jsxs("div", { className: "space-y-4", children: [_jsx(ToggleSetting, { label: "Auto Alt-Tag Generation", description: "Scan uploaded images and automatically generate descriptive alt text for accessibility and SEO", checked: aiAltTags, onChange: setAiAltTags }), _jsx(ToggleSetting, { label: "Media Auto-Categorization", description: "Automatically tag and categorize uploaded media based on visual content analysis", checked: aiMediaCategorize, onChange: setAiMediaCategorize })] })] }), _jsxs("div", { className: "rounded-lg border border-gray-200 bg-white p-4", children: [_jsxs("div", { className: "mb-1 flex items-center gap-2", children: [_jsx(FileCode2, { className: "h-4 w-4 text-purple-600" }), _jsx("h3", { className: "text-sm font-semibold text-gray-900", children: "Content SEO" })] }), _jsx("p", { className: "mb-4 text-xs text-gray-500", children: "AI-driven SEO optimization for your content" }), _jsxs("div", { className: "space-y-4", children: [_jsx(ToggleSetting, { label: "Meta Description Generation", description: "Auto-generate optimized meta descriptions by digesting page content", checked: aiMetaDescriptions, onChange: setAiMetaDescriptions }), _jsx(ToggleSetting, { label: "Readability Analysis", description: "Score content readability (Flesch-Kincaid, Gunning Fog) with improvement suggestions", checked: aiReadability, onChange: setAiReadability }), _jsx(ToggleSetting, { label: "Schema.org Enrichment", description: "Automatically detect content types and generate appropriate Schema.org JSON-LD markup", checked: aiSchema, onChange: setAiSchema })] })] }), _jsxs("div", { className: "rounded-lg border border-gray-200 bg-white p-4", children: [_jsxs("div", { className: "mb-1 flex items-center gap-2", children: [_jsx(MessageSquare, { className: "h-4 w-4 text-green-600" }), _jsx("h3", { className: "text-sm font-semibold text-gray-900", children: "Brand Voice & Writing" })] }), _jsx("p", { className: "mb-4 text-xs text-gray-500", children: "AI that understands and writes in your brand's voice" }), _jsxs("div", { className: "space-y-4", children: [_jsx(ToggleSetting, { label: "Brand Voice Training", description: "Analyze existing content to learn your brand's tone, style, and vocabulary", checked: aiBrandVoice, onChange: setAiBrandVoice }), _jsx(ToggleSetting, { label: "AI Writing Assistant", description: "In-editor AI helper for drafting, rewriting, and expanding content in your brand voice", checked: aiWritingAssistant, onChange: setAiWritingAssistant })] })] }), _jsxs("div", { className: "rounded-lg border border-gray-200 bg-white p-4", children: [_jsxs("div", { className: "mb-1 flex items-center gap-2", children: [_jsx(Sparkles, { className: "h-4 w-4 text-yellow-600" }), _jsx("h3", { className: "text-sm font-semibold text-gray-900", children: "Content Quality" })] }), _jsx("p", { className: "mb-4 text-xs text-gray-500", children: "Automated quality scoring and content intelligence" }), _jsxs("div", { className: "space-y-4", children: [_jsx(ToggleSetting, { label: "Content Scoring", description: "Automatically score content quality based on structure, readability, SEO, and completeness", checked: aiContentScoring, onChange: setAiContentScoring }), _jsx(ToggleSetting, { label: "AI-Powered Translation", description: "Translate content into target languages while preserving tone and meaning", checked: aiTranslation, onChange: setAiTranslation })] })] }), _jsxs("div", { className: "rounded-lg border border-indigo-200 bg-indigo-50 p-4", children: [_jsxs("div", { className: "mb-1 flex items-center gap-2", children: [_jsx(BookOpen, { className: "h-4 w-4 text-indigo-600" }), _jsx("h3", { className: "text-sm font-semibold text-indigo-900", children: "AI Usage This Month" })] }), _jsxs("div", { className: "mt-3 grid grid-cols-3 gap-4", children: [_jsxs("div", { children: [_jsx("div", { className: "text-lg font-semibold text-indigo-900", children: "0" }), _jsx("div", { className: "text-xs text-indigo-700", children: "API Calls" })] }), _jsxs("div", { children: [_jsx("div", { className: "text-lg font-semibold text-indigo-900", children: "0" }), _jsx("div", { className: "text-xs text-indigo-700", children: "Tokens Used" })] }), _jsxs("div", { children: [_jsx("div", { className: "text-lg font-semibold text-indigo-900", children: "$0.00" }), _jsx("div", { className: "text-xs text-indigo-700", children: "Estimated Cost" })] })] }), _jsx("p", { className: "mt-2 text-xs text-indigo-600", children: "Add an API key above to start using AI features" })] })] }), _jsx(Tabs.Content, { value: "users", children: _jsx(UsersView, { onNavigate: onNavigate, embedded: true }) }), _jsx(Tabs.Content, { value: "api-keys", children: _jsx(ApiKeysView, { onNavigate: onNavigate, embedded: true }) }), _jsx(Tabs.Content, { value: "updates", className: "space-y-4", children: _jsx(UpdatesPanel, {}) })] }), !SELF_MANAGED_TABS.has(activeTab) && (_jsx("div", { className: "mt-6 flex justify-end", children: _jsx("button", { type: "button", onClick: handleSave, disabled: saving, className: "rounded-lg bg-blue-600 px-6 py-2 text-sm text-white transition-colors hover:bg-blue-700 disabled:opacity-50", children: saving ? 'Saving...' : 'Save Changes' }) }))] }));
|
|
145
184
|
}
|
|
146
185
|
function ThemeSelect() {
|
|
147
186
|
const { theme, setTheme } = useTheme();
|