@dyrected/admin 2.0.0 → 2.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/CHANGELOG.md +46 -0
  2. package/package.json +4 -4
  3. package/scripts/prefix-tailwind-precision.py +98 -0
  4. package/scripts/prefix-tailwind.py +67 -0
  5. package/src/components/auth/auth-gate.tsx +4 -4
  6. package/src/components/error-boundary.tsx +4 -4
  7. package/src/components/forms/fields/block-builder.tsx +24 -24
  8. package/src/components/forms/fields/date-picker.tsx +7 -7
  9. package/src/components/forms/fields/json-editor.tsx +5 -5
  10. package/src/components/forms/fields/media-picker.tsx +39 -39
  11. package/src/components/forms/fields/multi-select.tsx +12 -12
  12. package/src/components/forms/fields/radio-field.tsx +8 -8
  13. package/src/components/forms/fields/relationship-picker.tsx +13 -13
  14. package/src/components/forms/fields/rich-text-editor.tsx +22 -22
  15. package/src/components/forms/fields/select-field.tsx +3 -3
  16. package/src/components/forms/form-engine.tsx +3 -3
  17. package/src/components/forms/form-field-renderer.tsx +37 -37
  18. package/src/components/layout/admin-shell.tsx +60 -60
  19. package/src/components/live-preview/LivePreviewPane.tsx +14 -14
  20. package/src/components/media/focal-point-picker.tsx +9 -9
  21. package/src/components/media/media-card.tsx +10 -10
  22. package/src/components/media/media-grid.tsx +3 -3
  23. package/src/components/media/media-library-dialog.tsx +105 -105
  24. package/src/components/ui/badge.tsx +5 -5
  25. package/src/components/ui/button.tsx +11 -11
  26. package/src/components/ui/calendar.tsx +36 -36
  27. package/src/components/ui/card.tsx +6 -6
  28. package/src/components/ui/checkbox.tsx +3 -3
  29. package/src/components/ui/command.tsx +12 -12
  30. package/src/components/ui/data-table.tsx +18 -18
  31. package/src/components/ui/dialog.tsx +9 -9
  32. package/src/components/ui/dropdown-menu.tsx +16 -16
  33. package/src/components/ui/form.tsx +4 -4
  34. package/src/components/ui/input.tsx +3 -3
  35. package/src/components/ui/label.tsx +1 -1
  36. package/src/components/ui/page-header.tsx +6 -6
  37. package/src/components/ui/pagination.tsx +6 -6
  38. package/src/components/ui/popover.tsx +1 -1
  39. package/src/components/ui/progress.tsx +2 -2
  40. package/src/components/ui/radio-group.tsx +4 -4
  41. package/src/components/ui/render-cell.tsx +16 -16
  42. package/src/components/ui/scroll-area.tsx +6 -6
  43. package/src/components/ui/select.tsx +14 -14
  44. package/src/components/ui/separator.tsx +2 -2
  45. package/src/components/ui/sheet.tsx +13 -13
  46. package/src/components/ui/sidebar.tsx +60 -60
  47. package/src/components/ui/skeleton.tsx +1 -1
  48. package/src/components/ui/sonner.tsx +1 -1
  49. package/src/components/ui/switch.tsx +2 -2
  50. package/src/components/ui/table.tsx +7 -7
  51. package/src/components/ui/tabs.tsx +3 -3
  52. package/src/components/ui/textarea.tsx +1 -1
  53. package/src/components/ui/toggle.tsx +6 -6
  54. package/src/components/ui/tooltip.tsx +1 -1
  55. package/src/index.css +27 -27
  56. package/src/index.tsx +4 -4
  57. package/src/lib/utils.ts +7 -3
  58. package/src/pages/auth/first-user-page.tsx +18 -18
  59. package/src/pages/auth/login-page.tsx +14 -14
  60. package/src/pages/collections/edit-page.tsx +37 -37
  61. package/src/pages/collections/list-page.tsx +23 -23
  62. package/src/pages/dashboard/dashboard.tsx +49 -49
  63. package/src/pages/globals/editor-page.tsx +13 -13
  64. package/src/pages/media/media-page.tsx +106 -106
  65. package/src/pages/setup/setup-prompt.tsx +73 -44
  66. package/tailwind.config.ts +1 -0
  67. package/vite.config.ts +0 -1
