@object-ui/plugin-detail 2.0.0 → 3.0.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/.turbo/turbo-build.log +8 -8
- package/CHANGELOG.md +20 -0
- package/dist/index.js +19953 -19684
- package/dist/index.umd.cjs +35 -26
- package/dist/plugin-detail.css +1 -1
- package/dist/src/DetailSection.d.ts.map +1 -1
- package/dist/src/DetailView.d.ts.map +1 -1
- package/dist/src/DetailView.stories.d.ts +37 -0
- package/dist/src/DetailView.stories.d.ts.map +1 -0
- package/package.json +8 -8
- package/src/DetailSection.tsx +113 -22
- package/src/DetailView.stories.tsx +258 -0
- package/src/DetailView.tsx +177 -42
package/src/DetailView.tsx
CHANGED
|
@@ -7,8 +7,32 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import * as React from 'react';
|
|
10
|
-
import {
|
|
11
|
-
|
|
10
|
+
import {
|
|
11
|
+
cn,
|
|
12
|
+
Button,
|
|
13
|
+
Skeleton,
|
|
14
|
+
DropdownMenu,
|
|
15
|
+
DropdownMenuContent,
|
|
16
|
+
DropdownMenuItem,
|
|
17
|
+
DropdownMenuSeparator,
|
|
18
|
+
DropdownMenuTrigger,
|
|
19
|
+
Tooltip,
|
|
20
|
+
TooltipContent,
|
|
21
|
+
TooltipProvider,
|
|
22
|
+
TooltipTrigger,
|
|
23
|
+
} from '@object-ui/components';
|
|
24
|
+
import {
|
|
25
|
+
ArrowLeft,
|
|
26
|
+
Edit,
|
|
27
|
+
Trash2,
|
|
28
|
+
MoreHorizontal,
|
|
29
|
+
Share2,
|
|
30
|
+
Copy,
|
|
31
|
+
Download,
|
|
32
|
+
History,
|
|
33
|
+
Star,
|
|
34
|
+
StarOff,
|
|
35
|
+
} from 'lucide-react';
|
|
12
36
|
import { DetailSection } from './DetailSection';
|
|
13
37
|
import { DetailTabs } from './DetailTabs';
|
|
14
38
|
import { RelatedList } from './RelatedList';
|
|
@@ -34,6 +58,7 @@ export const DetailView: React.FC<DetailViewProps> = ({
|
|
|
34
58
|
}) => {
|
|
35
59
|
const [data, setData] = React.useState<any>(schema.data);
|
|
36
60
|
const [loading, setLoading] = React.useState(!schema.data && !!((schema.api && schema.resourceId) || (dataSource && schema.objectName && schema.resourceId)));
|
|
61
|
+
const [isFavorite, setIsFavorite] = React.useState(false);
|
|
37
62
|
|
|
38
63
|
// Fetch data if API or DataSource provided
|
|
39
64
|
React.useEffect(() => {
|
|
@@ -108,6 +133,41 @@ export const DetailView: React.FC<DetailViewProps> = ({
|
|
|
108
133
|
}
|
|
109
134
|
}, [onDelete, schema]);
|
|
110
135
|
|
|
136
|
+
const handleShare = React.useCallback(() => {
|
|
137
|
+
// Share functionality - could trigger share dialog or copy link
|
|
138
|
+
if (navigator.share && schema.objectName && schema.resourceId) {
|
|
139
|
+
navigator.share({
|
|
140
|
+
title: schema.title || 'Record Details',
|
|
141
|
+
text: `${schema.objectName} #${schema.resourceId}`,
|
|
142
|
+
url: window.location.href,
|
|
143
|
+
}).catch((err) => console.log('Share failed:', err));
|
|
144
|
+
} else {
|
|
145
|
+
// Fallback: copy link to clipboard
|
|
146
|
+
navigator.clipboard.writeText(window.location.href).then(() => {
|
|
147
|
+
console.log('Link copied to clipboard');
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
}, [schema]);
|
|
151
|
+
|
|
152
|
+
const handleDuplicate = React.useCallback(() => {
|
|
153
|
+
// Duplicate functionality - could navigate to create page with prefilled data
|
|
154
|
+
console.log('Duplicate record:', data);
|
|
155
|
+
}, [data]);
|
|
156
|
+
|
|
157
|
+
const handleExport = React.useCallback(() => {
|
|
158
|
+
// Export functionality - could download as JSON, PDF, etc.
|
|
159
|
+
console.log('Export record:', data);
|
|
160
|
+
}, [data]);
|
|
161
|
+
|
|
162
|
+
const handleViewHistory = React.useCallback(() => {
|
|
163
|
+
// View history functionality
|
|
164
|
+
console.log('View history for record:', schema.resourceId);
|
|
165
|
+
}, [schema]);
|
|
166
|
+
|
|
167
|
+
const handleToggleFavorite = React.useCallback(() => {
|
|
168
|
+
setIsFavorite(!isFavorite);
|
|
169
|
+
}, [isFavorite]);
|
|
170
|
+
|
|
111
171
|
if (loading || schema.loading) {
|
|
112
172
|
return (
|
|
113
173
|
<div className={cn('space-y-4', className)}>
|
|
@@ -119,49 +179,123 @@ export const DetailView: React.FC<DetailViewProps> = ({
|
|
|
119
179
|
}
|
|
120
180
|
|
|
121
181
|
return (
|
|
122
|
-
<
|
|
123
|
-
{
|
|
124
|
-
|
|
125
|
-
<div className="flex items-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
<
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
</p>
|
|
182
|
+
<TooltipProvider>
|
|
183
|
+
<div className={cn('space-y-6', className)}>
|
|
184
|
+
{/* Header - Airtable-inspired layout */}
|
|
185
|
+
<div className="flex flex-col sm:flex-row items-start justify-between gap-3 sm:gap-4 pb-4 border-b">
|
|
186
|
+
<div className="flex items-start gap-2 sm:gap-3 flex-1 min-w-0">
|
|
187
|
+
{(schema.showBack ?? true) && (
|
|
188
|
+
<Tooltip>
|
|
189
|
+
<TooltipTrigger asChild>
|
|
190
|
+
<Button variant="ghost" size="icon" onClick={handleBack} className="shrink-0 mt-1">
|
|
191
|
+
<ArrowLeft className="h-4 w-4" />
|
|
192
|
+
</Button>
|
|
193
|
+
</TooltipTrigger>
|
|
194
|
+
<TooltipContent>Back</TooltipContent>
|
|
195
|
+
</Tooltip>
|
|
137
196
|
)}
|
|
197
|
+
<div className="flex-1 min-w-0">
|
|
198
|
+
<div className="flex items-center gap-2">
|
|
199
|
+
<h1 className="text-xl sm:text-2xl font-bold truncate">{schema.title || 'Details'}</h1>
|
|
200
|
+
<Tooltip>
|
|
201
|
+
<TooltipTrigger asChild>
|
|
202
|
+
<Button
|
|
203
|
+
variant="ghost"
|
|
204
|
+
size="icon"
|
|
205
|
+
className="h-6 w-6 shrink-0"
|
|
206
|
+
onClick={handleToggleFavorite}
|
|
207
|
+
>
|
|
208
|
+
{isFavorite ? (
|
|
209
|
+
<Star className="h-4 w-4 fill-yellow-400 text-yellow-400" />
|
|
210
|
+
) : (
|
|
211
|
+
<StarOff className="h-4 w-4 text-muted-foreground" />
|
|
212
|
+
)}
|
|
213
|
+
</Button>
|
|
214
|
+
</TooltipTrigger>
|
|
215
|
+
<TooltipContent>
|
|
216
|
+
{isFavorite ? 'Remove from favorites' : 'Add to favorites'}
|
|
217
|
+
</TooltipContent>
|
|
218
|
+
</Tooltip>
|
|
219
|
+
</div>
|
|
220
|
+
{schema.objectName && (
|
|
221
|
+
<p className="text-sm text-muted-foreground mt-1 flex items-center gap-1.5">
|
|
222
|
+
<span className="font-medium">{schema.objectName}</span>
|
|
223
|
+
<span className="text-muted-foreground/60">•</span>
|
|
224
|
+
<span>#{schema.resourceId}</span>
|
|
225
|
+
</p>
|
|
226
|
+
)}
|
|
227
|
+
</div>
|
|
138
228
|
</div>
|
|
139
|
-
</div>
|
|
140
229
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
230
|
+
<div className="flex flex-wrap items-center gap-1.5 shrink-0 w-full sm:w-auto">
|
|
231
|
+
{schema.actions?.map((action, index) => (
|
|
232
|
+
<SchemaRenderer key={index} schema={action} data={data} />
|
|
233
|
+
))}
|
|
234
|
+
|
|
235
|
+
{/* Share Button */}
|
|
236
|
+
<Tooltip>
|
|
237
|
+
<TooltipTrigger asChild>
|
|
238
|
+
<Button variant="outline" size="icon" onClick={handleShare}>
|
|
239
|
+
<Share2 className="h-4 w-4" />
|
|
240
|
+
</Button>
|
|
241
|
+
</TooltipTrigger>
|
|
242
|
+
<TooltipContent>Share</TooltipContent>
|
|
243
|
+
</Tooltip>
|
|
244
|
+
|
|
245
|
+
{/* Edit Button */}
|
|
246
|
+
{schema.showEdit && (
|
|
247
|
+
<Tooltip>
|
|
248
|
+
<TooltipTrigger asChild>
|
|
249
|
+
<Button variant="default" onClick={handleEdit} className="gap-2">
|
|
250
|
+
<Edit className="h-4 w-4" />
|
|
251
|
+
<span className="hidden sm:inline">Edit</span>
|
|
252
|
+
</Button>
|
|
253
|
+
</TooltipTrigger>
|
|
254
|
+
<TooltipContent>Edit record</TooltipContent>
|
|
255
|
+
</Tooltip>
|
|
256
|
+
)}
|
|
145
257
|
|
|
146
|
-
|
|
147
|
-
<
|
|
148
|
-
<
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
258
|
+
{/* More Actions Menu */}
|
|
259
|
+
<DropdownMenu>
|
|
260
|
+
<Tooltip>
|
|
261
|
+
<TooltipTrigger asChild>
|
|
262
|
+
<DropdownMenuTrigger asChild>
|
|
263
|
+
<Button variant="ghost" size="icon">
|
|
264
|
+
<MoreHorizontal className="h-4 w-4" />
|
|
265
|
+
</Button>
|
|
266
|
+
</DropdownMenuTrigger>
|
|
267
|
+
</TooltipTrigger>
|
|
268
|
+
<TooltipContent>More actions</TooltipContent>
|
|
269
|
+
</Tooltip>
|
|
270
|
+
<DropdownMenuContent align="end" className="w-[calc(100vw-2rem)] sm:w-48 max-h-[60vh] overflow-y-auto">
|
|
271
|
+
<DropdownMenuItem onClick={handleDuplicate}>
|
|
272
|
+
<Copy className="h-4 w-4 mr-2" />
|
|
273
|
+
Duplicate
|
|
274
|
+
</DropdownMenuItem>
|
|
275
|
+
<DropdownMenuItem onClick={handleExport}>
|
|
276
|
+
<Download className="h-4 w-4 mr-2" />
|
|
277
|
+
Export
|
|
278
|
+
</DropdownMenuItem>
|
|
279
|
+
<DropdownMenuItem onClick={handleViewHistory}>
|
|
280
|
+
<History className="h-4 w-4 mr-2" />
|
|
281
|
+
View history
|
|
282
|
+
</DropdownMenuItem>
|
|
283
|
+
{schema.showDelete && (
|
|
284
|
+
<>
|
|
285
|
+
<DropdownMenuSeparator />
|
|
286
|
+
<DropdownMenuItem
|
|
287
|
+
onClick={handleDelete}
|
|
288
|
+
className="text-destructive focus:text-destructive"
|
|
289
|
+
>
|
|
290
|
+
<Trash2 className="h-4 w-4 mr-2" />
|
|
291
|
+
Delete
|
|
292
|
+
</DropdownMenuItem>
|
|
293
|
+
</>
|
|
294
|
+
)}
|
|
295
|
+
</DropdownMenuContent>
|
|
296
|
+
</DropdownMenu>
|
|
297
|
+
</div>
|
|
163
298
|
</div>
|
|
164
|
-
</div>
|
|
165
299
|
|
|
166
300
|
{/* Custom Header */}
|
|
167
301
|
{schema.header && (
|
|
@@ -172,7 +306,7 @@ export const DetailView: React.FC<DetailViewProps> = ({
|
|
|
172
306
|
|
|
173
307
|
{/* Sections */}
|
|
174
308
|
{schema.sections && schema.sections.length > 0 && (
|
|
175
|
-
<div className="space-y-4">
|
|
309
|
+
<div className="space-y-3 sm:space-y-4">
|
|
176
310
|
{schema.sections.map((section, index) => (
|
|
177
311
|
<DetailSection
|
|
178
312
|
key={index}
|
|
@@ -223,6 +357,7 @@ export const DetailView: React.FC<DetailViewProps> = ({
|
|
|
223
357
|
<SchemaRenderer schema={schema.footer} data={data} />
|
|
224
358
|
</div>
|
|
225
359
|
)}
|
|
226
|
-
|
|
360
|
+
</div>
|
|
361
|
+
</TooltipProvider>
|
|
227
362
|
);
|
|
228
363
|
};
|