@sampleapp.ai/sdk 1.0.36 → 1.0.38
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/dist/components/sandbox/Sandbox.js +5 -0
- package/dist/components/sandbox/api.js +2 -2
- package/dist/components/sandbox/guardian/guardian-component.js +7 -38
- package/dist/components/sandbox/guardian/guardian-playground.js +2 -2
- package/dist/components/sandbox/guardian/hooks/use-sandbox-url-loader.js +12 -10
- package/dist/components/sandbox/guardian/index.js +1 -1
- package/dist/components/sandbox/guardian/right-view/right-top-down-view.js +2 -1
- package/dist/components/sandbox/guardian/ui/markdown.js +2 -2
- package/dist/components/sandbox/guardian/utils.js +4 -22
- package/dist/components/sandbox/index.js +1 -1
- package/dist/components/sandbox/sandbox-home/SandboxHome.js +5 -0
- package/dist/index.d.ts +8 -40
- package/dist/index.es.js +834 -870
- package/dist/index.js +1 -1
- package/dist/lib/api-client.js +9 -26
- package/package.json +1 -1
- package/dist/components/guardian/app-layout-no-sidebar.js +0 -8
- package/dist/components/guardian/ask-ai-view.js +0 -249
- package/dist/components/guardian/code-focus-section.d.ts +0 -41
- package/dist/components/guardian/code-focus-section.js +0 -174
- package/dist/components/guardian/context/guardian-context.js +0 -94
- package/dist/components/guardian/context/vm-context.js +0 -28
- package/dist/components/guardian/default-guide-view.js +0 -34
- package/dist/components/guardian/demo/guardian-demo.js +0 -35
- package/dist/components/guardian/demo/left-view/toggle.js +0 -28
- package/dist/components/guardian/demo/left-view.js +0 -49
- package/dist/components/guardian/guardian-component.js +0 -79
- package/dist/components/guardian/guardian-demo.js +0 -35
- package/dist/components/guardian/guardian-home.d.ts +0 -4
- package/dist/components/guardian/guardian-home.js +0 -61
- package/dist/components/guardian/guardian-playground.js +0 -45
- package/dist/components/guardian/guardian-style-wrapper.js +0 -29
- package/dist/components/guardian/guardian-upload-spec.d.ts +0 -14
- package/dist/components/guardian/guardian-upload-spec.js +0 -160
- package/dist/components/guardian/header/glassmorphic-combobox.d.ts +0 -15
- package/dist/components/guardian/header/glassmorphic-combobox.js +0 -30
- package/dist/components/guardian/header.js +0 -61
- package/dist/components/guardian/hooks/use-frame-messages.js +0 -65
- package/dist/components/guardian/hooks/use-frame-params.js +0 -44
- package/dist/components/guardian/hooks/use-sandbox-url-loader.js +0 -101
- package/dist/components/guardian/ide/browser.js +0 -538
- package/dist/components/guardian/index.js +0 -8
- package/dist/components/guardian/layout/app-layout-no-sidebar.js +0 -8
- package/dist/components/guardian/layout/header/glassmorphic-combobox.js +0 -48
- package/dist/components/guardian/layout/header.js +0 -63
- package/dist/components/guardian/right-view/code-view.js +0 -56
- package/dist/components/guardian/right-view/pill-file-selector.js +0 -233
- package/dist/components/guardian/right-view/preview-control-bar.js +0 -25
- package/dist/components/guardian/right-view/right-panel-view.js +0 -38
- package/dist/components/guardian/right-view/right-top-down-view.js +0 -289
- package/dist/components/guardian/right-view/right-view.js +0 -28
- package/dist/components/guardian/right-view/simplified-editor.js +0 -234
- package/dist/components/guardian/types/ide-types.js +0 -162
- package/dist/components/guardian/types.js +0 -3
- package/dist/components/guardian/ui/ai-loader.js +0 -48
- package/dist/components/guardian/ui/badge.js +0 -24
- package/dist/components/guardian/ui/button.js +0 -45
- package/dist/components/guardian/ui/command.js +0 -63
- package/dist/components/guardian/ui/console-with-app.js +0 -17
- package/dist/components/guardian/ui/dialog.js +0 -57
- package/dist/components/guardian/ui/dropdown-menu.js +0 -82
- package/dist/components/guardian/ui/markdown.js +0 -57
- package/dist/components/guardian/ui/popover.js +0 -25
- package/dist/components/guardian/ui/tooltip.js +0 -25
- package/dist/components/guardian/utils.js +0 -88
- package/dist/components/guardian/zip-to-codebase.js +0 -246
- package/dist/components/guardian/zip-to-filetree.js +0 -284
- package/dist/components/sandbox/SandboxHome.js +0 -141
- package/dist/components/sandbox/guardian/guardian-demo.js +0 -35
- package/dist/components/sandbox/guardian/guardian-home.d.ts +0 -4
- package/dist/components/sandbox/guardian/guardian-home.js +0 -61
- package/dist/components/sandbox/guardian/guardian-upload-spec.d.ts +0 -14
- package/dist/components/sandbox/guardian/guardian-upload-spec.js +0 -160
- package/dist/components/sandbox/guardian/ui/theme-color-context.d.ts +0 -6
- package/dist/components/sandbox/sandbox-control-bar.js +0 -91
- package/dist/components/sandbox/sandbox-header.js +0 -52
- package/dist/components/sandbox/sandbox-left-panel.js +0 -248
- package/dist/components/sandbox/sandbox-loading.js +0 -48
- package/dist/components/sandbox/sandbox-right-panel.js +0 -247
- package/dist/components/sandbox.js +0 -32
- package/dist/lib/api-client.example.js +0 -60
- package/dist/lib/ssr-safe-decode-entity.js +0 -16
|
@@ -1,141 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
import React, { useState } from "react";
|
|
3
|
-
// Default sandboxes array - will be replaced with API call in the future
|
|
4
|
-
const DEFAULT_SANDBOXES = [
|
|
5
|
-
{
|
|
6
|
-
id: "1",
|
|
7
|
-
title: "Next.js AI Chatbot",
|
|
8
|
-
description: "A full-featured, hackable Next.js AI chatbot built by Vercel",
|
|
9
|
-
sandboxId: "nextjs-ai-chatbot",
|
|
10
|
-
},
|
|
11
|
-
{
|
|
12
|
-
id: "2",
|
|
13
|
-
title: "Hume AI - Empathic Voice Interface",
|
|
14
|
-
description: "This template creates a voice chat using Hume AI's Empathic Voice Interface.",
|
|
15
|
-
sandboxId: "hume-ai-voice",
|
|
16
|
-
},
|
|
17
|
-
{
|
|
18
|
-
id: "3",
|
|
19
|
-
title: "Lead Agent",
|
|
20
|
-
description: "An inbound lead qualification and research agent built with Next.js, AI SDK, Workflow...",
|
|
21
|
-
sandboxId: "lead-agent",
|
|
22
|
-
},
|
|
23
|
-
{
|
|
24
|
-
id: "4",
|
|
25
|
-
title: "Slack Agent Template",
|
|
26
|
-
description: "This is a Slack Agent template built with Bolt for JavaScript (TypeScript) and the Nitro server...",
|
|
27
|
-
sandboxId: "slack-agent",
|
|
28
|
-
},
|
|
29
|
-
{
|
|
30
|
-
id: "5",
|
|
31
|
-
title: "Customer Reviews AI Summary",
|
|
32
|
-
description: "Use a Large Language Model to summarize customer feedback.",
|
|
33
|
-
sandboxId: "customer-reviews-ai",
|
|
34
|
-
},
|
|
35
|
-
{
|
|
36
|
-
id: "6",
|
|
37
|
-
title: "Nuxt AI Chatbot",
|
|
38
|
-
description: "An AI chatbot template to build your own chatbot powered by Nuxt MDC and Vercel AI...",
|
|
39
|
-
sandboxId: "nuxt-ai-chatbot",
|
|
40
|
-
},
|
|
41
|
-
{
|
|
42
|
-
id: "7",
|
|
43
|
-
title: "Morphic: AI-powered answer engine",
|
|
44
|
-
description: "AI answer engine with Generative UI.",
|
|
45
|
-
sandboxId: "morphic-ai",
|
|
46
|
-
},
|
|
47
|
-
{
|
|
48
|
-
id: "8",
|
|
49
|
-
title: "Pinecone - Vercel AI SDK Starter",
|
|
50
|
-
description: "A Next.js starter chatbot using Vercel's AI SDK and implements the Retrieval-Augmented...",
|
|
51
|
-
sandboxId: "pinecone-ai-sdk",
|
|
52
|
-
},
|
|
53
|
-
{
|
|
54
|
-
id: "9",
|
|
55
|
-
title: "qrGPT - AI QR Code Generator",
|
|
56
|
-
description: "QrGPT is an AI tool for you to generate beautiful QR codes using AI with one click. Powered by...",
|
|
57
|
-
sandboxId: "qrgpt-ai",
|
|
58
|
-
},
|
|
59
|
-
];
|
|
60
|
-
// Generate a deterministic gradient based on the title
|
|
61
|
-
function getGradientColors(title) {
|
|
62
|
-
// Defensive check - ensure we have a valid string
|
|
63
|
-
if (title === undefined || title === null || typeof title !== "string") {
|
|
64
|
-
return "from-slate-700 to-slate-900";
|
|
65
|
-
}
|
|
66
|
-
const safeTitle = String(title); // Convert to string as final safety
|
|
67
|
-
if (safeTitle.length === 0) {
|
|
68
|
-
return "from-slate-700 to-slate-900";
|
|
69
|
-
}
|
|
70
|
-
try {
|
|
71
|
-
const hash = safeTitle
|
|
72
|
-
.split("")
|
|
73
|
-
.reduce((acc, char) => char.charCodeAt(0) + acc, 0);
|
|
74
|
-
const gradients = [
|
|
75
|
-
"from-slate-700 to-slate-900",
|
|
76
|
-
"from-zinc-700 to-zinc-900",
|
|
77
|
-
"from-gray-700 to-gray-900",
|
|
78
|
-
"from-neutral-700 to-neutral-900",
|
|
79
|
-
"from-stone-700 to-stone-900",
|
|
80
|
-
"from-slate-600 to-slate-800",
|
|
81
|
-
"from-zinc-600 to-zinc-800",
|
|
82
|
-
"from-gray-600 to-gray-800",
|
|
83
|
-
];
|
|
84
|
-
return gradients[Math.abs(hash) % gradients.length];
|
|
85
|
-
}
|
|
86
|
-
catch (e) {
|
|
87
|
-
return "from-slate-700 to-slate-900";
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
// Individual Sandbox Card Component
|
|
91
|
-
function SandboxCard({ title, description, sandboxId, }) {
|
|
92
|
-
// Ensure title is always a string
|
|
93
|
-
const safeTitle = title || "";
|
|
94
|
-
const safeDescription = description || "";
|
|
95
|
-
const gradient = getGradientColors(safeTitle);
|
|
96
|
-
return (React.createElement("div", { className: "group relative block min-w-[240px] w-full h-[200px] border border-[#333] bg-[#0a0a0a] rounded-lg overflow-hidden transition-all duration-100 ease-out hover:border-[#444] focus-visible:outline-none" },
|
|
97
|
-
React.createElement("div", { className: "flex flex-col gap-1 px-6 py-5" },
|
|
98
|
-
React.createElement("div", { className: "flex items-center max-w-max pr-2.5" },
|
|
99
|
-
React.createElement("h3", { className: "text-[16px] font-medium m-0 w-max whitespace-nowrap overflow-hidden text-ellipsis flex-1 mr-0 text-white" }, safeTitle),
|
|
100
|
-
React.createElement("svg", { className: "rotate-[-45deg] translate-x-[-2px] opacity-0 transition-all duration-100 ease-out origin-center group-hover:opacity-100 group-hover:translate-x-[4px] ml-1", height: "16", strokeLinejoin: "round", style: { width: 12, height: 12, color: "currentColor" }, viewBox: "0 0 16 16", width: "16" },
|
|
101
|
-
React.createElement("path", { fillRule: "evenodd", clipRule: "evenodd", d: "M9.53033 2.21968L9 1.68935L7.93934 2.75001L8.46967 3.28034L12.4393 7.25001H1.75H1V8.75001H1.75H12.4393L8.46967 12.7197L7.93934 13.25L9 14.3107L9.53033 13.7803L14.6036 8.70711C14.9941 8.31659 14.9941 7.68342 14.6036 7.2929L9.53033 2.21968Z", fill: "currentColor" }))),
|
|
102
|
-
React.createElement("p", { className: "text-[14px] text-gray-400 m-0 line-clamp-2" }, safeDescription)),
|
|
103
|
-
React.createElement("div", { className: "absolute top-[110px] -right-10 w-[300px] h-[100px] rounded-lg border border-[#333] overflow-hidden shadow-lg transition-transform duration-100 ease-out rotate-[-5deg] group-hover:rotate-[-3deg] group-hover:-translate-y-1 group-hover:-translate-x-0.5" },
|
|
104
|
-
React.createElement("div", { className: `w-full h-full bg-gradient-to-br ${gradient} flex items-center justify-center` },
|
|
105
|
-
React.createElement("div", { className: "w-full px-6 space-y-2" },
|
|
106
|
-
React.createElement("div", { className: "h-2 bg-white/20 rounded w-1/2 mx-auto" }),
|
|
107
|
-
React.createElement("div", { className: "h-1.5 bg-white/10 rounded w-3/4 mx-auto" }),
|
|
108
|
-
React.createElement("div", { className: "h-1.5 bg-white/10 rounded w-2/3 mx-auto" }))))));
|
|
109
|
-
}
|
|
110
|
-
/**
|
|
111
|
-
* SandboxHome component - displays a grid of template cards for sandbox applications
|
|
112
|
-
*
|
|
113
|
-
* @example
|
|
114
|
-
* ```tsx
|
|
115
|
-
* <SandboxHome
|
|
116
|
-
* apiKey={process.env.NEXT_PUBLIC_SAMPLEAPP_API_KEY!}
|
|
117
|
-
* orgid="org-123"
|
|
118
|
-
* sandboxes={[
|
|
119
|
-
* {
|
|
120
|
-
* id: "1",
|
|
121
|
-
* title: "Next.js AI Chatbot",
|
|
122
|
-
* description: "A full-featured, hackable Next.js AI chatbot built by Vercel",
|
|
123
|
-
* sandboxId: "nextjs-ai-chatbot"
|
|
124
|
-
* }
|
|
125
|
-
* ]}
|
|
126
|
-
* />
|
|
127
|
-
* ```
|
|
128
|
-
*/
|
|
129
|
-
export const SandboxHome = ({ apiKey, orgid, sandboxes, }) => {
|
|
130
|
-
const [loading, setLoading] = useState(false);
|
|
131
|
-
const [error, setError] = useState(null);
|
|
132
|
-
// Use provided sandboxes or default array
|
|
133
|
-
// TODO: Replace DEFAULT_SANDBOXES with API call using apiKey and orgid
|
|
134
|
-
// const displaySandboxes = await fetchSandboxes(apiKey, orgid);
|
|
135
|
-
const displaySandboxes = sandboxes || DEFAULT_SANDBOXES;
|
|
136
|
-
return (React.createElement("div", { className: "min-h-screen bg-black" },
|
|
137
|
-
React.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-4" }, displaySandboxes && displaySandboxes.length > 0 ? (displaySandboxes
|
|
138
|
-
.filter((sandbox) => sandbox && sandbox.title && sandbox.description)
|
|
139
|
-
.map((sandbox) => (React.createElement(SandboxCard, { key: sandbox.id, title: sandbox.title || "", description: sandbox.description || "", sandboxId: sandbox.sandboxId })))) : (React.createElement("div", { className: "col-span-full text-center py-16" },
|
|
140
|
-
React.createElement("p", { className: "text-gray-500 text-lg" }, "No sandboxes available. Provide sandboxes prop to display cards."))))));
|
|
141
|
-
};
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
import React, { useEffect, useState, useCallback } from "react";
|
|
3
|
-
import ConsoleWithApp from "./ui/console-with-app";
|
|
4
|
-
import { useGuardianContext } from "./context/guardian-context";
|
|
5
|
-
import ConsoleWithGuide from "./demo/left-view";
|
|
6
|
-
import RightView from "./right-view/right-view";
|
|
7
|
-
export default function GuardianDemo({ CustomConsole, GuideView, browserUrl, playgroundUid, useVm, codeZipFile, completeCodeZipFile, variant, themeColor, hasPreview, isFrame = false, isGuardian = false, }) {
|
|
8
|
-
const { isBrowserMaximized } = useGuardianContext();
|
|
9
|
-
const { setCurrentView } = useGuardianContext();
|
|
10
|
-
const [reloadCounter, setReloadCounter] = useState(0);
|
|
11
|
-
const [overlayStage, setOverlayStage] = useState("hidden");
|
|
12
|
-
const handleReloadPreview = useCallback(() => {
|
|
13
|
-
setReloadCounter((c) => c + 1);
|
|
14
|
-
}, []);
|
|
15
|
-
const handleStageChange = useCallback((stage) => {
|
|
16
|
-
setOverlayStage(stage);
|
|
17
|
-
if (stage === "rebuilding") {
|
|
18
|
-
// Simulate a 3-second rebuild then hide
|
|
19
|
-
setTimeout(() => setOverlayStage("hidden"), 3000);
|
|
20
|
-
}
|
|
21
|
-
}, []);
|
|
22
|
-
useEffect(() => {
|
|
23
|
-
setCurrentView("preview");
|
|
24
|
-
}, [setCurrentView]);
|
|
25
|
-
// If isFrame, just return RightView directly
|
|
26
|
-
if (isFrame) {
|
|
27
|
-
return (React.createElement(RightView, { reloadCounter: reloadCounter, overlayStage: overlayStage, browserUrl: browserUrl, useVm: useVm, codeZipFile: codeZipFile, hasPreview: hasPreview, variant: variant, themeColor: themeColor, completeCodeZipFile: completeCodeZipFile, isGuardian: isGuardian }));
|
|
28
|
-
}
|
|
29
|
-
// If browser is maximized, render RightView at full size without the console
|
|
30
|
-
if (isBrowserMaximized && isGuardian) {
|
|
31
|
-
return (React.createElement("div", { className: "w-full h-full rounded-2xl border overflow-hidden" },
|
|
32
|
-
React.createElement(RightView, { reloadCounter: reloadCounter, overlayStage: overlayStage, browserUrl: browserUrl, useVm: useVm, codeZipFile: codeZipFile, hasPreview: hasPreview, variant: variant, themeColor: themeColor, completeCodeZipFile: completeCodeZipFile, isGuardian: isGuardian, isBrowserMaximized: true })));
|
|
33
|
-
}
|
|
34
|
-
return (React.createElement(ConsoleWithApp, { containerClassName: "rounded-2xl border", console: React.createElement(ConsoleWithGuide, { CustomConsole: CustomConsole, GuideView: GuideView, playgroundUid: playgroundUid, onReloadPreview: handleReloadPreview, onStageChange: handleStageChange, codeZipFile: codeZipFile, themeColor: themeColor }), app: React.createElement(RightView, { reloadCounter: reloadCounter, overlayStage: overlayStage, browserUrl: browserUrl, useVm: useVm, codeZipFile: codeZipFile, hasPreview: hasPreview, variant: variant, themeColor: themeColor, completeCodeZipFile: completeCodeZipFile, isGuardian: isGuardian }) }));
|
|
35
|
-
}
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
import Link from "next/link";
|
|
3
|
-
import AppLayoutNoSidebar from "./app-layout-no-sidebar";
|
|
4
|
-
import { useSandboxUrlLoader } from "./hooks/use-sandbox-url-loader";
|
|
5
|
-
import { useEffect, useRef } from "react";
|
|
6
|
-
export default function GuardianHome({ nestedConfig, }) {
|
|
7
|
-
var _a, _b, _c;
|
|
8
|
-
const { preloadSandboxUrls } = useSandboxUrlLoader();
|
|
9
|
-
const hasPreloadedRef = useRef(false);
|
|
10
|
-
// Preload all sandbox URLs when the home page loads (only once)
|
|
11
|
-
useEffect(() => {
|
|
12
|
-
// Prevent multiple preload attempts
|
|
13
|
-
if (hasPreloadedRef.current) {
|
|
14
|
-
return;
|
|
15
|
-
}
|
|
16
|
-
hasPreloadedRef.current = true;
|
|
17
|
-
// Extract all framework configs from nested structure
|
|
18
|
-
const configs = Object.values(nestedConfig).flatMap((uc) => Object.values(uc.frameworks).flatMap((fw) => {
|
|
19
|
-
// Include the main framework config
|
|
20
|
-
const mainConfig = {
|
|
21
|
-
sandboxUid: fw.sandboxUid,
|
|
22
|
-
browserUrl: fw.browserUrl,
|
|
23
|
-
useVm: fw.useVm,
|
|
24
|
-
};
|
|
25
|
-
// Include additional URLs from consoleUrlConfigs (urlsToPreload)
|
|
26
|
-
const additionalConfigs = fw.consoleUrlConfigs || [];
|
|
27
|
-
return [mainConfig, ...additionalConfigs];
|
|
28
|
-
}));
|
|
29
|
-
// Preload all URLs in the background
|
|
30
|
-
preloadSandboxUrls(configs).catch((error) => {
|
|
31
|
-
console.error("Failed to preload some sandbox URLs:", error);
|
|
32
|
-
});
|
|
33
|
-
}, [nestedConfig, preloadSandboxUrls]);
|
|
34
|
-
// Build unique use cases list with first framework for each
|
|
35
|
-
const uniqueUseCases = Object.entries(nestedConfig).map(([id, uc]) => {
|
|
36
|
-
const firstFramework = Object.keys(uc.frameworks)[0];
|
|
37
|
-
return {
|
|
38
|
-
id,
|
|
39
|
-
name: uc.name,
|
|
40
|
-
description: uc.description,
|
|
41
|
-
firstFramework,
|
|
42
|
-
};
|
|
43
|
-
});
|
|
44
|
-
// Get playground logo from the first framework of the first use case
|
|
45
|
-
const playgroundLogo = (_c = (_a = Object.values(nestedConfig)[0]) === null || _a === void 0 ? void 0 : _a.frameworks[Object.keys(((_b = Object.values(nestedConfig)[0]) === null || _b === void 0 ? void 0 : _b.frameworks) || {})[0]]) === null || _c === void 0 ? void 0 : _c.playgroundLogo;
|
|
46
|
-
return (React.createElement(AppLayoutNoSidebar, { header: React.createElement("div", { className: "flex items-center gap-3 ml-6" }, playgroundLogo) },
|
|
47
|
-
React.createElement("div", { className: "h-full flex flex-col" },
|
|
48
|
-
React.createElement("div", { className: "flex-1 px-6 py-6 space-y-8" },
|
|
49
|
-
React.createElement("div", { className: "space-y-3" },
|
|
50
|
-
React.createElement("div", { className: "text-xs font-medium text-gray-400 tracking-wider uppercase" }, "Examples"),
|
|
51
|
-
React.createElement("h1", { className: "text-2xl font-semibold text-gray-100" }, "Sample apps"),
|
|
52
|
-
React.createElement("p", { className: "text-sm text-gray-400" }, "Select a sample app to explore and interact with")),
|
|
53
|
-
React.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6" }, uniqueUseCases.map((useCase) => (React.createElement(Link, { href: `/${useCase.id}?framework=${useCase.firstFramework}`, key: useCase.id },
|
|
54
|
-
React.createElement("div", { className: "bg-[#1a1b23] rounded-lg border border-gray-800 p-6 flex flex-col justify-between min-h-[180px] hover:border-gray-700 transition-colors cursor-pointer" },
|
|
55
|
-
React.createElement("div", null,
|
|
56
|
-
React.createElement("div", { className: "flex items-center gap-3 mb-2" },
|
|
57
|
-
React.createElement("h2", { className: "font-semibold text-base text-gray-100" }, useCase.name)),
|
|
58
|
-
React.createElement("div", { className: "text-gray-400 text-sm mb-6" }, useCase.description)),
|
|
59
|
-
React.createElement("div", { className: "flex items-center gap-2" },
|
|
60
|
-
React.createElement("span", { className: "text-xs text-gray-500" }, "View app \u2192")))))))))));
|
|
61
|
-
}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
type UploadedFile = {
|
|
3
|
-
name: string;
|
|
4
|
-
size: number;
|
|
5
|
-
type: string;
|
|
6
|
-
content?: string;
|
|
7
|
-
};
|
|
8
|
-
type GuardianUploadSpecProps = {
|
|
9
|
-
onBack: () => void;
|
|
10
|
-
onContinue: (file: UploadedFile) => void;
|
|
11
|
-
isLoading?: boolean;
|
|
12
|
-
};
|
|
13
|
-
export default function GuardianUploadSpec({ onBack, onContinue, isLoading, }: GuardianUploadSpecProps): React.JSX.Element;
|
|
14
|
-
export {};
|
|
@@ -1,160 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
import React from "react";
|
|
3
|
-
"use client";
|
|
4
|
-
import { useState, useCallback } from "react";
|
|
5
|
-
import { Upload, FileText, X, Check, AlertCircle } from "lucide-react";
|
|
6
|
-
import { cn } from "../../../lib/utils";
|
|
7
|
-
export default function GuardianUploadSpec({ onBack, onContinue, isLoading = false, }) {
|
|
8
|
-
const [uploadedFile, setUploadedFile] = useState(null);
|
|
9
|
-
const [isDragging, setIsDragging] = useState(false);
|
|
10
|
-
const [error, setError] = useState(null);
|
|
11
|
-
const [isValidating, setIsValidating] = useState(false);
|
|
12
|
-
const validateFile = (file) => {
|
|
13
|
-
// Check file size (max 10MB)
|
|
14
|
-
if (file.size > 10 * 1024 * 1024) {
|
|
15
|
-
return "File size must be less than 10MB";
|
|
16
|
-
}
|
|
17
|
-
// Check file type
|
|
18
|
-
const validTypes = [
|
|
19
|
-
"application/json",
|
|
20
|
-
"application/x-yaml",
|
|
21
|
-
"application/yaml",
|
|
22
|
-
"text/yaml",
|
|
23
|
-
"text/x-yaml",
|
|
24
|
-
"text/plain",
|
|
25
|
-
];
|
|
26
|
-
const validExtensions = [".json", ".yaml", ".yml"];
|
|
27
|
-
const hasValidType = validTypes.includes(file.type);
|
|
28
|
-
const hasValidExtension = validExtensions.some((ext) => file.name.toLowerCase().endsWith(ext));
|
|
29
|
-
if (!hasValidType && !hasValidExtension) {
|
|
30
|
-
return "Please upload a JSON or YAML file";
|
|
31
|
-
}
|
|
32
|
-
return null;
|
|
33
|
-
};
|
|
34
|
-
const handleFile = useCallback((file) => {
|
|
35
|
-
setError(null);
|
|
36
|
-
setIsValidating(true);
|
|
37
|
-
const validationError = validateFile(file);
|
|
38
|
-
if (validationError) {
|
|
39
|
-
setError(validationError);
|
|
40
|
-
setIsValidating(false);
|
|
41
|
-
return;
|
|
42
|
-
}
|
|
43
|
-
const reader = new FileReader();
|
|
44
|
-
reader.onload = (e) => {
|
|
45
|
-
var _a;
|
|
46
|
-
const content = (_a = e.target) === null || _a === void 0 ? void 0 : _a.result;
|
|
47
|
-
// Basic validation that it's valid JSON or YAML
|
|
48
|
-
try {
|
|
49
|
-
if (file.name.toLowerCase().endsWith(".json")) {
|
|
50
|
-
JSON.parse(content);
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
catch (_b) {
|
|
54
|
-
setError("Invalid JSON file");
|
|
55
|
-
setIsValidating(false);
|
|
56
|
-
return;
|
|
57
|
-
}
|
|
58
|
-
setUploadedFile({
|
|
59
|
-
name: file.name,
|
|
60
|
-
size: file.size,
|
|
61
|
-
type: file.type,
|
|
62
|
-
content,
|
|
63
|
-
});
|
|
64
|
-
setIsValidating(false);
|
|
65
|
-
};
|
|
66
|
-
reader.onerror = () => {
|
|
67
|
-
setError("Failed to read file");
|
|
68
|
-
setIsValidating(false);
|
|
69
|
-
};
|
|
70
|
-
reader.readAsText(file);
|
|
71
|
-
}, []);
|
|
72
|
-
const handleDrop = useCallback((e) => {
|
|
73
|
-
e.preventDefault();
|
|
74
|
-
setIsDragging(false);
|
|
75
|
-
const files = Array.from(e.dataTransfer.files);
|
|
76
|
-
if (files.length > 0) {
|
|
77
|
-
handleFile(files[0]);
|
|
78
|
-
}
|
|
79
|
-
}, [handleFile]);
|
|
80
|
-
const handleDragOver = useCallback((e) => {
|
|
81
|
-
e.preventDefault();
|
|
82
|
-
setIsDragging(true);
|
|
83
|
-
}, []);
|
|
84
|
-
const handleDragLeave = useCallback((e) => {
|
|
85
|
-
e.preventDefault();
|
|
86
|
-
setIsDragging(false);
|
|
87
|
-
}, []);
|
|
88
|
-
const handleFileInput = useCallback((e) => {
|
|
89
|
-
const files = e.target.files;
|
|
90
|
-
if (files && files.length > 0) {
|
|
91
|
-
handleFile(files[0]);
|
|
92
|
-
}
|
|
93
|
-
}, [handleFile]);
|
|
94
|
-
const handleRemoveFile = () => {
|
|
95
|
-
setUploadedFile(null);
|
|
96
|
-
setError(null);
|
|
97
|
-
};
|
|
98
|
-
const formatFileSize = (bytes) => {
|
|
99
|
-
if (bytes < 1024)
|
|
100
|
-
return bytes + " B";
|
|
101
|
-
if (bytes < 1024 * 1024)
|
|
102
|
-
return (bytes / 1024).toFixed(1) + " KB";
|
|
103
|
-
return (bytes / (1024 * 1024)).toFixed(1) + " MB";
|
|
104
|
-
};
|
|
105
|
-
return (React.createElement("div", { className: "min-h-screen bg-white flex flex-col items-center justify-center p-8" },
|
|
106
|
-
React.createElement("div", { className: "w-full max-w-xl" },
|
|
107
|
-
React.createElement("div", { className: "mb-8" },
|
|
108
|
-
React.createElement("button", { type: "button", onClick: onBack, disabled: isLoading, className: "text-sm text-gray-500 hover:text-gray-700 font-medium mb-4 flex items-center gap-1 disabled:opacity-50 disabled:cursor-not-allowed" }, isLoading ? (React.createElement(React.Fragment, null,
|
|
109
|
-
React.createElement("div", { className: "h-3 w-3 animate-spin rounded-full border-2 border-gray-300 border-t-gray-700" }),
|
|
110
|
-
React.createElement("span", null, "Back"))) : (React.createElement(React.Fragment, null, "\u2190 Back"))),
|
|
111
|
-
React.createElement("h1", { className: "text-3xl font-semibold text-black mb-3" }, "Upload OpenAPI spec"),
|
|
112
|
-
React.createElement("p", { className: "text-sm text-gray-600" }, "Upload your OpenAPI specification file (JSON or YAML format) to generate sample apps.")),
|
|
113
|
-
!uploadedFile ? (React.createElement("div", { onDrop: handleDrop, onDragOver: handleDragOver, onDragLeave: handleDragLeave, className: cn("relative rounded-xl border-2 border-dashed transition-all", isDragging
|
|
114
|
-
? "border-blue-500 bg-blue-50"
|
|
115
|
-
: "border-gray-200 bg-gray-50", error && "border-red-300 bg-red-50") },
|
|
116
|
-
React.createElement("label", { className: "flex flex-col items-center justify-center px-8 py-12 cursor-pointer" },
|
|
117
|
-
React.createElement("input", { type: "file", className: "hidden", accept: ".json,.yaml,.yml", onChange: handleFileInput, disabled: isValidating }),
|
|
118
|
-
isValidating ? (React.createElement(React.Fragment, null,
|
|
119
|
-
React.createElement("div", { className: "h-12 w-12 mb-4 animate-spin rounded-full border-4 border-gray-200 border-t-blue-600" }),
|
|
120
|
-
React.createElement("p", { className: "text-sm font-medium text-gray-900 mb-1" }, "Validating file..."))) : (React.createElement(React.Fragment, null,
|
|
121
|
-
React.createElement("div", { className: cn("flex h-14 w-14 items-center justify-center rounded-full mb-4 transition-colors", isDragging ? "bg-blue-100" : "bg-white", error && "bg-red-100") }, error ? (React.createElement(AlertCircle, { className: "h-7 w-7 text-red-600" })) : (React.createElement(Upload, { className: cn("h-7 w-7", isDragging ? "text-blue-600" : "text-gray-400") }))),
|
|
122
|
-
React.createElement("p", { className: "text-sm font-medium text-gray-900 mb-1" }, isDragging ? ("Drop your file here") : (React.createElement(React.Fragment, null,
|
|
123
|
-
React.createElement("span", { className: "text-blue-600" }, "Click to upload"),
|
|
124
|
-
" ",
|
|
125
|
-
"or drag and drop"))),
|
|
126
|
-
React.createElement("p", { className: "text-xs text-gray-500 mb-2" }, "JSON or YAML (max 10MB)"))),
|
|
127
|
-
error && (React.createElement("div", { className: "mt-3 text-xs text-red-600 font-medium flex items-center gap-1.5" },
|
|
128
|
-
React.createElement(AlertCircle, { className: "h-3.5 w-3.5" }),
|
|
129
|
-
error))))) : (React.createElement("div", { className: "space-y-4" },
|
|
130
|
-
React.createElement("div", { className: "rounded-xl border border-gray-200 bg-white p-4 transition hover:bg-gray-50" },
|
|
131
|
-
React.createElement("div", { className: "flex items-start justify-between gap-3" },
|
|
132
|
-
React.createElement("div", { className: "flex items-start gap-3 flex-1" },
|
|
133
|
-
React.createElement("div", { className: "flex h-10 w-10 items-center justify-center rounded-full bg-green-50" },
|
|
134
|
-
React.createElement(FileText, { className: "h-5 w-5 text-green-600" })),
|
|
135
|
-
React.createElement("div", { className: "flex-1 min-w-0" },
|
|
136
|
-
React.createElement("div", { className: "flex items-center gap-2 mb-1" },
|
|
137
|
-
React.createElement("p", { className: "text-sm font-medium text-gray-900 truncate" }, uploadedFile.name),
|
|
138
|
-
React.createElement("div", { className: "flex h-5 w-5 items-center justify-center rounded-full bg-green-500 flex-shrink-0" },
|
|
139
|
-
React.createElement(Check, { className: "h-3 w-3 text-white" }))),
|
|
140
|
-
React.createElement("p", { className: "text-xs text-gray-500" }, formatFileSize(uploadedFile.size)))),
|
|
141
|
-
React.createElement("button", { type: "button", onClick: handleRemoveFile, className: "flex h-8 w-8 items-center justify-center rounded-full hover:bg-gray-100 transition-colors text-gray-400 hover:text-gray-600" },
|
|
142
|
-
React.createElement(X, { className: "h-4 w-4" })))),
|
|
143
|
-
React.createElement("div", { className: "rounded-xl bg-blue-50 border border-blue-100 p-4" },
|
|
144
|
-
React.createElement("p", { className: "text-xs text-blue-900 font-medium mb-2" }, "What happens next?"),
|
|
145
|
-
React.createElement("ul", { className: "space-y-1.5 text-xs text-blue-800" },
|
|
146
|
-
React.createElement("li", { className: "flex items-start gap-2" },
|
|
147
|
-
React.createElement("span", null, "\u2022"),
|
|
148
|
-
React.createElement("span", null, "We'll parse your OpenAPI spec and extract all endpoints")),
|
|
149
|
-
React.createElement("li", { className: "flex items-start gap-2" },
|
|
150
|
-
React.createElement("span", null, "\u2022"),
|
|
151
|
-
React.createElement("span", null, "You'll choose frameworks for which to generate sample apps")),
|
|
152
|
-
React.createElement("li", { className: "flex items-start gap-2" },
|
|
153
|
-
React.createElement("span", null, "\u2022"),
|
|
154
|
-
React.createElement("span", null, "Each app will be pre-configured with auth and example calls")))),
|
|
155
|
-
React.createElement("div", { className: "flex items-center justify-end gap-3 pt-2" },
|
|
156
|
-
React.createElement("button", { type: "button", onClick: handleRemoveFile, disabled: isLoading, className: "rounded-full border border-gray-200 bg-white px-5 py-2.5 text-sm font-medium text-gray-700 hover:bg-gray-50 transition-colors disabled:opacity-50 disabled:cursor-not-allowed" }, "Choose different file"),
|
|
157
|
-
React.createElement("button", { type: "button", onClick: () => onContinue(uploadedFile), disabled: isLoading, className: "inline-flex items-center gap-2 rounded-full bg-[#2563EB] px-6 py-2.5 text-sm font-medium text-white hover:bg-[#1d4ed8] transition-colors disabled:opacity-50 disabled:cursor-not-allowed" }, isLoading ? (React.createElement(React.Fragment, null,
|
|
158
|
-
React.createElement("div", { className: "h-4 w-4 animate-spin rounded-full border-2 border-white/30 border-t-white" }),
|
|
159
|
-
React.createElement("span", null, "Processing..."))) : (React.createElement("span", null, "Continue")))))))));
|
|
160
|
-
}
|
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import { ExternalLinkIcon, RefreshCwIcon, LoaderIcon } from "../icons";
|
|
3
|
-
/**
|
|
4
|
-
* Control bar for the sandbox with refresh and external link buttons.
|
|
5
|
-
*/
|
|
6
|
-
export function SandboxControlBar({ src, themeColor, onRefresh, onOpenExternal, isLoading, }) {
|
|
7
|
-
return (React.createElement("div", { style: {
|
|
8
|
-
display: "flex",
|
|
9
|
-
alignItems: "center",
|
|
10
|
-
justifyContent: "space-between",
|
|
11
|
-
padding: "8px 12px",
|
|
12
|
-
borderBottom: "1px solid rgba(255, 255, 255, 0.1)",
|
|
13
|
-
backgroundColor: "rgba(0, 0, 0, 0.3)",
|
|
14
|
-
backdropFilter: "blur(8px)",
|
|
15
|
-
} },
|
|
16
|
-
React.createElement("div", { style: {
|
|
17
|
-
display: "flex",
|
|
18
|
-
alignItems: "center",
|
|
19
|
-
gap: "8px",
|
|
20
|
-
flex: 1,
|
|
21
|
-
minWidth: 0,
|
|
22
|
-
} },
|
|
23
|
-
React.createElement("div", { style: {
|
|
24
|
-
width: "8px",
|
|
25
|
-
height: "8px",
|
|
26
|
-
borderRadius: "50%",
|
|
27
|
-
backgroundColor: isLoading ? "#f59e0b" : "#22c55e",
|
|
28
|
-
flexShrink: 0,
|
|
29
|
-
} }),
|
|
30
|
-
React.createElement("span", { style: {
|
|
31
|
-
fontSize: "12px",
|
|
32
|
-
color: "rgba(255, 255, 255, 0.6)",
|
|
33
|
-
overflow: "hidden",
|
|
34
|
-
textOverflow: "ellipsis",
|
|
35
|
-
whiteSpace: "nowrap",
|
|
36
|
-
fontFamily: "monospace",
|
|
37
|
-
} }, src)),
|
|
38
|
-
React.createElement("div", { style: {
|
|
39
|
-
display: "flex",
|
|
40
|
-
alignItems: "center",
|
|
41
|
-
gap: "4px",
|
|
42
|
-
} },
|
|
43
|
-
React.createElement("button", { onClick: onRefresh, disabled: isLoading, style: {
|
|
44
|
-
display: "flex",
|
|
45
|
-
alignItems: "center",
|
|
46
|
-
justifyContent: "center",
|
|
47
|
-
width: "28px",
|
|
48
|
-
height: "28px",
|
|
49
|
-
borderRadius: "6px",
|
|
50
|
-
border: "none",
|
|
51
|
-
backgroundColor: "transparent",
|
|
52
|
-
color: "rgba(255, 255, 255, 0.7)",
|
|
53
|
-
cursor: isLoading ? "not-allowed" : "pointer",
|
|
54
|
-
opacity: isLoading ? 0.5 : 1,
|
|
55
|
-
transition: "all 0.15s ease",
|
|
56
|
-
}, onMouseEnter: (e) => {
|
|
57
|
-
if (!isLoading) {
|
|
58
|
-
e.currentTarget.style.backgroundColor = "rgba(255, 255, 255, 0.1)";
|
|
59
|
-
e.currentTarget.style.color = themeColor;
|
|
60
|
-
}
|
|
61
|
-
}, onMouseLeave: (e) => {
|
|
62
|
-
e.currentTarget.style.backgroundColor = "transparent";
|
|
63
|
-
e.currentTarget.style.color = "rgba(255, 255, 255, 0.7)";
|
|
64
|
-
}, title: "Refresh" }, isLoading ? (React.createElement(LoaderIcon, { size: 14, style: { animation: "spin 1s linear infinite" } })) : (React.createElement(RefreshCwIcon, { size: 14 }))),
|
|
65
|
-
React.createElement("button", { onClick: onOpenExternal, style: {
|
|
66
|
-
display: "flex",
|
|
67
|
-
alignItems: "center",
|
|
68
|
-
justifyContent: "center",
|
|
69
|
-
width: "28px",
|
|
70
|
-
height: "28px",
|
|
71
|
-
borderRadius: "6px",
|
|
72
|
-
border: "none",
|
|
73
|
-
backgroundColor: "transparent",
|
|
74
|
-
color: "rgba(255, 255, 255, 0.7)",
|
|
75
|
-
cursor: "pointer",
|
|
76
|
-
transition: "all 0.15s ease",
|
|
77
|
-
}, onMouseEnter: (e) => {
|
|
78
|
-
e.currentTarget.style.backgroundColor = "rgba(255, 255, 255, 0.1)";
|
|
79
|
-
e.currentTarget.style.color = themeColor;
|
|
80
|
-
}, onMouseLeave: (e) => {
|
|
81
|
-
e.currentTarget.style.backgroundColor = "transparent";
|
|
82
|
-
e.currentTarget.style.color = "rgba(255, 255, 255, 0.7)";
|
|
83
|
-
}, title: "Open in new tab" },
|
|
84
|
-
React.createElement(ExternalLinkIcon, { size: 14 }))),
|
|
85
|
-
React.createElement("style", null, `
|
|
86
|
-
@keyframes spin {
|
|
87
|
-
from { transform: rotate(0deg); }
|
|
88
|
-
to { transform: rotate(360deg); }
|
|
89
|
-
}
|
|
90
|
-
`)));
|
|
91
|
-
}
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
/**
|
|
3
|
-
* Header component for the Sandbox
|
|
4
|
-
*/
|
|
5
|
-
export function SandboxHeader({ title, description, logo, themeColor, }) {
|
|
6
|
-
return (React.createElement("header", { style: {
|
|
7
|
-
display: "flex",
|
|
8
|
-
height: "64px",
|
|
9
|
-
alignItems: "center",
|
|
10
|
-
justifyContent: "space-between",
|
|
11
|
-
padding: "0 24px",
|
|
12
|
-
borderBottom: "1px solid rgba(255, 255, 255, 0.1)",
|
|
13
|
-
backgroundColor: "rgba(0, 0, 0, 0.3)",
|
|
14
|
-
backdropFilter: "blur(8px)",
|
|
15
|
-
flexShrink: 0,
|
|
16
|
-
} },
|
|
17
|
-
React.createElement("div", { style: { display: "flex", alignItems: "center", gap: "12px" } }, logo),
|
|
18
|
-
title && (React.createElement("div", { style: { textAlign: "center" } },
|
|
19
|
-
React.createElement("h1", { style: {
|
|
20
|
-
fontSize: "14px",
|
|
21
|
-
fontWeight: 600,
|
|
22
|
-
color: "rgba(255, 255, 255, 0.9)",
|
|
23
|
-
margin: 0,
|
|
24
|
-
} }, title),
|
|
25
|
-
description && (React.createElement("p", { style: {
|
|
26
|
-
fontSize: "12px",
|
|
27
|
-
color: "rgba(255, 255, 255, 0.5)",
|
|
28
|
-
margin: 0,
|
|
29
|
-
marginTop: "2px",
|
|
30
|
-
} }, description)))),
|
|
31
|
-
React.createElement("div", { style: {
|
|
32
|
-
display: "flex",
|
|
33
|
-
alignItems: "center",
|
|
34
|
-
gap: "8px",
|
|
35
|
-
padding: "6px 12px",
|
|
36
|
-
borderRadius: "9999px",
|
|
37
|
-
border: `1px solid ${themeColor}30`,
|
|
38
|
-
backgroundColor: `${themeColor}10`,
|
|
39
|
-
} },
|
|
40
|
-
React.createElement("span", { style: {
|
|
41
|
-
width: "8px",
|
|
42
|
-
height: "8px",
|
|
43
|
-
borderRadius: "50%",
|
|
44
|
-
backgroundColor: themeColor,
|
|
45
|
-
boxShadow: `0 0 0 3px ${themeColor}25`,
|
|
46
|
-
} }),
|
|
47
|
-
React.createElement("span", { style: {
|
|
48
|
-
fontSize: "12px",
|
|
49
|
-
fontWeight: 500,
|
|
50
|
-
color: themeColor,
|
|
51
|
-
} }, "Sandbox"))));
|
|
52
|
-
}
|