@djangocfg/ui-nextjs 2.1.89 → 2.1.91

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 (161) hide show
  1. package/README.md +6 -15
  2. package/package.json +6 -25
  3. package/src/blocks/SplitHero/SplitHeroMedia.tsx +1 -1
  4. package/src/components/index.ts +0 -40
  5. package/src/hooks/index.ts +0 -6
  6. package/src/index.ts +2 -11
  7. package/src/components/button-download.tsx +0 -277
  8. package/src/components/markdown/MarkdownMessage.tsx +0 -340
  9. package/src/components/markdown/index.ts +0 -5
  10. package/src/components/menubar.tsx +0 -275
  11. package/src/components/multi-select-pro/async.tsx +0 -598
  12. package/src/components/multi-select-pro/helpers.tsx +0 -84
  13. package/src/components/multi-select-pro/index.tsx +0 -612
  14. package/src/components/navigation-menu.tsx +0 -154
  15. package/src/components/otp/index.tsx +0 -197
  16. package/src/components/otp/types.ts +0 -133
  17. package/src/components/otp/use-otp-input.ts +0 -225
  18. package/src/components/phone-input.tsx +0 -277
  19. package/src/components/sonner.tsx +0 -32
  20. package/src/hooks/useLocalStorage.ts +0 -300
  21. package/src/hooks/useSessionStorage.ts +0 -290
  22. package/src/lib/index.ts +0 -5
  23. package/src/lib/logger/index.ts +0 -10
  24. package/src/lib/logger/logStore.ts +0 -122
  25. package/src/lib/logger/logger.ts +0 -175
  26. package/src/lib/logger/types.ts +0 -82
  27. package/src/stores/index.ts +0 -8
  28. package/src/stores/mediaCache.ts +0 -534
  29. package/src/tools/AudioPlayer/README.md +0 -206
  30. package/src/tools/AudioPlayer/components/HybridAudioPlayer.tsx +0 -216
  31. package/src/tools/AudioPlayer/components/HybridSimplePlayer.tsx +0 -280
  32. package/src/tools/AudioPlayer/components/HybridWaveform.tsx +0 -279
  33. package/src/tools/AudioPlayer/components/ReactiveCover/AudioReactiveCover.tsx +0 -149
  34. package/src/tools/AudioPlayer/components/ReactiveCover/effects/GlowEffect.tsx +0 -110
  35. package/src/tools/AudioPlayer/components/ReactiveCover/effects/MeshEffect.tsx +0 -58
  36. package/src/tools/AudioPlayer/components/ReactiveCover/effects/OrbsEffect.tsx +0 -45
  37. package/src/tools/AudioPlayer/components/ReactiveCover/effects/SpotlightEffect.tsx +0 -82
  38. package/src/tools/AudioPlayer/components/ReactiveCover/effects/index.ts +0 -8
  39. package/src/tools/AudioPlayer/components/ReactiveCover/index.ts +0 -6
  40. package/src/tools/AudioPlayer/components/index.ts +0 -22
  41. package/src/tools/AudioPlayer/context/HybridAudioProvider.tsx +0 -158
  42. package/src/tools/AudioPlayer/context/index.ts +0 -16
  43. package/src/tools/AudioPlayer/effects/index.ts +0 -412
  44. package/src/tools/AudioPlayer/hooks/index.ts +0 -35
  45. package/src/tools/AudioPlayer/hooks/useHybridAudio.ts +0 -387
  46. package/src/tools/AudioPlayer/hooks/useHybridAudioAnalysis.ts +0 -95
  47. package/src/tools/AudioPlayer/hooks/useVisualization.tsx +0 -207
  48. package/src/tools/AudioPlayer/index.ts +0 -133
  49. package/src/tools/AudioPlayer/types/effects.ts +0 -73
  50. package/src/tools/AudioPlayer/types/index.ts +0 -27
  51. package/src/tools/AudioPlayer/utils/debug.ts +0 -14
  52. package/src/tools/AudioPlayer/utils/formatTime.ts +0 -10
  53. package/src/tools/AudioPlayer/utils/index.ts +0 -6
  54. package/src/tools/ImageViewer/@refactoring/00-PLAN.md +0 -71
  55. package/src/tools/ImageViewer/@refactoring/01-TYPES.md +0 -121
  56. package/src/tools/ImageViewer/@refactoring/02-UTILS.md +0 -143
  57. package/src/tools/ImageViewer/@refactoring/03-HOOKS.md +0 -261
  58. package/src/tools/ImageViewer/@refactoring/04-COMPONENTS.md +0 -427
  59. package/src/tools/ImageViewer/@refactoring/05-EXECUTION-CHECKLIST.md +0 -126
  60. package/src/tools/ImageViewer/README.md +0 -200
  61. package/src/tools/ImageViewer/components/ImageInfo.tsx +0 -44
  62. package/src/tools/ImageViewer/components/ImageToolbar.tsx +0 -150
  63. package/src/tools/ImageViewer/components/ImageViewer.tsx +0 -241
  64. package/src/tools/ImageViewer/components/index.ts +0 -7
  65. package/src/tools/ImageViewer/hooks/index.ts +0 -9
  66. package/src/tools/ImageViewer/hooks/useImageLoading.ts +0 -204
  67. package/src/tools/ImageViewer/hooks/useImageTransform.ts +0 -101
  68. package/src/tools/ImageViewer/index.ts +0 -60
  69. package/src/tools/ImageViewer/types.ts +0 -81
  70. package/src/tools/ImageViewer/utils/constants.ts +0 -59
  71. package/src/tools/ImageViewer/utils/debug.ts +0 -14
  72. package/src/tools/ImageViewer/utils/index.ts +0 -17
  73. package/src/tools/ImageViewer/utils/lqip.ts +0 -47
  74. package/src/tools/JsonForm/JsonSchemaForm.tsx +0 -197
  75. package/src/tools/JsonForm/examples/BotConfigExample.tsx +0 -249
  76. package/src/tools/JsonForm/examples/RealBotConfigExample.tsx +0 -161
  77. package/src/tools/JsonForm/index.ts +0 -46
  78. package/src/tools/JsonForm/templates/ArrayFieldItemTemplate.tsx +0 -47
  79. package/src/tools/JsonForm/templates/ArrayFieldTemplate.tsx +0 -74
  80. package/src/tools/JsonForm/templates/BaseInputTemplate.tsx +0 -107
  81. package/src/tools/JsonForm/templates/ErrorListTemplate.tsx +0 -35
  82. package/src/tools/JsonForm/templates/FieldTemplate.tsx +0 -62
  83. package/src/tools/JsonForm/templates/ObjectFieldTemplate.tsx +0 -116
  84. package/src/tools/JsonForm/templates/index.ts +0 -12
  85. package/src/tools/JsonForm/types.ts +0 -83
  86. package/src/tools/JsonForm/utils.ts +0 -213
  87. package/src/tools/JsonForm/widgets/CheckboxWidget.tsx +0 -37
  88. package/src/tools/JsonForm/widgets/ColorWidget.tsx +0 -219
  89. package/src/tools/JsonForm/widgets/NumberWidget.tsx +0 -89
  90. package/src/tools/JsonForm/widgets/SelectWidget.tsx +0 -97
  91. package/src/tools/JsonForm/widgets/SliderWidget.tsx +0 -148
  92. package/src/tools/JsonForm/widgets/SwitchWidget.tsx +0 -35
  93. package/src/tools/JsonForm/widgets/TextWidget.tsx +0 -96
  94. package/src/tools/JsonForm/widgets/index.ts +0 -14
  95. package/src/tools/JsonTree/index.tsx +0 -243
  96. package/src/tools/LottiePlayer/LottiePlayer.client.tsx +0 -213
  97. package/src/tools/LottiePlayer/index.tsx +0 -55
  98. package/src/tools/LottiePlayer/types.ts +0 -108
  99. package/src/tools/LottiePlayer/useLottie.ts +0 -164
  100. package/src/tools/Mermaid/Mermaid.client.tsx +0 -82
  101. package/src/tools/Mermaid/components/MermaidCodeViewer.tsx +0 -95
  102. package/src/tools/Mermaid/components/MermaidFullscreenModal.tsx +0 -103
  103. package/src/tools/Mermaid/hooks/index.ts +0 -4
  104. package/src/tools/Mermaid/hooks/useMermaidCleanup.ts +0 -73
  105. package/src/tools/Mermaid/hooks/useMermaidFullscreen.ts +0 -46
  106. package/src/tools/Mermaid/hooks/useMermaidRenderer.ts +0 -226
  107. package/src/tools/Mermaid/hooks/useMermaidValidation.ts +0 -29
  108. package/src/tools/Mermaid/index.tsx +0 -41
  109. package/src/tools/Mermaid/utils/mermaid-helpers.ts +0 -33
  110. package/src/tools/OpenapiViewer/components/EndpointInfo.tsx +0 -149
  111. package/src/tools/OpenapiViewer/components/EndpointsLibrary.tsx +0 -263
  112. package/src/tools/OpenapiViewer/components/PlaygroundLayout.tsx +0 -125
  113. package/src/tools/OpenapiViewer/components/PlaygroundStepper.tsx +0 -100
  114. package/src/tools/OpenapiViewer/components/RequestBuilder.tsx +0 -157
  115. package/src/tools/OpenapiViewer/components/RequestParametersForm.tsx +0 -253
  116. package/src/tools/OpenapiViewer/components/ResponseViewer.tsx +0 -173
  117. package/src/tools/OpenapiViewer/components/VersionSelector.tsx +0 -68
  118. package/src/tools/OpenapiViewer/components/index.ts +0 -14
  119. package/src/tools/OpenapiViewer/constants.ts +0 -39
  120. package/src/tools/OpenapiViewer/context/PlaygroundContext.tsx +0 -337
  121. package/src/tools/OpenapiViewer/hooks/index.ts +0 -8
  122. package/src/tools/OpenapiViewer/hooks/useMobile.ts +0 -10
  123. package/src/tools/OpenapiViewer/hooks/useOpenApiSchema.ts +0 -199
  124. package/src/tools/OpenapiViewer/index.tsx +0 -38
  125. package/src/tools/OpenapiViewer/types.ts +0 -151
  126. package/src/tools/OpenapiViewer/utils/apiKeyManager.ts +0 -149
  127. package/src/tools/OpenapiViewer/utils/formatters.ts +0 -71
  128. package/src/tools/OpenapiViewer/utils/index.ts +0 -9
  129. package/src/tools/OpenapiViewer/utils/versionManager.ts +0 -161
  130. package/src/tools/PrettyCode/PrettyCode.client.tsx +0 -208
  131. package/src/tools/PrettyCode/index.tsx +0 -45
  132. package/src/tools/VideoPlayer/@refactoring/00-PLAN.md +0 -91
  133. package/src/tools/VideoPlayer/@refactoring/01-TYPES.md +0 -284
  134. package/src/tools/VideoPlayer/@refactoring/02-UTILS.md +0 -141
  135. package/src/tools/VideoPlayer/@refactoring/03-HOOKS.md +0 -178
  136. package/src/tools/VideoPlayer/@refactoring/04-COMPONENTS.md +0 -95
  137. package/src/tools/VideoPlayer/@refactoring/05-EXECUTION-CHECKLIST.md +0 -139
  138. package/src/tools/VideoPlayer/README.md +0 -264
  139. package/src/tools/VideoPlayer/components/VideoControls.tsx +0 -138
  140. package/src/tools/VideoPlayer/components/VideoErrorFallback.tsx +0 -174
  141. package/src/tools/VideoPlayer/components/VideoPlayer.tsx +0 -201
  142. package/src/tools/VideoPlayer/components/index.ts +0 -14
  143. package/src/tools/VideoPlayer/context/VideoPlayerContext.tsx +0 -52
  144. package/src/tools/VideoPlayer/context/index.ts +0 -8
  145. package/src/tools/VideoPlayer/hooks/index.ts +0 -12
  146. package/src/tools/VideoPlayer/hooks/useVideoPlayerSettings.ts +0 -70
  147. package/src/tools/VideoPlayer/hooks/useVideoPositionCache.ts +0 -116
  148. package/src/tools/VideoPlayer/index.ts +0 -77
  149. package/src/tools/VideoPlayer/providers/NativeProvider.tsx +0 -284
  150. package/src/tools/VideoPlayer/providers/StreamProvider.tsx +0 -505
  151. package/src/tools/VideoPlayer/providers/VidstackProvider.tsx +0 -400
  152. package/src/tools/VideoPlayer/providers/index.ts +0 -8
  153. package/src/tools/VideoPlayer/types/index.ts +0 -38
  154. package/src/tools/VideoPlayer/types/player.ts +0 -116
  155. package/src/tools/VideoPlayer/types/provider.ts +0 -93
  156. package/src/tools/VideoPlayer/types/sources.ts +0 -97
  157. package/src/tools/VideoPlayer/utils/debug.ts +0 -14
  158. package/src/tools/VideoPlayer/utils/fileSource.ts +0 -78
  159. package/src/tools/VideoPlayer/utils/index.ts +0 -12
  160. package/src/tools/VideoPlayer/utils/resolvers.ts +0 -75
  161. package/src/tools/index.ts +0 -170
