@actuate-media/cms-admin 0.66.0 → 0.68.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/CHANGELOG.md +37 -0
- package/dist/AdminRoot.d.ts.map +1 -1
- package/dist/AdminRoot.js +36 -9
- package/dist/AdminRoot.js.map +1 -1
- package/dist/__tests__/components/inspector-pane.test.d.ts +2 -0
- package/dist/__tests__/components/inspector-pane.test.d.ts.map +1 -0
- package/dist/__tests__/components/inspector-pane.test.js +31 -0
- package/dist/__tests__/components/inspector-pane.test.js.map +1 -0
- package/dist/__tests__/hooks/useIdleLogout.test.d.ts +2 -0
- package/dist/__tests__/hooks/useIdleLogout.test.d.ts.map +1 -0
- package/dist/__tests__/hooks/useIdleLogout.test.js +64 -0
- package/dist/__tests__/hooks/useIdleLogout.test.js.map +1 -0
- package/dist/__tests__/lib/pages-tree.test.d.ts +2 -0
- package/dist/__tests__/lib/pages-tree.test.d.ts.map +1 -0
- package/dist/__tests__/lib/pages-tree.test.js +173 -0
- package/dist/__tests__/lib/pages-tree.test.js.map +1 -0
- package/dist/__tests__/lib/post-types-service.test.d.ts +2 -0
- package/dist/__tests__/lib/post-types-service.test.d.ts.map +1 -0
- package/dist/__tests__/lib/post-types-service.test.js +88 -0
- package/dist/__tests__/lib/post-types-service.test.js.map +1 -0
- package/dist/__tests__/views/collection-list-nav.render.test.js +43 -5
- package/dist/__tests__/views/collection-list-nav.render.test.js.map +1 -1
- package/dist/__tests__/views/dashboard.test.js +7 -3
- package/dist/__tests__/views/dashboard.test.js.map +1 -1
- package/dist/__tests__/views/forms-list.render.test.js +25 -6
- package/dist/__tests__/views/forms-list.render.test.js.map +1 -1
- package/dist/__tests__/views/media-seo-audit.render.test.d.ts +2 -0
- package/dist/__tests__/views/media-seo-audit.render.test.d.ts.map +1 -0
- package/dist/__tests__/views/media-seo-audit.render.test.js +102 -0
- package/dist/__tests__/views/media-seo-audit.render.test.js.map +1 -0
- package/dist/__tests__/views/onboarding-block.render.test.d.ts +2 -0
- package/dist/__tests__/views/onboarding-block.render.test.d.ts.map +1 -0
- package/dist/__tests__/views/onboarding-block.render.test.js +146 -0
- package/dist/__tests__/views/onboarding-block.render.test.js.map +1 -0
- package/dist/__tests__/views/page-builder-sections-panel.render.test.d.ts +2 -0
- package/dist/__tests__/views/page-builder-sections-panel.render.test.d.ts.map +1 -0
- package/dist/__tests__/views/page-builder-sections-panel.render.test.js +121 -0
- package/dist/__tests__/views/page-builder-sections-panel.render.test.js.map +1 -0
- package/dist/__tests__/views/page-templates.render.test.d.ts +2 -0
- package/dist/__tests__/views/page-templates.render.test.d.ts.map +1 -0
- package/dist/__tests__/views/page-templates.render.test.js +105 -0
- package/dist/__tests__/views/page-templates.render.test.js.map +1 -0
- package/dist/__tests__/views/pages-list-view.test.js +77 -1
- package/dist/__tests__/views/pages-list-view.test.js.map +1 -1
- package/dist/__tests__/views/post-type-editor.render.test.d.ts +2 -0
- package/dist/__tests__/views/post-type-editor.render.test.d.ts.map +1 -0
- package/dist/__tests__/views/post-type-editor.render.test.js +102 -0
- package/dist/__tests__/views/post-type-editor.render.test.js.map +1 -0
- package/dist/__tests__/views/security-settings.render.test.js +85 -4
- package/dist/__tests__/views/security-settings.render.test.js.map +1 -1
- package/dist/__tests__/views/seo-content-pane.render.test.d.ts +2 -0
- package/dist/__tests__/views/seo-content-pane.render.test.d.ts.map +1 -0
- package/dist/__tests__/views/seo-content-pane.render.test.js +117 -0
- package/dist/__tests__/views/seo-content-pane.render.test.js.map +1 -0
- package/dist/actuate-admin.css +1 -1
- package/dist/components/collections/EntryDetailPane.d.ts +10 -0
- package/dist/components/collections/EntryDetailPane.d.ts.map +1 -0
- package/dist/components/collections/EntryDetailPane.js +92 -0
- package/dist/components/collections/EntryDetailPane.js.map +1 -0
- package/dist/components/forms/FieldsPanel.js +1 -1
- package/dist/components/forms/FieldsPanel.js.map +1 -1
- package/dist/components/forms/FormSchemaPane.d.ts +8 -0
- package/dist/components/forms/FormSchemaPane.d.ts.map +1 -0
- package/dist/components/forms/FormSchemaPane.js +95 -0
- package/dist/components/forms/FormSchemaPane.js.map +1 -0
- package/dist/components/script-tags/ScriptTagEditorPane.d.ts +26 -0
- package/dist/components/script-tags/ScriptTagEditorPane.d.ts.map +1 -0
- package/dist/components/script-tags/ScriptTagEditorPane.js +160 -0
- package/dist/components/script-tags/ScriptTagEditorPane.js.map +1 -0
- package/dist/components/seo/SeoEditorPane.d.ts +9 -0
- package/dist/components/seo/SeoEditorPane.d.ts.map +1 -0
- package/dist/components/seo/SeoEditorPane.js +175 -0
- package/dist/components/seo/SeoEditorPane.js.map +1 -0
- package/dist/components/ui/Badge.d.ts +1 -1
- package/dist/components/ui/Button.d.ts +1 -1
- package/dist/components/ui/InspectorPane.d.ts +51 -0
- package/dist/components/ui/InspectorPane.d.ts.map +1 -0
- package/dist/components/ui/InspectorPane.js +42 -0
- package/dist/components/ui/InspectorPane.js.map +1 -0
- package/dist/components/ui/StatusBadge.d.ts +1 -1
- package/dist/components/ui/index.d.ts +2 -0
- package/dist/components/ui/index.d.ts.map +1 -1
- package/dist/components/ui/index.js +1 -0
- package/dist/components/ui/index.js.map +1 -1
- package/dist/hooks/useIdleLogout.d.ts +18 -0
- package/dist/hooks/useIdleLogout.d.ts.map +1 -0
- package/dist/hooks/useIdleLogout.js +66 -0
- package/dist/hooks/useIdleLogout.js.map +1 -0
- package/dist/lib/api.d.ts +1 -0
- package/dist/lib/api.d.ts.map +1 -1
- package/dist/lib/api.js +7 -1
- package/dist/lib/api.js.map +1 -1
- package/dist/lib/page-editor-service.d.ts +11 -2
- package/dist/lib/page-editor-service.d.ts.map +1 -1
- package/dist/lib/page-editor-service.js +8 -2
- package/dist/lib/page-editor-service.js.map +1 -1
- package/dist/lib/pages-tree.d.ts +44 -0
- package/dist/lib/pages-tree.d.ts.map +1 -0
- package/dist/lib/pages-tree.js +106 -0
- package/dist/lib/pages-tree.js.map +1 -0
- package/dist/lib/post-types-service.d.ts +44 -0
- package/dist/lib/post-types-service.d.ts.map +1 -0
- package/dist/lib/post-types-service.js +83 -0
- package/dist/lib/post-types-service.js.map +1 -0
- package/dist/views/CollectionList.d.ts.map +1 -1
- package/dist/views/CollectionList.js +23 -4
- package/dist/views/CollectionList.js.map +1 -1
- package/dist/views/Dashboard.d.ts.map +1 -1
- package/dist/views/Dashboard.js +31 -2
- package/dist/views/Dashboard.js.map +1 -1
- package/dist/views/Forms.d.ts.map +1 -1
- package/dist/views/Forms.js +25 -21
- package/dist/views/Forms.js.map +1 -1
- package/dist/views/MediaBrowser.d.ts.map +1 -1
- package/dist/views/MediaBrowser.js +28 -2
- package/dist/views/MediaBrowser.js.map +1 -1
- package/dist/views/MediaSeoAudit.d.ts +25 -0
- package/dist/views/MediaSeoAudit.d.ts.map +1 -0
- package/dist/views/MediaSeoAudit.js +97 -0
- package/dist/views/MediaSeoAudit.js.map +1 -0
- package/dist/views/Pages/PagesListView.d.ts.map +1 -1
- package/dist/views/Pages/PagesListView.js +90 -10
- package/dist/views/Pages/PagesListView.js.map +1 -1
- package/dist/views/Pages/PagesTreeTable.d.ts +35 -0
- package/dist/views/Pages/PagesTreeTable.d.ts.map +1 -0
- package/dist/views/Pages/PagesTreeTable.js +28 -0
- package/dist/views/Pages/PagesTreeTable.js.map +1 -0
- package/dist/views/Posts/PostTypeEditor.d.ts +16 -0
- package/dist/views/Posts/PostTypeEditor.d.ts.map +1 -0
- package/dist/views/Posts/PostTypeEditor.js +159 -0
- package/dist/views/Posts/PostTypeEditor.js.map +1 -0
- package/dist/views/Posts/PostTypesView.d.ts +3 -2
- package/dist/views/Posts/PostTypesView.d.ts.map +1 -1
- package/dist/views/Posts/PostTypesView.js +1 -1
- package/dist/views/Posts/PostTypesView.js.map +1 -1
- package/dist/views/ScriptTags.d.ts +5 -1
- package/dist/views/ScriptTags.d.ts.map +1 -1
- package/dist/views/ScriptTags.js +32 -7
- package/dist/views/ScriptTags.js.map +1 -1
- package/dist/views/dashboard/OnboardingBlock.d.ts +29 -0
- package/dist/views/dashboard/OnboardingBlock.d.ts.map +1 -0
- package/dist/views/dashboard/OnboardingBlock.js +71 -0
- package/dist/views/dashboard/OnboardingBlock.js.map +1 -0
- package/dist/views/page-builder/BuilderSectionsPanel.d.ts +20 -0
- package/dist/views/page-builder/BuilderSectionsPanel.d.ts.map +1 -0
- package/dist/views/page-builder/BuilderSectionsPanel.js +105 -0
- package/dist/views/page-builder/BuilderSectionsPanel.js.map +1 -0
- package/dist/views/page-builder/PageBuilder.d.ts.map +1 -1
- package/dist/views/page-builder/PageBuilder.js +51 -2
- package/dist/views/page-builder/PageBuilder.js.map +1 -1
- package/dist/views/page-builder/PageTemplates.d.ts.map +1 -1
- package/dist/views/page-builder/PageTemplates.js +113 -6
- package/dist/views/page-builder/PageTemplates.js.map +1 -1
- package/dist/views/page-editor/PageSectionEditor.d.ts +7 -1
- package/dist/views/page-editor/PageSectionEditor.d.ts.map +1 -1
- package/dist/views/page-editor/PageSectionEditor.js +3 -3
- package/dist/views/page-editor/PageSectionEditor.js.map +1 -1
- package/dist/views/page-editor/PageSettingsModal.d.ts +1 -1
- package/dist/views/page-editor/PageSettingsModal.d.ts.map +1 -1
- package/dist/views/page-editor/PageSettingsModal.js +42 -3
- package/dist/views/page-editor/PageSettingsModal.js.map +1 -1
- package/dist/views/seo/ContentTab.d.ts.map +1 -1
- package/dist/views/seo/ContentTab.js +22 -6
- package/dist/views/seo/ContentTab.js.map +1 -1
- package/dist/views/settings/AccessProtectionCard.d.ts +5 -1
- package/dist/views/settings/AccessProtectionCard.d.ts.map +1 -1
- package/dist/views/settings/AccessProtectionCard.js +13 -10
- package/dist/views/settings/AccessProtectionCard.js.map +1 -1
- package/dist/views/settings/SecurityTab.d.ts.map +1 -1
- package/dist/views/settings/SecurityTab.js +3 -3
- package/dist/views/settings/SecurityTab.js.map +1 -1
- package/dist/views/settings/SessionPolicyCard.d.ts +1 -2
- package/dist/views/settings/SessionPolicyCard.d.ts.map +1 -1
- package/dist/views/settings/SessionPolicyCard.js +12 -5
- package/dist/views/settings/SessionPolicyCard.js.map +1 -1
- package/dist/views/settings/useSecuritySettings.d.ts +13 -1
- package/dist/views/settings/useSecuritySettings.d.ts.map +1 -1
- package/dist/views/settings/useSecuritySettings.js +47 -4
- package/dist/views/settings/useSecuritySettings.js.map +1 -1
- package/package.json +2 -2
- package/src/AdminRoot.tsx +43 -10
- package/src/__tests__/components/inspector-pane.test.tsx +64 -0
- package/src/__tests__/hooks/useIdleLogout.test.tsx +86 -0
- package/src/__tests__/lib/pages-tree.test.ts +197 -0
- package/src/__tests__/lib/post-types-service.test.ts +112 -0
- package/src/__tests__/views/collection-list-nav.render.test.tsx +51 -5
- package/src/__tests__/views/dashboard.test.tsx +7 -3
- package/src/__tests__/views/forms-list.render.test.tsx +34 -6
- package/src/__tests__/views/media-seo-audit.render.test.tsx +117 -0
- package/src/__tests__/views/onboarding-block.render.test.tsx +193 -0
- package/src/__tests__/views/page-builder-sections-panel.render.test.tsx +138 -0
- package/src/__tests__/views/page-templates.render.test.tsx +142 -0
- package/src/__tests__/views/pages-list-view.test.tsx +93 -1
- package/src/__tests__/views/post-type-editor.render.test.tsx +116 -0
- package/src/__tests__/views/security-settings.render.test.tsx +111 -4
- package/src/__tests__/views/seo-content-pane.render.test.tsx +142 -0
- package/src/components/collections/EntryDetailPane.tsx +182 -0
- package/src/components/forms/FieldsPanel.tsx +3 -1
- package/src/components/forms/FormSchemaPane.tsx +192 -0
- package/src/components/script-tags/ScriptTagEditorPane.tsx +474 -0
- package/src/components/seo/SeoEditorPane.tsx +533 -0
- package/src/components/ui/InspectorPane.tsx +129 -0
- package/src/components/ui/index.ts +10 -0
- package/src/hooks/useIdleLogout.ts +77 -0
- package/src/lib/api.ts +8 -2
- package/src/lib/page-editor-service.ts +16 -2
- package/src/lib/pages-tree.ts +145 -0
- package/src/lib/post-types-service.ts +129 -0
- package/src/views/CollectionList.tsx +158 -110
- package/src/views/Dashboard.tsx +238 -196
- package/src/views/Forms.tsx +154 -126
- package/src/views/MediaBrowser.tsx +641 -511
- package/src/views/MediaSeoAudit.tsx +320 -0
- package/src/views/Pages/PagesListView.tsx +352 -183
- package/src/views/Pages/PagesTreeTable.tsx +339 -0
- package/src/views/Posts/PostTypeEditor.tsx +568 -0
- package/src/views/Posts/PostTypesView.tsx +5 -4
- package/src/views/ScriptTags.tsx +204 -129
- package/src/views/dashboard/OnboardingBlock.tsx +233 -0
- package/src/views/page-builder/BuilderSectionsPanel.tsx +304 -0
- package/src/views/page-builder/PageBuilder.tsx +69 -2
- package/src/views/page-builder/PageTemplates.tsx +340 -57
- package/src/views/page-editor/PageSectionEditor.tsx +9 -2
- package/src/views/page-editor/PageSettingsModal.tsx +75 -2
- package/src/views/seo/ContentTab.tsx +113 -80
- package/src/views/settings/AccessProtectionCard.tsx +83 -53
- package/src/views/settings/SecurityTab.tsx +23 -2
- package/src/views/settings/SessionPolicyCard.tsx +45 -9
- package/src/views/settings/useSecuritySettings.ts +78 -22
- package/dist/components/forms/FormSchemaDrawer.d.ts +0 -9
- package/dist/components/forms/FormSchemaDrawer.d.ts.map +0 -1
- package/dist/components/forms/FormSchemaDrawer.js +0 -99
- package/dist/components/forms/FormSchemaDrawer.js.map +0 -1
- package/dist/components/seo/SeoEditorDrawer.d.ts +0 -8
- package/dist/components/seo/SeoEditorDrawer.d.ts.map +0 -1
- package/dist/components/seo/SeoEditorDrawer.js +0 -172
- package/dist/components/seo/SeoEditorDrawer.js.map +0 -1
- package/dist/views/ScriptTagEditor.d.ts +0 -6
- package/dist/views/ScriptTagEditor.d.ts.map +0 -1
- package/dist/views/ScriptTagEditor.js +0 -111
- package/dist/views/ScriptTagEditor.js.map +0 -1
- package/src/components/forms/FormSchemaDrawer.tsx +0 -192
- package/src/components/seo/SeoEditorDrawer.tsx +0 -529
- package/src/views/ScriptTagEditor.tsx +0 -353
|
@@ -1,353 +0,0 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
import { useState, useEffect } from 'react'
|
|
4
|
-
import { ArrowLeft, Loader2, AlertTriangle, Trash2, X, Plus } from 'lucide-react'
|
|
5
|
-
import { toast } from 'sonner'
|
|
6
|
-
import { EnabledSwitch } from '../components/EnabledSwitch.js'
|
|
7
|
-
import { useApiData } from '../lib/useApiData.js'
|
|
8
|
-
import { cmsApi } from '../lib/api.js'
|
|
9
|
-
|
|
10
|
-
export interface ScriptTagEditorProps {
|
|
11
|
-
tagId?: string
|
|
12
|
-
onNavigate?: (path: string) => void
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export function ScriptTagEditor({ tagId, onNavigate }: ScriptTagEditorProps) {
|
|
16
|
-
const isNew = !tagId
|
|
17
|
-
const { data, loading, error } = useApiData<any>(tagId ? `/script-tags` : null)
|
|
18
|
-
|
|
19
|
-
const [name, setName] = useState('')
|
|
20
|
-
const [code, setCode] = useState('')
|
|
21
|
-
const [placement, setPlacement] = useState('head')
|
|
22
|
-
const [scope, setScope] = useState('site')
|
|
23
|
-
const [targetPaths, setTargetPaths] = useState<string[]>([])
|
|
24
|
-
const [pathInput, setPathInput] = useState('')
|
|
25
|
-
const [priority, setPriority] = useState(100)
|
|
26
|
-
const [enabled, setEnabled] = useState(true)
|
|
27
|
-
const [saving, setSaving] = useState(false)
|
|
28
|
-
const [deleting, setDeleting] = useState(false)
|
|
29
|
-
const [showDeleteConfirm, setShowDeleteConfirm] = useState(false)
|
|
30
|
-
|
|
31
|
-
useEffect(() => {
|
|
32
|
-
if (data && tagId) {
|
|
33
|
-
const tags = Array.isArray(data) ? data : []
|
|
34
|
-
const tag = tags.find((t: any) => t.id === tagId)
|
|
35
|
-
if (tag) {
|
|
36
|
-
setName(tag.name ?? '')
|
|
37
|
-
setCode(tag.code ?? '')
|
|
38
|
-
setPlacement(tag.placement ?? 'head')
|
|
39
|
-
setScope(tag.scope ?? 'site')
|
|
40
|
-
setTargetPaths(tag.targetPaths ?? [])
|
|
41
|
-
setPriority(tag.priority ?? 100)
|
|
42
|
-
setEnabled(tag.enabled ?? true)
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
}, [data, tagId])
|
|
46
|
-
|
|
47
|
-
const addPath = () => {
|
|
48
|
-
const trimmed = pathInput.trim()
|
|
49
|
-
if (!trimmed) return
|
|
50
|
-
const normalized = trimmed.startsWith('/') ? trimmed : `/${trimmed}`
|
|
51
|
-
if (!targetPaths.includes(normalized)) {
|
|
52
|
-
setTargetPaths([...targetPaths, normalized])
|
|
53
|
-
}
|
|
54
|
-
setPathInput('')
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
const removePath = (path: string) => {
|
|
58
|
-
setTargetPaths(targetPaths.filter((p) => p !== path))
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
const handleSave = async () => {
|
|
62
|
-
if (!name.trim()) {
|
|
63
|
-
toast.error('Name is required')
|
|
64
|
-
return
|
|
65
|
-
}
|
|
66
|
-
if (!code.trim()) {
|
|
67
|
-
toast.error('Code snippet is required')
|
|
68
|
-
return
|
|
69
|
-
}
|
|
70
|
-
if (scope !== 'site' && targetPaths.length === 0) {
|
|
71
|
-
toast.error('At least one target path is required for this scope')
|
|
72
|
-
return
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
setSaving(true)
|
|
76
|
-
const payload = {
|
|
77
|
-
name: name.trim(),
|
|
78
|
-
code,
|
|
79
|
-
placement,
|
|
80
|
-
scope,
|
|
81
|
-
targetPaths: scope === 'site' ? [] : targetPaths,
|
|
82
|
-
priority,
|
|
83
|
-
enabled,
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
const res = isNew
|
|
87
|
-
? await cmsApi('/script-tags', { method: 'POST', body: JSON.stringify(payload) })
|
|
88
|
-
: await cmsApi(`/script-tags/${tagId}`, { method: 'PUT', body: JSON.stringify(payload) })
|
|
89
|
-
|
|
90
|
-
setSaving(false)
|
|
91
|
-
if (res.error) {
|
|
92
|
-
toast.error(res.error)
|
|
93
|
-
} else {
|
|
94
|
-
toast.success(isNew ? 'Tag created' : 'Tag updated')
|
|
95
|
-
onNavigate?.('/script-tags')
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
const handleDelete = async () => {
|
|
100
|
-
if (!tagId) return
|
|
101
|
-
setDeleting(true)
|
|
102
|
-
const res = await cmsApi(`/script-tags/${tagId}`, { method: 'DELETE' })
|
|
103
|
-
setDeleting(false)
|
|
104
|
-
if (res.error) {
|
|
105
|
-
toast.error(res.error)
|
|
106
|
-
} else {
|
|
107
|
-
toast.success('Tag deleted')
|
|
108
|
-
onNavigate?.('/script-tags')
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
if (loading && !isNew) {
|
|
113
|
-
return (
|
|
114
|
-
<div className="flex h-64 items-center justify-center p-3 pr-6 sm:p-4 sm:pr-8">
|
|
115
|
-
<Loader2 className="text-primary h-6 w-6 animate-spin" />
|
|
116
|
-
</div>
|
|
117
|
-
)
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
return (
|
|
121
|
-
<div className="max-w-3xl p-3 pr-6 sm:p-4 sm:pr-8">
|
|
122
|
-
{error && (
|
|
123
|
-
<div className="border-destructive/30 bg-destructive/10 mb-4 flex items-center gap-3 rounded-lg border p-3">
|
|
124
|
-
<AlertTriangle className="text-destructive h-5 w-5 shrink-0" />
|
|
125
|
-
<span className="text-destructive flex-1 text-sm">{error}</span>
|
|
126
|
-
</div>
|
|
127
|
-
)}
|
|
128
|
-
|
|
129
|
-
<div className="mb-6">
|
|
130
|
-
<button
|
|
131
|
-
type="button"
|
|
132
|
-
onClick={() => onNavigate?.('/script-tags')}
|
|
133
|
-
className="text-muted-foreground hover:text-foreground mb-3 flex items-center gap-1.5 text-sm transition-colors"
|
|
134
|
-
>
|
|
135
|
-
<ArrowLeft className="h-4 w-4" />
|
|
136
|
-
Back to Script Tags
|
|
137
|
-
</button>
|
|
138
|
-
<h1 className="text-foreground">{isNew ? 'New Script Tag' : 'Edit Script Tag'}</h1>
|
|
139
|
-
</div>
|
|
140
|
-
|
|
141
|
-
<div className="border-warning/30 bg-warning/10 mb-6 rounded-lg border p-3">
|
|
142
|
-
<div className="flex items-start gap-2">
|
|
143
|
-
<AlertTriangle className="text-warning mt-0.5 h-4 w-4 shrink-0" />
|
|
144
|
-
<p className="text-warning text-sm">
|
|
145
|
-
This code will run on public pages matching the scope below. Only add trusted code from
|
|
146
|
-
verified sources (e.g. Google Analytics, Meta Pixel).
|
|
147
|
-
</p>
|
|
148
|
-
</div>
|
|
149
|
-
</div>
|
|
150
|
-
|
|
151
|
-
<div className="space-y-6">
|
|
152
|
-
<div className="border-border bg-card space-y-4 rounded-lg border p-4">
|
|
153
|
-
<div>
|
|
154
|
-
<label className="text-foreground mb-1 block text-sm font-medium">Name</label>
|
|
155
|
-
<input
|
|
156
|
-
type="text"
|
|
157
|
-
value={name}
|
|
158
|
-
onChange={(e) => setName(e.target.value)}
|
|
159
|
-
placeholder="e.g. Google Tag Manager, Facebook Pixel"
|
|
160
|
-
className="border-input focus:ring-ring w-full rounded-lg border px-3 py-2 text-sm focus:ring-2 focus:outline-none"
|
|
161
|
-
/>
|
|
162
|
-
</div>
|
|
163
|
-
|
|
164
|
-
<div>
|
|
165
|
-
<label className="text-foreground mb-1 block text-sm font-medium">Code</label>
|
|
166
|
-
<textarea
|
|
167
|
-
value={code}
|
|
168
|
-
onChange={(e) => setCode(e.target.value)}
|
|
169
|
-
placeholder="Paste your HTML/JavaScript snippet here..."
|
|
170
|
-
rows={10}
|
|
171
|
-
className="border-input focus:ring-ring w-full rounded-lg border px-3 py-2 font-mono text-sm focus:ring-2 focus:outline-none"
|
|
172
|
-
spellCheck={false}
|
|
173
|
-
/>
|
|
174
|
-
<p className="text-muted-foreground mt-1 text-xs">
|
|
175
|
-
Paste the full code snippet including {'<script>'} tags.
|
|
176
|
-
</p>
|
|
177
|
-
</div>
|
|
178
|
-
</div>
|
|
179
|
-
|
|
180
|
-
<div className="border-border bg-card space-y-4 rounded-lg border p-4">
|
|
181
|
-
<h3 className="text-foreground text-sm font-medium">Placement & Scope</h3>
|
|
182
|
-
|
|
183
|
-
<div>
|
|
184
|
-
<label className="text-foreground mb-1 block text-sm font-medium">Placement</label>
|
|
185
|
-
<select
|
|
186
|
-
value={placement}
|
|
187
|
-
onChange={(e) => setPlacement(e.target.value)}
|
|
188
|
-
className="border-input focus:ring-ring w-full rounded-lg border px-3 py-2 text-sm focus:ring-2 focus:outline-none"
|
|
189
|
-
>
|
|
190
|
-
<option value="head">Head — inside {'<head>'}</option>
|
|
191
|
-
<option value="body_open">Body Open — right after {'<body>'}</option>
|
|
192
|
-
<option value="body_close">Body Close — before {'</body>'}</option>
|
|
193
|
-
</select>
|
|
194
|
-
<p className="text-muted-foreground mt-1 text-xs">
|
|
195
|
-
{placement === 'head' && 'Best for analytics scripts, meta tags, and custom CSS.'}
|
|
196
|
-
{placement === 'body_open' && 'Best for GTM noscript tags and early-loading scripts.'}
|
|
197
|
-
{placement === 'body_close' &&
|
|
198
|
-
'Best for chat widgets, deferred scripts, and tracking pixels.'}
|
|
199
|
-
</p>
|
|
200
|
-
</div>
|
|
201
|
-
|
|
202
|
-
<div>
|
|
203
|
-
<label className="text-foreground mb-1 block text-sm font-medium">Scope</label>
|
|
204
|
-
<select
|
|
205
|
-
value={scope}
|
|
206
|
-
onChange={(e) => setScope(e.target.value)}
|
|
207
|
-
className="border-input focus:ring-ring w-full rounded-lg border px-3 py-2 text-sm focus:ring-2 focus:outline-none"
|
|
208
|
-
>
|
|
209
|
-
<option value="site">Entire Website</option>
|
|
210
|
-
<option value="parents">Specific Parent Pages (includes child pages)</option>
|
|
211
|
-
<option value="urls">Specific URLs (exact match)</option>
|
|
212
|
-
</select>
|
|
213
|
-
</div>
|
|
214
|
-
|
|
215
|
-
{scope !== 'site' && (
|
|
216
|
-
<div>
|
|
217
|
-
<label className="text-foreground mb-1 block text-sm font-medium">
|
|
218
|
-
{scope === 'parents' ? 'Parent Paths' : 'URL Paths'}
|
|
219
|
-
</label>
|
|
220
|
-
<div className="flex gap-2">
|
|
221
|
-
<input
|
|
222
|
-
type="text"
|
|
223
|
-
value={pathInput}
|
|
224
|
-
onChange={(e) => setPathInput(e.target.value)}
|
|
225
|
-
onKeyDown={(e) => {
|
|
226
|
-
if (e.key === 'Enter') {
|
|
227
|
-
e.preventDefault()
|
|
228
|
-
addPath()
|
|
229
|
-
}
|
|
230
|
-
}}
|
|
231
|
-
placeholder="/services"
|
|
232
|
-
className="border-input focus:ring-ring flex-1 rounded-lg border px-3 py-2 font-mono text-sm focus:ring-2 focus:outline-none"
|
|
233
|
-
/>
|
|
234
|
-
<button
|
|
235
|
-
type="button"
|
|
236
|
-
onClick={addPath}
|
|
237
|
-
className="border-input hover:bg-muted rounded-lg border px-3 py-2 text-sm transition-colors"
|
|
238
|
-
>
|
|
239
|
-
<Plus className="h-4 w-4" />
|
|
240
|
-
</button>
|
|
241
|
-
</div>
|
|
242
|
-
{scope === 'parents' && (
|
|
243
|
-
<p className="text-muted-foreground mt-1 text-xs">
|
|
244
|
-
This tag will also apply to all child pages under each path.
|
|
245
|
-
</p>
|
|
246
|
-
)}
|
|
247
|
-
{targetPaths.length > 0 && (
|
|
248
|
-
<div className="mt-2 flex flex-wrap gap-2">
|
|
249
|
-
{targetPaths.map((p) => (
|
|
250
|
-
<span
|
|
251
|
-
key={p}
|
|
252
|
-
className="bg-muted text-foreground inline-flex items-center gap-1 rounded-full px-3 py-1 font-mono text-xs"
|
|
253
|
-
>
|
|
254
|
-
{p}
|
|
255
|
-
<button
|
|
256
|
-
type="button"
|
|
257
|
-
onClick={() => removePath(p)}
|
|
258
|
-
className="text-muted-foreground hover:text-muted-foreground ml-0.5"
|
|
259
|
-
>
|
|
260
|
-
<X className="h-3 w-3" />
|
|
261
|
-
</button>
|
|
262
|
-
</span>
|
|
263
|
-
))}
|
|
264
|
-
</div>
|
|
265
|
-
)}
|
|
266
|
-
</div>
|
|
267
|
-
)}
|
|
268
|
-
|
|
269
|
-
<div className="grid grid-cols-2 gap-4">
|
|
270
|
-
<div>
|
|
271
|
-
<label className="text-foreground mb-1 block text-sm font-medium">Priority</label>
|
|
272
|
-
<input
|
|
273
|
-
type="number"
|
|
274
|
-
value={priority}
|
|
275
|
-
onChange={(e) => setPriority(parseInt(e.target.value, 10) || 0)}
|
|
276
|
-
min={0}
|
|
277
|
-
className="border-input focus:ring-ring w-full rounded-lg border px-3 py-2 text-sm focus:ring-2 focus:outline-none"
|
|
278
|
-
/>
|
|
279
|
-
<p className="text-muted-foreground mt-1 text-xs">
|
|
280
|
-
Lower numbers load first (e.g. 1 = first, 100 = default)
|
|
281
|
-
</p>
|
|
282
|
-
</div>
|
|
283
|
-
<div>
|
|
284
|
-
<label className="text-foreground mb-1 block text-sm font-medium">Enabled</label>
|
|
285
|
-
<div className="pt-2">
|
|
286
|
-
<EnabledSwitch
|
|
287
|
-
checked={enabled}
|
|
288
|
-
onCheckedChange={setEnabled}
|
|
289
|
-
aria-label={enabled ? 'Disable script tag' : 'Enable script tag'}
|
|
290
|
-
/>
|
|
291
|
-
</div>
|
|
292
|
-
</div>
|
|
293
|
-
</div>
|
|
294
|
-
</div>
|
|
295
|
-
|
|
296
|
-
<div className="flex items-center justify-between">
|
|
297
|
-
<div>
|
|
298
|
-
{!isNew && (
|
|
299
|
-
<>
|
|
300
|
-
{showDeleteConfirm ? (
|
|
301
|
-
<div className="flex items-center gap-2">
|
|
302
|
-
<span className="text-destructive text-sm">Delete this tag?</span>
|
|
303
|
-
<button
|
|
304
|
-
type="button"
|
|
305
|
-
onClick={handleDelete}
|
|
306
|
-
disabled={deleting}
|
|
307
|
-
className="bg-destructive text-destructive-foreground hover:bg-destructive/90 rounded-lg px-3 py-1.5 text-sm disabled:opacity-50"
|
|
308
|
-
>
|
|
309
|
-
{deleting ? 'Deleting...' : 'Confirm'}
|
|
310
|
-
</button>
|
|
311
|
-
<button
|
|
312
|
-
type="button"
|
|
313
|
-
onClick={() => setShowDeleteConfirm(false)}
|
|
314
|
-
className="border-input hover:bg-muted rounded-lg border px-3 py-1.5 text-sm"
|
|
315
|
-
>
|
|
316
|
-
Cancel
|
|
317
|
-
</button>
|
|
318
|
-
</div>
|
|
319
|
-
) : (
|
|
320
|
-
<button
|
|
321
|
-
type="button"
|
|
322
|
-
onClick={() => setShowDeleteConfirm(true)}
|
|
323
|
-
className="text-destructive hover:text-destructive flex items-center gap-1.5 text-sm transition-colors"
|
|
324
|
-
>
|
|
325
|
-
<Trash2 className="h-4 w-4" />
|
|
326
|
-
Delete
|
|
327
|
-
</button>
|
|
328
|
-
)}
|
|
329
|
-
</>
|
|
330
|
-
)}
|
|
331
|
-
</div>
|
|
332
|
-
<div className="flex items-center gap-3">
|
|
333
|
-
<button
|
|
334
|
-
type="button"
|
|
335
|
-
onClick={() => onNavigate?.('/script-tags')}
|
|
336
|
-
className="border-input text-foreground hover:bg-muted rounded-lg border px-4 py-2 text-sm transition-colors"
|
|
337
|
-
>
|
|
338
|
-
Cancel
|
|
339
|
-
</button>
|
|
340
|
-
<button
|
|
341
|
-
type="button"
|
|
342
|
-
onClick={handleSave}
|
|
343
|
-
disabled={saving}
|
|
344
|
-
className="bg-primary text-primary-foreground hover:bg-primary/90 rounded-lg px-6 py-2 text-sm transition-colors disabled:opacity-50"
|
|
345
|
-
>
|
|
346
|
-
{saving ? 'Saving...' : isNew ? 'Create Tag' : 'Save Changes'}
|
|
347
|
-
</button>
|
|
348
|
-
</div>
|
|
349
|
-
</div>
|
|
350
|
-
</div>
|
|
351
|
-
</div>
|
|
352
|
-
)
|
|
353
|
-
}
|