@actuate-media/cms-admin 0.49.0 → 0.49.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/dist/AdminRoot.d.ts.map +1 -1
  3. package/dist/AdminRoot.js +10 -11
  4. package/dist/AdminRoot.js.map +1 -1
  5. package/dist/__tests__/components/modal.render.test.d.ts +2 -0
  6. package/dist/__tests__/components/modal.render.test.d.ts.map +1 -0
  7. package/dist/__tests__/components/modal.render.test.js +37 -0
  8. package/dist/__tests__/components/modal.render.test.js.map +1 -0
  9. package/dist/actuate-admin.css +1 -1
  10. package/dist/components/FolderTree.js +19 -19
  11. package/dist/components/FolderTree.js.map +1 -1
  12. package/dist/components/MediaPickerModal.d.ts +1 -1
  13. package/dist/components/MediaPickerModal.d.ts.map +1 -1
  14. package/dist/components/MediaPickerModal.js +12 -11
  15. package/dist/components/MediaPickerModal.js.map +1 -1
  16. package/dist/components/SchedulePublishDialog.d.ts +1 -1
  17. package/dist/components/SchedulePublishDialog.d.ts.map +1 -1
  18. package/dist/components/SchedulePublishDialog.js +6 -4
  19. package/dist/components/SchedulePublishDialog.js.map +1 -1
  20. package/dist/components/SharePreviewLinkDialog.d.ts +1 -1
  21. package/dist/components/SharePreviewLinkDialog.d.ts.map +1 -1
  22. package/dist/components/SharePreviewLinkDialog.js +10 -9
  23. package/dist/components/SharePreviewLinkDialog.js.map +1 -1
  24. package/dist/components/VersionHistory.d.ts +1 -1
  25. package/dist/components/VersionHistory.d.ts.map +1 -1
  26. package/dist/components/VersionHistory.js +14 -14
  27. package/dist/components/VersionHistory.js.map +1 -1
  28. package/dist/components/ui/Modal.d.ts +17 -1
  29. package/dist/components/ui/Modal.d.ts.map +1 -1
  30. package/dist/components/ui/Modal.js +16 -15
  31. package/dist/components/ui/Modal.js.map +1 -1
  32. package/dist/fields/BlockBuilderField.d.ts.map +1 -1
  33. package/dist/fields/BlockBuilderField.js +6 -4
  34. package/dist/fields/BlockBuilderField.js.map +1 -1
  35. package/dist/views/MediaBrowser.d.ts.map +1 -1
  36. package/dist/views/MediaBrowser.js +16 -16
  37. package/dist/views/MediaBrowser.js.map +1 -1
  38. package/dist/views/Pages/PagesListView.d.ts.map +1 -1
  39. package/dist/views/Pages/PagesListView.js +3 -3
  40. package/dist/views/Pages/PagesListView.js.map +1 -1
  41. package/dist/views/Posts/PostsListView.d.ts.map +1 -1
  42. package/dist/views/Posts/PostsListView.js +3 -3
  43. package/dist/views/Posts/PostsListView.js.map +1 -1
  44. package/dist/views/Redirects.d.ts.map +1 -1
  45. package/dist/views/Redirects.js +7 -7
  46. package/dist/views/Redirects.js.map +1 -1
  47. package/dist/views/ScriptTagEditor.js +4 -4
  48. package/dist/views/ScriptTagEditor.js.map +1 -1
  49. package/dist/views/ScriptTags.d.ts.map +1 -1
  50. package/dist/views/ScriptTags.js +5 -5
  51. package/dist/views/ScriptTags.js.map +1 -1
  52. package/dist/views/page-builder/AIGenerateDialog.d.ts +1 -1
  53. package/dist/views/page-builder/AIGenerateDialog.d.ts.map +1 -1
  54. package/dist/views/page-builder/AIGenerateDialog.js +23 -23
  55. package/dist/views/page-builder/AIGenerateDialog.js.map +1 -1
  56. package/package.json +1 -1
  57. package/src/AdminRoot.tsx +35 -30
  58. package/src/__tests__/components/modal.render.test.tsx +57 -0
  59. package/src/components/FolderTree.tsx +32 -32
  60. package/src/components/MediaPickerModal.tsx +143 -119
  61. package/src/components/SchedulePublishDialog.tsx +118 -93
  62. package/src/components/SharePreviewLinkDialog.tsx +115 -93
  63. package/src/components/VersionHistory.tsx +98 -82
  64. package/src/components/ui/Modal.tsx +48 -39
  65. package/src/fields/BlockBuilderField.tsx +26 -19
  66. package/src/views/MediaBrowser.tsx +128 -120
  67. package/src/views/Pages/PagesListView.tsx +123 -115
  68. package/src/views/Posts/PostsListView.tsx +114 -110
  69. package/src/views/Redirects.tsx +48 -44
  70. package/src/views/ScriptTagEditor.tsx +40 -40
  71. package/src/views/ScriptTags.tsx +34 -30
  72. package/src/views/page-builder/AIGenerateDialog.tsx +347 -335
