@sampleapp.ai/sdk 1.0.29 → 1.0.31
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/guardian/app-layout-no-sidebar.js +8 -0
- package/dist/components/guardian/ask-ai-view.js +249 -0
- package/dist/components/guardian/code-focus-section.d.ts +41 -0
- package/dist/components/guardian/code-focus-section.js +174 -0
- package/dist/components/guardian/context/guardian-context.js +94 -0
- package/dist/components/guardian/context/vm-context.js +28 -0
- package/dist/components/guardian/default-guide-view.js +34 -0
- package/dist/components/guardian/demo/guardian-demo.js +35 -0
- package/dist/components/guardian/demo/left-view/toggle.js +28 -0
- package/dist/components/guardian/demo/left-view.js +49 -0
- package/dist/components/guardian/guardian-component.js +79 -0
- package/dist/components/guardian/guardian-demo.js +35 -0
- package/dist/components/guardian/guardian-home.d.ts +4 -0
- package/dist/components/guardian/guardian-home.js +61 -0
- package/dist/components/guardian/guardian-playground.js +45 -0
- package/dist/components/guardian/guardian-style-wrapper.js +29 -0
- package/dist/components/guardian/guardian-upload-spec.d.ts +14 -0
- package/dist/components/guardian/guardian-upload-spec.js +160 -0
- package/dist/components/guardian/header/glassmorphic-combobox.d.ts +15 -0
- package/dist/components/guardian/header/glassmorphic-combobox.js +30 -0
- package/dist/components/guardian/header.js +61 -0
- package/dist/components/guardian/hooks/use-frame-messages.js +65 -0
- package/dist/components/guardian/hooks/use-frame-params.js +44 -0
- package/dist/components/guardian/hooks/use-sandbox-url-loader.js +101 -0
- package/dist/components/guardian/ide/browser.js +538 -0
- package/dist/components/guardian/index.js +8 -0
- package/dist/components/guardian/layout/app-layout-no-sidebar.js +8 -0
- package/dist/components/guardian/layout/header/glassmorphic-combobox.js +48 -0
- package/dist/components/guardian/layout/header.js +63 -0
- package/dist/components/guardian/right-view/code-view.js +56 -0
- package/dist/components/guardian/right-view/pill-file-selector.js +233 -0
- package/dist/components/guardian/right-view/preview-control-bar.js +25 -0
- package/dist/components/guardian/right-view/right-panel-view.js +38 -0
- package/dist/components/guardian/right-view/right-top-down-view.js +289 -0
- package/dist/components/guardian/right-view/right-view.js +28 -0
- package/dist/components/guardian/right-view/simplified-editor.js +234 -0
- package/dist/components/guardian/types/ide-types.js +162 -0
- package/dist/components/guardian/types.js +3 -0
- package/dist/components/guardian/ui/ai-loader.js +48 -0
- package/dist/components/guardian/ui/badge.js +24 -0
- package/dist/components/guardian/ui/button.js +45 -0
- package/dist/components/guardian/ui/command.js +63 -0
- package/dist/components/guardian/ui/console-with-app.js +17 -0
- package/dist/components/guardian/ui/dialog.js +57 -0
- package/dist/components/guardian/ui/dropdown-menu.js +82 -0
- package/dist/components/guardian/ui/markdown.js +57 -0
- package/dist/components/guardian/ui/popover.js +25 -0
- package/dist/components/guardian/ui/tooltip.js +25 -0
- package/dist/components/guardian/utils.js +88 -0
- package/dist/components/guardian/zip-to-codebase.js +246 -0
- package/dist/components/guardian/zip-to-filetree.js +284 -0
- package/dist/components/icons.js +22 -0
- package/dist/components/sandbox/Sandbox.js +88 -0
- package/dist/components/sandbox/SandboxHome.js +141 -0
- package/dist/components/sandbox/api.js +84 -0
- package/dist/components/sandbox/guardian/app-layout-no-sidebar.js +11 -0
- package/dist/components/sandbox/guardian/ask-ai-view.js +249 -0
- package/dist/components/sandbox/guardian/code-focus-section.js +174 -0
- package/dist/components/sandbox/guardian/context/guardian-context.js +94 -0
- package/dist/components/sandbox/guardian/context/vm-context.js +28 -0
- package/dist/components/sandbox/guardian/default-guide-view.js +34 -0
- package/dist/components/sandbox/guardian/demo/guardian-demo.js +35 -0
- package/dist/components/sandbox/guardian/demo/left-view/toggle.js +28 -0
- package/dist/components/sandbox/guardian/demo/left-view.js +70 -0
- package/dist/components/sandbox/guardian/guardian-component.js +99 -0
- package/dist/components/sandbox/guardian/guardian-demo.js +35 -0
- package/dist/components/sandbox/guardian/guardian-home.d.ts +4 -0
- package/dist/components/sandbox/guardian/guardian-home.js +61 -0
- package/dist/components/sandbox/guardian/guardian-playground.js +45 -0
- package/dist/components/sandbox/guardian/guardian-style-wrapper.js +47 -0
- package/dist/components/sandbox/guardian/guardian-upload-spec.d.ts +14 -0
- package/dist/components/sandbox/guardian/guardian-upload-spec.js +160 -0
- package/dist/components/sandbox/guardian/header/glassmorphic-combobox.js +30 -0
- package/dist/components/sandbox/guardian/header.js +61 -0
- package/dist/components/sandbox/guardian/hooks/use-frame-messages.js +65 -0
- package/dist/components/sandbox/guardian/hooks/use-frame-params.js +44 -0
- package/dist/components/sandbox/guardian/hooks/use-sandbox-url-loader.js +125 -0
- package/dist/components/sandbox/guardian/ide/browser.js +538 -0
- package/dist/components/sandbox/guardian/index.js +8 -0
- package/dist/components/sandbox/guardian/right-view/code-view.js +60 -0
- package/dist/components/sandbox/guardian/right-view/pill-file-selector.js +246 -0
- package/dist/components/sandbox/guardian/right-view/preview-control-bar.js +25 -0
- package/dist/components/sandbox/guardian/right-view/right-panel-view.js +51 -0
- package/dist/components/sandbox/guardian/right-view/right-top-down-view.js +281 -0
- package/dist/components/sandbox/guardian/right-view/right-view.js +28 -0
- package/dist/components/sandbox/guardian/right-view/simplified-editor.js +234 -0
- package/dist/components/sandbox/guardian/types/ide-types.js +162 -0
- package/dist/components/sandbox/guardian/types.js +3 -0
- package/dist/components/sandbox/guardian/ui/ai-loader.js +91 -0
- package/dist/components/sandbox/guardian/ui/badge.js +24 -0
- package/dist/components/sandbox/guardian/ui/button.js +45 -0
- package/dist/components/sandbox/guardian/ui/command.js +63 -0
- package/dist/components/sandbox/guardian/ui/console-with-app.js +17 -0
- package/dist/components/sandbox/guardian/ui/dialog.js +57 -0
- package/dist/components/sandbox/guardian/ui/download-and-open-buttons.js +117 -0
- package/dist/components/sandbox/guardian/ui/dropdown-menu.js +82 -0
- package/dist/components/sandbox/guardian/ui/markdown/accordion-group/accordion.js +62 -0
- package/dist/components/sandbox/guardian/ui/markdown/accordion-group.js +23 -0
- package/dist/components/sandbox/guardian/ui/markdown/callout/callout-check.js +4 -0
- package/dist/components/sandbox/guardian/ui/markdown/callout/callout-error.js +4 -0
- package/dist/components/sandbox/guardian/ui/markdown/callout/callout-info.js +4 -0
- package/dist/components/sandbox/guardian/ui/markdown/callout/callout-note.js +4 -0
- package/dist/components/sandbox/guardian/ui/markdown/callout/callout-tip.js +4 -0
- package/dist/components/sandbox/guardian/ui/markdown/callout/callout-warning.js +4 -0
- package/dist/components/sandbox/guardian/ui/markdown/callout/shared/callout.js +9 -0
- package/dist/components/sandbox/guardian/ui/markdown/callout/shared/types.js +1 -0
- package/dist/components/sandbox/guardian/ui/markdown/card-group/card.js +18 -0
- package/dist/components/sandbox/guardian/ui/markdown/card-group.js +25 -0
- package/dist/components/sandbox/guardian/ui/markdown/code-group/code-block.js +54 -0
- package/dist/components/sandbox/guardian/ui/markdown/code-group.js +101 -0
- package/dist/components/sandbox/guardian/ui/markdown/icon.js +31 -0
- package/dist/components/sandbox/guardian/ui/markdown.js +791 -0
- package/dist/components/sandbox/guardian/ui/popover.js +25 -0
- package/dist/components/sandbox/guardian/ui/tooltip.js +25 -0
- package/dist/components/sandbox/guardian/utils.js +89 -0
- package/dist/components/sandbox/guardian/zip-to-codebase.js +259 -0
- package/dist/components/sandbox/guardian/zip-to-filetree.js +284 -0
- package/dist/components/sandbox/index.js +4 -0
- package/dist/components/sandbox/sandbox-control-bar.js +91 -0
- package/dist/components/sandbox/sandbox-header.js +52 -0
- package/dist/components/sandbox/sandbox-home/SandboxCard.js +65 -0
- package/dist/components/sandbox/sandbox-home/SandboxHome.js +115 -0
- package/dist/components/sandbox/sandbox-home/SearchBar.js +12 -0
- package/dist/components/sandbox/sandbox-home/index.js +3 -0
- package/dist/components/sandbox/sandbox-left-panel.js +248 -0
- package/dist/components/sandbox/sandbox-loading.js +48 -0
- package/dist/components/sandbox/sandbox-right-panel.js +247 -0
- package/dist/components/sandbox/types.js +1 -0
- package/dist/components/sandbox.js +32 -0
- package/dist/components/tailwind-example.js +46 -0
- package/dist/components/ui/skeleton.js +18 -0
- package/dist/index.d.ts +32 -103
- package/dist/index.es.js +90529 -423
- package/dist/index.js +13 -2
- package/dist/index.standalone.js +61 -53
- package/dist/index.standalone.umd.js +17 -24
- package/dist/lib/api-client.example.js +60 -0
- package/dist/lib/api-client.js +140 -0
- package/dist/lib/generated-css.js +4 -0
- package/dist/lib/inject-styles.js +42 -0
- package/dist/lib/shadow-dom-wrapper.js +42 -0
- package/dist/lib/utils.js +5 -0
- package/dist/sdk.css +1 -1
- package/dist/tailwind.css +1 -0
- package/package.json +41 -9
|
@@ -0,0 +1,61 @@
|
|
|
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
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import React from "react";
|
|
3
|
+
import GuardianComponent from "./guardian-component";
|
|
4
|
+
import { useFrameParams } from "./hooks/use-frame-params";
|
|
5
|
+
import { GuardianStyleWrapper } from "./guardian-style-wrapper";
|
|
6
|
+
/**
|
|
7
|
+
* Guardian Playground component with nested config structure.
|
|
8
|
+
* Expects config[useCaseId].frameworks[frameworkKey] structure.
|
|
9
|
+
*
|
|
10
|
+
* When isFrame=true, reads framework from URL params client-side.
|
|
11
|
+
*/
|
|
12
|
+
export default function GuardianPlayground({ nestedConfig, useCase, framework: serverFramework, isFrame = false, apiKey, env, chatUid, }) {
|
|
13
|
+
var _a, _b;
|
|
14
|
+
// When in frame mode, allow URL params to override framework
|
|
15
|
+
const frameParams = useFrameParams();
|
|
16
|
+
const framework = isFrame && frameParams.framework ? frameParams.framework : serverFramework;
|
|
17
|
+
const useCaseConfig = nestedConfig[useCase];
|
|
18
|
+
if (!useCaseConfig) {
|
|
19
|
+
return (React.createElement("div", { className: "flex items-center justify-center h-screen" },
|
|
20
|
+
React.createElement("p", { className: "text-red-500" },
|
|
21
|
+
"Use case \"",
|
|
22
|
+
useCase,
|
|
23
|
+
"\" not found")));
|
|
24
|
+
}
|
|
25
|
+
const frameworkConfig = useCaseConfig.frameworks[framework];
|
|
26
|
+
if (!frameworkConfig) {
|
|
27
|
+
return (React.createElement("div", { className: "flex items-center justify-center h-screen" },
|
|
28
|
+
React.createElement("p", { className: "text-red-500" },
|
|
29
|
+
"Framework \"",
|
|
30
|
+
framework,
|
|
31
|
+
"\" not found in use case \"",
|
|
32
|
+
useCase,
|
|
33
|
+
"\"")));
|
|
34
|
+
}
|
|
35
|
+
// Build a map of use case ID to first available framework key
|
|
36
|
+
const firstFrameworkByUseCase = {};
|
|
37
|
+
Object.entries(nestedConfig).forEach(([useCaseId, uc]) => {
|
|
38
|
+
const firstFrameworkKey = Object.keys(uc.frameworks)[0];
|
|
39
|
+
if (firstFrameworkKey) {
|
|
40
|
+
firstFrameworkByUseCase[useCaseId] = firstFrameworkKey;
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
return (React.createElement(GuardianStyleWrapper, { themeColor: frameworkConfig.themeColor },
|
|
44
|
+
React.createElement(GuardianComponent, { demoOptions: frameworkConfig.demoOptions, frameworkOptions: frameworkConfig.frameworkOptions, firstFrameworkByUseCase: firstFrameworkByUseCase, currentFramework: frameworkConfig.currentFramework, CustomConsole: frameworkConfig.CustomConsole, GuideView: frameworkConfig.GuideView, playgroundUid: frameworkConfig.playgroundUid, browserUrl: (_a = frameParams.iframeUrl) !== null && _a !== void 0 ? _a : frameworkConfig.browserUrl, useVm: frameworkConfig.useVm, playgroundLogo: frameworkConfig.playgroundLogo, sandboxUid: frameworkConfig.sandboxUid, name: frameworkConfig.name, description: frameworkConfig.description, codeZipFile: frameworkConfig.codeZipFile, completeCodeZipFile: frameworkConfig.completeCodeZipFile, consoleUrlConfigs: frameworkConfig.consoleUrlConfigs, variant: frameworkConfig.variant, themeColor: frameworkConfig.themeColor, hasPreview: (_b = frameworkConfig.hasPreview) !== null && _b !== void 0 ? _b : true, currentUseCase: useCase, isFrame: isFrame, apiKey: apiKey, env: env, chatUid: chatUid, gitUrl: frameworkConfig.gitUrl })));
|
|
45
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import React, { useEffect, useRef, useState } from "react";
|
|
3
|
+
import { TAILWIND_CSS } from "../../../lib/generated-css";
|
|
4
|
+
/**
|
|
5
|
+
* Style wrapper for Guardian components that injects Tailwind CSS
|
|
6
|
+
* into the document without using Shadow DOM (preserves React context)
|
|
7
|
+
*/
|
|
8
|
+
export const GuardianStyleWrapper = ({ children, themeColor = "#3b82f6", }) => {
|
|
9
|
+
const [stylesInjected, setStylesInjected] = useState(false);
|
|
10
|
+
const rootRef = useRef(null);
|
|
11
|
+
useEffect(() => {
|
|
12
|
+
// Only run on client side
|
|
13
|
+
if (typeof window === "undefined" || typeof document === "undefined") {
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
// Check if styles are already injected
|
|
17
|
+
const existingStyle = document.getElementById("guardian-sdk-styles");
|
|
18
|
+
if (existingStyle) {
|
|
19
|
+
setStylesInjected(true);
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
// Inject styles into document head
|
|
23
|
+
const styleElement = document.createElement("style");
|
|
24
|
+
styleElement.id = "guardian-sdk-styles";
|
|
25
|
+
// Scope styles to guardian-sdk class to avoid conflicts
|
|
26
|
+
styleElement.textContent = TAILWIND_CSS;
|
|
27
|
+
document.head.appendChild(styleElement);
|
|
28
|
+
setStylesInjected(true);
|
|
29
|
+
return () => {
|
|
30
|
+
// Don't remove styles on unmount as other Guardian components might use them
|
|
31
|
+
};
|
|
32
|
+
}, []);
|
|
33
|
+
// Set CSS variables for colors based on themeColor
|
|
34
|
+
useEffect(() => {
|
|
35
|
+
if (rootRef.current) {
|
|
36
|
+
rootRef.current.style.setProperty("--colors-primary", themeColor);
|
|
37
|
+
// Create a slightly lighter version for secondary
|
|
38
|
+
const secondaryColor = themeColor; // Can be customized if needed
|
|
39
|
+
rootRef.current.style.setProperty("--colors-secondary", secondaryColor);
|
|
40
|
+
}
|
|
41
|
+
}, [themeColor]);
|
|
42
|
+
return (React.createElement("div", { ref: rootRef, className: "guardian-sdk-root dark bg-background text-foreground", style: {
|
|
43
|
+
width: "100%",
|
|
44
|
+
height: "100%",
|
|
45
|
+
fontFamily: 'ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"',
|
|
46
|
+
} }, children));
|
|
47
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
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 {};
|
|
@@ -0,0 +1,160 @@
|
|
|
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
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import React, { useState } from "react";
|
|
3
|
+
import { Button } from "../ui/button";
|
|
4
|
+
import { Popover, PopoverContent, PopoverTrigger } from "../ui/popover";
|
|
5
|
+
import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, } from "../ui/command";
|
|
6
|
+
import { CheckIcon, ChevronsUpDown } from "lucide-react";
|
|
7
|
+
import { cn } from "../../../../lib/utils";
|
|
8
|
+
export default function GlassmorphicCombobox({ options, value, placeholder, className, searchPlaceholder, }) {
|
|
9
|
+
var _a;
|
|
10
|
+
const [open, setOpen] = useState(false);
|
|
11
|
+
const selectedLabel = (_a = options.find((o) => o.value === value)) === null || _a === void 0 ? void 0 : _a.label;
|
|
12
|
+
return (React.createElement(Popover, { open: open, onOpenChange: setOpen },
|
|
13
|
+
React.createElement(PopoverTrigger, { asChild: true },
|
|
14
|
+
React.createElement(Button, { variant: "outline", role: "combobox", "aria-expanded": open, className: cn("w-64 justify-between rounded-xl border-white/20 bg-white/10 backdrop-blur-md", "text-white/90 shadow-[inset_0_1px_0_0_rgba(255,255,255,0.25)] hover:bg-white/15", "data-[state=open]:bg-white/15", className) },
|
|
15
|
+
React.createElement("span", { className: "truncate min-w-0" }, selectedLabel !== null && selectedLabel !== void 0 ? selectedLabel : placeholder),
|
|
16
|
+
React.createElement(ChevronsUpDown, { className: "ml-2 h-4 w-4 shrink-0 opacity-70" }))),
|
|
17
|
+
React.createElement(PopoverContent, { className: cn("w-64 p-0 rounded-xl border border-white/20 bg-black/40 backdrop-blur-xl", "shadow-xl") },
|
|
18
|
+
React.createElement(Command, { className: "bg-transparent" },
|
|
19
|
+
React.createElement(CommandInput, { placeholder: searchPlaceholder, className: "bg-transparent placeholder:text-white/60" }),
|
|
20
|
+
React.createElement(CommandList, { className: "bg-transparent" },
|
|
21
|
+
React.createElement(CommandEmpty, { className: "text-white/80" }, "No results found."),
|
|
22
|
+
React.createElement(CommandGroup, { className: "bg-transparent" }, options.map((option) => (React.createElement(CommandItem, { key: option.value, value: option.value, className: "cursor-pointer", onSelect: () => {
|
|
23
|
+
setOpen(false);
|
|
24
|
+
if (option.href && typeof window !== "undefined") {
|
|
25
|
+
window.location.href = option.href;
|
|
26
|
+
}
|
|
27
|
+
} },
|
|
28
|
+
React.createElement(CheckIcon, { className: cn("mr-2 h-4 w-4", value === option.value ? "opacity-100" : "opacity-0") }),
|
|
29
|
+
option.label)))))))));
|
|
30
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import React from "react";
|
|
3
|
+
import { Badge } from "./ui/badge";
|
|
4
|
+
import GlassmorphicCombobox from "./header/glassmorphic-combobox";
|
|
5
|
+
export default function Header({ demoOptions, frameworkOptions, firstFrameworkByUseCase, currentFramework, playgroundLogo, currentUseCase, }) {
|
|
6
|
+
var _a, _b;
|
|
7
|
+
// Derive values directly from props (which come from the URL)
|
|
8
|
+
// No internal state - the URL is the source of truth
|
|
9
|
+
const selectedUseCase = currentUseCase || ((_a = demoOptions[0]) === null || _a === void 0 ? void 0 : _a.value);
|
|
10
|
+
const selectedFramework = currentFramework || ((_b = frameworkOptions[0]) === null || _b === void 0 ? void 0 : _b.value);
|
|
11
|
+
// Build options with hrefs
|
|
12
|
+
const demoOptionsWithHrefs = demoOptions.map((opt) => {
|
|
13
|
+
var _a;
|
|
14
|
+
return (Object.assign(Object.assign({}, opt), {
|
|
15
|
+
// Link to first available framework for this use case
|
|
16
|
+
href: `/${opt.value}?framework=${(firstFrameworkByUseCase === null || firstFrameworkByUseCase === void 0 ? void 0 : firstFrameworkByUseCase[opt.value]) || ((_a = frameworkOptions[0]) === null || _a === void 0 ? void 0 : _a.value)}` }));
|
|
17
|
+
});
|
|
18
|
+
const frameworkOptionsWithHrefs = frameworkOptions.map((opt) => (Object.assign(Object.assign({}, opt), { href: `/${selectedUseCase}?framework=${opt.value}` })));
|
|
19
|
+
// Derive environment metadata for badge styling and label
|
|
20
|
+
const environment = (process.env.NEXT_PUBLIC_ENVIRONMENT ||
|
|
21
|
+
process.env.NODE_ENV ||
|
|
22
|
+
"development").toLowerCase();
|
|
23
|
+
const envMeta = {
|
|
24
|
+
production: {
|
|
25
|
+
label: "Production",
|
|
26
|
+
badgeClass: "border-emerald-500/30 bg-emerald-500/10 text-emerald-200",
|
|
27
|
+
dotClass: "bg-emerald-400 shadow-[0_0_0_3px_rgba(16,185,129,0.25)]",
|
|
28
|
+
},
|
|
29
|
+
staging: {
|
|
30
|
+
label: "Staging",
|
|
31
|
+
badgeClass: "border-amber-500/30 bg-amber-500/10 text-amber-100",
|
|
32
|
+
dotClass: "bg-amber-400 shadow-[0_0_0_3px_rgba(245,158,11,0.25)]",
|
|
33
|
+
},
|
|
34
|
+
test: {
|
|
35
|
+
label: "Test",
|
|
36
|
+
badgeClass: "border-cyan-500/30 bg-cyan-500/10 text-cyan-100",
|
|
37
|
+
dotClass: "bg-cyan-400 shadow-[0_0_0_3px_rgba(34,211,238,0.25)]",
|
|
38
|
+
},
|
|
39
|
+
preview: {
|
|
40
|
+
label: "Preview",
|
|
41
|
+
badgeClass: "border-sky-500/30 bg-sky-500/10 text-sky-100",
|
|
42
|
+
dotClass: "bg-sky-400 shadow-[0_0_0_3px_rgba(56,189,248,0.25)]",
|
|
43
|
+
},
|
|
44
|
+
development: {
|
|
45
|
+
label: "Demo Environment",
|
|
46
|
+
badgeClass: "border-violet-500/30 bg-violet-500/10 text-violet-100",
|
|
47
|
+
dotClass: "bg-violet-400 shadow-[0_0_0_3px_rgba(139,92,246,0.25)]",
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
const meta = envMeta[environment] || envMeta.development;
|
|
51
|
+
return (React.createElement("div", { className: "grid grid-cols-[1fr_auto_1fr] items-center w-full ml-6" },
|
|
52
|
+
React.createElement("div", { className: "justify-self-start" }, playgroundLogo),
|
|
53
|
+
React.createElement("div", { className: "justify-self-center" },
|
|
54
|
+
React.createElement("div", { className: "flex gap-2" },
|
|
55
|
+
React.createElement(GlassmorphicCombobox, { options: demoOptionsWithHrefs, value: selectedUseCase, placeholder: "Select use case...", searchPlaceholder: "Search use case..." }),
|
|
56
|
+
React.createElement(GlassmorphicCombobox, { options: frameworkOptionsWithHrefs, value: selectedFramework, placeholder: "Select framework...", searchPlaceholder: "Search framework...", className: "w-32" }))),
|
|
57
|
+
React.createElement("div", { className: "justify-self-end mr-6" },
|
|
58
|
+
React.createElement(Badge, { className: `rounded-full px-5 py-3 flex items-center gap-2 border ${meta.badgeClass} backdrop-blur-sm shadow-[inset_0_1px_0_rgba(255,255,255,0.04)] text-sm`, "aria-label": `${meta.label} environment` },
|
|
59
|
+
React.createElement("span", { className: `inline-block h-2 w-2 rounded-full ${meta.dotClass}` }),
|
|
60
|
+
meta.label))));
|
|
61
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useEffect, useRef } from "react";
|
|
3
|
+
/**
|
|
4
|
+
* Hook to handle postMessage communication with parent window when in iframe mode.
|
|
5
|
+
* - Sends IFRAME_READY when mounted
|
|
6
|
+
* - Listens for UPDATE_VIEW messages and updates URL params accordingly
|
|
7
|
+
* - Works with useFrameParams() which reads the updated URL params
|
|
8
|
+
*
|
|
9
|
+
* Supported UPDATE_VIEW message fields:
|
|
10
|
+
* - framework: Switch between frameworks (e.g., "nextjs", "react")
|
|
11
|
+
* - activeFilePath: Change the active file in the editor
|
|
12
|
+
* - linesStart/linesEnd: Highlight specific line range in the editor
|
|
13
|
+
* - theme: Override the theme color (hex color)
|
|
14
|
+
*/
|
|
15
|
+
export function useFrameMessages() {
|
|
16
|
+
const hasSignaledReady = useRef(false);
|
|
17
|
+
useEffect(() => {
|
|
18
|
+
if (typeof window === "undefined")
|
|
19
|
+
return;
|
|
20
|
+
// Check if we're in an iframe
|
|
21
|
+
const isFrame = window.self !== window.top;
|
|
22
|
+
if (!isFrame)
|
|
23
|
+
return;
|
|
24
|
+
// Signal to parent that we're ready to receive messages
|
|
25
|
+
if (!hasSignaledReady.current && window.parent) {
|
|
26
|
+
window.parent.postMessage({ type: "IFRAME_READY" }, "*");
|
|
27
|
+
hasSignaledReady.current = true;
|
|
28
|
+
}
|
|
29
|
+
const handleMessage = (event) => {
|
|
30
|
+
// Optional: Add origin validation for security in production
|
|
31
|
+
// if (event.origin !== 'https://your-allowed-origin.com') return;
|
|
32
|
+
const data = event.data;
|
|
33
|
+
if (data.type === "UPDATE_VIEW") {
|
|
34
|
+
const url = new URL(window.location.href);
|
|
35
|
+
// Update URL params based on message
|
|
36
|
+
if (data.framework !== undefined) {
|
|
37
|
+
url.searchParams.set("framework", data.framework);
|
|
38
|
+
}
|
|
39
|
+
if (data.activeFilePath !== undefined) {
|
|
40
|
+
url.searchParams.set("activeFilePath", data.activeFilePath);
|
|
41
|
+
}
|
|
42
|
+
if (data.linesStart !== undefined) {
|
|
43
|
+
url.searchParams.set("linesStart", String(data.linesStart));
|
|
44
|
+
}
|
|
45
|
+
if (data.linesEnd !== undefined) {
|
|
46
|
+
url.searchParams.set("linesEnd", String(data.linesEnd));
|
|
47
|
+
}
|
|
48
|
+
if (data.theme !== undefined) {
|
|
49
|
+
url.searchParams.set("theme", data.theme);
|
|
50
|
+
}
|
|
51
|
+
if (data.iframeUrl !== undefined) {
|
|
52
|
+
url.searchParams.set("iframeUrl", data.iframeUrl);
|
|
53
|
+
}
|
|
54
|
+
// Update URL without page reload
|
|
55
|
+
window.history.replaceState({}, "", url.toString());
|
|
56
|
+
// Dispatch a custom event so React components can react immediately
|
|
57
|
+
// (useFrameParams may have a slight delay)
|
|
58
|
+
window.dispatchEvent(new CustomEvent("frameParamsUpdated", { detail: data }));
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
window.addEventListener("message", handleMessage);
|
|
62
|
+
return () => window.removeEventListener("message", handleMessage);
|
|
63
|
+
}, []);
|
|
64
|
+
return {};
|
|
65
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { useMemo } from "react";
|
|
2
|
+
/**
|
|
3
|
+
* Hook to read frame-mode search parameters from URL.
|
|
4
|
+
* These params override config/context when isFrame=true.
|
|
5
|
+
*
|
|
6
|
+
* Note: This is a simplified version that reads from window.location.search.
|
|
7
|
+
* For Next.js apps, you can use the Next.js version that uses useSearchParams.
|
|
8
|
+
*/
|
|
9
|
+
export function useFrameParams() {
|
|
10
|
+
return useMemo(() => {
|
|
11
|
+
if (typeof window === "undefined") {
|
|
12
|
+
return {
|
|
13
|
+
isFrame: false,
|
|
14
|
+
framework: undefined,
|
|
15
|
+
theme: undefined,
|
|
16
|
+
activeFilePath: undefined,
|
|
17
|
+
linesStart: undefined,
|
|
18
|
+
linesEnd: undefined,
|
|
19
|
+
iframeUrl: undefined,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
const searchParams = new URLSearchParams(window.location.search);
|
|
23
|
+
const isFrame = searchParams.get("isFrame") === "true";
|
|
24
|
+
const framework = searchParams.get("framework") || undefined;
|
|
25
|
+
const theme = searchParams.get("theme") || undefined;
|
|
26
|
+
const activeFilePath = searchParams.get("activeFilePath") || undefined;
|
|
27
|
+
const linesStart = searchParams.get("linesStart")
|
|
28
|
+
? parseInt(searchParams.get("linesStart"), 10)
|
|
29
|
+
: undefined;
|
|
30
|
+
const linesEnd = searchParams.get("linesEnd")
|
|
31
|
+
? parseInt(searchParams.get("linesEnd"), 10)
|
|
32
|
+
: undefined;
|
|
33
|
+
const iframeUrl = searchParams.get("iframeUrl") || undefined;
|
|
34
|
+
return {
|
|
35
|
+
isFrame,
|
|
36
|
+
framework,
|
|
37
|
+
theme,
|
|
38
|
+
activeFilePath,
|
|
39
|
+
linesStart,
|
|
40
|
+
linesEnd,
|
|
41
|
+
iframeUrl,
|
|
42
|
+
};
|
|
43
|
+
}, [typeof window !== "undefined" ? window.location.search : ""]);
|
|
44
|
+
}
|