@dyrected/admin 2.0.1 → 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.
- package/CHANGELOG.md +29 -0
- package/package.json +4 -4
- package/scripts/prefix-tailwind-precision.py +98 -0
- package/scripts/prefix-tailwind.py +67 -0
- package/src/components/auth/auth-gate.tsx +4 -4
- package/src/components/error-boundary.tsx +4 -4
- package/src/components/forms/fields/block-builder.tsx +24 -24
- package/src/components/forms/fields/date-picker.tsx +7 -7
- package/src/components/forms/fields/json-editor.tsx +5 -5
- package/src/components/forms/fields/media-picker.tsx +39 -39
- package/src/components/forms/fields/multi-select.tsx +12 -12
- package/src/components/forms/fields/radio-field.tsx +8 -8
- package/src/components/forms/fields/relationship-picker.tsx +13 -13
- package/src/components/forms/fields/rich-text-editor.tsx +22 -22
- package/src/components/forms/fields/select-field.tsx +3 -3
- package/src/components/forms/form-engine.tsx +3 -3
- package/src/components/forms/form-field-renderer.tsx +37 -37
- package/src/components/layout/admin-shell.tsx +60 -60
- package/src/components/live-preview/LivePreviewPane.tsx +14 -14
- package/src/components/media/focal-point-picker.tsx +9 -9
- package/src/components/media/media-card.tsx +10 -10
- package/src/components/media/media-grid.tsx +3 -3
- package/src/components/media/media-library-dialog.tsx +105 -105
- package/src/components/ui/badge.tsx +5 -5
- package/src/components/ui/button.tsx +11 -11
- package/src/components/ui/calendar.tsx +36 -36
- package/src/components/ui/card.tsx +6 -6
- package/src/components/ui/checkbox.tsx +3 -3
- package/src/components/ui/command.tsx +12 -12
- package/src/components/ui/data-table.tsx +18 -18
- package/src/components/ui/dialog.tsx +9 -9
- package/src/components/ui/dropdown-menu.tsx +16 -16
- package/src/components/ui/form.tsx +4 -4
- package/src/components/ui/input.tsx +3 -3
- package/src/components/ui/label.tsx +1 -1
- package/src/components/ui/page-header.tsx +6 -6
- package/src/components/ui/pagination.tsx +6 -6
- package/src/components/ui/popover.tsx +1 -1
- package/src/components/ui/progress.tsx +2 -2
- package/src/components/ui/radio-group.tsx +4 -4
- package/src/components/ui/render-cell.tsx +16 -16
- package/src/components/ui/scroll-area.tsx +6 -6
- package/src/components/ui/select.tsx +14 -14
- package/src/components/ui/separator.tsx +2 -2
- package/src/components/ui/sheet.tsx +13 -13
- package/src/components/ui/sidebar.tsx +60 -60
- package/src/components/ui/skeleton.tsx +1 -1
- package/src/components/ui/sonner.tsx +1 -1
- package/src/components/ui/switch.tsx +2 -2
- package/src/components/ui/table.tsx +7 -7
- package/src/components/ui/tabs.tsx +3 -3
- package/src/components/ui/textarea.tsx +1 -1
- package/src/components/ui/toggle.tsx +6 -6
- package/src/components/ui/tooltip.tsx +1 -1
- package/src/index.css +27 -27
- package/src/index.tsx +4 -4
- package/src/lib/utils.ts +7 -3
- package/src/pages/auth/first-user-page.tsx +18 -18
- package/src/pages/auth/login-page.tsx +14 -14
- package/src/pages/collections/edit-page.tsx +37 -37
- package/src/pages/collections/list-page.tsx +23 -23
- package/src/pages/dashboard/dashboard.tsx +49 -49
- package/src/pages/globals/editor-page.tsx +13 -13
- package/src/pages/media/media-page.tsx +106 -106
- package/src/pages/setup/setup-prompt.tsx +48 -48
- package/tailwind.config.ts +1 -0
- package/vite.config.ts +0 -1
|
@@ -72,40 +72,40 @@ export function GlobalEditorPage() {
|
|
|
72
72
|
if (isGlobalLoading) return <div>Loading global settings...</div>
|
|
73
73
|
|
|
74
74
|
return (
|
|
75
|
-
<div className="space-y-8 max-w-5xl mx-auto">
|
|
76
|
-
<div className="flex items-center justify-between gap-4 border-b border-border/50 pb-6">
|
|
77
|
-
<div className="flex items-center gap-4">
|
|
78
|
-
<div className="p-2 bg-primary/10 text-primary rounded-lg shrink-0">
|
|
79
|
-
<Globe className="h-5 w-5" />
|
|
75
|
+
<div className="dy-space-y-8 dy-max-w-5xl dy-mx-auto">
|
|
76
|
+
<div className="dy-flex dy-items-center dy-justify-between dy-gap-4 dy-border-b dy-border-border/50 dy-pb-6">
|
|
77
|
+
<div className="dy-flex dy-items-center dy-gap-4">
|
|
78
|
+
<div className="dy-p-2 dy-bg-primary/10 dy-text-primary dy-rounded-lg dy-shrink-0">
|
|
79
|
+
<Globe className="dy-h-5 dy-w-5" />
|
|
80
80
|
</div>
|
|
81
81
|
<div>
|
|
82
|
-
<h1 className="text-lg font-serif font-bold tracking-tight text-foreground truncate">
|
|
82
|
+
<h1 className="dy-text-lg dy-font-serif dy-font-bold dy-tracking-tight dy-text-foreground dy-truncate">
|
|
83
83
|
{schema.label || schema.slug}
|
|
84
84
|
</h1>
|
|
85
|
-
<p className="text-[10px] font-bold uppercase tracking-widest text-muted-foreground/40 leading-none mt-1">
|
|
85
|
+
<p className="dy-text-[10px] dy-font-bold dy-uppercase dy-tracking-widest dy-text-muted-foreground/40 dy-leading-none dy-mt-1">
|
|
86
86
|
Global Configuration
|
|
87
87
|
</p>
|
|
88
88
|
</div>
|
|
89
89
|
</div>
|
|
90
90
|
|
|
91
|
-
<div className="flex items-center gap-2">
|
|
91
|
+
<div className="dy-flex dy-items-center dy-gap-2">
|
|
92
92
|
<Button
|
|
93
93
|
size="icon"
|
|
94
|
-
className="h-9 w-9 rounded-lg shadow-sm"
|
|
94
|
+
className="dy-h-9 dy-w-9 dy-rounded-lg dy-shadow-sm"
|
|
95
95
|
onClick={() => document.getElementById('dyrected-form-submit')?.click()}
|
|
96
96
|
disabled={saveMutation.isPending}
|
|
97
97
|
title="Save Changes (⌘S)"
|
|
98
98
|
>
|
|
99
99
|
{saveMutation.isPending ? (
|
|
100
|
-
<div className="h-4 w-4 animate-spin border-2 border-current border-t-transparent rounded-full" />
|
|
100
|
+
<div className="dy-h-4 dy-w-4 dy-animate-spin dy-border-2 dy-border-current dy-border-t-transparent dy-rounded-full" />
|
|
101
101
|
) : (
|
|
102
|
-
<Save className="h-4 w-4" />
|
|
102
|
+
<Save className="dy-h-4 dy-w-4" />
|
|
103
103
|
)}
|
|
104
104
|
</Button>
|
|
105
105
|
</div>
|
|
106
106
|
</div>
|
|
107
107
|
|
|
108
|
-
<div className="animate-in space-y-8 pb-20">
|
|
108
|
+
<div className="dy-animate-in dy-space-y-8 dy-pb-20">
|
|
109
109
|
<FormEngine
|
|
110
110
|
collection={slug!}
|
|
111
111
|
fields={schema.fields}
|
|
@@ -115,7 +115,7 @@ export function GlobalEditorPage() {
|
|
|
115
115
|
onChange={(dirty) => setIsDirty(dirty)}
|
|
116
116
|
submitLabel="Save Changes"
|
|
117
117
|
/>
|
|
118
|
-
<button id="dyrected-form-submit" type="submit" className="hidden" />
|
|
118
|
+
<button id="dyrected-form-submit" type="submit" className="dy-hidden" />
|
|
119
119
|
</div>
|
|
120
120
|
</div>
|
|
121
121
|
)
|
|
@@ -93,41 +93,41 @@ export function MediaPage({ collectionSlug, schema }: { collectionSlug?: string,
|
|
|
93
93
|
})
|
|
94
94
|
|
|
95
95
|
return (
|
|
96
|
-
<div {...getRootProps()} className="min-h-full space-y-8 animate-in relative">
|
|
96
|
+
<div {...getRootProps()} className="dy-min-h-full dy-space-y-8 dy-animate-in dy-relative">
|
|
97
97
|
<input {...getInputProps()} />
|
|
98
98
|
|
|
99
99
|
{isDragActive && (
|
|
100
|
-
<div className="absolute inset-0 z-50 bg-primary/10 backdrop-blur-[2px] border-4 border-dashed border-primary rounded-2xl flex items-center justify-center pointer-events-none">
|
|
101
|
-
<div className="bg-white p-8 rounded-2xl shadow-2xl flex flex-col items-center gap-4">
|
|
102
|
-
<div className="h-16 w-16 rounded-full bg-primary/10 flex items-center justify-center">
|
|
103
|
-
<Upload className="h-8 w-8 text-primary animate-bounce" />
|
|
100
|
+
<div className="dy-absolute dy-inset-0 dy-z-50 dy-bg-primary/10 dy-backdrop-blur-[2px] dy-border-4 dy-border-dashed dy-border-primary dy-rounded-2xl dy-flex dy-items-center dy-justify-center dy-pointer-events-none">
|
|
101
|
+
<div className="dy-bg-white dy-p-8 dy-rounded-2xl dy-shadow-2xl dy-flex dy-flex-col dy-items-center dy-gap-4">
|
|
102
|
+
<div className="dy-h-16 dy-w-16 dy-rounded-full dy-bg-primary/10 dy-flex dy-items-center dy-justify-center">
|
|
103
|
+
<Upload className="dy-h-8 dy-w-8 dy-text-primary dy-animate-bounce" />
|
|
104
104
|
</div>
|
|
105
|
-
<p className="text-xl font-bold">Drop to upload assets</p>
|
|
105
|
+
<p className="dy-text-xl dy-font-bold">Drop to upload assets</p>
|
|
106
106
|
</div>
|
|
107
107
|
</div>
|
|
108
108
|
)}
|
|
109
|
-
<div className="flex items-end justify-between border-b border-border/50 pb-6">
|
|
109
|
+
<div className="dy-flex dy-items-end dy-justify-between dy-border-b dy-border-border/50 dy-pb-6">
|
|
110
110
|
<div>
|
|
111
|
-
<div className="flex items-center gap-2 mb-1">
|
|
112
|
-
<ImageIcon className="h-5 w-5 text-primary" />
|
|
113
|
-
<h1 className="text-3xl font-bold tracking-tight text-foreground">
|
|
111
|
+
<div className="dy-flex dy-items-center dy-gap-2 dy-mb-1">
|
|
112
|
+
<ImageIcon className="dy-h-5 dy-w-5 dy-text-primary" />
|
|
113
|
+
<h1 className="dy-text-3xl dy-font-bold dy-tracking-tight dy-text-foreground">
|
|
114
114
|
{schema?.labels?.plural ?? schema?.label ?? "Media Library"}
|
|
115
115
|
</h1>
|
|
116
116
|
</div>
|
|
117
|
-
<p className="text-sm text-muted-foreground">
|
|
117
|
+
<p className="dy-text-sm dy-text-muted-foreground">
|
|
118
118
|
Manage your images, documents, and other assets for this site.
|
|
119
119
|
</p>
|
|
120
120
|
</div>
|
|
121
121
|
<Dialog open={isUploadOpen} onOpenChange={setIsUploadOpen}>
|
|
122
122
|
<DialogTrigger asChild>
|
|
123
|
-
<Button className="h-10 px-4 rounded-lg bg-primary hover:bg-primary/90 shadow-md transition-all active:scale-95">
|
|
124
|
-
<Upload className="mr-2 h-4 w-4" />
|
|
123
|
+
<Button className="dy-h-10 dy-px-4 dy-rounded-lg dy-bg-primary hover:dy-bg-primary/90 dy-shadow-md dy-transition-all active:dy-scale-95">
|
|
124
|
+
<Upload className="dy-mr-2 dy-h-4 dy-w-4" />
|
|
125
125
|
Upload Assets
|
|
126
126
|
</Button>
|
|
127
127
|
</DialogTrigger>
|
|
128
|
-
<DialogContent className="sm:max-w-[600px] rounded-2xl overflow-hidden border-none shadow-2xl">
|
|
129
|
-
<DialogHeader className="pb-4 border-b border-border/40">
|
|
130
|
-
<DialogTitle className="text-xl font-bold">Upload Media Assets</DialogTitle>
|
|
128
|
+
<DialogContent className="sm:dy-max-w-[600px] dy-rounded-2xl dy-overflow-hidden dy-border-none dy-shadow-2xl">
|
|
129
|
+
<DialogHeader className="dy-pb-4 dy-border-b dy-border-border/40">
|
|
130
|
+
<DialogTitle className="dy-text-xl dy-font-bold">Upload Media Assets</DialogTitle>
|
|
131
131
|
</DialogHeader>
|
|
132
132
|
<FileUploader
|
|
133
133
|
collectionSlug={collectionSlug}
|
|
@@ -140,35 +140,35 @@ export function MediaPage({ collectionSlug, schema }: { collectionSlug?: string,
|
|
|
140
140
|
</Dialog>
|
|
141
141
|
</div>
|
|
142
142
|
|
|
143
|
-
<div className="flex items-center gap-4">
|
|
144
|
-
<div className="relative flex-1 max-w-sm">
|
|
145
|
-
<Search className="absolute left-3 top-1/2
|
|
143
|
+
<div className="dy-flex dy-items-center dy-gap-4">
|
|
144
|
+
<div className="dy-relative dy-flex-1 dy-max-w-sm">
|
|
145
|
+
<Search className="dy-absolute dy-left-3 dy-top-1/2 dy--translate-y-1/2 dy-h-4 dy-w-4 dy-text-muted-foreground/60" />
|
|
146
146
|
<Input
|
|
147
147
|
placeholder="Search assets by filename..."
|
|
148
|
-
className="pl-10 h-11 bg-white border-border/60 rounded-xl shadow-sm focus-visible:ring-primary/20"
|
|
148
|
+
className="dy-pl-10 dy-h-11 dy-bg-white dy-border-border/60 dy-rounded-xl dy-shadow-sm focus-visible:dy-ring-primary/20"
|
|
149
149
|
value={search}
|
|
150
150
|
onChange={(e) => setSearch(e.target.value)}
|
|
151
151
|
/>
|
|
152
152
|
</div>
|
|
153
153
|
</div>
|
|
154
154
|
|
|
155
|
-
<ScrollArea className="h-[calc(100vh-320px)] pr-4">
|
|
155
|
+
<ScrollArea className="dy-h-[calc(100vh-320px)] dy-pr-4">
|
|
156
156
|
{isLoading ? (
|
|
157
|
-
<div className="flex h-60 items-center justify-center">
|
|
158
|
-
<div className="animate-spin rounded-full border-4 border-primary/20 border-t-primary h-10 w-10"></div>
|
|
157
|
+
<div className="dy-flex dy-h-60 dy-items-center dy-justify-center">
|
|
158
|
+
<div className="dy-animate-spin dy-rounded-full dy-border-4 dy-border-primary/20 dy-border-t-primary dy-h-10 dy-w-10"></div>
|
|
159
159
|
</div>
|
|
160
160
|
) : mediaResponse?.length === 0 ? (
|
|
161
|
-
<div className="flex h-80 flex-col items-center justify-center rounded-2xl border-2 border-dashed border-border/60 bg-muted/5 text-center animate-in">
|
|
162
|
-
<div className="h-16 w-16 rounded-2xl bg-muted/40 flex items-center justify-center mb-4">
|
|
163
|
-
<FileIcon className="h-8 w-8 text-muted-foreground/50" />
|
|
161
|
+
<div className="dy-flex dy-h-80 dy-flex-col dy-items-center dy-justify-center dy-rounded-2xl dy-border-2 dy-border-dashed dy-border-border/60 dy-bg-muted/5 dy-text-center dy-animate-in">
|
|
162
|
+
<div className="dy-h-16 dy-w-16 dy-rounded-2xl dy-bg-muted/40 dy-flex dy-items-center dy-justify-center dy-mb-4">
|
|
163
|
+
<FileIcon className="dy-h-8 dy-w-8 dy-text-muted-foreground/50" />
|
|
164
164
|
</div>
|
|
165
|
-
<h3 className="text-lg font-bold text-foreground">No assets found</h3>
|
|
166
|
-
<p className="text-sm text-muted-foreground max-w-xs mx-auto">
|
|
165
|
+
<h3 className="dy-text-lg dy-font-bold dy-text-foreground">No assets found</h3>
|
|
166
|
+
<p className="dy-text-sm dy-text-muted-foreground dy-max-w-xs dy-mx-auto">
|
|
167
167
|
Your media library is empty. Upload some files to start building your content.
|
|
168
168
|
</p>
|
|
169
169
|
</div>
|
|
170
170
|
) : (
|
|
171
|
-
<div className="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 xl:grid-cols-5 2xl:grid-cols-6 gap-6 pb-8">
|
|
171
|
+
<div className="dy-grid dy-grid-cols-2 md:dy-grid-cols-3 lg:dy-grid-cols-4 xl:dy-grid-cols-5 2xl:dy-grid-cols-6 dy-gap-6 dy-pb-8">
|
|
172
172
|
{mediaResponse?.map((item) => (
|
|
173
173
|
<MediaCard
|
|
174
174
|
key={item.id}
|
|
@@ -206,17 +206,17 @@ function MediaCard({ item, baseUrl, onDelete, onClick, isSelected }: {
|
|
|
206
206
|
return (
|
|
207
207
|
<Card
|
|
208
208
|
className={cn(
|
|
209
|
-
"overflow-hidden group relative border-border/40 bg-white shadow-sm hover:shadow-xl transition-all duration-300 rounded-xl cursor-pointer",
|
|
210
|
-
isSelected && "ring-2 ring-primary ring-offset-2 shadow-lg scale-[0.98]"
|
|
209
|
+
"dy-overflow-hidden dy-group dy-relative dy-border-border/40 dy-bg-white dy-shadow-sm hover:dy-shadow-xl dy-transition-all dy-duration-300 dy-rounded-xl dy-cursor-pointer",
|
|
210
|
+
isSelected && "dy-ring-2 dy-ring-primary dy-ring-offset-2 dy-shadow-lg dy-scale-[0.98]"
|
|
211
211
|
)}
|
|
212
212
|
onClick={onClick}
|
|
213
213
|
>
|
|
214
|
-
<CardHeader className="p-0 border-b border-border/10">
|
|
215
|
-
<AspectRatio ratio={1 / 1} className="bg-muted/30 overflow-hidden relative">
|
|
214
|
+
<CardHeader className="dy-p-0 dy-border-b dy-border-border/10">
|
|
215
|
+
<AspectRatio ratio={1 / 1} className="dy-bg-muted/30 dy-overflow-hidden dy-relative">
|
|
216
216
|
{isImage ? (
|
|
217
217
|
<>
|
|
218
218
|
{item.blurhash && (
|
|
219
|
-
<div className="absolute inset-0 z-0">
|
|
219
|
+
<div className="dy-absolute dy-inset-0 dy-z-0">
|
|
220
220
|
<Blurhash
|
|
221
221
|
hash={item.blurhash}
|
|
222
222
|
width="100%"
|
|
@@ -230,35 +230,35 @@ function MediaCard({ item, baseUrl, onDelete, onClick, isSelected }: {
|
|
|
230
230
|
<img
|
|
231
231
|
src={url}
|
|
232
232
|
alt={item.filename}
|
|
233
|
-
className="object-cover w-full h-full transition-transform duration-500 group-hover:scale-110 relative z-10"
|
|
233
|
+
className="dy-object-cover dy-w-full dy-h-full dy-transition-transform dy-duration-500 dy-group-hover:dy-scale-110 dy-relative dy-z-10"
|
|
234
234
|
loading="lazy"
|
|
235
235
|
/>
|
|
236
236
|
</>
|
|
237
237
|
) : (
|
|
238
|
-
<div className="flex items-center justify-center h-full bg-primary/5">
|
|
239
|
-
<FileIcon className="h-10 w-10 text-primary/40" />
|
|
238
|
+
<div className="dy-flex dy-items-center dy-justify-center dy-h-full dy-bg-primary/5">
|
|
239
|
+
<FileIcon className="dy-h-10 dy-w-10 dy-text-primary/40" />
|
|
240
240
|
</div>
|
|
241
241
|
)}
|
|
242
242
|
</AspectRatio>
|
|
243
243
|
</CardHeader>
|
|
244
|
-
<CardContent className="p-3 bg-white">
|
|
245
|
-
<p className="text-[11px] font-bold truncate text-foreground/90 mb-0.5" title={item.filename}>
|
|
244
|
+
<CardContent className="dy-p-3 dy-bg-white">
|
|
245
|
+
<p className="dy-text-[11px] dy-font-bold dy-truncate dy-text-foreground/90 dy-mb-0.5" title={item.filename}>
|
|
246
246
|
{item.filename}
|
|
247
247
|
</p>
|
|
248
|
-
<div className="flex items-center justify-between">
|
|
249
|
-
<p className="text-[9px] text-muted-foreground font-bold uppercase tracking-wider">
|
|
248
|
+
<div className="dy-flex dy-items-center dy-justify-between">
|
|
249
|
+
<p className="dy-text-[9px] dy-text-muted-foreground dy-font-bold dy-uppercase dy-tracking-wider">
|
|
250
250
|
{item.mimeType?.split("/")[1] || "file"}
|
|
251
251
|
</p>
|
|
252
|
-
<p className="text-[9px] text-muted-foreground font-medium">
|
|
252
|
+
<p className="dy-text-[9px] dy-text-muted-foreground dy-font-medium">
|
|
253
253
|
{((item.filesize || item.size || 0) / 1024).toFixed(1)} KB
|
|
254
254
|
</p>
|
|
255
255
|
</div>
|
|
256
256
|
</CardContent>
|
|
257
|
-
<div className="absolute top-2 right-2 flex gap-2 opacity-0 group-hover:opacity-100 transition-opacity">
|
|
257
|
+
<div className="dy-absolute dy-top-2 dy-right-2 dy-flex dy-gap-2 dy-opacity-0 dy-group-hover:dy-opacity-100 dy-transition-opacity">
|
|
258
258
|
<Button
|
|
259
259
|
size="icon"
|
|
260
260
|
variant="destructive"
|
|
261
|
-
className="h-7 w-7 rounded-lg shadow-lg"
|
|
261
|
+
className="dy-h-7 dy-w-7 dy-rounded-lg dy-shadow-lg"
|
|
262
262
|
onClick={(e) => {
|
|
263
263
|
e.stopPropagation()
|
|
264
264
|
if (confirm("Are you sure you want to delete this file?")) {
|
|
@@ -266,7 +266,7 @@ function MediaCard({ item, baseUrl, onDelete, onClick, isSelected }: {
|
|
|
266
266
|
}
|
|
267
267
|
}}
|
|
268
268
|
>
|
|
269
|
-
<Trash2 className="h-3.5 w-3.5" />
|
|
269
|
+
<Trash2 className="dy-h-3.5 dy-w-3.5" />
|
|
270
270
|
</Button>
|
|
271
271
|
</div>
|
|
272
272
|
</Card>
|
|
@@ -313,22 +313,22 @@ function MediaSidebar({ item, onClose, baseUrl, onUpdate }: {
|
|
|
313
313
|
|
|
314
314
|
return (
|
|
315
315
|
<Sheet open={!!item} onOpenChange={onClose}>
|
|
316
|
-
<SheetContent className="sm:max-w-md p-0 flex flex-col h-full border-l border-border/40 bg-white shadow-2xl">
|
|
317
|
-
<SheetHeader className="p-6 border-b border-border/40 bg-white">
|
|
318
|
-
<SheetTitle className="flex items-center gap-2">
|
|
319
|
-
<Info className="h-5 w-5 text-primary" />
|
|
316
|
+
<SheetContent className="sm:dy-max-w-md dy-p-0 dy-flex dy-flex-col dy-h-full dy-border-l dy-border-border/40 dy-bg-white dy-shadow-2xl">
|
|
317
|
+
<SheetHeader className="dy-p-6 dy-border-b dy-border-border/40 dy-bg-white">
|
|
318
|
+
<SheetTitle className="dy-flex dy-items-center dy-gap-2">
|
|
319
|
+
<Info className="dy-h-5 dy-w-5 dy-text-primary" />
|
|
320
320
|
File Details
|
|
321
321
|
</SheetTitle>
|
|
322
322
|
</SheetHeader>
|
|
323
323
|
|
|
324
|
-
<ScrollArea className="flex-1 bg-white">
|
|
325
|
-
<div className="p-6 space-y-8">
|
|
326
|
-
<div className="rounded-xl overflow-hidden border border-border/40 bg-muted/10 relative shadow-inner">
|
|
324
|
+
<ScrollArea className="dy-flex-1 dy-bg-white">
|
|
325
|
+
<div className="dy-p-6 dy-space-y-8">
|
|
326
|
+
<div className="dy-rounded-xl dy-overflow-hidden dy-border dy-border-border/40 dy-bg-muted/10 dy-relative dy-shadow-inner">
|
|
327
327
|
<AspectRatio ratio={16 / 9}>
|
|
328
328
|
{isImage ? (
|
|
329
329
|
<>
|
|
330
330
|
{item.blurhash && (
|
|
331
|
-
<div className="absolute inset-0 z-0">
|
|
331
|
+
<div className="dy-absolute dy-inset-0 dy-z-0">
|
|
332
332
|
<Blurhash
|
|
333
333
|
hash={item.blurhash}
|
|
334
334
|
width="100%"
|
|
@@ -339,49 +339,49 @@ function MediaSidebar({ item, onClose, baseUrl, onUpdate }: {
|
|
|
339
339
|
/>
|
|
340
340
|
</div>
|
|
341
341
|
)}
|
|
342
|
-
<img src={url} alt={item.filename} className="object-contain w-full h-full bg-checkered relative z-10" />
|
|
342
|
+
<img src={url} alt={item.filename} className="dy-object-contain dy-w-full dy-h-full dy-bg-checkered dy-relative dy-z-10" />
|
|
343
343
|
</>
|
|
344
344
|
) : (
|
|
345
|
-
<div className="flex items-center justify-center h-full">
|
|
346
|
-
<FileIcon className="h-16 w-16 text-muted-foreground/30" />
|
|
345
|
+
<div className="dy-flex dy-items-center dy-justify-center dy-h-full">
|
|
346
|
+
<FileIcon className="dy-h-16 dy-w-16 dy-text-muted-foreground/30" />
|
|
347
347
|
</div>
|
|
348
348
|
)}
|
|
349
349
|
</AspectRatio>
|
|
350
350
|
</div>
|
|
351
351
|
|
|
352
|
-
<div className="space-y-6">
|
|
353
|
-
<div className="space-y-4">
|
|
354
|
-
<div className="space-y-2">
|
|
355
|
-
<label className="text-[10px] font-bold uppercase tracking-widest text-muted-foreground/80">Filename</label>
|
|
352
|
+
<div className="dy-space-y-6">
|
|
353
|
+
<div className="dy-space-y-4">
|
|
354
|
+
<div className="dy-space-y-2">
|
|
355
|
+
<label className="dy-text-[10px] dy-font-bold dy-uppercase dy-tracking-widest dy-text-muted-foreground/80">Filename</label>
|
|
356
356
|
<Input
|
|
357
357
|
value={formData.filename}
|
|
358
358
|
onChange={(e) => setFormData({ ...formData, filename: e.target.value })}
|
|
359
|
-
className="h-10 rounded-lg bg-white border-border/60 focus:ring-1 focus:ring-primary/20"
|
|
359
|
+
className="dy-h-10 dy-rounded-lg dy-bg-white dy-border-border/60 focus:dy-ring-1 focus:dy-ring-primary/20"
|
|
360
360
|
/>
|
|
361
361
|
</div>
|
|
362
|
-
<div className="space-y-2">
|
|
363
|
-
<label className="text-[10px] font-bold uppercase tracking-widest text-muted-foreground/80">Alt Text</label>
|
|
362
|
+
<div className="dy-space-y-2">
|
|
363
|
+
<label className="dy-text-[10px] dy-font-bold dy-uppercase dy-tracking-widest dy-text-muted-foreground/80">Alt Text</label>
|
|
364
364
|
<Input
|
|
365
365
|
value={formData.alt}
|
|
366
366
|
onChange={(e) => setFormData({ ...formData, alt: e.target.value })}
|
|
367
367
|
placeholder="Describe the image for accessibility..."
|
|
368
|
-
className="h-10 rounded-lg bg-white border-border/60 focus:ring-1 focus:ring-primary/20"
|
|
368
|
+
className="dy-h-10 dy-rounded-lg dy-bg-white dy-border-border/60 focus:dy-ring-1 focus:dy-ring-primary/20"
|
|
369
369
|
/>
|
|
370
370
|
</div>
|
|
371
|
-
<div className="space-y-2">
|
|
372
|
-
<label className="text-[10px] font-bold uppercase tracking-widest text-muted-foreground/80">Caption</label>
|
|
371
|
+
<div className="dy-space-y-2">
|
|
372
|
+
<label className="dy-text-[10px] dy-font-bold dy-uppercase dy-tracking-widest dy-text-muted-foreground/80">Caption</label>
|
|
373
373
|
<textarea
|
|
374
374
|
value={formData.caption}
|
|
375
375
|
onChange={(e) => setFormData({ ...formData, caption: e.target.value })}
|
|
376
376
|
placeholder="Add a caption..."
|
|
377
|
-
className="flex min-h-[80px] w-full rounded-lg border border-border/60 bg-white px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-primary/20 disabled:cursor-not-allowed disabled:opacity-50"
|
|
377
|
+
className="dy-flex dy-min-h-[80px] dy-w-full dy-rounded-lg dy-border dy-border-border/60 dy-bg-white dy-px-3 dy-py-2 dy-text-sm dy-ring-offset-background placeholder:dy-text-muted-foreground focus-visible:dy-outline-none focus-visible:dy-ring-1 focus-visible:dy-ring-primary/20 disabled:dy-cursor-not-allowed disabled:dy-opacity-50"
|
|
378
378
|
/>
|
|
379
379
|
</div>
|
|
380
380
|
</div>
|
|
381
381
|
|
|
382
|
-
<Separator className="bg-border/40" />
|
|
382
|
+
<Separator className="dy-bg-border/40" />
|
|
383
383
|
|
|
384
|
-
<div className="grid grid-cols-2 gap-6">
|
|
384
|
+
<div className="dy-grid dy-grid-cols-2 dy-gap-6">
|
|
385
385
|
<DetailItem label="File ID" value={item.id} copyable />
|
|
386
386
|
<DetailItem label="Size" value={`${((item.filesize || item.size || 0) / 1024).toFixed(1)} KB`} />
|
|
387
387
|
<DetailItem label="Type" value={item.mimeType || "Unknown"} />
|
|
@@ -393,10 +393,10 @@ function MediaSidebar({ item, onClose, baseUrl, onUpdate }: {
|
|
|
393
393
|
</div>
|
|
394
394
|
|
|
395
395
|
{/* {isImage && (
|
|
396
|
-
<div className="space-y-4">
|
|
397
|
-
<Separator className="bg-border/40" />
|
|
398
|
-
<div className="space-y-4">
|
|
399
|
-
<label className="text-[10px] font-bold uppercase tracking-widest text-muted-foreground/80">Focal Point</label>
|
|
396
|
+
<div className="dy-space-y-4">
|
|
397
|
+
<Separator className="dy-bg-border/40" />
|
|
398
|
+
<div className="dy-space-y-4">
|
|
399
|
+
<label className="dy-text-[10px] dy-font-bold dy-uppercase dy-tracking-widest dy-text-muted-foreground/80">Focal Point</label>
|
|
400
400
|
<FocalPointPicker
|
|
401
401
|
url={url}
|
|
402
402
|
value={item.focalPoint}
|
|
@@ -410,19 +410,19 @@ function MediaSidebar({ item, onClose, baseUrl, onUpdate }: {
|
|
|
410
410
|
</div>
|
|
411
411
|
</ScrollArea>
|
|
412
412
|
|
|
413
|
-
<div className="p-6 border-t border-border/40 bg-muted/5 space-y-3">
|
|
413
|
+
<div className="dy-p-6 dy-border-t dy-border-border/40 dy-bg-muted/5 dy-space-y-3">
|
|
414
414
|
{hasChanges && (
|
|
415
415
|
<Button
|
|
416
|
-
className="w-full h-12 rounded-xl font-bold bg-primary text-white shadow-lg shadow-primary/20 animate-in fade-in slide-in-from-bottom-2"
|
|
416
|
+
className="dy-w-full dy-h-12 dy-rounded-xl dy-font-bold dy-bg-primary dy-text-white dy-shadow-lg dy-shadow-primary/20 dy-animate-in dy-fade-in dy-slide-in-from-bottom-2"
|
|
417
417
|
onClick={handleSave}
|
|
418
418
|
disabled={isSaving}
|
|
419
419
|
>
|
|
420
420
|
{isSaving ? "Saving..." : "Save Changes"}
|
|
421
421
|
</Button>
|
|
422
422
|
)}
|
|
423
|
-
<Button className="w-full h-11 rounded-xl font-bold gap-2 bg-white" variant="outline" asChild>
|
|
423
|
+
<Button className="dy-w-full dy-h-11 dy-rounded-xl dy-font-bold dy-gap-2 dy-bg-white" variant="outline" asChild>
|
|
424
424
|
<a href={url} target="_blank" rel="noreferrer">
|
|
425
|
-
<ExternalLink className="h-4 w-4" />
|
|
425
|
+
<ExternalLink className="dy-h-4 dy-w-4" />
|
|
426
426
|
Open Original
|
|
427
427
|
</a>
|
|
428
428
|
</Button>
|
|
@@ -438,18 +438,18 @@ function DetailItem({ label, value, copyable }: {
|
|
|
438
438
|
copyable?: boolean
|
|
439
439
|
}) {
|
|
440
440
|
return (
|
|
441
|
-
<div className="space-y-1.5">
|
|
442
|
-
<label className="text-[10px] font-bold uppercase tracking-widest text-muted-foreground/80">{label}</label>
|
|
443
|
-
<div className="flex items-center gap-2 group">
|
|
444
|
-
<p className="text-sm font-medium text-foreground truncate flex-1">{value}</p>
|
|
441
|
+
<div className="dy-space-y-1.5">
|
|
442
|
+
<label className="dy-text-[10px] dy-font-bold dy-uppercase dy-tracking-widest dy-text-muted-foreground/80">{label}</label>
|
|
443
|
+
<div className="dy-flex dy-items-center dy-gap-2 dy-group">
|
|
444
|
+
<p className="dy-text-sm dy-font-medium dy-text-foreground dy-truncate dy-flex-1">{value}</p>
|
|
445
445
|
{copyable && (
|
|
446
446
|
<Button
|
|
447
447
|
size="icon"
|
|
448
448
|
variant="ghost"
|
|
449
|
-
className="h-7 w-7 text-muted-foreground hover:text-primary transition-colors"
|
|
449
|
+
className="dy-h-7 dy-w-7 dy-text-muted-foreground hover:dy-text-primary dy-transition-colors"
|
|
450
450
|
onClick={() => navigator.clipboard.writeText(value)}
|
|
451
451
|
>
|
|
452
|
-
<Copy className="h-3.5 w-3.5" />
|
|
452
|
+
<Copy className="dy-h-3.5 dy-w-3.5" />
|
|
453
453
|
</Button>
|
|
454
454
|
)}
|
|
455
455
|
</div>
|
|
@@ -492,7 +492,7 @@ function FileUploader({ collectionSlug, onComplete }: { collectionSlug?: string,
|
|
|
492
492
|
}
|
|
493
493
|
|
|
494
494
|
return (
|
|
495
|
-
<div className="space-y-6 py-6 px-4">
|
|
495
|
+
<div className="dy-space-y-6 dy-py-6 dy-px-4">
|
|
496
496
|
<div
|
|
497
497
|
{...getRootProps()}
|
|
498
498
|
className={`border-2 border-dashed rounded-2xl p-12 text-center cursor-pointer transition-all duration-300 ${isDragActive
|
|
@@ -501,32 +501,32 @@ function FileUploader({ collectionSlug, onComplete }: { collectionSlug?: string,
|
|
|
501
501
|
}`}
|
|
502
502
|
>
|
|
503
503
|
<input {...getInputProps()} />
|
|
504
|
-
<div className="h-16 w-16 rounded-2xl bg-primary/10 flex items-center justify-center mx-auto mb-4">
|
|
505
|
-
<Upload className="h-8 w-8 text-primary" />
|
|
504
|
+
<div className="dy-h-16 dy-w-16 dy-rounded-2xl dy-bg-primary/10 dy-flex dy-items-center dy-justify-center dy-mx-auto dy-mb-4">
|
|
505
|
+
<Upload className="dy-h-8 dy-w-8 dy-text-primary" />
|
|
506
506
|
</div>
|
|
507
|
-
<p className="text-xl font-bold text-foreground">Drag & drop assets</p>
|
|
508
|
-
<p className="text-sm text-muted-foreground mt-1">or click to browse your files</p>
|
|
507
|
+
<p className="dy-text-xl dy-font-bold dy-text-foreground">Drag & drop assets</p>
|
|
508
|
+
<p className="dy-text-sm dy-text-muted-foreground dy-mt-1">or click to browse your files</p>
|
|
509
509
|
</div>
|
|
510
510
|
|
|
511
511
|
{files.length > 0 && (
|
|
512
|
-
<div className="space-y-4 animate-in fade-in slide-in-from-bottom-4">
|
|
513
|
-
<div className="flex items-center justify-between">
|
|
514
|
-
<p className="text-sm font-bold text-foreground">{files.length} assets selected</p>
|
|
515
|
-
<Button variant="ghost" size="sm" onClick={() => setFiles([])} disabled={uploading} className="text-xs h-8">
|
|
512
|
+
<div className="dy-space-y-4 dy-animate-in dy-fade-in dy-slide-in-from-bottom-4">
|
|
513
|
+
<div className="dy-flex dy-items-center dy-justify-between">
|
|
514
|
+
<p className="dy-text-sm dy-font-bold dy-text-foreground">{files.length} assets selected</p>
|
|
515
|
+
<Button variant="ghost" size="sm" onClick={() => setFiles([])} disabled={uploading} className="dy-text-xs dy-h-8">
|
|
516
516
|
Clear All
|
|
517
517
|
</Button>
|
|
518
518
|
</div>
|
|
519
519
|
|
|
520
|
-
<div className="max-h-[240px] overflow-auto space-y-2 pr-2 custom-scrollbar">
|
|
520
|
+
<div className="dy-max-h-[240px] dy-overflow-auto dy-space-y-2 dy-pr-2 dy-custom-scrollbar">
|
|
521
521
|
{files.map((file, idx) => (
|
|
522
|
-
<div key={idx} className="flex items-center justify-between p-3 bg-muted/30 border border-border/40 rounded-xl text-sm group transition-colors hover:bg-muted/50">
|
|
523
|
-
<div className="flex items-center gap-3 truncate">
|
|
524
|
-
<div className="h-8 w-8 rounded-lg bg-white border border-border/60 flex items-center justify-center flex-shrink-0">
|
|
525
|
-
<FileIcon className="h-4 w-4 text-muted-foreground" />
|
|
522
|
+
<div key={idx} className="dy-flex dy-items-center dy-justify-between dy-p-3 dy-bg-muted/30 dy-border dy-border-border/40 dy-rounded-xl dy-text-sm dy-group dy-transition-colors hover:dy-bg-muted/50">
|
|
523
|
+
<div className="dy-flex dy-items-center dy-gap-3 dy-truncate">
|
|
524
|
+
<div className="dy-h-8 dy-w-8 dy-rounded-lg dy-bg-white dy-border dy-border-border/60 dy-flex dy-items-center dy-justify-center dy-flex-shrink-0">
|
|
525
|
+
<FileIcon className="dy-h-4 dy-w-4 dy-text-muted-foreground" />
|
|
526
526
|
</div>
|
|
527
|
-
<span className="truncate font-medium text-foreground/80">{file.name}</span>
|
|
527
|
+
<span className="dy-truncate dy-font-medium dy-text-foreground/80">{file.name}</span>
|
|
528
528
|
</div>
|
|
529
|
-
<span className="text-muted-foreground text-[10px] font-bold bg-white px-2 py-1 rounded border border-border/40 ml-4">
|
|
529
|
+
<span className="dy-text-muted-foreground dy-text-[10px] dy-font-bold dy-bg-white dy-px-2 dy-py-1 dy-rounded dy-border dy-border-border/40 dy-ml-4">
|
|
530
530
|
{(file.size / 1024).toFixed(1)} KB
|
|
531
531
|
</span>
|
|
532
532
|
</div>
|
|
@@ -534,24 +534,24 @@ function FileUploader({ collectionSlug, onComplete }: { collectionSlug?: string,
|
|
|
534
534
|
</div>
|
|
535
535
|
|
|
536
536
|
{uploading && (
|
|
537
|
-
<div className="space-y-2 pt-2">
|
|
538
|
-
<div className="flex justify-between text-[11px] font-bold uppercase tracking-wider text-muted-foreground">
|
|
537
|
+
<div className="dy-space-y-2 dy-pt-2">
|
|
538
|
+
<div className="dy-flex dy-justify-between dy-text-[11px] dy-font-bold dy-uppercase dy-tracking-wider dy-text-muted-foreground">
|
|
539
539
|
<span>Uploading...</span>
|
|
540
540
|
<span>{Math.round(progress)}%</span>
|
|
541
541
|
</div>
|
|
542
|
-
<Progress value={progress} className="h-2 rounded-full" />
|
|
542
|
+
<Progress value={progress} className="dy-h-2 dy-rounded-full" />
|
|
543
543
|
</div>
|
|
544
544
|
)}
|
|
545
545
|
|
|
546
|
-
<div className="flex justify-end pt-4 border-t border-border/40">
|
|
546
|
+
<div className="dy-flex dy-justify-end dy-pt-4 dy-border-t dy-border-border/40">
|
|
547
547
|
<Button
|
|
548
548
|
onClick={handleUpload}
|
|
549
549
|
disabled={uploading || files.length === 0}
|
|
550
|
-
className="w-full h-12 rounded-xl bg-primary hover:bg-primary/90 text-white font-bold shadow-lg shadow-primary/20 transition-all active:scale-[0.98]"
|
|
550
|
+
className="dy-w-full dy-h-12 dy-rounded-xl dy-bg-primary hover:dy-bg-primary/90 dy-text-white dy-font-bold dy-shadow-lg dy-shadow-primary/20 dy-transition-all active:dy-scale-[0.98]"
|
|
551
551
|
>
|
|
552
552
|
{uploading ? (
|
|
553
|
-
<span className="flex items-center gap-2">
|
|
554
|
-
<div className="h-4 w-4 border-2 border-white/30 border-t-white rounded-full animate-spin" />
|
|
553
|
+
<span className="dy-flex dy-items-center dy-gap-2">
|
|
554
|
+
<div className="dy-h-4 dy-w-4 dy-border-2 dy-border-white/30 dy-border-t-white dy-rounded-full dy-animate-spin" />
|
|
555
555
|
Uploading Assets...
|
|
556
556
|
</span>
|
|
557
557
|
) : `Upload ${files.length} Assets`}
|