@@ -102,7 +102,7 @@ export function Redirects({ onNavigate }: RedirectsProps) {
102
102
  <button
103
103
  type="button"
104
104
  onClick={() => setSortConfig(toggleSort(sortConfig, sortKey))}
105
- className="flex items-center gap-1 text-xs font-medium text-gray-700 transition-colors hover:text-gray-900"
105
+ className="text-foreground hover:text-foreground flex items-center gap-1 text-xs font-medium transition-colors"
106
106
  >
107
107
  {label}
108
108
  {active ? (
@@ -112,7 +112,7 @@ export function Redirects({ onNavigate }: RedirectsProps) {
112
112
  <ArrowDown className="h-3 w-3" />
113
113
  )
114
114
  ) : (
115
- <ArrowUpDown className="h-3 w-3 text-gray-400" />
115
+ <ArrowUpDown className="text-muted-foreground h-3 w-3" />
116
116
  )}
117
117
  </button>
118
118
  )
@@ -121,7 +121,7 @@ export function Redirects({ onNavigate }: RedirectsProps) {
121
121
  if (loading) {
122
122
  return (
123
123
  <div className="flex h-64 items-center justify-center p-3 pr-6 sm:p-4 sm:pr-8">
124
- <Loader2 className="h-6 w-6 animate-spin text-blue-600" />
124
+ <Loader2 className="text-primary h-6 w-6 animate-spin" />
125
125
  </div>
126
126
  )
127
127
  }
@@ -129,12 +129,12 @@ export function Redirects({ onNavigate }: RedirectsProps) {
129
129
  return (
130
130
  <div className="p-3 pr-6 sm:p-4 sm:pr-8">
131
131
  {error && (
132
- <div className="mb-4 flex items-center gap-3 rounded-lg border border-red-200 bg-red-50 p-3">
133
- <AlertTriangle className="h-5 w-5 shrink-0 text-red-600" />
134
- <span className="flex-1 text-sm text-red-800">{error}</span>
132
+ <div className="border-destructive/30 bg-destructive/10 mb-4 flex items-center gap-3 rounded-lg border p-3">
133
+ <AlertTriangle className="text-destructive h-5 w-5 shrink-0" />
134
+ <span className="text-destructive flex-1 text-sm">{error}</span>
135
135
  <button
136
136
  onClick={refetch}
137
- className="rounded-lg border border-red-300 px-3 py-1 text-sm text-red-700 transition-colors hover:bg-red-100"
137
+ className="border-destructive/40 text-destructive hover:bg-destructive/15 rounded-lg border px-3 py-1 text-sm transition-colors"
138
138
  >
139
139
  Retry
140
140
  </button>
@@ -143,35 +143,37 @@ export function Redirects({ onNavigate }: RedirectsProps) {
143
143
 
144
144
  <div className="mb-4 flex items-center justify-between">
145
145
  <div>
146
- <h1 className="mb-1 text-xl font-semibold text-gray-900 sm:text-2xl">Redirects</h1>
147
- <p className="text-sm text-gray-600">{filteredAndSorted.length} total redirects</p>
146
+ <h1 className="text-foreground mb-1 text-xl font-semibold sm:text-2xl">Redirects</h1>
147
+ <p className="text-muted-foreground text-sm">
148
+ {filteredAndSorted.length} total redirects
149
+ </p>
148
150
  </div>
149
151
  <button
150
152
  type="button"
151
153
  onClick={() => setShowAddDialog(true)}
152
- className="flex items-center gap-2 rounded-lg bg-blue-600 px-4 py-2 text-sm text-white transition-colors hover:bg-blue-700"
154
+ className="bg-primary text-primary-foreground hover:bg-primary/90 flex items-center gap-2 rounded-lg px-4 py-2 text-sm transition-colors"
153
155
  >
154
156
  <Plus className="h-4 w-4" />
155
157
  Add Redirect
156
158
  </button>
157
159
  </div>
158
160
 
159
- <div className="mb-4 rounded-lg border border-gray-200 bg-white">
161
+ <div className="border-border bg-card mb-4 rounded-lg border">
160
162
  <div className="flex flex-col gap-3 p-3 sm:flex-row">
161
163
  <div className="relative flex-1">
162
- <Search className="absolute top-1/2 left-3 h-4 w-4 -translate-y-1/2 text-gray-400" />
164
+ <Search className="text-muted-foreground absolute top-1/2 left-3 h-4 w-4 -translate-y-1/2" />
163
165
  <input
164
166
  type="text"
165
167
  placeholder="Search by source or destination URL..."
166
168
  value={searchQuery}
167
169
  onChange={(e) => setSearchQuery(e.target.value)}
168
- 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"
170
+ className="border-input focus:ring-ring w-full rounded-lg border py-2 pr-3 pl-9 text-sm focus:ring-2 focus:outline-none"
169
171
  />
170
172
  </div>
171
173
  <select
172
174
  value={filterType}
173
175
  onChange={(e) => setFilterType(e.target.value)}
174
- className="rounded-lg border border-gray-300 px-3 py-2 text-sm focus:ring-2 focus:ring-blue-500 focus:outline-none"
176
+ className="border-input focus:ring-ring rounded-lg border px-3 py-2 text-sm focus:ring-2 focus:outline-none"
175
177
  >
176
178
  <option value="all">All Types</option>
177
179
  <option value="301">301 (Permanent)</option>
@@ -182,17 +184,17 @@ export function Redirects({ onNavigate }: RedirectsProps) {
182
184
 
183
185
  {filteredAndSorted.length === 0 && !loading ? (
184
186
  <div className="flex flex-col items-center justify-center py-16 text-center">
185
- <div className="mb-4 flex h-12 w-12 items-center justify-center rounded-full bg-gray-100">
186
- <ArrowRightLeft className="h-6 w-6 text-gray-400" />
187
+ <div className="bg-muted mb-4 flex h-12 w-12 items-center justify-center rounded-full">
188
+ <ArrowRightLeft className="text-muted-foreground h-6 w-6" />
187
189
  </div>
188
- <h3 className="mb-1 text-sm font-medium text-gray-900">No redirects yet</h3>
189
- <p className="text-sm text-gray-500">Add your first redirect to get started.</p>
190
+ <h3 className="text-foreground mb-1 text-sm font-medium">No redirects yet</h3>
191
+ <p className="text-muted-foreground text-sm">Add your first redirect to get started.</p>
190
192
  </div>
191
193
  ) : (
192
- <div className="rounded-lg border border-gray-200 bg-white">
194
+ <div className="border-border bg-card rounded-lg border">
193
195
  <div className="overflow-x-auto">
194
196
  <table className="w-full">
195
- <thead className="border-b border-gray-200 bg-gray-50">
197
+ <thead className="border-border bg-muted border-b">
196
198
  <tr>
197
199
  <th className="px-4 py-2 text-left">
198
200
  <SortHeader label="Source URL" sortKey="from" />
@@ -209,19 +211,21 @@ export function Redirects({ onNavigate }: RedirectsProps) {
209
211
  <th className="px-4 py-2 text-left">
210
212
  <SortHeader label="Status" sortKey="active" />
211
213
  </th>
212
- <th className="px-4 py-2 text-left text-xs font-medium text-gray-700">Actions</th>
214
+ <th className="text-foreground px-4 py-2 text-left text-xs font-medium">
215
+ Actions
216
+ </th>
213
217
  </tr>
214
218
  </thead>
215
- <tbody className="divide-y divide-gray-200">
219
+ <tbody className="divide-border divide-y">
216
220
  {filteredAndSorted.map((redirect) => (
217
- <tr key={redirect.id} className="transition-colors hover:bg-gray-50">
221
+ <tr key={redirect.id} className="hover:bg-muted transition-colors">
218
222
  <td className="px-4 py-3">
219
- <code className="rounded bg-gray-100 px-2 py-1 text-xs text-gray-900">
223
+ <code className="bg-muted text-foreground rounded px-2 py-1 text-xs">
220
224
  {redirect.from}
221
225
  </code>
222
226
  </td>
223
227
  <td className="px-4 py-3">
224
- <code className="rounded bg-gray-100 px-2 py-1 text-xs text-gray-900">
228
+ <code className="bg-muted text-foreground rounded px-2 py-1 text-xs">
225
229
  {redirect.to}
226
230
  </code>
227
231
  </td>
@@ -229,22 +233,22 @@ export function Redirects({ onNavigate }: RedirectsProps) {
229
233
  <span
230
234
  className={`inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium ${
231
235
  redirect.type === '301'
232
- ? 'bg-blue-100 text-blue-800'
233
- : 'bg-purple-100 text-purple-800'
236
+ ? 'bg-primary/15 text-primary'
237
+ : 'bg-accent text-accent-foreground'
234
238
  }`}
235
239
  >
236
240
  {redirect.type}
237
241
  </span>
238
242
  </td>
239
- <td className="px-4 py-3 text-sm text-gray-600">
243
+ <td className="text-muted-foreground px-4 py-3 text-sm">
240
244
  {redirect.hits.toLocaleString()}
241
245
  </td>
242
246
  <td className="px-4 py-3">
243
247
  <span
244
248
  className={`inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium ${
245
249
  redirect.active
246
- ? 'bg-green-100 text-green-800'
247
- : 'bg-gray-100 text-gray-800'
250
+ ? 'bg-success/15 text-success'
251
+ : 'bg-muted text-foreground'
248
252
  }`}
249
253
  >
250
254
  {redirect.active ? 'Active' : 'Inactive'}
@@ -255,18 +259,18 @@ export function Redirects({ onNavigate }: RedirectsProps) {
255
259
  <button
256
260
  type="button"
257
261
  onClick={() => onNavigate?.(`/redirects/${redirect.id}/edit`)}
258
- className="rounded p-1.5 transition-colors hover:bg-gray-100"
262
+ className="hover:bg-muted rounded p-1.5 transition-colors"
259
263
  aria-label="Edit redirect"
260
264
  >
261
- <Pencil className="h-4 w-4 text-gray-600" />
265
+ <Pencil className="text-muted-foreground h-4 w-4" />
262
266
  </button>
263
267
  <button
264
268
  type="button"
265
269
  onClick={() => handleDelete(redirect.id)}
266
- className="rounded p-1.5 transition-colors hover:bg-gray-100"
270
+ className="hover:bg-muted rounded p-1.5 transition-colors"
267
271
  aria-label="Delete redirect"
268
272
  >
269
- <Trash2 className="h-4 w-4 text-red-600" />
273
+ <Trash2 className="text-destructive h-4 w-4" />
270
274
  </button>
271
275
  </div>
272
276
  </td>
@@ -281,24 +285,24 @@ export function Redirects({ onNavigate }: RedirectsProps) {
281
285
  <Dialog.Root open={showAddDialog} onOpenChange={setShowAddDialog}>
282
286
  <Dialog.Portal container={adminPortalContainer()}>
283
287
  <Dialog.Overlay className="fixed inset-0 z-50 bg-black/50" />
284
- <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">
285
- <Dialog.Title className="mb-4 text-lg font-semibold text-gray-900">
288
+ <Dialog.Content className="bg-card fixed top-1/2 left-1/2 z-50 w-full max-w-md -translate-x-1/2 -translate-y-1/2 rounded-lg p-6 shadow-lg">
289
+ <Dialog.Title className="text-foreground mb-4 text-lg font-semibold">
286
290
  Add Redirect
287
291
  </Dialog.Title>
288
292
  <form onSubmit={handleSubmit} className="space-y-4">
289
293
  <div>
290
- <label className="mb-1 block text-sm font-medium text-gray-700">Source URL</label>
294
+ <label className="text-foreground mb-1 block text-sm font-medium">Source URL</label>
291
295
  <input
292
296
  type="text"
293
297
  value={newRedirect.source}
294
298
  onChange={(e) => setNewRedirect({ ...newRedirect, source: e.target.value })}
295
299
  placeholder="/old-page"
296
- 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"
300
+ className="border-input focus:ring-ring w-full rounded-lg border px-3 py-2 text-sm focus:ring-2 focus:outline-none"
297
301
  required
298
302
  />
299
303
  </div>
300
304
  <div>
301
- <label className="mb-1 block text-sm font-medium text-gray-700">
305
+ <label className="text-foreground mb-1 block text-sm font-medium">
302
306
  Destination URL
303
307
  </label>
304
308
  <input
@@ -306,12 +310,12 @@ export function Redirects({ onNavigate }: RedirectsProps) {
306
310
  value={newRedirect.destination}
307
311
  onChange={(e) => setNewRedirect({ ...newRedirect, destination: e.target.value })}
308
312
  placeholder="/new-page"
309
- 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"
313
+ className="border-input focus:ring-ring w-full rounded-lg border px-3 py-2 text-sm focus:ring-2 focus:outline-none"
310
314
  required
311
315
  />
312
316
  </div>
313
317
  <div>
314
- <label className="mb-1 block text-sm font-medium text-gray-700">
318
+ <label className="text-foreground mb-1 block text-sm font-medium">
315
319
  Redirect Type
316
320
  </label>
317
321
  <select
@@ -319,7 +323,7 @@ export function Redirects({ onNavigate }: RedirectsProps) {
319
323
  onChange={(e) =>
320
324
  setNewRedirect({ ...newRedirect, type: e.target.value as '301' | '302' })
321
325
  }
322
- 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"
326
+ className="border-input focus:ring-ring w-full rounded-lg border px-3 py-2 text-sm focus:ring-2 focus:outline-none"
323
327
  >
324
328
  <option value="301">301 (Permanent)</option>
325
329
  <option value="302">302 (Temporary)</option>
@@ -329,14 +333,14 @@ export function Redirects({ onNavigate }: RedirectsProps) {
329
333
  <Dialog.Close asChild>
330
334
  <button
331
335
  type="button"
332
- className="rounded-lg border border-gray-300 px-4 py-2 text-sm transition-colors hover:bg-gray-50"
336
+ className="border-input hover:bg-muted rounded-lg border px-4 py-2 text-sm transition-colors"
333
337
  >
334
338
  Cancel
335
339
  </button>
336
340
  </Dialog.Close>
337
341
  <button
338
342
  type="submit"
339
- className="rounded-lg bg-blue-600 px-4 py-2 text-sm text-white transition-colors hover:bg-blue-700"
343
+ className="bg-primary text-primary-foreground hover:bg-primary/90 rounded-lg px-4 py-2 text-sm transition-colors"
340
344
  >
341
345
  Add Redirect
342
346
  </button>
@@ -111,7 +111,7 @@ export function ScriptTagEditor({ tagId, onNavigate }: ScriptTagEditorProps) {
111
111
  if (loading && !isNew) {
112
112
  return (
113
113
  <div className="flex h-64 items-center justify-center p-3 pr-6 sm:p-4 sm:pr-8">
114
- <Loader2 className="h-6 w-6 animate-spin text-blue-600" />
114
+ <Loader2 className="text-primary h-6 w-6 animate-spin" />
115
115
  </div>
116
116
  )
117
117
  }
@@ -119,9 +119,9 @@ export function ScriptTagEditor({ tagId, onNavigate }: ScriptTagEditorProps) {
119
119
  return (
120
120
  <div className="max-w-3xl p-3 pr-6 sm:p-4 sm:pr-8">
121
121
  {error && (
122
- <div className="mb-4 flex items-center gap-3 rounded-lg border border-red-200 bg-red-50 p-3">
123
- <AlertTriangle className="h-5 w-5 shrink-0 text-red-600" />
124
- <span className="flex-1 text-sm text-red-800">{error}</span>
122
+ <div className="border-destructive/30 bg-destructive/10 mb-4 flex items-center gap-3 rounded-lg border p-3">
123
+ <AlertTriangle className="text-destructive h-5 w-5 shrink-0" />
124
+ <span className="text-destructive flex-1 text-sm">{error}</span>
125
125
  </div>
126
126
  )}
127
127
 
@@ -129,20 +129,20 @@ export function ScriptTagEditor({ tagId, onNavigate }: ScriptTagEditorProps) {
129
129
  <button
130
130
  type="button"
131
131
  onClick={() => onNavigate?.('/script-tags')}
132
- className="mb-3 flex items-center gap-1.5 text-sm text-gray-500 transition-colors hover:text-gray-700"
132
+ className="text-muted-foreground hover:text-foreground mb-3 flex items-center gap-1.5 text-sm transition-colors"
133
133
  >
134
134
  <ArrowLeft className="h-4 w-4" />
135
135
  Back to Script Tags
136
136
  </button>
137
- <h1 className="text-2xl font-semibold text-gray-900">
137
+ <h1 className="text-foreground text-2xl font-semibold">
138
138
  {isNew ? 'New Script Tag' : 'Edit Script Tag'}
139
139
  </h1>
140
140
  </div>
141
141
 
142
- <div className="mb-6 rounded-lg border border-amber-200 bg-amber-50 p-3">
142
+ <div className="border-warning/30 bg-warning/10 mb-6 rounded-lg border p-3">
143
143
  <div className="flex items-start gap-2">
144
- <AlertTriangle className="mt-0.5 h-4 w-4 shrink-0 text-amber-600" />
145
- <p className="text-sm text-amber-800">
144
+ <AlertTriangle className="text-warning mt-0.5 h-4 w-4 shrink-0" />
145
+ <p className="text-warning text-sm">
146
146
  This code will run on public pages matching the scope below. Only add trusted code from
147
147
  verified sources (e.g. Google Analytics, Meta Pixel).
148
148
  </p>
@@ -150,49 +150,49 @@ export function ScriptTagEditor({ tagId, onNavigate }: ScriptTagEditorProps) {
150
150
  </div>
151
151
 
152
152
  <div className="space-y-6">
153
- <div className="space-y-4 rounded-lg border border-gray-200 bg-white p-4">
153
+ <div className="border-border bg-card space-y-4 rounded-lg border p-4">
154
154
  <div>
155
- <label className="mb-1 block text-sm font-medium text-gray-700">Name</label>
155
+ <label className="text-foreground mb-1 block text-sm font-medium">Name</label>
156
156
  <input
157
157
  type="text"
158
158
  value={name}
159
159
  onChange={(e) => setName(e.target.value)}
160
160
  placeholder="e.g. Google Tag Manager, Facebook Pixel"
161
- 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"
161
+ className="border-input focus:ring-ring w-full rounded-lg border px-3 py-2 text-sm focus:ring-2 focus:outline-none"
162
162
  />
163
163
  </div>
164
164
 
165
165
  <div>
166
- <label className="mb-1 block text-sm font-medium text-gray-700">Code</label>
166
+ <label className="text-foreground mb-1 block text-sm font-medium">Code</label>
167
167
  <textarea
168
168
  value={code}
169
169
  onChange={(e) => setCode(e.target.value)}
170
170
  placeholder="Paste your HTML/JavaScript snippet here..."
171
171
  rows={10}
172
- className="w-full rounded-lg border border-gray-300 px-3 py-2 font-mono text-sm focus:ring-2 focus:ring-blue-500 focus:outline-none"
172
+ 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"
173
173
  spellCheck={false}
174
174
  />
175
- <p className="mt-1 text-xs text-gray-500">
175
+ <p className="text-muted-foreground mt-1 text-xs">
176
176
  Paste the full code snippet including {'<script>'} tags.
177
177
  </p>
178
178
  </div>
179
179
  </div>
180
180
 
181
- <div className="space-y-4 rounded-lg border border-gray-200 bg-white p-4">
182
- <h3 className="text-sm font-semibold text-gray-900">Placement & Scope</h3>
181
+ <div className="border-border bg-card space-y-4 rounded-lg border p-4">
182
+ <h3 className="text-foreground text-sm font-semibold">Placement & Scope</h3>
183
183
 
184
184
  <div>
185
- <label className="mb-1 block text-sm font-medium text-gray-700">Placement</label>
185
+ <label className="text-foreground mb-1 block text-sm font-medium">Placement</label>
186
186
  <select
187
187
  value={placement}
188
188
  onChange={(e) => setPlacement(e.target.value)}
189
- 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"
189
+ className="border-input focus:ring-ring w-full rounded-lg border px-3 py-2 text-sm focus:ring-2 focus:outline-none"
190
190
  >
191
191
  <option value="head">Head — inside {'<head>'}</option>
192
192
  <option value="body_open">Body Open — right after {'<body>'}</option>
193
193
  <option value="body_close">Body Close — before {'</body>'}</option>
194
194
  </select>
195
- <p className="mt-1 text-xs text-gray-500">
195
+ <p className="text-muted-foreground mt-1 text-xs">
196
196
  {placement === 'head' && 'Best for analytics scripts, meta tags, and custom CSS.'}
197
197
  {placement === 'body_open' && 'Best for GTM noscript tags and early-loading scripts.'}
198
198
  {placement === 'body_close' &&
@@ -201,11 +201,11 @@ export function ScriptTagEditor({ tagId, onNavigate }: ScriptTagEditorProps) {
201
201
  </div>
202
202
 
203
203
  <div>
204
- <label className="mb-1 block text-sm font-medium text-gray-700">Scope</label>
204
+ <label className="text-foreground mb-1 block text-sm font-medium">Scope</label>
205
205
  <select
206
206
  value={scope}
207
207
  onChange={(e) => setScope(e.target.value)}
208
- 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"
208
+ className="border-input focus:ring-ring w-full rounded-lg border px-3 py-2 text-sm focus:ring-2 focus:outline-none"
209
209
  >
210
210
  <option value="site">Entire Website</option>
211
211
  <option value="parents">Specific Parent Pages (includes child pages)</option>
@@ -215,7 +215,7 @@ export function ScriptTagEditor({ tagId, onNavigate }: ScriptTagEditorProps) {
215
215
 
216
216
  {scope !== 'site' && (
217
217
  <div>
218
- <label className="mb-1 block text-sm font-medium text-gray-700">
218
+ <label className="text-foreground mb-1 block text-sm font-medium">
219
219
  {scope === 'parents' ? 'Parent Paths' : 'URL Paths'}
220
220
  </label>
221
221
  <div className="flex gap-2">
@@ -230,18 +230,18 @@ export function ScriptTagEditor({ tagId, onNavigate }: ScriptTagEditorProps) {
230
230
  }
231
231
  }}
232
232
  placeholder="/services"
233
- className="flex-1 rounded-lg border border-gray-300 px-3 py-2 font-mono text-sm focus:ring-2 focus:ring-blue-500 focus:outline-none"
233
+ 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"
234
234
  />
235
235
  <button
236
236
  type="button"
237
237
  onClick={addPath}
238
- className="rounded-lg border border-gray-300 px-3 py-2 text-sm transition-colors hover:bg-gray-50"
238
+ className="border-input hover:bg-muted rounded-lg border px-3 py-2 text-sm transition-colors"
239
239
  >
240
240
  <Plus className="h-4 w-4" />
241
241
  </button>
242
242
  </div>
243
243
  {scope === 'parents' && (
244
- <p className="mt-1 text-xs text-gray-500">
244
+ <p className="text-muted-foreground mt-1 text-xs">
245
245
  This tag will also apply to all child pages under each path.
246
246
  </p>
247
247
  )}
@@ -250,13 +250,13 @@ export function ScriptTagEditor({ tagId, onNavigate }: ScriptTagEditorProps) {
250
250
  {targetPaths.map((p) => (
251
251
  <span
252
252
  key={p}
253
- className="inline-flex items-center gap-1 rounded-full bg-gray-100 px-3 py-1 font-mono text-xs text-gray-700"
253
+ className="bg-muted text-foreground inline-flex items-center gap-1 rounded-full px-3 py-1 font-mono text-xs"
254
254
  >
255
255
  {p}
256
256
  <button
257
257
  type="button"
258
258
  onClick={() => removePath(p)}
259
- className="ml-0.5 text-gray-400 hover:text-gray-600"
259
+ className="text-muted-foreground hover:text-muted-foreground ml-0.5"
260
260
  >
261
261
  <X className="h-3 w-3" />
262
262
  </button>
@@ -269,29 +269,29 @@ export function ScriptTagEditor({ tagId, onNavigate }: ScriptTagEditorProps) {
269
269
 
270
270
  <div className="grid grid-cols-2 gap-4">
271
271
  <div>
272
- <label className="mb-1 block text-sm font-medium text-gray-700">Priority</label>
272
+ <label className="text-foreground mb-1 block text-sm font-medium">Priority</label>
273
273
  <input
274
274
  type="number"
275
275
  value={priority}
276
276
  onChange={(e) => setPriority(parseInt(e.target.value, 10) || 0)}
277
277
  min={0}
278
- 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"
278
+ className="border-input focus:ring-ring w-full rounded-lg border px-3 py-2 text-sm focus:ring-2 focus:outline-none"
279
279
  />
280
- <p className="mt-1 text-xs text-gray-500">
280
+ <p className="text-muted-foreground mt-1 text-xs">
281
281
  Lower numbers load first (e.g. 1 = first, 100 = default)
282
282
  </p>
283
283
  </div>
284
284
  <div>
285
- <label className="mb-1 block text-sm font-medium text-gray-700">Enabled</label>
285
+ <label className="text-foreground mb-1 block text-sm font-medium">Enabled</label>
286
286
  <div className="pt-2">
287
287
  <button
288
288
  type="button"
289
289
  onClick={() => setEnabled(!enabled)}
290
- className={`relative h-6 w-11 shrink-0 rounded-full transition-colors ${enabled ? 'bg-blue-600' : 'bg-gray-300'}`}
290
+ className={`relative h-6 w-11 shrink-0 rounded-full transition-colors ${enabled ? 'bg-primary' : 'bg-switch-background'}`}
291
291
  aria-pressed={enabled}
292
292
  >
293
293
  <span
294
- className={`absolute top-0.5 block h-5 w-5 rounded-full bg-white transition-transform ${
294
+ className={`bg-card absolute top-0.5 block h-5 w-5 rounded-full transition-transform ${
295
295
  enabled ? 'translate-x-[22px]' : 'translate-x-0.5'
296
296
  }`}
297
297
  />
@@ -307,19 +307,19 @@ export function ScriptTagEditor({ tagId, onNavigate }: ScriptTagEditorProps) {
307
307
  <>
308
308
  {showDeleteConfirm ? (
309
309
  <div className="flex items-center gap-2">
310
- <span className="text-sm text-red-600">Delete this tag?</span>
310
+ <span className="text-destructive text-sm">Delete this tag?</span>
311
311
  <button
312
312
  type="button"
313
313
  onClick={handleDelete}
314
314
  disabled={deleting}
315
- className="rounded-lg bg-red-600 px-3 py-1.5 text-sm text-white hover:bg-red-700 disabled:opacity-50"
315
+ className="bg-destructive text-destructive-foreground hover:bg-destructive/90 rounded-lg px-3 py-1.5 text-sm disabled:opacity-50"
316
316
  >
317
317
  {deleting ? 'Deleting...' : 'Confirm'}
318
318
  </button>
319
319
  <button
320
320
  type="button"
321
321
  onClick={() => setShowDeleteConfirm(false)}
322
- className="rounded-lg border border-gray-300 px-3 py-1.5 text-sm hover:bg-gray-50"
322
+ className="border-input hover:bg-muted rounded-lg border px-3 py-1.5 text-sm"
323
323
  >
324
324
  Cancel
325
325
  </button>
@@ -328,7 +328,7 @@ export function ScriptTagEditor({ tagId, onNavigate }: ScriptTagEditorProps) {
328
328
  <button
329
329
  type="button"
330
330
  onClick={() => setShowDeleteConfirm(true)}
331
- className="flex items-center gap-1.5 text-sm text-red-600 transition-colors hover:text-red-700"
331
+ className="text-destructive hover:text-destructive flex items-center gap-1.5 text-sm transition-colors"
332
332
  >
333
333
  <Trash2 className="h-4 w-4" />
334
334
  Delete
@@ -341,7 +341,7 @@ export function ScriptTagEditor({ tagId, onNavigate }: ScriptTagEditorProps) {
341
341
  <button
342
342
  type="button"
343
343
  onClick={() => onNavigate?.('/script-tags')}
344
- className="rounded-lg border border-gray-300 px-4 py-2 text-sm text-gray-700 transition-colors hover:bg-gray-50"
344
+ className="border-input text-foreground hover:bg-muted rounded-lg border px-4 py-2 text-sm transition-colors"
345
345
  >
346
346
  Cancel
347
347
  </button>
@@ -349,7 +349,7 @@ export function ScriptTagEditor({ tagId, onNavigate }: ScriptTagEditorProps) {
349
349
  type="button"
350
350
  onClick={handleSave}
351
351
  disabled={saving}
352
- className="rounded-lg bg-blue-600 px-6 py-2 text-sm text-white transition-colors hover:bg-blue-700 disabled:opacity-50"
352
+ className="bg-primary text-primary-foreground hover:bg-primary/90 rounded-lg px-6 py-2 text-sm transition-colors disabled:opacity-50"
353
353
  >
354
354
  {saving ? 'Saving...' : isNew ? 'Create Tag' : 'Save Changes'}
355
355
  </button>