@@ -1,263 +0,0 @@
1
- 'use client';
2
-
3
- import {
4
- BarChart3, Code, Database, FileText, Filter, Grid3X3, List, Search, Settings, Shield, Users
5
- } from 'lucide-react';
6
- import React, { useMemo } from 'react';
7
-
8
- import {
9
- Badge, Button, Card, CardContent, CardHeader, CardTitle, Input, Select, SelectContent,
10
- SelectItem, SelectTrigger, SelectValue, Skeleton, Table, TableBody, TableCell, TableHead,
11
- TableHeader, TableRow
12
- } from '@djangocfg/ui-core/components';
13
-
14
- import { usePlaygroundContext } from '../context/PlaygroundContext';
15
- import useOpenApiSchema from '../hooks/useOpenApiSchema';
16
- import { getMethodColor } from '../utils';
17
- import { deduplicateEndpoints } from '../utils/versionManager';
18
- import { VersionSelector } from './VersionSelector';
19
-
20
- import type { ApiEndpoint } from '../types';
21
- const categoryIcons: Record<string, React.ReactNode> = {
22
- 'Authentication': <Shield className="h-4 w-4" />,
23
- 'Users': <Users className="h-4 w-4" />,
24
- 'Data': <Database className="h-4 w-4" />,
25
- 'Analytics': <BarChart3 className="h-4 w-4" />,
26
- 'Files': <FileText className="h-4 w-4" />,
27
- 'Settings': <Settings className="h-4 w-4" />,
28
- 'Other': <Code className="h-4 w-4" />,
29
- };
30
-
31
- export const EndpointsLibrary: React.FC = () => {
32
- const { state, config, setSelectedEndpoint, setSelectedCategory, setSearchTerm } = usePlaygroundContext();
33
- const { endpoints, categories, loading, error } = useOpenApiSchema({
34
- schemas: config.schemas,
35
- defaultSchemaId: config.defaultSchemaId,
36
- });
37
- const [viewMode, setViewMode] = React.useState<'table' | 'grid'>('table');
38
-
39
- // Helper to extract relative path from full URL
40
- const getRelativePath = (fullPath: string): string => {
41
- try {
42
- const url = new URL(fullPath);
43
- return url.pathname;
44
- } catch {
45
- // If not a valid URL, return as is (already relative)
46
- return fullPath;
47
- }
48
- };
49
-
50
- const filteredEndpoints = useMemo(() => {
51
- // First, deduplicate endpoints based on selected version
52
- let filtered = deduplicateEndpoints(endpoints, state.selectedVersion);
53
-
54
- // Filter by category
55
- if (state.selectedCategory && state.selectedCategory !== 'All') {
56
- filtered = filtered.filter((endpoint) => endpoint.category === state.selectedCategory);
57
- }
58
-
59
- // Filter by search term
60
- if (state.searchTerm) {
61
- const searchLower = state.searchTerm.toLowerCase();
62
- filtered = filtered.filter(
63
- (endpoint) =>
64
- endpoint.name.toLowerCase().includes(searchLower) ||
65
- endpoint.description.toLowerCase().includes(searchLower) ||
66
- endpoint.path.toLowerCase().includes(searchLower)
67
- );
68
- }
69
-
70
- return filtered;
71
- }, [endpoints, state.selectedCategory, state.searchTerm, state.selectedVersion]);
72
-
73
- const handleEndpointSelect = (endpoint: ApiEndpoint) => {
74
- setSelectedEndpoint(endpoint);
75
- };
76
-
77
- const getMethodBadges = (methods: string) => {
78
- return methods.split(', ').map((method) => (
79
- <Badge key={method} variant={getMethodColor(method) === 'success' ? 'default' : 'secondary'} className="text-xs">
80
- {method}
81
- </Badge>
82
- ));
83
- };
84
-
85
- if (loading) {
86
- return (
87
- <div className="space-y-4">
88
- <div className="flex items-center justify-between">
89
- <h2 className="text-lg font-semibold text-foreground">API Endpoints</h2>
90
- <div className="flex items-center space-x-2">
91
- <Skeleton className="h-8 w-32" />
92
- <Skeleton className="h-8 w-48" />
93
- </div>
94
- </div>
95
- <div className="space-y-2">
96
- {Array.from({ length: 5 }).map((_, i) => (
97
- <Skeleton key={i} className="h-20 w-full" />
98
- ))}
99
- </div>
100
- </div>
101
- );
102
- }
103
-
104
- if (error) {
105
- return (
106
- <div className="space-y-4">
107
- <div className="flex items-center justify-between">
108
- <h2 className="text-lg font-semibold text-foreground">API Endpoints</h2>
109
- </div>
110
- <Card className="bg-destructive/10 border-destructive/20">
111
- <CardContent className="p-4">
112
- <p className="text-sm text-destructive">Error loading endpoints: {error}</p>
113
- </CardContent>
114
- </Card>
115
- </div>
116
- );
117
- }
118
-
119
- return (
120
- <div className="space-y-4">
121
- {/* Header */}
122
- <div className="flex flex-col gap-4">
123
- <div className="flex flex-col sm:flex-row sm:items-center justify-between gap-4">
124
- <h2 className="text-lg font-semibold text-foreground">API Endpoints</h2>
125
- <VersionSelector />
126
- </div>
127
-
128
- <div className="flex flex-col sm:flex-row sm:items-center justify-between gap-4">
129
- <div className="flex items-center space-x-2">
130
- {/* View Mode Toggle */}
131
- <div className="flex items-center border rounded-md">
132
- <Button
133
- variant={viewMode === 'table' ? 'default' : 'ghost'}
134
- size="sm"
135
- onClick={() => setViewMode('table')}
136
- className="rounded-r-none"
137
- >
138
- <List className="h-4 w-4" />
139
- </Button>
140
- <Button
141
- variant={viewMode === 'grid' ? 'default' : 'ghost'}
142
- size="sm"
143
- onClick={() => setViewMode('grid')}
144
- className="rounded-l-none"
145
- >
146
- <Grid3X3 className="h-4 w-4" />
147
- </Button>
148
- </div>
149
-
150
- {/* Category Filter */}
151
- <Select value={state.selectedCategory} onValueChange={setSelectedCategory}>
152
- <SelectTrigger className="w-32">
153
- <Filter className="h-4 w-4 mr-2" />
154
- <SelectValue />
155
- </SelectTrigger>
156
- <SelectContent>
157
- <SelectItem value="All">All</SelectItem>
158
- {categories.map((category) => (
159
- <SelectItem key={category} value={category}>
160
- {category}
161
- </SelectItem>
162
- ))}
163
- </SelectContent>
164
- </Select>
165
-
166
- {/* Search */}
167
- <div className="relative">
168
- <Search className="absolute left-2 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground" />
169
- <Input
170
- placeholder="Search endpoints..."
171
- value={state.searchTerm}
172
- onChange={(e: React.ChangeEvent<HTMLInputElement>) => setSearchTerm(e.target.value)}
173
- className="w-48 pl-8"
174
- />
175
- </div>
176
- </div>
177
- </div>
178
- </div>
179
-
180
- {/* Content */}
181
- {viewMode === 'table' ? (
182
- <Card>
183
- <Table>
184
- <TableHeader>
185
- <TableRow>
186
- <TableHead className="text-foreground">Methods</TableHead>
187
- <TableHead className="text-foreground">Path</TableHead>
188
- <TableHead className="text-foreground">Description</TableHead>
189
- </TableRow>
190
- </TableHeader>
191
- <TableBody>
192
- {filteredEndpoints.length === 0 ? (
193
- <TableRow>
194
- <TableCell colSpan={3} className="text-center py-8 text-muted-foreground">
195
- No endpoints found
196
- </TableCell>
197
- </TableRow>
198
- ) : (
199
- filteredEndpoints.map((endpoint) => (
200
- <TableRow
201
- key={`${endpoint.method}-${endpoint.path}`}
202
- className={`cursor-pointer transition-colors hover:bg-muted/50 ${state.selectedEndpoint?.path === endpoint.path ? 'bg-primary/10' : ''
203
- }`}
204
- onClick={() => handleEndpointSelect(endpoint)}
205
- >
206
- <TableCell>
207
- <div className="flex space-x-1">
208
- {getMethodBadges(endpoint.method)}
209
- </div>
210
- </TableCell>
211
- <TableCell className="font-mono text-sm text-muted-foreground">
212
- {getRelativePath(endpoint.path)}
213
- </TableCell>
214
- <TableCell className="text-sm text-muted-foreground max-w-xs truncate">
215
- {endpoint.description}
216
- </TableCell>
217
- </TableRow>
218
- ))
219
- )}
220
- </TableBody>
221
- </Table>
222
- </Card>
223
- ) : (
224
- <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
225
- {filteredEndpoints.length === 0 ? (
226
- <div className="col-span-full text-center py-8 text-muted-foreground">
227
- No endpoints found
228
- </div>
229
- ) : (
230
- filteredEndpoints.map((endpoint) => (
231
- <Card
232
- key={`${endpoint.method}-${endpoint.path}`}
233
- className={`cursor-pointer transition-all hover:shadow-md ${state.selectedEndpoint?.path === endpoint.path ? 'ring-2 ring-primary' : ''
234
- }`}
235
- onClick={() => handleEndpointSelect(endpoint)}
236
- >
237
- <CardHeader className="pb-3">
238
- <CardTitle className="flex items-center justify-between text-sm">
239
- <div className="flex items-center space-x-2">
240
- {categoryIcons[endpoint.category] || <Code className="h-4 w-4" />}
241
- <span className="truncate">{endpoint.name}</span>
242
- </div>
243
- <div className="flex space-x-1">
244
- {getMethodBadges(endpoint.method)}
245
- </div>
246
- </CardTitle>
247
- </CardHeader>
248
- <CardContent className="space-y-2">
249
- <p className="text-xs font-mono text-muted-foreground break-all">
250
- {getRelativePath(endpoint.path)}
251
- </p>
252
- <p className="text-xs text-muted-foreground line-clamp-2">
253
- {endpoint.description}
254
- </p>
255
- </CardContent>
256
- </Card>
257
- ))
258
- )}
259
- </div>
260
- )}
261
- </div>
262
- );
263
- };
@@ -1,125 +0,0 @@
1
- 'use client';
2
-
3
- import { Menu, X } from 'lucide-react';
4
- import React from 'react';
5
-
6
- import { Button, Sheet, SheetContent, SheetTrigger } from '@djangocfg/ui-core/components';
7
-
8
- import { usePlaygroundContext } from '../context/PlaygroundContext';
9
- import { useMobile } from '../hooks/useMobile';
10
- import { EndpointsLibrary } from './EndpointsLibrary';
11
- import { PlaygroundStepper } from './PlaygroundStepper';
12
- import { RequestBuilder } from './RequestBuilder';
13
- import { ResponseViewer } from './ResponseViewer';
14
-
15
- export const PlaygroundLayout: React.FC = () => {
16
- const { state, setSidebarOpen } = usePlaygroundContext();
17
- const { isMobile } = useMobile();
18
-
19
- const renderStepContent = () => {
20
- switch (state.currentStep) {
21
- case 'endpoints':
22
- return <EndpointsLibrary />;
23
- case 'request':
24
- return <RequestBuilder />;
25
- case 'response':
26
- return <ResponseViewer />;
27
- default:
28
- return <EndpointsLibrary />;
29
- }
30
- };
31
-
32
- const getStepTitle = () => {
33
- switch (state.currentStep) {
34
- case 'endpoints':
35
- return 'API Endpoints';
36
- case 'request':
37
- return 'Request Builder';
38
- case 'response':
39
- return 'Response Viewer';
40
- default:
41
- return 'API Playground';
42
- }
43
- };
44
-
45
- return (
46
- <div className="min-h-screen">
47
- {/* Header */}
48
- <div className="border-b">
49
- <div className="container mx-auto px-4 py-4">
50
- <div className="flex items-center justify-between">
51
- <div className="flex items-center space-x-4">
52
- <h1 className="text-xl font-bold text-foreground">API Playground</h1>
53
- <p className="text-sm text-muted-foreground hidden sm:block">
54
- Test and explore API endpoints
55
- </p>
56
- </div>
57
-
58
- {/* Mobile Menu */}
59
- {isMobile && (
60
- <Sheet open={state.sidebarOpen} onOpenChange={setSidebarOpen}>
61
- <SheetTrigger asChild>
62
- <Button variant="outline" size="sm">
63
- <Menu className="h-4 w-4" />
64
- </Button>
65
- </SheetTrigger>
66
- <SheetContent side="left" className="w-80">
67
- <div className="space-y-4">
68
- <div className="flex items-center justify-between">
69
- <h2 className="text-lg font-semibold text-foreground">Navigation</h2>
70
- <Button
71
- variant="ghost"
72
- size="sm"
73
- onClick={() => setSidebarOpen(false)}
74
- >
75
- <X className="h-4 w-4" />
76
- </Button>
77
- </div>
78
- <PlaygroundStepper />
79
- </div>
80
- </SheetContent>
81
- </Sheet>
82
- )}
83
- </div>
84
- </div>
85
- </div>
86
-
87
- {/* Desktop Stepper */}
88
- {!isMobile && <PlaygroundStepper />}
89
-
90
- {/* Main Content */}
91
- <div className="container mx-auto px-6 py-6">
92
- {/* Step Title */}
93
- <div className="mb-6">
94
- <h2 className="text-2xl font-bold text-foreground">{getStepTitle()}</h2>
95
- <p className="text-muted-foreground mt-1">
96
- {state.currentStep === 'endpoints' && 'Browse and select API endpoints'}
97
- {state.currentStep === 'request' && 'Configure your API request'}
98
- {state.currentStep === 'response' && 'View API response and details'}
99
- </p>
100
- </div>
101
-
102
- {/* Content */}
103
- <div className="space-y-6">
104
- {renderStepContent()}
105
- </div>
106
- </div>
107
-
108
- {/* Mobile Floating Action Button */}
109
- {isMobile && state.currentStep === 'request' && (
110
- <div className="fixed bottom-4 right-4 z-50">
111
- <Button
112
- size="lg"
113
- className="rounded-full shadow-lg"
114
- onClick={() => {
115
- // Auto-advance to response step
116
- // This would be handled by the context
117
- }}
118
- >
119
- Send Request
120
- </Button>
121
- </div>
122
- )}
123
- </div>
124
- );
125
- };
@@ -1,100 +0,0 @@
1
- 'use client';
2
-
3
- import { Check, ChevronLeft, ChevronRight, Code, FileText, Send } from 'lucide-react';
4
- import React from 'react';
5
-
6
- import { Badge, Button } from '@djangocfg/ui-core/components';
7
-
8
- import { usePlaygroundContext } from '../context/PlaygroundContext';
9
- import { PlaygroundStep } from '../types';
10
-
11
- const stepConfig = {
12
- endpoints: {
13
- title: 'Endpoints',
14
- icon: Code,
15
- description: 'Select API endpoint'
16
- },
17
- request: {
18
- title: 'Request',
19
- icon: Send,
20
- description: 'Configure request'
21
- },
22
- response: {
23
- title: 'Response',
24
- icon: FileText,
25
- description: 'View response'
26
- }
27
- };
28
-
29
- export const PlaygroundStepper: React.FC = () => {
30
- const { state, setCurrentStep, goToNextStep, goToPreviousStep } = usePlaygroundContext();
31
- const { currentStep, steps } = state;
32
-
33
- const currentIndex = steps.indexOf(currentStep);
34
- const canGoNext = currentIndex < steps.length - 1;
35
- const canGoPrevious = currentIndex > 0;
36
-
37
- return (
38
- <div className="flex items-center justify-between p-4 border-b">
39
- {/* Steps */}
40
- <div className="flex items-center space-x-4">
41
- {steps.map((step, index) => {
42
- const config = stepConfig[step];
43
- const Icon = config.icon;
44
- const isActive = step === currentStep;
45
- const isCompleted = index < currentIndex;
46
- const isClickable = index <= currentIndex + 1;
47
-
48
- return (
49
- <div key={step} className="flex items-center space-x-2">
50
- <Button
51
- variant={isActive ? 'default' : 'ghost'}
52
- size="sm"
53
- onClick={() => isClickable && setCurrentStep(step)}
54
- className={`flex items-center space-x-2 ${isClickable ? 'cursor-pointer' : 'cursor-not-allowed opacity-50'
55
- }`}
56
- disabled={!isClickable}
57
- >
58
- {isCompleted ? (
59
- <Check className="h-4 w-4" />
60
- ) : (
61
- <Icon className="h-4 w-4" />
62
- )}
63
- <span className="hidden sm:inline">{config.title}</span>
64
- </Button>
65
-
66
- {index < steps.length - 1 && (
67
- <div className="w-8 h-px bg-border" />
68
- )}
69
- </div>
70
- );
71
- })}
72
- </div>
73
-
74
- {/* Navigation */}
75
- <div className="flex items-center space-x-2">
76
- <Button
77
- variant="outline"
78
- size="sm"
79
- onClick={goToPreviousStep}
80
- disabled={!canGoPrevious}
81
- className="flex items-center space-x-1"
82
- >
83
- <ChevronLeft className="h-4 w-4" />
84
- <span className="hidden sm:inline">Previous</span>
85
- </Button>
86
-
87
- <Button
88
- variant="outline"
89
- size="sm"
90
- onClick={goToNextStep}
91
- disabled={!canGoNext}
92
- className="flex items-center space-x-1"
93
- >
94
- <span className="hidden sm:inline">Next</span>
95
- <ChevronRight className="h-4 w-4" />
96
- </Button>
97
- </div>
98
- </div>
99
- );
100
- };
@@ -1,157 +0,0 @@
1
- 'use client';
2
-
3
- import { Key, Loader2, Send } from 'lucide-react';
4
- import React, { useCallback } from 'react';
5
-
6
- import {
7
- Button, Card, CardContent, CardHeader, CardTitle, CopyButton, Input, Textarea
8
- } from '@djangocfg/ui-core/components';
9
-
10
- import PrettyCode from '../../PrettyCode';
11
- import { usePlaygroundContext } from '../context/PlaygroundContext';
12
- import { findApiKeyById, isValidJson, parseRequestHeaders } from '../utils';
13
- import { EndpointInfo } from './EndpointInfo';
14
- import { RequestParametersForm } from './RequestParametersForm';
15
-
16
- export const RequestBuilder: React.FC = () => {
17
- const {
18
- state,
19
- apiKeys,
20
- setRequestBody,
21
- setManualApiToken,
22
- sendRequest
23
- } = usePlaygroundContext();
24
-
25
- const isJsonValid = state.requestBody ? isValidJson(state.requestBody) : true;
26
-
27
- // Generate cURL command
28
- const generateCurlCommand = () => {
29
- if (!state.requestUrl) return '';
30
-
31
- const apiKey = state.selectedApiKey ? findApiKeyById(apiKeys, state.selectedApiKey) : null;
32
- const headers = parseRequestHeaders(state.requestHeaders);
33
-
34
- if (apiKey) {
35
- headers['X-API-Key'] = apiKey.id || ''; // Note: using id as full key not available
36
- }
37
-
38
- let curl = `curl -X ${state.requestMethod} "${state.requestUrl}"`;
39
-
40
- // Add headers
41
- Object.entries(headers).forEach(([key, value]) => {
42
- curl += ` \\\n -H "${key}: ${value}"`;
43
- });
44
-
45
- // Add body for non-GET requests
46
- if (state.requestBody && state.requestMethod !== 'GET' && isJsonValid) {
47
- curl += ` \\\n -d '${state.requestBody}'`;
48
- }
49
-
50
- return curl;
51
- };
52
-
53
- const curlCommand = generateCurlCommand();
54
-
55
- const handleSendRequest = useCallback(async () => {
56
- await sendRequest();
57
- }, [sendRequest]);
58
-
59
- return (
60
- <div className="space-y-4">
61
- {/* Endpoint Info */}
62
- {state.selectedEndpoint && <EndpointInfo />}
63
-
64
- {/* Request Parameters Form */}
65
- {state.selectedEndpoint && (
66
- <RequestParametersForm />
67
- )}
68
-
69
- {/* Request Body */}
70
- {state.requestMethod !== 'GET' && (
71
- <Card className="">
72
- <CardHeader>
73
- <CardTitle className="text-sm text-foreground">Request Body</CardTitle>
74
- </CardHeader>
75
- <CardContent>
76
- <Textarea
77
- placeholder='{\n "key": "value"\n}'
78
- value={state.requestBody}
79
- onChange={(e) => setRequestBody(e.target.value)}
80
- className={`font-mono text-sm ${
81
- !isJsonValid ? 'border-destructive' : ''
82
- }`}
83
- rows={6}
84
- />
85
- {!isJsonValid && (
86
- <p className="mt-1 text-xs text-destructive">Invalid JSON format</p>
87
- )}
88
- </CardContent>
89
- </Card>
90
- )}
91
-
92
- {/* Bearer Token Authentication */}
93
- <Card className="">
94
- <CardHeader>
95
- <CardTitle className="flex items-center space-x-2 text-sm text-foreground">
96
- <Key className="h-4 w-4" />
97
- <span>Bearer Token</span>
98
- </CardTitle>
99
- </CardHeader>
100
- <CardContent>
101
- <div className="flex flex-col sm:flex-row sm:items-center gap-2">
102
- <div className="flex-1">
103
- <Input
104
- type="password"
105
- placeholder="Enter Bearer token (optional, uses JWT if empty)"
106
- value={state.manualApiToken}
107
- onChange={(e) => setManualApiToken(e.target.value)}
108
- className="font-mono text-sm"
109
- />
110
- <p className="mt-1 text-xs text-muted-foreground">
111
- Leave empty to use JWT token from localStorage
112
- </p>
113
- </div>
114
- <Button
115
- onClick={handleSendRequest}
116
- disabled={state.loading || !state.requestUrl || !isJsonValid}
117
- className="bg-primary hover:bg-primary/90 text-primary-foreground flex items-center gap-2"
118
- >
119
- {state.loading ? (
120
- <>
121
- <Loader2 className="h-4 w-4 animate-spin" />
122
- <span className="hidden sm:inline">Sending...</span>
123
- </>
124
- ) : (
125
- <>
126
- <Send className="h-4 w-4" />
127
- <span className="hidden sm:inline">Send Request</span>
128
- </>
129
- )}
130
- </Button>
131
- </div>
132
- </CardContent>
133
- </Card>
134
-
135
- {/* cURL Command */}
136
- {curlCommand && (
137
- <Card>
138
- <CardHeader>
139
- <div className="flex items-center justify-between">
140
- <CardTitle className="text-sm text-foreground">cURL Command</CardTitle>
141
- <CopyButton
142
- value={curlCommand}
143
- variant="outline"
144
- size="sm"
145
- >
146
- Copy cURL
147
- </CopyButton>
148
- </div>
149
- </CardHeader>
150
- <CardContent>
151
- <PrettyCode data={curlCommand} language="bash" />
152
- </CardContent>
153
- </Card>
154
- )}
155
- </div>
156
- );
157
- };