@sampleapp.ai/sdk 1.0.30 → 1.0.32
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 +3 -2
- package/dist/components/sandbox/api.js +4 -28
- package/dist/components/sandbox/guardian/app-layout-no-sidebar.js +6 -3
- package/dist/components/sandbox/guardian/demo/guardian-demo.js +2 -2
- package/dist/components/sandbox/guardian/demo/left-view.js +17 -5
- package/dist/components/sandbox/guardian/guardian-component.js +7 -5
- package/dist/components/sandbox/guardian/guardian-playground.js +2 -2
- package/dist/components/sandbox/guardian/guardian-style-wrapper.js +17 -3
- package/dist/components/sandbox/guardian/hooks/use-sandbox-url-loader.js +0 -20
- package/dist/components/sandbox/guardian/right-view/pill-file-selector.js +13 -0
- package/dist/components/sandbox/guardian/right-view/right-panel-view.js +17 -4
- package/dist/components/sandbox/guardian/right-view/right-top-down-view.js +42 -50
- package/dist/components/sandbox/guardian/ui/ai-loader.js +56 -13
- package/dist/components/sandbox/guardian/ui/download-and-open-buttons.js +117 -0
- package/dist/components/sandbox/guardian/ui/markdown/code-group/code-block.js +33 -66
- package/dist/components/sandbox/guardian/ui/markdown.js +15 -10
- package/dist/components/sandbox/guardian/ui/theme-color-context.d.ts +6 -0
- package/dist/components/sandbox/guardian/utils.js +1 -0
- package/dist/components/sandbox/sandbox-home/SandboxCard.js +14 -8
- package/dist/components/sandbox/sandbox-home/SandboxHome.js +22 -81
- package/dist/components/sandbox/sandbox-home/SearchBar.js +1 -1
- package/dist/components/ui/skeleton.js +18 -0
- package/dist/index.d.ts +8 -2
- package/dist/index.es.js +23944 -23548
- package/dist/index.standalone.umd.js +13 -13
- package/dist/lib/api-client.js +47 -5
- package/dist/lib/generated-css.js +1 -1
- package/dist/sdk.css +1 -1
- package/dist/tailwind.css +1 -1
- package/package.json +12 -7
|
@@ -5,6 +5,7 @@ import GuardianPlayground from "./guardian/guardian-playground";
|
|
|
5
5
|
import { GuardianProvider } from "./guardian/context/guardian-context";
|
|
6
6
|
import { VmProvider } from "./guardian/context/vm-context";
|
|
7
7
|
import { buildGuardianConfig } from "./guardian/utils";
|
|
8
|
+
import { Skeleton } from "../ui/skeleton";
|
|
8
9
|
/**
|
|
9
10
|
* Sandbox component - simplified API for embedding sandboxes
|
|
10
11
|
*
|
|
@@ -54,8 +55,8 @@ export default function Sandbox({ apiKey, sandboxId, env, themeColor, }) {
|
|
|
54
55
|
};
|
|
55
56
|
}, [apiKey, sandboxId, themeColor]);
|
|
56
57
|
if (loading) {
|
|
57
|
-
return (React.createElement("div", { className: "
|
|
58
|
-
React.createElement(
|
|
58
|
+
return (React.createElement("div", { className: "h-screen w-screen bg-black" },
|
|
59
|
+
React.createElement(Skeleton, { className: "w-full h-full bg-zinc-900" })));
|
|
59
60
|
}
|
|
60
61
|
if (error) {
|
|
61
62
|
return (React.createElement("div", { className: "flex items-center justify-center h-screen bg-black" },
|
|
@@ -1,29 +1,5 @@
|
|
|
1
1
|
import { Framework, } from "./guardian/types/ide-types";
|
|
2
2
|
import { createApiClient } from "../../lib/api-client";
|
|
3
|
-
/**
|
|
4
|
-
* Get the base URL for API requests
|
|
5
|
-
* In browser, use relative URL or environment variable
|
|
6
|
-
* In Node.js, use environment variable or default
|
|
7
|
-
*/
|
|
8
|
-
function getBaseUrl() {
|
|
9
|
-
return "https://api.sampleapp.ai";
|
|
10
|
-
// return "http://127.0.0.1:8000";
|
|
11
|
-
// if (typeof window !== "undefined") {
|
|
12
|
-
// // Browser: try to get from environment or use relative URL
|
|
13
|
-
// return (
|
|
14
|
-
// (window as any).__SAMPLEAPP_API_BASE_URL__ ||f
|
|
15
|
-
// process.env.NEXT_PUBLIC_FASTAPI_APP_URL ||
|
|
16
|
-
// process.env.FASTAPI_APP_URL ||
|
|
17
|
-
// "http://127.0.0.1:8000"
|
|
18
|
-
// );
|
|
19
|
-
// }
|
|
20
|
-
// // Node.js: use environment variable or default
|
|
21
|
-
// return (
|
|
22
|
-
// process.env.FASTAPI_APP_URL ||
|
|
23
|
-
// process.env.NEXT_PUBLIC_FASTAPI_APP_URL ||
|
|
24
|
-
// "http://127.0.0.1:8000"
|
|
25
|
-
// );
|
|
26
|
-
}
|
|
27
3
|
/**
|
|
28
4
|
* Helper function to download a file from a URL
|
|
29
5
|
*/
|
|
@@ -45,9 +21,7 @@ function createDownloadLink(downloadEndpoint) {
|
|
|
45
21
|
* @returns Sandbox configuration
|
|
46
22
|
*/
|
|
47
23
|
export async function fetchSandboxConfig(apiKey, sandboxId) {
|
|
48
|
-
const baseUrl = getBaseUrl();
|
|
49
24
|
const client = createApiClient({
|
|
50
|
-
baseUrl,
|
|
51
25
|
apiKey,
|
|
52
26
|
});
|
|
53
27
|
// Fetch sandbox content from API
|
|
@@ -70,8 +44,8 @@ export async function fetchSandboxConfig(apiKey, sandboxId) {
|
|
|
70
44
|
// document.body.removeChild(link);
|
|
71
45
|
const containerId = ""; // Will be populated when sandbox is started via sdk.startSandbox()
|
|
72
46
|
const completeCodeZipFile = containerId
|
|
73
|
-
? `${
|
|
74
|
-
: `${
|
|
47
|
+
? `${"hello there"}/fileshare?container_id=${containerId}`
|
|
48
|
+
: `${"hello there"}/fileshare?container_id=placeholder`; // Placeholder until sandbox is started
|
|
75
49
|
// Transform SandboxContent to SandboxConfig
|
|
76
50
|
const config = {
|
|
77
51
|
id: sandboxContent.uid,
|
|
@@ -99,6 +73,8 @@ export async function fetchSandboxConfig(apiKey, sandboxId) {
|
|
|
99
73
|
// CustomConsole is now sandboxContent.markdown
|
|
100
74
|
CustomConsole: sandboxContent.markdown || "",
|
|
101
75
|
GuideView: "Default Guide",
|
|
76
|
+
// Get gitUrl from sandboxContent.github_url
|
|
77
|
+
gitUrl: sandboxContent.github_url || undefined,
|
|
102
78
|
},
|
|
103
79
|
],
|
|
104
80
|
},
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { cn } from "../../../lib/utils";
|
|
3
|
-
export default function AppLayoutNoSidebar({ header, hasBodyPadding = true, children,
|
|
4
|
-
return (React.createElement("div",
|
|
3
|
+
export default function AppLayoutNoSidebar({ header, hasBodyPadding = true, children, textColorStyle, }) {
|
|
4
|
+
return (React.createElement("div", { className: "flex flex-col h-full" },
|
|
5
5
|
header && (React.createElement("header", { className: "flex h-24 shrink-0 items-center gap-2 transition-[width,height] ease-linear group-has-[[data-collapsible=icon]]/sidebar-wrapper:h-12 w-full" },
|
|
6
6
|
React.createElement("div", { className: "flex items-center gap-2 px-4 w-full" }, header))),
|
|
7
|
-
React.createElement("div", { className: cn("flex flex-1 flex-col pt-0", hasBodyPadding && "gap-4 p-4",
|
|
7
|
+
React.createElement("div", { className: cn("flex flex-1 flex-col pt-0 min-h-0", hasBodyPadding && "gap-4 p-4",
|
|
8
|
+
// Use CSS variable with Tailwind arbitrary value
|
|
9
|
+
textColorStyle &&
|
|
10
|
+
"text-[var(--guardian-text-color)] dark:text-[var(--guardian-text-color-dark)]"), style: textColorStyle }, children)));
|
|
8
11
|
}
|
|
@@ -4,7 +4,7 @@ import ConsoleWithApp from "../ui/console-with-app";
|
|
|
4
4
|
import { useGuardianContext } from "../context/guardian-context";
|
|
5
5
|
import ConsoleWithGuide from "./left-view";
|
|
6
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, }) {
|
|
7
|
+
export default function GuardianDemo({ CustomConsole, GuideView, browserUrl, playgroundUid, useVm, codeZipFile, completeCodeZipFile, variant, themeColor, hasPreview, isFrame = false, isGuardian = false, gitUrl, }) {
|
|
8
8
|
const { isBrowserMaximized } = useGuardianContext();
|
|
9
9
|
const { setCurrentView } = useGuardianContext();
|
|
10
10
|
const [reloadCounter, setReloadCounter] = useState(0);
|
|
@@ -31,5 +31,5 @@ export default function GuardianDemo({ CustomConsole, GuideView, browserUrl, pla
|
|
|
31
31
|
return (React.createElement("div", { className: "w-full h-full rounded-2xl border border-border overflow-hidden" },
|
|
32
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
33
|
}
|
|
34
|
-
return (React.createElement(ConsoleWithApp, { containerClassName: "rounded-2xl border border-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 }) }));
|
|
34
|
+
return (React.createElement(ConsoleWithApp, { containerClassName: "rounded-2xl border border-border", console: React.createElement(ConsoleWithGuide, { CustomConsole: CustomConsole, GuideView: GuideView, playgroundUid: playgroundUid, onReloadPreview: handleReloadPreview, onStageChange: handleStageChange, codeZipFile: codeZipFile, themeColor: themeColor, browserUrl: browserUrl, gitUrl: gitUrl }), 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
35
|
}
|
|
@@ -4,7 +4,14 @@ import SlidingConsoleGuideToggle from "./left-view/toggle";
|
|
|
4
4
|
// import AskAiView from "../ask-ai-view";
|
|
5
5
|
// import DefaultGuideView from "../default-guide-view";
|
|
6
6
|
import { Markdown } from "../ui/markdown";
|
|
7
|
-
|
|
7
|
+
import sampleappLogo from "../../../../assets/sampleapp-logo.png";
|
|
8
|
+
function Logo({ href, width }) {
|
|
9
|
+
return (React.createElement("div", { className: "flex justify-center md:justify-start" },
|
|
10
|
+
React.createElement("a", { href: href ? href : "https://sampleapp.ai", className: "flex", target: "_blank", rel: "noopener noreferrer" },
|
|
11
|
+
React.createElement("div", { className: "invert dark:invert-0" },
|
|
12
|
+
React.createElement("img", { src: sampleappLogo, alt: "SampleApp Logo", width: width || 160, height: 40 })))));
|
|
13
|
+
}
|
|
14
|
+
export default function ConsoleWithGuide({ CustomConsole, GuideView, playgroundUid, onReloadPreview, onStageChange, codeZipFile, themeColor, browserUrl, gitUrl, }) {
|
|
8
15
|
const [currentView, setCurrentView] = useState("console");
|
|
9
16
|
const isConsoleView = useMemo(() => currentView === "console", [currentView]);
|
|
10
17
|
// const isGuideView = useMemo(() => currentView === "guide", [currentView]);
|
|
@@ -13,7 +20,7 @@ export default function ConsoleWithGuide({ CustomConsole, GuideView, playgroundU
|
|
|
13
20
|
if (typeof CustomConsole === "string") {
|
|
14
21
|
return (React.createElement("div", { className: "h-full flex flex-col" },
|
|
15
22
|
React.createElement("div", { className: "flex-1 px-8 py-6" },
|
|
16
|
-
React.createElement(Markdown, { className: "text-gray-100", themeColor: themeColor }, CustomConsole))));
|
|
23
|
+
React.createElement(Markdown, { className: "text-gray-100", themeColor: themeColor, browserUrl: browserUrl, gitUrl: gitUrl }, CustomConsole))));
|
|
17
24
|
}
|
|
18
25
|
const CustomConsoleComponent = CustomConsole;
|
|
19
26
|
return (React.createElement(CustomConsoleComponent, { onReloadPreview: onReloadPreview !== null && onReloadPreview !== void 0 ? onReloadPreview : (() => { }), onStageChange: onStageChange !== null && onStageChange !== void 0 ? onStageChange : (() => { }), themeColor: themeColor }));
|
|
@@ -46,13 +53,18 @@ export default function ConsoleWithGuide({ CustomConsole, GuideView, playgroundU
|
|
|
46
53
|
// const GuideComponent = GuideView as ComponentType;
|
|
47
54
|
// return <GuideComponent />;
|
|
48
55
|
// };
|
|
49
|
-
return (React.createElement("div", { className: "flex-1 min-h-0 relative" },
|
|
56
|
+
return (React.createElement("div", { className: "flex-1 min-h-0 relative flex flex-col" },
|
|
50
57
|
React.createElement("div", { className: "flex justify-center border-b border-border" },
|
|
51
58
|
React.createElement(SlidingConsoleGuideToggle, { playgroundUid: playgroundUid, variant: "pill", buttonClassName: "text-sm px-4 py-1", currentView: currentView, setCurrentView: setCurrentView, tabs: [
|
|
52
59
|
{ id: "console", label: "Guide" },
|
|
53
60
|
// ...(GuideView ? [{id: "guide-og", label: "Guide OG"}] : []),
|
|
54
61
|
// {id: "chat", label: "Ask AI"},
|
|
55
62
|
] })),
|
|
56
|
-
React.createElement("div", { className: "h-[calc(100vh-9.5rem)] min-h-0 overflow-hidden" },
|
|
57
|
-
React.createElement("div", { className: "
|
|
63
|
+
React.createElement("div", { className: "h-[calc(100vh-9.5rem)] min-h-0 overflow-hidden flex-1 flex flex-col" },
|
|
64
|
+
React.createElement("div", { className: "flex-1 min-h-0 overflow-y-auto" }, isConsoleView && renderCustomConsole()),
|
|
65
|
+
React.createElement("div", { className: "relative" },
|
|
66
|
+
React.createElement("div", { className: "flex flex-row w-full items-center text-xs justify-center opacity-30 mt-1 pb-2 bg-background" },
|
|
67
|
+
React.createElement("span", { className: "text-gray-300" }, "Powered by"),
|
|
68
|
+
React.createElement("span", { className: "hover:bg-accent rounded-sm p-1 mx-1" },
|
|
69
|
+
React.createElement(Logo, { width: 100, href: "https://sampleapp.ai" })))))));
|
|
58
70
|
}
|
|
@@ -6,7 +6,9 @@ import React, { useEffect, useRef } from "react";
|
|
|
6
6
|
import { useGuardianContext } from "./context/guardian-context";
|
|
7
7
|
import { useSandboxUrlLoader, } from "./hooks/use-sandbox-url-loader";
|
|
8
8
|
import { useFrameMessages } from "./hooks/use-frame-messages";
|
|
9
|
-
|
|
9
|
+
import { cn } from "../../../lib/utils";
|
|
10
|
+
export default function GuardianComponent({ demoOptions, frameworkOptions, firstFrameworkByUseCase, currentFramework, currentUseCase, CustomConsole, GuideView, playgroundLogo, playgroundUid, browserUrl, useVm, sandboxUid, codeZipFile, consoleUrlConfigs, completeCodeZipFile, variant, themeColor, hasPreview = true, isFrame = false, apiKey, env, chatUid, hideHeader = true, // Hardcoded to true by default, not exposed in Sandbox.tsx
|
|
11
|
+
gitUrl, }) {
|
|
10
12
|
const { previewUrl, setPreviewUrl } = useGuardianContext();
|
|
11
13
|
// Debug: Log the props received for sandbox configuration
|
|
12
14
|
console.log("[GuardianComponent] API config props:", {
|
|
@@ -89,9 +91,9 @@ export default function GuardianComponent({ demoOptions, frameworkOptions, first
|
|
|
89
91
|
// If isFrame, just render GuardianDemo without the header/layout wrapper
|
|
90
92
|
if (isFrame) {
|
|
91
93
|
return (React.createElement("div", { className: "h-[100vh]" },
|
|
92
|
-
React.createElement(GuardianDemo, { CustomConsole: CustomConsole, GuideView: GuideView, browserUrl: previewUrl, playgroundUid: playgroundUid, useVm: useVm, codeZipFile: codeZipFile, completeCodeZipFile: completeCodeZipFile, variant: variant, themeColor: themeColor, hasPreview: hasPreview, isFrame: isFrame, isGuardian: true })));
|
|
94
|
+
React.createElement(GuardianDemo, { CustomConsole: CustomConsole, GuideView: GuideView, browserUrl: previewUrl, playgroundUid: playgroundUid, useVm: useVm, codeZipFile: codeZipFile, completeCodeZipFile: completeCodeZipFile, variant: variant, themeColor: themeColor, hasPreview: hasPreview, isFrame: isFrame, isGuardian: true, gitUrl: gitUrl })));
|
|
93
95
|
}
|
|
94
|
-
return (React.createElement(AppLayoutNoSidebar, { header: React.createElement(Header, { demoOptions: demoOptions, frameworkOptions: frameworkOptions, currentFramework: currentFramework, currentUseCase: currentUseCase, playgroundLogo: playgroundLogo, firstFrameworkByUseCase: firstFrameworkByUseCase }) },
|
|
95
|
-
React.createElement("div", { className: "
|
|
96
|
-
React.createElement(GuardianDemo, { CustomConsole: CustomConsole, GuideView: GuideView, browserUrl: previewUrl, playgroundUid: playgroundUid, useVm: useVm, codeZipFile: codeZipFile, completeCodeZipFile: completeCodeZipFile, variant: variant, themeColor: themeColor, hasPreview: hasPreview, isFrame: isFrame, isGuardian: true }))));
|
|
96
|
+
return (React.createElement(AppLayoutNoSidebar, { header: !hideHeader ? (React.createElement(Header, { demoOptions: demoOptions, frameworkOptions: frameworkOptions, currentFramework: currentFramework, currentUseCase: currentUseCase, playgroundLogo: playgroundLogo, firstFrameworkByUseCase: firstFrameworkByUseCase })) : undefined, hasBodyPadding: false },
|
|
97
|
+
React.createElement("div", { className: cn("flex-1 min-h-0 flex flex-col px-4 pb-4", hideHeader && "pt-4") },
|
|
98
|
+
React.createElement(GuardianDemo, { CustomConsole: CustomConsole, GuideView: GuideView, browserUrl: previewUrl, playgroundUid: playgroundUid, useVm: useVm, codeZipFile: codeZipFile, completeCodeZipFile: completeCodeZipFile, variant: variant, themeColor: themeColor, hasPreview: hasPreview, isFrame: isFrame, isGuardian: true, gitUrl: gitUrl }))));
|
|
97
99
|
}
|
|
@@ -40,6 +40,6 @@ export default function GuardianPlayground({ nestedConfig, useCase, framework: s
|
|
|
40
40
|
firstFrameworkByUseCase[useCaseId] = firstFrameworkKey;
|
|
41
41
|
}
|
|
42
42
|
});
|
|
43
|
-
return (React.createElement(GuardianStyleWrapper,
|
|
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 })));
|
|
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
45
|
}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import React, { useEffect, useState } from "react";
|
|
2
|
+
import React, { useEffect, useRef, useState } from "react";
|
|
3
3
|
import { TAILWIND_CSS } from "../../../lib/generated-css";
|
|
4
4
|
/**
|
|
5
5
|
* Style wrapper for Guardian components that injects Tailwind CSS
|
|
6
6
|
* into the document without using Shadow DOM (preserves React context)
|
|
7
7
|
*/
|
|
8
|
-
export const GuardianStyleWrapper = ({ children, }) => {
|
|
8
|
+
export const GuardianStyleWrapper = ({ children, themeColor = "#3b82f6", }) => {
|
|
9
9
|
const [stylesInjected, setStylesInjected] = useState(false);
|
|
10
|
+
const rootRef = useRef(null);
|
|
10
11
|
useEffect(() => {
|
|
11
12
|
// Only run on client side
|
|
12
13
|
if (typeof window === "undefined" || typeof document === "undefined") {
|
|
@@ -29,5 +30,18 @@ export const GuardianStyleWrapper = ({ children, }) => {
|
|
|
29
30
|
// Don't remove styles on unmount as other Guardian components might use them
|
|
30
31
|
};
|
|
31
32
|
}, []);
|
|
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));
|
|
33
47
|
};
|
|
@@ -2,24 +2,6 @@
|
|
|
2
2
|
import { useCallback } from "react";
|
|
3
3
|
import { useVmContext } from "../context/vm-context";
|
|
4
4
|
import { createApiClient } from "../../../../lib/api-client";
|
|
5
|
-
/**
|
|
6
|
-
* Get the base URL for API requests
|
|
7
|
-
* In browser, use relative URL or environment variable
|
|
8
|
-
* In Node.js, use environment variable or default
|
|
9
|
-
*/
|
|
10
|
-
function getBaseUrl() {
|
|
11
|
-
if (typeof window !== "undefined") {
|
|
12
|
-
// Browser: try to get from environment or use relative URL
|
|
13
|
-
return (window.__SAMPLEAPP_API_BASE_URL__ ||
|
|
14
|
-
process.env.NEXT_PUBLIC_FASTAPI_APP_URL ||
|
|
15
|
-
process.env.FASTAPI_APP_URL ||
|
|
16
|
-
"http://127.0.0.1:8000");
|
|
17
|
-
}
|
|
18
|
-
// Node.js: use environment variable or default
|
|
19
|
-
return (process.env.FASTAPI_APP_URL ||
|
|
20
|
-
process.env.NEXT_PUBLIC_FASTAPI_APP_URL ||
|
|
21
|
-
"http://127.0.0.1:8000");
|
|
22
|
-
}
|
|
23
5
|
/**
|
|
24
6
|
* Creates a cache key from sandboxUid and browserUrl.
|
|
25
7
|
* This allows caching different URLs for the same sandbox.
|
|
@@ -87,9 +69,7 @@ export function useSandboxUrlLoader(startSandboxConfig) {
|
|
|
87
69
|
// Non-VM mode: call startSandbox API to get container URL
|
|
88
70
|
if (startSandboxConfig) {
|
|
89
71
|
try {
|
|
90
|
-
const baseUrl = getBaseUrl();
|
|
91
72
|
const client = createApiClient({
|
|
92
|
-
baseUrl,
|
|
93
73
|
apiKey: startSandboxConfig.apiKey,
|
|
94
74
|
});
|
|
95
75
|
const response = await client.sdk.startSandbox({
|
|
@@ -88,12 +88,25 @@ export default function PillFileSelector({ themeColor }) {
|
|
|
88
88
|
};
|
|
89
89
|
// Exclude certain files from display
|
|
90
90
|
const excludedFiles = [
|
|
91
|
+
// Common config/environment files
|
|
91
92
|
".env",
|
|
93
|
+
// Vite/plugin instrumentation files
|
|
92
94
|
"vite-plugin-react-instrumentation.ts",
|
|
93
95
|
"instrumentation-client.ts",
|
|
96
|
+
// Global styles (often not needed in code editor)
|
|
97
|
+
"globals.css",
|
|
94
98
|
];
|
|
95
99
|
const filteredFiles = fileEntries.filter(([filePath]) => {
|
|
96
100
|
const fileName = filePath.split("/").pop() || filePath;
|
|
101
|
+
// Exclude markdown files (*.md)
|
|
102
|
+
if (fileName.endsWith(".md")) {
|
|
103
|
+
return false;
|
|
104
|
+
}
|
|
105
|
+
// Exclude .gitignore files
|
|
106
|
+
if (fileName === ".gitignore" || fileName.endsWith(".gitignore")) {
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
// Exclude other specific files
|
|
97
110
|
return !excludedFiles.includes(fileName);
|
|
98
111
|
});
|
|
99
112
|
// Scroll a pill into view whenever the active file changes
|
|
@@ -1,12 +1,25 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import React from "react";
|
|
2
|
+
import React, { useState, useEffect } from "react";
|
|
3
3
|
import SlidingEditPreviewToggle from "../demo/left-view/toggle";
|
|
4
4
|
import Browser from "../ide/browser";
|
|
5
5
|
import CodeView from "./code-view";
|
|
6
6
|
import { useGuardianContext } from "../context/guardian-context";
|
|
7
7
|
import { Component as AiLoader } from "../ui/ai-loader";
|
|
8
|
-
export default function RightPanelView({ reloadCounter, overlayStage, browserUrl, useVm, codeZipFile, }) {
|
|
8
|
+
export default function RightPanelView({ reloadCounter, overlayStage, browserUrl, useVm, codeZipFile, themeColor = "#3b82f6", }) {
|
|
9
9
|
const { setCurrentView, currentView } = useGuardianContext();
|
|
10
|
+
const [showLoader, setShowLoader] = useState(!browserUrl);
|
|
11
|
+
// Delay hiding the loader for 5 seconds after browserUrl becomes available
|
|
12
|
+
useEffect(() => {
|
|
13
|
+
if (browserUrl) {
|
|
14
|
+
const timer = setTimeout(() => {
|
|
15
|
+
setShowLoader(false);
|
|
16
|
+
}, 7000);
|
|
17
|
+
return () => clearTimeout(timer);
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
setShowLoader(true);
|
|
21
|
+
}
|
|
22
|
+
}, [browserUrl]);
|
|
10
23
|
return (React.createElement("div", null,
|
|
11
24
|
React.createElement("div", { className: "flex justify-center border-b" },
|
|
12
25
|
React.createElement(SlidingEditPreviewToggle, { playgroundUid: "guardian", currentView: currentView, setCurrentView: (view) => setCurrentView(view), variant: "pill", buttonClassName: "text-sm px-4 py-1 h-auto", tabs: [
|
|
@@ -15,8 +28,8 @@ export default function RightPanelView({ reloadCounter, overlayStage, browserUrl
|
|
|
15
28
|
] })),
|
|
16
29
|
React.createElement("div", { style: {
|
|
17
30
|
display: currentView === "preview" ? "block" : "none",
|
|
18
|
-
} },
|
|
19
|
-
React.createElement(AiLoader, { text: "Booting up...", fullScreen: false }))) : (React.createElement(Browser, { previewUrl: browserUrl, setPreviewUrl: () => { }, containerEndpoint: browserUrl, outerContainerClassName: useVm
|
|
31
|
+
} }, showLoader ? (React.createElement("div", { className: "h-[calc(100vh-12.2rem)] w-full relative overflow-hidden rounded-b-none" },
|
|
32
|
+
React.createElement(AiLoader, { text: "Booting up...", fullScreen: false, themeColor: themeColor }))) : (React.createElement(Browser, { previewUrl: browserUrl, setPreviewUrl: () => { }, containerEndpoint: browserUrl, outerContainerClassName: useVm
|
|
20
33
|
? "h-[calc(100vh-9.6rem)] w-full border-none rounded-b-none"
|
|
21
34
|
: "h-[calc(100vh-12.2rem)] w-full border-none rounded-b-none", reloadSignal: reloadCounter, useVm: useVm }, overlayStage !== "hidden" && (React.createElement("div", { className: "absolute inset-0 z-20 flex items-center justify-center" },
|
|
22
35
|
overlayStage === "error" && (React.createElement("div", { className: "w-full h-full bg-red-950 text-red-200 flex items-center justify-center" },
|
|
@@ -9,26 +9,41 @@ import { useGuardianContext } from "../context/guardian-context";
|
|
|
9
9
|
import { useEffect, useMemo, useState } from "react";
|
|
10
10
|
import { zipPathToFileTree } from "../zip-to-filetree";
|
|
11
11
|
import { codeZipFileToCodebase } from "../zip-to-codebase";
|
|
12
|
-
import { DownloadIcon, Globe
|
|
12
|
+
import { DownloadIcon, Globe } from "lucide-react";
|
|
13
13
|
import { useFrameParams } from "../hooks/use-frame-params";
|
|
14
14
|
import { cn } from "../../../../lib/utils";
|
|
15
|
+
import { extractContainerIdFromUrl } from "../../../../lib/api-client";
|
|
15
16
|
export default function RightView({ reloadCounter, overlayStage, browserUrl, useVm, codeZipFile, themeColor, completeCodeZipFile, hasPreview, isPreviewMinimized = false, isGuardian = false, isBrowserMaximized = false, }) {
|
|
16
17
|
const { setFileTree, setGeneratedCode } = useGuardianContext();
|
|
17
18
|
const frameParams = useFrameParams();
|
|
18
19
|
const [activeTab, setActiveTab] = useState("code");
|
|
19
20
|
const [networkRequests, setNetworkRequests] = useState([]);
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
21
|
+
const [showLoader, setShowLoader] = useState(!browserUrl);
|
|
22
|
+
// Delay hiding the loader for 5 seconds after browserUrl becomes available
|
|
23
|
+
useEffect(() => {
|
|
24
|
+
if (browserUrl) {
|
|
25
|
+
const timer = setTimeout(() => {
|
|
26
|
+
setShowLoader(false);
|
|
27
|
+
}, 5000);
|
|
28
|
+
return () => clearTimeout(timer);
|
|
26
29
|
}
|
|
27
|
-
|
|
28
|
-
|
|
30
|
+
else {
|
|
31
|
+
setShowLoader(true);
|
|
29
32
|
}
|
|
30
|
-
|
|
31
|
-
|
|
33
|
+
}, [browserUrl]);
|
|
34
|
+
// Use frame param override for theme if in frame mode
|
|
35
|
+
const effectiveThemeColor = frameParams.isFrame && frameParams.theme ? frameParams.theme : themeColor;
|
|
36
|
+
// Extract container ID from browserUrl and build download URL
|
|
37
|
+
const downloadCodeUrl = useMemo(() => {
|
|
38
|
+
if (!browserUrl)
|
|
39
|
+
return null;
|
|
40
|
+
const containerId = extractContainerIdFromUrl(browserUrl);
|
|
41
|
+
if (!containerId)
|
|
42
|
+
return null;
|
|
43
|
+
// Use the API base URL for the download endpoint
|
|
44
|
+
const baseUrl = process.env.BASE_API_URL || "https://api.sampleapp.ai";
|
|
45
|
+
return `${baseUrl}/api/v1/sdk/download-code?container_id=${encodeURIComponent(containerId)}`;
|
|
46
|
+
}, [browserUrl]);
|
|
32
47
|
// Extract only the nested children (actual API calls to external services)
|
|
33
48
|
const childrenRequests = useMemo(() => {
|
|
34
49
|
const children = [];
|
|
@@ -85,8 +100,8 @@ export default function RightView({ reloadCounter, overlayStage, browserUrl, use
|
|
|
85
100
|
}, []);
|
|
86
101
|
// When browser is maximized, render only the browser at full size
|
|
87
102
|
if (isBrowserMaximized) {
|
|
88
|
-
return (React.createElement("div", { className: "h-full w-full" },
|
|
89
|
-
React.createElement(AiLoader, { text: "Booting up...", fullScreen: false }))) : (React.createElement(Browser, { previewUrl: browserUrl, setPreviewUrl: () => { }, containerEndpoint: browserUrl, outerContainerClassName: "h-full w-full border-none", reloadSignal: reloadCounter, useVm: useVm, isGuardian: isGuardian }, overlayStage !== "hidden" && (React.createElement("div", { className: "absolute inset-0 z-20 flex items-center justify-center" },
|
|
103
|
+
return (React.createElement("div", { className: "h-full w-full" }, showLoader ? (React.createElement("div", { className: "h-full w-full relative overflow-hidden" },
|
|
104
|
+
React.createElement(AiLoader, { text: "Booting up...", fullScreen: false, themeColor: effectiveThemeColor }))) : (React.createElement(Browser, { previewUrl: browserUrl, setPreviewUrl: () => { }, containerEndpoint: browserUrl, outerContainerClassName: "h-full w-full border-none", reloadSignal: reloadCounter, useVm: useVm, isGuardian: isGuardian }, overlayStage !== "hidden" && (React.createElement("div", { className: "absolute inset-0 z-20 flex items-center justify-center" },
|
|
90
105
|
overlayStage === "error" && (React.createElement("div", { className: "w-full h-full bg-red-950 text-red-200 flex items-center justify-center" },
|
|
91
106
|
React.createElement("div", { className: "text-center" },
|
|
92
107
|
React.createElement("div", { className: "text-2xl font-semibold" }, "Service Unavailable"),
|
|
@@ -104,8 +119,8 @@ export default function RightView({ reloadCounter, overlayStage, browserUrl, use
|
|
|
104
119
|
React.createElement(PanelGroup, { direction: "vertical", className: "relative h-full" },
|
|
105
120
|
hasPreview && !isPreviewMinimized && (React.createElement(React.Fragment, null,
|
|
106
121
|
React.createElement(Panel, { defaultSize: 58, minSize: 20, maxSize: 80, order: 1 },
|
|
107
|
-
React.createElement("div", { className: "h-full w-full" },
|
|
108
|
-
React.createElement(AiLoader, { text: "Booting up...", fullScreen: false }))) : (React.createElement(Browser, { previewUrl: browserUrl, setPreviewUrl: () => { }, containerEndpoint: browserUrl, outerContainerClassName: "h-full w-full border-none", reloadSignal: reloadCounter, useVm: useVm, isGuardian: isGuardian }, overlayStage !== "hidden" && (React.createElement("div", { className: "absolute inset-0 z-20 flex items-center justify-center" },
|
|
122
|
+
React.createElement("div", { className: "h-full w-full" }, showLoader ? (React.createElement("div", { className: "h-full w-full relative overflow-hidden" },
|
|
123
|
+
React.createElement(AiLoader, { text: "Booting up...", fullScreen: false, themeColor: effectiveThemeColor }))) : (React.createElement(Browser, { previewUrl: browserUrl, setPreviewUrl: () => { }, containerEndpoint: browserUrl, outerContainerClassName: "h-full w-full border-none", reloadSignal: reloadCounter, useVm: useVm, isGuardian: isGuardian }, overlayStage !== "hidden" && (React.createElement("div", { className: "absolute inset-0 z-20 flex items-center justify-center" },
|
|
109
124
|
overlayStage === "error" && (React.createElement("div", { className: "w-full h-full bg-red-950 text-red-200 flex items-center justify-center" },
|
|
110
125
|
React.createElement("div", { className: "text-center" },
|
|
111
126
|
React.createElement("div", { className: "text-2xl font-semibold" }, "Service Unavailable"),
|
|
@@ -125,41 +140,18 @@ export default function RightView({ reloadCounter, overlayStage, browserUrl, use
|
|
|
125
140
|
React.createElement("div", { className: "h-full w-px bg-border group-hover:bg-blue-400 transition-colors relative z-10" }))))),
|
|
126
141
|
React.createElement(Panel, { defaultSize: 42, minSize: 20, maxSize: 80, order: 2 },
|
|
127
142
|
React.createElement("div", { className: "h-full w-full flex flex-col" },
|
|
128
|
-
React.createElement("div", { className: "flex
|
|
129
|
-
React.createElement(
|
|
130
|
-
React.createElement("
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
React.createElement("button", { type: "button", onClick: () => setActiveTab("network"), className: cn("flex items-center gap-1.5 px-3 py-1.5 text-xs font-medium transition-colors border-b-2", activeTab === "network"
|
|
141
|
-
? "border-current text-white"
|
|
142
|
-
: "border-transparent text-zinc-500 hover:text-zinc-300"), style: activeTab === "network"
|
|
143
|
-
? {
|
|
144
|
-
borderColor: effectiveThemeColor,
|
|
145
|
-
color: effectiveThemeColor,
|
|
146
|
-
}
|
|
147
|
-
: undefined },
|
|
148
|
-
React.createElement(Globe, { className: "w-3.5 h-3.5" }),
|
|
149
|
-
"Network",
|
|
150
|
-
childrenRequests.length > 0 && (React.createElement("span", { className: "ml-1 px-1.5 py-0.5 text-[10px] rounded-full bg-zinc-700 text-zinc-300" }, childrenRequests.length)))),
|
|
151
|
-
activeTab === "network" && childrenRequests.length > 0 && (React.createElement("button", { type: "button", className: "px-2 text-[10px] font-medium text-zinc-500 hover:text-zinc-300 transition-colors", onClick: () => setNetworkRequests([]) }, "Clear"))),
|
|
152
|
-
React.createElement("div", { className: "flex-1 min-h-0 flex flex-col" }, activeTab === "code" ? (React.createElement(React.Fragment, null,
|
|
153
|
-
React.createElement("div", { className: "flex items-center justify-between border-b border-zinc-800 dark:border-zinc-700 bg-zinc-900 dark:bg-zinc-950" },
|
|
154
|
-
React.createElement(PillFileSelector, { themeColor: effectiveThemeColor }),
|
|
155
|
-
React.createElement("div", { className: "px-2 flex-shrink-0" },
|
|
156
|
-
React.createElement("button", { type: "button", className: "inline-flex items-center gap-1 text-[10px] font-medium transition-colors hover:opacity-80", style: { color: effectiveThemeColor }, onClick: () => {
|
|
157
|
-
window.open(normalizedZipDownloadPath, "_blank");
|
|
158
|
-
} },
|
|
159
|
-
React.createElement(DownloadIcon, { className: "w-4 h-4" }),
|
|
160
|
-
"Download Code"))),
|
|
161
|
-
React.createElement("div", { className: "flex-1 min-h-0" },
|
|
162
|
-
React.createElement(SimplifiedEditor, { themeColor: effectiveThemeColor })))) : (React.createElement(NetworkRequestsView, { requests: childrenRequests, themeColor: effectiveThemeColor }))))))));
|
|
143
|
+
React.createElement("div", { className: "flex-1 min-h-0 flex flex-col" },
|
|
144
|
+
React.createElement(React.Fragment, null,
|
|
145
|
+
React.createElement("div", { className: "flex items-center justify-between border-b border-zinc-800 dark:border-zinc-700 bg-zinc-900 dark:bg-zinc-950" },
|
|
146
|
+
React.createElement(PillFileSelector, { themeColor: effectiveThemeColor }),
|
|
147
|
+
downloadCodeUrl && (React.createElement("div", { className: "px-2 flex-shrink-0" },
|
|
148
|
+
React.createElement("button", { type: "button", className: "inline-flex items-center gap-1 text-[10px] font-medium transition-colors hover:opacity-80", style: { color: effectiveThemeColor }, onClick: () => {
|
|
149
|
+
window.open(downloadCodeUrl, "_blank");
|
|
150
|
+
} },
|
|
151
|
+
React.createElement(DownloadIcon, { className: "w-4 h-4" }),
|
|
152
|
+
"Download Code")))),
|
|
153
|
+
React.createElement("div", { className: "flex-1 min-h-0" },
|
|
154
|
+
React.createElement(SimplifiedEditor, { themeColor: effectiveThemeColor })))))))));
|
|
163
155
|
}
|
|
164
156
|
// Simple Network Requests View Component
|
|
165
157
|
function NetworkRequestsView({ requests, themeColor, }) {
|
|
@@ -1,32 +1,75 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
|
|
2
|
+
// Helper to convert hex to RGB
|
|
3
|
+
function hexToRgb(hex) {
|
|
4
|
+
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
|
|
5
|
+
return result
|
|
6
|
+
? {
|
|
7
|
+
r: parseInt(result[1], 16),
|
|
8
|
+
g: parseInt(result[2], 16),
|
|
9
|
+
b: parseInt(result[3], 16),
|
|
10
|
+
}
|
|
11
|
+
: null;
|
|
12
|
+
}
|
|
13
|
+
// Helper to darken a color
|
|
14
|
+
function darkenColor(hex, percent) {
|
|
15
|
+
const rgb = hexToRgb(hex);
|
|
16
|
+
if (!rgb)
|
|
17
|
+
return hex;
|
|
18
|
+
const factor = 1 - percent / 100;
|
|
19
|
+
const r = Math.round(rgb.r * factor);
|
|
20
|
+
const g = Math.round(rgb.g * factor);
|
|
21
|
+
const b = Math.round(rgb.b * factor);
|
|
22
|
+
return `rgb(${r}, ${g}, ${b})`;
|
|
23
|
+
}
|
|
24
|
+
export const Component = ({ size = 180, text = "Generating", fullScreen = true, themeColor = "#3b82f6", // Default blue
|
|
25
|
+
}) => {
|
|
3
26
|
const letters = text.split("");
|
|
27
|
+
// Generate color variants from themeColor
|
|
28
|
+
const rgb = hexToRgb(themeColor);
|
|
29
|
+
const colorDark = darkenColor(themeColor, 60);
|
|
30
|
+
const colorMid = darkenColor(themeColor, 40);
|
|
31
|
+
const colorLight = darkenColor(themeColor, 20);
|
|
32
|
+
const rgbaGlow = rgb
|
|
33
|
+
? `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, 0.3)`
|
|
34
|
+
: "rgba(59, 130, 246, 0.3)";
|
|
35
|
+
// Generate gradient colors for dark mode
|
|
36
|
+
const gradientFrom = darkenColor(themeColor, 30);
|
|
4
37
|
return (React.createElement("div", { className: [
|
|
5
|
-
"flex items-center justify-center
|
|
38
|
+
"flex items-center justify-center",
|
|
6
39
|
fullScreen ? "fixed inset-0 z-50" : "w-full h-full",
|
|
7
|
-
].join(" ")
|
|
40
|
+
].join(" "), style: {
|
|
41
|
+
background: `linear-gradient(to bottom, ${gradientFrom}, #0f172a, black)`,
|
|
42
|
+
} },
|
|
8
43
|
React.createElement("div", { className: "relative flex items-center justify-center font-inter select-none", style: { width: size, height: size } },
|
|
9
44
|
letters.map((letter, index) => {
|
|
10
45
|
// Preserve visual spacing for spaces by using a non‑breaking space
|
|
11
46
|
const displayChar = letter === " " ? "\u00A0" : letter;
|
|
12
|
-
return (React.createElement("span", { key: `${letter}-${index}`, className: "inline-block text-
|
|
47
|
+
return (React.createElement("span", { key: `${letter}-${index}`, className: "inline-block text-white opacity-40 animate-loaderLetter", style: { animationDelay: `${index * 0.1}s` } }, displayChar));
|
|
13
48
|
}),
|
|
14
|
-
React.createElement("div", { className: "absolute inset-0 rounded-full animate-loaderCircle"
|
|
49
|
+
React.createElement("div", { className: "absolute inset-0 rounded-full animate-loaderCircle", style: {
|
|
50
|
+
// @ts-ignore - CSS custom property
|
|
51
|
+
"--loader-color-dark": colorDark,
|
|
52
|
+
"--loader-color-mid": colorMid,
|
|
53
|
+
"--loader-color-light": colorLight,
|
|
54
|
+
"--loader-color-glow": rgbaGlow,
|
|
55
|
+
} })),
|
|
15
56
|
React.createElement("style", null, `
|
|
16
57
|
@keyframes loaderCircle {
|
|
17
58
|
0% {
|
|
18
59
|
transform: rotate(90deg);
|
|
19
|
-
box-shadow: 0 6px 12px 0
|
|
20
|
-
0
|
|
21
|
-
0
|
|
22
|
-
0 0
|
|
60
|
+
box-shadow: 0 6px 12px 0 var(--loader-color-dark) inset,
|
|
61
|
+
0 12px 18px 0 var(--loader-color-mid) inset,
|
|
62
|
+
0 36px 36px 0 var(--loader-color-light) inset,
|
|
63
|
+
0 0 3px 1.2px var(--loader-color-glow),
|
|
64
|
+
0 0 0 0 var(--loader-color-glow);
|
|
23
65
|
}
|
|
24
66
|
100% {
|
|
25
67
|
transform: rotate(450deg);
|
|
26
|
-
box-shadow: 0 6px 12px 0
|
|
27
|
-
0
|
|
28
|
-
0
|
|
29
|
-
0 0
|
|
68
|
+
box-shadow: 0 6px 12px 0 var(--loader-color-dark) inset,
|
|
69
|
+
0 12px 18px 0 var(--loader-color-mid) inset,
|
|
70
|
+
0 36px 36px 0 var(--loader-color-light) inset,
|
|
71
|
+
0 0 3px 1.2px var(--loader-color-glow),
|
|
72
|
+
0 0 0 0 var(--loader-color-glow);
|
|
30
73
|
}
|
|
31
74
|
}
|
|
32
75
|
@keyframes loaderLetter {
|