@@ -47,18 +47,18 @@ export function FirstUserPage({
47
47
  };
48
48
 
49
49
  return (
50
- <div className="flex min-h-screen items-center justify-center bg-background px-4">
51
- <div className="w-full max-w-sm space-y-8">
52
- <div className="space-y-2 text-center">
53
- <div className="mx-auto h-12 w-12 rounded-full bg-primary/5 flex items-center justify-center mb-4">
54
- <div className="h-6 w-6 rounded-full border-2 border-primary border-t-transparent animate-pulse" />
50
+ <div className="dy-flex dy-min-h-screen dy-items-center dy-justify-center dy-bg-background dy-px-4">
51
+ <div className="dy-w-full dy-max-w-sm dy-space-y-8">
52
+ <div className="dy-space-y-2 dy-text-center">
53
+ <div className="dy-mx-auto dy-h-12 dy-w-12 dy-rounded-full dy-bg-primary/5 dy-flex dy-items-center dy-justify-center dy-mb-4">
54
+ <div className="dy-h-6 dy-w-6 dy-rounded-full dy-border-2 dy-border-primary dy-border-t-transparent dy-animate-pulse" />
55
55
  </div>
56
- <h1 className="text-2xl font-semibold tracking-tight">Setup Admin Account</h1>
57
- <p className="text-sm text-muted-foreground">Create the first administrative user to get started</p>
56
+ <h1 className="dy-text-2xl dy-font-semibold dy-tracking-tight">Setup Admin Account</h1>
57
+ <p className="dy-text-sm dy-text-muted-foreground">Create the first administrative user to get started</p>
58
58
  </div>
59
59
 
60
- <form onSubmit={handleSubmit} className="space-y-4">
61
- <div className="space-y-2">
60
+ <form onSubmit={handleSubmit} className="dy-space-y-4">
61
+ <div className="dy-space-y-2">
62
62
  <Label htmlFor="email">Admin Email</Label>
63
63
  <Input
64
64
  id="email"
@@ -67,10 +67,10 @@ export function FirstUserPage({
67
67
  value={email}
68
68
  onChange={(e) => setEmail(e.target.value)}
69
69
  required
70
- className="bg-transparent"
70
+ className="dy-bg-transparent"
71
71
  />
72
72
  </div>
73
- <div className="space-y-2">
73
+ <div className="dy-space-y-2">
74
74
  <Label htmlFor="password">Password</Label>
75
75
  <Input
76
76
  id="password"
@@ -78,10 +78,10 @@ export function FirstUserPage({
78
78
  value={password}
79
79
  onChange={(e) => setPassword(e.target.value)}
80
80
  required
81
- className="bg-transparent"
81
+ className="dy-bg-transparent"
82
82
  />
83
83
  </div>
84
- <div className="space-y-2">
84
+ <div className="dy-space-y-2">
85
85
  <Label htmlFor="confirm-password">Confirm Password</Label>
86
86
  <Input
87
87
  id="confirm-password"
@@ -89,23 +89,23 @@ export function FirstUserPage({
89
89
  value={confirmPassword}
90
90
  onChange={(e) => setConfirmPassword(e.target.value)}
91
91
  required
92
- className="bg-transparent"
92
+ className="dy-bg-transparent"
93
93
  />
94
94
  </div>
95
95
 
96
96
  {error && (
97
- <div className="text-xs text-destructive font-medium bg-destructive/10 p-3 rounded-md">
97
+ <div className="dy-text-xs dy-text-destructive dy-font-medium dy-bg-destructive/10 dy-p-3 dy-rounded-md">
98
98
  {error}
99
99
  </div>
100
100
  )}
101
101
 
102
- <Button type="submit" className="w-full" disabled={loading}>
102
+ <Button type="submit" className="dy-w-full" disabled={loading}>
103
103
  {loading ? "Creating account..." : "Create Admin Account"}
104
104
  </Button>
105
105
  </form>
106
106
 
107
- <div className="pt-4 border-t text-center space-y-2">
108
- <p className="text-[10px] text-muted-foreground uppercase tracking-widest">
107
+ <div className="dy-pt-4 dy-border-t dy-text-center dy-space-y-2">
108
+ <p className="dy-text-[10px] dy-text-muted-foreground dy-uppercase dy-tracking-widest">
109
109
  Dyrected CMS · Initial Setup
110
110
  </p>
111
111
  </div>
@@ -37,15 +37,15 @@ export function LoginPage({
37
37
  };
38
38
 
39
39
  return (
40
- <div className="flex min-h-screen items-center justify-center bg-background px-4">
41
- <div className="w-full max-w-sm space-y-8">
42
- <div className="space-y-2 text-center">
43
- <h1 className="text-2xl font-semibold tracking-tight">Welcome back</h1>
44
- <p className="text-sm text-muted-foreground">Enter your credentials to access the dashboard</p>
40
+ <div className="dy-flex dy-min-h-screen dy-items-center dy-justify-center dy-bg-background dy-px-4">
41
+ <div className="dy-w-full dy-max-w-sm dy-space-y-8">
42
+ <div className="dy-space-y-2 dy-text-center">
43
+ <h1 className="dy-text-2xl dy-font-semibold dy-tracking-tight">Welcome back</h1>
44
+ <p className="dy-text-sm dy-text-muted-foreground">Enter your credentials to access the dashboard</p>
45
45
  </div>
46
46
 
47
- <form onSubmit={handleSubmit} className="space-y-4">
48
- <div className="space-y-2">
47
+ <form onSubmit={handleSubmit} className="dy-space-y-4">
48
+ <div className="dy-space-y-2">
49
49
  <Label htmlFor="email">Email</Label>
50
50
  <Input
51
51
  id="email"
@@ -54,11 +54,11 @@ export function LoginPage({
54
54
  value={email}
55
55
  onChange={(e) => setEmail(e.target.value)}
56
56
  required
57
- className="bg-transparent"
57
+ className="dy-bg-transparent"
58
58
  />
59
59
  </div>
60
- <div className="space-y-2">
61
- <div className="flex items-center justify-between">
60
+ <div className="dy-space-y-2">
61
+ <div className="dy-flex dy-items-center dy-justify-between">
62
62
  <Label htmlFor="password">Password</Label>
63
63
  </div>
64
64
  <Input
@@ -67,22 +67,22 @@ export function LoginPage({
67
67
  value={password}
68
68
  onChange={(e) => setPassword(e.target.value)}
69
69
  required
70
- className="bg-transparent"
70
+ className="dy-bg-transparent"
71
71
  />
72
72
  </div>
73
73
 
74
74
  {error && (
75
- <div className="text-xs text-destructive font-medium bg-destructive/10 p-3 rounded-md">
75
+ <div className="dy-text-xs dy-text-destructive dy-font-medium dy-bg-destructive/10 dy-p-3 dy-rounded-md">
76
76
  {error}
77
77
  </div>
78
78
  )}
79
79
 
80
- <Button type="submit" className="w-full" disabled={loading}>
80
+ <Button type="submit" className="dy-w-full" disabled={loading}>
81
81
  {loading ? "Signing in..." : "Sign In"}
82
82
  </Button>
83
83
  </form>
84
84
 
85
- <p className="text-center text-xs text-muted-foreground uppercase tracking-widest">
85
+ <p className="dy-text-center dy-text-xs dy-text-muted-foreground dy-uppercase dy-tracking-widest">
86
86
  Dyrected CMS
87
87
  </p>
88
88
  </div>
@@ -138,33 +138,33 @@ export function EditEntryPage() {
138
138
  const canUpdate = (schema.access as any)?.update !== false
139
139
 
140
140
  return (
141
- <div className="flex h-[calc(100vh-0px)] overflow-hidden -mt-6 -mx-4 lg:-mt-10 lg:-mx-6">
141
+ <div className="dy-flex dy-h-[calc(100vh-0px)] dy-overflow-hidden dy--mt-6 dy--mx-4 lg:dy--mt-10 lg:dy--mx-6">
142
142
  {/* Left Column: Header + Form */}
143
143
  <div className={cn(
144
- "flex-1 overflow-y-auto px-6 py-6 lg:px-10 lg:py-10 transition-all duration-500",
145
- showPreview ? "max-w-2xl xl:max-w-3xl" : "max-w-5xl mx-auto w-full"
144
+ "dy-flex-1 dy-overflow-y-auto dy-px-6 dy-py-6 lg:dy-px-10 lg:dy-py-10 dy-transition-all dy-duration-500",
145
+ showPreview ? "dy-max-w-2xl xl:dy-max-w-3xl" : "dy-max-w-5xl dy-mx-auto dy-w-full"
146
146
  )}>
147
- <div className="space-y-8">
147
+ <div className="dy-space-y-8">
148
148
  {/* Header */}
149
- <div className="flex items-center justify-between gap-4 border-b border-border/50 pb-6">
150
- <div className="flex items-center gap-4">
149
+ <div className="dy-flex dy-items-center dy-justify-between dy-gap-4 dy-border-b dy-border-border/50 dy-pb-6">
150
+ <div className="dy-flex dy-items-center dy-gap-4">
151
151
  <Button
152
152
  variant="ghost"
153
153
  size="icon"
154
- className="h-8 w-8 rounded-lg hover:bg-muted shrink-0"
154
+ className="dy-h-8 dy-w-8 dy-rounded-lg hover:dy-bg-muted dy-shrink-0"
155
155
  onClick={() => navigate(`/collections/${slug}`)}
156
156
  >
157
- <ChevronLeft className="h-4 w-4" />
157
+ <ChevronLeft className="dy-h-4 dy-w-4" />
158
158
  </Button>
159
159
  <div>
160
- <div className="flex items-center gap-3">
161
- <h1 className="text-lg font-serif font-bold tracking-tight text-foreground truncate">
160
+ <div className="dy-flex dy-items-center dy-gap-3">
161
+ <h1 className="dy-text-lg dy-font-serif dy-font-bold dy-tracking-tight dy-text-foreground dy-truncate">
162
162
  {isEdit ? `Edit ${schema.label || schema.slug}` : `New ${schema.label || schema.slug}`}
163
163
  </h1>
164
164
  {hasStatus && (
165
165
  <Badge className={cn(
166
- "px-2 py-0 rounded-full text-[10px] font-bold uppercase tracking-wider",
167
- currentStatus === "published" ? "bg-emerald-100 text-emerald-700 border-emerald-200" : "bg-amber-100 text-amber-700 border-amber-200"
166
+ "dy-px-2 dy-py-0 dy-rounded-full dy-text-[10px] dy-font-bold dy-uppercase dy-tracking-wider",
167
+ currentStatus === "published" ? "dy-bg-emerald-100 dy-text-emerald-700 dy-border-emerald-200" : "dy-bg-amber-100 dy-text-amber-700 dy-border-amber-200"
168
168
  )} variant="outline">
169
169
  {currentStatus === "published" ? "Live" : "Draft"}
170
170
  </Badge>
@@ -173,42 +173,42 @@ export function EditEntryPage() {
173
173
  </div>
174
174
  </div>
175
175
 
176
- <div className="flex items-center gap-2">
176
+ <div className="dy-flex dy-items-center dy-gap-2">
177
177
  {previewUrl && (
178
178
  <Button
179
179
  variant="ghost"
180
180
  size="icon"
181
181
  className={cn(
182
- "h-9 w-9 rounded-lg transition-colors",
183
- showPreview ? "bg-primary/10 text-primary hover:bg-primary/20" : "hover:bg-muted"
182
+ "dy-h-9 dy-w-9 dy-rounded-lg dy-transition-colors",
183
+ showPreview ? "dy-bg-primary/10 dy-text-primary hover:dy-bg-primary/20" : "hover:dy-bg-muted"
184
184
  )}
185
185
  onClick={() => setShowPreview(!showPreview)}
186
186
  title={showPreview ? "Hide Preview" : "Live Preview"}
187
187
  >
188
- {showPreview ? <EyeOff className="h-4 w-4" /> : <Eye className="h-4 w-4" />}
188
+ {showPreview ? <EyeOff className="dy-h-4 dy-w-4" /> : <Eye className="dy-h-4 dy-w-4" />}
189
189
  </Button>
190
190
  )}
191
191
  <Button
192
192
  size="icon"
193
- className="h-9 w-9 rounded-lg shadow-sm"
193
+ className="dy-h-9 dy-w-9 dy-rounded-lg dy-shadow-sm"
194
194
  onClick={() => document.getElementById('dyrected-form-submit')?.click()}
195
195
  disabled={saveMutation.isPending || (isEdit ? !canUpdate : !canCreate)}
196
196
  title={isEdit ? "Save Changes (⌘S)" : "Create Entry (⌘S)"}
197
197
  >
198
198
  {saveMutation.isPending ? (
199
- <div className="h-4 w-4 animate-spin border-2 border-current border-t-transparent rounded-full" />
199
+ <div className="dy-h-4 dy-w-4 dy-animate-spin dy-border-2 dy-border-current dy-border-t-transparent dy-rounded-full" />
200
200
  ) : (
201
- <Save className="h-4 w-4" />
201
+ <Save className="dy-h-4 dy-w-4" />
202
202
  )}
203
203
  </Button>
204
204
  </div>
205
205
  </div>
206
206
 
207
207
  {/* Form */}
208
- <div className="animate-in space-y-8 pb-20">
208
+ <div className="dy-animate-in dy-space-y-8 dy-pb-20">
209
209
  {!canUpdate && isEdit && (
210
- <div className="p-4 rounded-lg bg-amber-50 border border-amber-200 text-amber-800 text-sm flex items-center gap-3">
211
- <Archive className="h-4 w-4" />
210
+ <div className="dy-p-4 dy-rounded-lg dy-bg-amber-50 dy-border dy-border-amber-200 dy-text-amber-800 dy-text-sm dy-flex dy-items-center dy-gap-3">
211
+ <Archive className="dy-h-4 dy-w-4" />
212
212
  You have read-only access to this collection.
213
213
  </div>
214
214
  )}
@@ -223,29 +223,29 @@ export function EditEntryPage() {
223
223
  submitLabel={isEdit ? "Save Changes" : "Create Entry"}
224
224
  readOnly={isEdit ? !canUpdate : !canCreate}
225
225
  />
226
- <button id="dyrected-form-submit" type="submit" className="hidden" />
226
+ <button id="dyrected-form-submit" type="submit" className="dy-hidden" />
227
227
 
228
228
  {/* Document Meta */}
229
- <div className="pt-8 border-t border-border/40">
230
- <div className="flex flex-wrap items-center gap-x-8 gap-y-4">
231
- <div className="space-y-1">
232
- <p className="text-[10px] font-bold uppercase tracking-wider text-muted-foreground/40 text-nowrap">Document ID</p>
233
- <code className="text-xs font-mono text-muted-foreground/80 select-all">
229
+ <div className="dy-pt-8 dy-border-t dy-border-border/40">
230
+ <div className="dy-flex dy-flex-wrap dy-items-center dy-gap-x-8 dy-gap-y-4">
231
+ <div className="dy-space-y-1">
232
+ <p className="dy-text-[10px] dy-font-bold dy-uppercase dy-tracking-wider dy-text-muted-foreground/40 dy-text-nowrap">Document ID</p>
233
+ <code className="dy-text-xs dy-font-mono dy-text-muted-foreground/80 dy-select-all">
234
234
  {isEdit ? id : "Pending..."}
235
235
  </code>
236
236
  </div>
237
237
 
238
238
  {isEdit && (
239
239
  <>
240
- <div className="space-y-1">
241
- <p className="text-[10px] font-bold uppercase tracking-wider text-muted-foreground/40 text-nowrap">Created At</p>
242
- <p className="text-xs font-medium text-muted-foreground/80">
240
+ <div className="dy-space-y-1">
241
+ <p className="dy-text-[10px] dy-font-bold dy-uppercase dy-tracking-wider dy-text-muted-foreground/40 dy-text-nowrap">Created At</p>
242
+ <p className="dy-text-xs dy-font-medium dy-text-muted-foreground/80">
243
243
  {entry?.createdAt ? new Date(entry.createdAt).toLocaleString() : 'N/A'}
244
244
  </p>
245
245
  </div>
246
- <div className="space-y-1">
247
- <p className="text-[10px] font-bold uppercase tracking-wider text-muted-foreground/40 text-nowrap">Last Updated</p>
248
- <p className="text-xs font-medium text-muted-foreground/80">
246
+ <div className="dy-space-y-1">
247
+ <p className="dy-text-[10px] dy-font-bold dy-uppercase dy-tracking-wider dy-text-muted-foreground/40 dy-text-nowrap">Last Updated</p>
248
+ <p className="dy-text-xs dy-font-medium dy-text-muted-foreground/80">
249
249
  {entry?.updatedAt ? new Date(entry.updatedAt).toLocaleString() : 'N/A'}
250
250
  </p>
251
251
  </div>
@@ -260,13 +260,13 @@ export function EditEntryPage() {
260
260
  {/* Right Column: Preview (starts from top) */}
261
261
  {previewUrl && (
262
262
  <div className={cn(
263
- "hidden lg:block border-l border-border/50 bg-muted/5 transition-all duration-500 overflow-hidden",
264
- showPreview ? "flex-1 opacity-100" : "w-0 opacity-0 border-l-0"
263
+ "dy-hidden lg:dy-block dy-border-l dy-border-border/50 dy-bg-muted/5 dy-transition-all dy-duration-500 dy-overflow-hidden",
264
+ showPreview ? "dy-flex-1 dy-opacity-100" : "dy-w-0 dy-opacity-0 dy-border-l-0"
265
265
  )}>
266
266
  {/* We use negative margins to pull the preview up and out to the shell's padding edges if possible,
267
267
  but since we're inside a parent with padding, we'll just make it height-full.
268
268
  */}
269
- <div className="h-full">
269
+ <div className="dy-h-full">
270
270
  <LivePreviewPane
271
271
  previewUrl={previewUrl}
272
272
  data={previewData || entry}
@@ -127,7 +127,7 @@ export function CollectionListPage({ slug }: CollectionListPageProps) {
127
127
  {
128
128
  accessorKey: "id",
129
129
  header: "ID",
130
- cell: ({ row }) => <span className="font-mono text-xs">{row.getValue("id")}</span>,
130
+ cell: ({ row }) => <span className="dy-font-mono dy-text-xs">{row.getValue("id")}</span>,
131
131
  },
132
132
  ]
133
133
 
@@ -173,9 +173,9 @@ export function CollectionListPage({ slug }: CollectionListPageProps) {
173
173
  cell: ({ row }) => {
174
174
  const date = new Date(row.getValue("updatedAt"))
175
175
  return (
176
- <div className="flex items-center gap-2 text-muted-foreground">
177
- <Calendar className="h-3 w-3" />
178
- <span className="text-xs">{date.toLocaleDateString()}</span>
176
+ <div className="dy-flex dy-items-center dy-gap-2 dy-text-muted-foreground">
177
+ <Calendar className="dy-h-3 dy-w-3" />
178
+ <span className="dy-text-xs">{date.toLocaleDateString()}</span>
179
179
  </div>
180
180
  )
181
181
  }
@@ -189,9 +189,9 @@ export function CollectionListPage({ slug }: CollectionListPageProps) {
189
189
  return (
190
190
  <DropdownMenu>
191
191
  <DropdownMenuTrigger asChild>
192
- <Button variant="ghost" className="h-8 w-8 p-0">
193
- <span className="sr-only">Open menu</span>
194
- <MoreHorizontal className="h-4 w-4" />
192
+ <Button variant="ghost" className="dy-h-8 dy-w-8 dy-p-0">
193
+ <span className="dy-sr-only">Open menu</span>
194
+ <MoreHorizontal className="dy-h-4 dy-w-4" />
195
195
  </Button>
196
196
  </DropdownMenuTrigger>
197
197
  <DropdownMenuContent align="end">
@@ -201,17 +201,17 @@ export function CollectionListPage({ slug }: CollectionListPageProps) {
201
201
  </DropdownMenuItem>
202
202
  <DropdownMenuSeparator />
203
203
  <Link to={`/collections/${slug}/edit/${item.id}`}>
204
- <DropdownMenuItem className="flex gap-2">
205
- <Pencil className="h-4 w-4" />
204
+ <DropdownMenuItem className="dy-flex dy-gap-2">
205
+ <Pencil className="dy-h-4 dy-w-4" />
206
206
  Edit
207
207
  </DropdownMenuItem>
208
208
  </Link>
209
209
  <DropdownMenuItem
210
- className="flex gap-2 text-destructive focus:text-destructive"
210
+ className="dy-flex dy-gap-2 dy-text-destructive focus:dy-text-destructive"
211
211
  onClick={() => handleDelete(item.id)}
212
212
  disabled={deleteMutation.isPending}
213
213
  >
214
- <Trash2 className="h-4 w-4" />
214
+ <Trash2 className="dy-h-4 dy-w-4" />
215
215
  {deleteMutation.isPending ? "Deleting..." : "Delete"}
216
216
  </DropdownMenuItem>
217
217
  </DropdownMenuContent>
@@ -246,8 +246,8 @@ export function CollectionListPage({ slug }: CollectionListPageProps) {
246
246
 
247
247
  if (isLoading) {
248
248
  return (
249
- <div className="flex h-[400px] items-center justify-center">
250
- <div className="animate-spin rounded-full border-4 border-primary border-t-transparent h-8 w-8"></div>
249
+ <div className="dy-flex dy-h-[400px] dy-items-center dy-justify-center">
250
+ <div className="dy-animate-spin dy-rounded-full dy-border-4 dy-border-primary dy-border-t-transparent dy-h-8 dy-w-8"></div>
251
251
  </div>
252
252
  )
253
253
  }
@@ -258,15 +258,15 @@ export function CollectionListPage({ slug }: CollectionListPageProps) {
258
258
 
259
259
  if (slug === "media") {
260
260
  return (
261
- <div className="space-y-8 animate-in">
261
+ <div className="dy-space-y-8 dy-animate-in">
262
262
  <PageHeader
263
263
  title="Media Library"
264
264
  description="Manage your media assets and uploads."
265
265
  icon={ImageIcon}
266
266
  >
267
267
  <Link to={`/collections/${slug}/new`}>
268
- <Button className="h-8 px-4 text-[11px] rounded-md bg-primary hover:bg-primary/90 shadow-sm transition-all active:scale-95">
269
- <Plus className="mr-1.5 h-3 w-3" />
268
+ <Button className="dy-h-8 dy-px-4 dy-text-[11px] dy-rounded-md dy-bg-primary hover:dy-bg-primary/90 dy-shadow-sm dy-transition-all active:dy-scale-95">
269
+ <Plus className="dy-mr-1.5 dy-h-3 dy-w-3" />
270
270
  Upload New
271
271
  </Button>
272
272
  </Link>
@@ -285,28 +285,28 @@ export function CollectionListPage({ slug }: CollectionListPageProps) {
285
285
  hasPrevPage={hasPrevPage}
286
286
  hasNextPage={hasNextPage}
287
287
  onPageChange={setPage}
288
- className="mt-8"
288
+ className="dy-mt-8"
289
289
  />
290
290
  </div>
291
291
  )
292
292
  }
293
293
 
294
294
  return (
295
- <div className="space-y-8 animate-in">
295
+ <div className="dy-space-y-8 dy-animate-in">
296
296
  <PageHeader
297
297
  title={schema.labels?.plural || schema.label || schema.slug}
298
298
  description={`Manage your ${schema.slug} entries and update content.`}
299
299
  icon={Database}
300
300
  >
301
301
  <Link to={`/collections/${slug}/new`}>
302
- <Button className="h-8 px-4 text-[11px] rounded-md bg-primary hover:bg-primary/90 shadow-sm transition-all active:scale-95">
303
- <Plus className="mr-1.5 h-3 w-3" />
302
+ <Button className="dy-h-8 dy-px-4 dy-text-[11px] dy-rounded-md dy-bg-primary hover:dy-bg-primary/90 dy-shadow-sm dy-transition-all active:dy-scale-95">
303
+ <Plus className="dy-mr-1.5 dy-h-3 dy-w-3" />
304
304
  Create New
305
305
  </Button>
306
306
  </Link>
307
307
  </PageHeader>
308
308
 
309
- <div className="overflow-hidden">
309
+ <div className="dy-overflow-hidden">
310
310
  <DataTable
311
311
  key={slug}
312
312
  columns={columns}
@@ -320,11 +320,11 @@ export function CollectionListPage({ slug }: CollectionListPageProps) {
320
320
  <Button
321
321
  variant="destructive"
322
322
  size="sm"
323
- className="h-8"
323
+ className="dy-h-8"
324
324
  onClick={() => handleBulkDelete(selectedIds)}
325
325
  disabled={bulkDeleteMutation.isPending}
326
326
  >
327
- <Trash2 className="h-4 w-4 mr-2" />
327
+ <Trash2 className="dy-h-4 dy-w-4 dy-mr-2" />
328
328
  Delete Selected ({selectedIds.length})
329
329
  </Button>
330
330
  )}
@@ -26,8 +26,8 @@ export function Dashboard() {
26
26
 
27
27
  if (isLoadingSchemas) {
28
28
  return (
29
- <div className="flex items-center justify-center h-64">
30
- <div className="animate-spin rounded-full h-8 w-8 border-b-2 border-primary"></div>
29
+ <div className="dy-flex dy-items-center dy-justify-center dy-h-64">
30
+ <div className="dy-animate-spin dy-rounded-full dy-h-8 dy-w-8 dy-border-b-2 dy-border-primary"></div>
31
31
  </div>
32
32
  );
33
33
  }
@@ -35,9 +35,9 @@ export function Dashboard() {
35
35
  // No schema yet — route to /setup
36
36
  if (collections.length === 0 && globals.length === 0) {
37
37
  return (
38
- <div className="flex items-center justify-center h-64">
39
- <div className="text-center space-y-4">
40
- <p className="text-muted-foreground">No collections configured yet.</p>
38
+ <div className="dy-flex dy-items-center dy-justify-center dy-h-64">
39
+ <div className="dy-text-center dy-space-y-4">
40
+ <p className="dy-text-muted-foreground">No collections configured yet.</p>
41
41
  <Button asChild>
42
42
  <Link to="/setup">View Integration Guide</Link>
43
43
  </Button>
@@ -47,72 +47,72 @@ export function Dashboard() {
47
47
  }
48
48
 
49
49
  return (
50
- <div className="space-y-8 animate-in fade-in duration-500">
50
+ <div className="dy-space-y-8 dy-animate-in dy-fade-in dy-duration-500">
51
51
  <div>
52
- <h2 className="text-2xl font-semibold tracking-tight">Overview</h2>
53
- <p className="text-muted-foreground">Monitor and manage your site's content and structure.</p>
52
+ <h2 className="dy-text-2xl dy-font-semibold dy-tracking-tight">Overview</h2>
53
+ <p className="dy-text-muted-foreground">Monitor and manage your site's content and structure.</p>
54
54
  </div>
55
55
 
56
- <div className="grid gap-6 md:grid-cols-2 lg:grid-cols-3">
57
- <div className="p-1 space-y-2 group border border-card">
58
- <div className="flex items-center gap-3">
59
- <div className="rounded-md bg-primary/5 p-1.5 text-primary/60 group-hover:bg-primary/10 group-hover:text-primary transition-colors">
60
- <Database className="h-4 w-4" />
56
+ <div className="dy-grid dy-gap-6 md:dy-grid-cols-2 lg:dy-grid-cols-3">
57
+ <div className="dy-p-1 dy-space-y-2 dy-group dy-border dy-border-card">
58
+ <div className="dy-flex dy-items-center dy-gap-3">
59
+ <div className="dy-rounded-md dy-bg-primary/5 dy-p-1.5 dy-text-primary/60 dy-group-hover:dy-bg-primary/10 dy-group-hover:dy-text-primary dy-transition-colors">
60
+ <Database className="dy-h-4 dy-w-4" />
61
61
  </div>
62
- <h3 className="text-[10px] font-bold text-muted-foreground/40 uppercase tracking-widest">Collections</h3>
62
+ <h3 className="dy-text-[10px] dy-font-bold dy-text-muted-foreground/40 dy-uppercase dy-tracking-widest">Collections</h3>
63
63
  </div>
64
- <p className="text-3xl font-bold tracking-tight">{collections.length}</p>
64
+ <p className="dy-text-3xl dy-font-bold dy-tracking-tight">{collections.length}</p>
65
65
  </div>
66
66
 
67
- <div className="p-1 space-y-2 group border border-card">
68
- <div className="flex items-center gap-3">
69
- <div className="rounded-md bg-secondary/5 p-1.5 text-muted-foreground/60 group-hover:bg-accent group-hover:text-foreground transition-colors">
70
- <Globe className="h-4 w-4" />
67
+ <div className="dy-p-1 dy-space-y-2 dy-group dy-border dy-border-card">
68
+ <div className="dy-flex dy-items-center dy-gap-3">
69
+ <div className="dy-rounded-md dy-bg-secondary/5 dy-p-1.5 dy-text-muted-foreground/60 dy-group-hover:dy-bg-accent dy-group-hover:dy-text-foreground dy-transition-colors">
70
+ <Globe className="dy-h-4 dy-w-4" />
71
71
  </div>
72
- <h3 className="text-[10px] font-bold text-muted-foreground/40 uppercase tracking-widest">Global Configs</h3>
72
+ <h3 className="dy-text-[10px] dy-font-bold dy-text-muted-foreground/40 dy-uppercase dy-tracking-widest">Global Configs</h3>
73
73
  </div>
74
- <p className="text-3xl font-bold tracking-tight">{globals.length}</p>
74
+ <p className="dy-text-3xl dy-font-bold dy-tracking-tight">{globals.length}</p>
75
75
  </div>
76
76
 
77
- <div className="p-1 space-y-2 group border border-card">
78
- <div className="flex items-center gap-3">
79
- <div className="rounded-md bg-accent p-1.5 text-muted-foreground/60 group-hover:bg-accent group-hover:text-foreground transition-colors">
80
- <ImageIcon className="h-4 w-4" />
77
+ <div className="dy-p-1 dy-space-y-2 dy-group dy-border dy-border-card">
78
+ <div className="dy-flex dy-items-center dy-gap-3">
79
+ <div className="dy-rounded-md dy-bg-accent dy-p-1.5 dy-text-muted-foreground/60 dy-group-hover:dy-bg-accent dy-group-hover:dy-text-foreground dy-transition-colors">
80
+ <ImageIcon className="dy-h-4 dy-w-4" />
81
81
  </div>
82
- <h3 className="text-[10px] font-bold text-muted-foreground/40 uppercase tracking-widest">Media Files</h3>
82
+ <h3 className="dy-text-[10px] dy-font-bold dy-text-muted-foreground/40 dy-uppercase dy-tracking-widest">Media Files</h3>
83
83
  </div>
84
- <p className="text-3xl font-bold tracking-tight">-</p>
84
+ <p className="dy-text-3xl dy-font-bold dy-tracking-tight">-</p>
85
85
  </div>
86
86
  </div>
87
87
 
88
- <div className="grid gap-8 md:grid-cols-2">
88
+ <div className="dy-grid dy-gap-8 md:dy-grid-cols-2">
89
89
  <section >
90
- <div className="flex items-center justify-between mb-4">
91
- <h3 className="text-lg font-semibold flex items-center gap-2">
92
- <Database className="h-5 w-5 text-primary" />
90
+ <div className="dy-flex dy-items-center dy-justify-between dy-mb-4">
91
+ <h3 className="dy-text-lg dy-font-semibold dy-flex dy-items-center dy-gap-2">
92
+ <Database className="dy-h-5 dy-w-5 dy-text-primary" />
93
93
  Collections
94
94
  </h3>
95
- {/* <Button variant="ghost" size="sm" asChild className="text-xs">
95
+ {/* <Button variant="ghost" size="sm" asChild className="dy-text-xs">
96
96
  <Link to="/collections">View All</Link>
97
97
  </Button> */}
98
98
  </div>
99
- <div className="space-y-1 border border-card">
99
+ <div className="dy-space-y-1 dy-border dy-border-card">
100
100
  {collections.map((col: any, idx: number) => (
101
101
  <Link
102
102
  key={col.slug}
103
103
  to={`/collections/${col.slug}`}
104
- className="group flex items-center justify-between p-3 rounded-md hover:bg-primary/[0.02] transition-colors"
104
+ className="dy-group dy-flex dy-items-center dy-justify-between dy-p-3 dy-rounded-md hover:dy-bg-primary/[0.02] dy-transition-colors"
105
105
  >
106
106
  <div>
107
- <p className="font-medium group-hover:text-primary transition-colors">{col.labels?.plural || col.slug}</p>
108
- <p className="text-xs text-muted-foreground uppercase">{col.slug}</p>
107
+ <p className="dy-font-medium dy-group-hover:dy-text-primary dy-transition-colors">{col.labels?.plural || col.slug}</p>
108
+ <p className="dy-text-xs dy-text-muted-foreground dy-uppercase">{col.slug}</p>
109
109
  </div>
110
- <div className="flex items-center gap-3">
111
- <div className="text-right mr-4">
112
- <p className="text-sm font-semibold">{collectionCounts[idx]?.data?.total || 0}</p>
113
- <p className="text-[10px] text-muted-foreground uppercase">Entries</p>
110
+ <div className="dy-flex dy-items-center dy-gap-3">
111
+ <div className="dy-text-right dy-mr-4">
112
+ <p className="dy-text-sm dy-font-semibold">{collectionCounts[idx]?.data?.total || 0}</p>
113
+ <p className="dy-text-[10px] dy-text-muted-foreground dy-uppercase">Entries</p>
114
114
  </div>
115
- <ArrowRight className="h-4 w-4 text-muted-foreground group-hover:text-primary transition-transform group-hover:translate-x-0.5" />
115
+ <ArrowRight className="dy-h-4 dy-w-4 dy-text-muted-foreground dy-group-hover:dy-text-primary dy-transition-transform dy-group-hover:dy-translate-x-0.5" />
116
116
  </div>
117
117
  </Link>
118
118
  ))}
@@ -120,24 +120,24 @@ export function Dashboard() {
120
120
  </section>
121
121
 
122
122
  <section>
123
- <div className="flex items-center justify-between mb-4">
124
- <h3 className="text-lg font-semibold flex items-center gap-2">
125
- <Globe className="h-5 w-5 text-secondary-foreground" />
123
+ <div className="dy-flex dy-items-center dy-justify-between dy-mb-4">
124
+ <h3 className="dy-text-lg dy-font-semibold dy-flex dy-items-center dy-gap-2">
125
+ <Globe className="dy-h-5 dy-w-5 dy-text-secondary-foreground" />
126
126
  Global Settings
127
127
  </h3>
128
128
  </div>
129
- <div className="space-y-1 border border-card">
129
+ <div className="dy-space-y-1 dy-border dy-border-card">
130
130
  {globals.map((glb: any) => (
131
131
  <Link
132
132
  key={glb.slug}
133
133
  to={`/globals/${glb.slug}`}
134
- className="group flex items-center justify-between p-3 rounded-md hover:bg-primary/[0.02] transition-colors"
134
+ className="dy-group dy-flex dy-items-center dy-justify-between dy-p-3 dy-rounded-md hover:dy-bg-primary/[0.02] dy-transition-colors"
135
135
  >
136
136
  <div>
137
- <p className="font-medium group-hover:text-secondary-foreground transition-colors">{glb.label || glb.slug}</p>
138
- <p className="text-xs text-muted-foreground uppercase">{glb.slug}</p>
137
+ <p className="dy-font-medium dy-group-hover:dy-text-secondary-foreground dy-transition-colors">{glb.label || glb.slug}</p>
138
+ <p className="dy-text-xs dy-text-muted-foreground dy-uppercase">{glb.slug}</p>
139
139
  </div>
140
- <div className="bg-secondary/10 px-2 py-1 rounded text-[10px] font-bold text-secondary-foreground uppercase">
140
+ <div className="dy-bg-secondary/10 dy-px-2 dy-py-1 dy-rounded dy-text-[10px] dy-font-bold dy-text-secondary-foreground dy-uppercase">
141
141
  Global
142
142
  </div>
143
143
  </Link>