@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.
Files changed (145) hide show
  1. package/dist/components/guardian/app-layout-no-sidebar.js +8 -0
  2. package/dist/components/guardian/ask-ai-view.js +249 -0
  3. package/dist/components/guardian/code-focus-section.d.ts +41 -0
  4. package/dist/components/guardian/code-focus-section.js +174 -0
  5. package/dist/components/guardian/context/guardian-context.js +94 -0
  6. package/dist/components/guardian/context/vm-context.js +28 -0
  7. package/dist/components/guardian/default-guide-view.js +34 -0
  8. package/dist/components/guardian/demo/guardian-demo.js +35 -0
  9. package/dist/components/guardian/demo/left-view/toggle.js +28 -0
  10. package/dist/components/guardian/demo/left-view.js +49 -0
  11. package/dist/components/guardian/guardian-component.js +79 -0
  12. package/dist/components/guardian/guardian-demo.js +35 -0
  13. package/dist/components/guardian/guardian-home.d.ts +4 -0
  14. package/dist/components/guardian/guardian-home.js +61 -0
  15. package/dist/components/guardian/guardian-playground.js +45 -0
  16. package/dist/components/guardian/guardian-style-wrapper.js +29 -0
  17. package/dist/components/guardian/guardian-upload-spec.d.ts +14 -0
  18. package/dist/components/guardian/guardian-upload-spec.js +160 -0
  19. package/dist/components/guardian/header/glassmorphic-combobox.d.ts +15 -0
  20. package/dist/components/guardian/header/glassmorphic-combobox.js +30 -0
  21. package/dist/components/guardian/header.js +61 -0
  22. package/dist/components/guardian/hooks/use-frame-messages.js +65 -0
  23. package/dist/components/guardian/hooks/use-frame-params.js +44 -0
  24. package/dist/components/guardian/hooks/use-sandbox-url-loader.js +101 -0
  25. package/dist/components/guardian/ide/browser.js +538 -0
  26. package/dist/components/guardian/index.js +8 -0
  27. package/dist/components/guardian/layout/app-layout-no-sidebar.js +8 -0
  28. package/dist/components/guardian/layout/header/glassmorphic-combobox.js +48 -0
  29. package/dist/components/guardian/layout/header.js +63 -0
  30. package/dist/components/guardian/right-view/code-view.js +56 -0
  31. package/dist/components/guardian/right-view/pill-file-selector.js +233 -0
  32. package/dist/components/guardian/right-view/preview-control-bar.js +25 -0
  33. package/dist/components/guardian/right-view/right-panel-view.js +38 -0
  34. package/dist/components/guardian/right-view/right-top-down-view.js +289 -0
  35. package/dist/components/guardian/right-view/right-view.js +28 -0
  36. package/dist/components/guardian/right-view/simplified-editor.js +234 -0
  37. package/dist/components/guardian/types/ide-types.js +162 -0
  38. package/dist/components/guardian/types.js +3 -0
  39. package/dist/components/guardian/ui/ai-loader.js +48 -0
  40. package/dist/components/guardian/ui/badge.js +24 -0
  41. package/dist/components/guardian/ui/button.js +45 -0
  42. package/dist/components/guardian/ui/command.js +63 -0
  43. package/dist/components/guardian/ui/console-with-app.js +17 -0
  44. package/dist/components/guardian/ui/dialog.js +57 -0
  45. package/dist/components/guardian/ui/dropdown-menu.js +82 -0
  46. package/dist/components/guardian/ui/markdown.js +57 -0
  47. package/dist/components/guardian/ui/popover.js +25 -0
  48. package/dist/components/guardian/ui/tooltip.js +25 -0
  49. package/dist/components/guardian/utils.js +88 -0
  50. package/dist/components/guardian/zip-to-codebase.js +246 -0
  51. package/dist/components/guardian/zip-to-filetree.js +284 -0
  52. package/dist/components/icons.js +22 -0
  53. package/dist/components/sandbox/Sandbox.js +88 -0
  54. package/dist/components/sandbox/SandboxHome.js +141 -0
  55. package/dist/components/sandbox/api.js +84 -0
  56. package/dist/components/sandbox/guardian/app-layout-no-sidebar.js +11 -0
  57. package/dist/components/sandbox/guardian/ask-ai-view.js +249 -0
  58. package/dist/components/sandbox/guardian/code-focus-section.js +174 -0
  59. package/dist/components/sandbox/guardian/context/guardian-context.js +94 -0
  60. package/dist/components/sandbox/guardian/context/vm-context.js +28 -0
  61. package/dist/components/sandbox/guardian/default-guide-view.js +34 -0
  62. package/dist/components/sandbox/guardian/demo/guardian-demo.js +35 -0
  63. package/dist/components/sandbox/guardian/demo/left-view/toggle.js +28 -0
  64. package/dist/components/sandbox/guardian/demo/left-view.js +70 -0
  65. package/dist/components/sandbox/guardian/guardian-component.js +99 -0
  66. package/dist/components/sandbox/guardian/guardian-demo.js +35 -0
  67. package/dist/components/sandbox/guardian/guardian-home.d.ts +4 -0
  68. package/dist/components/sandbox/guardian/guardian-home.js +61 -0
  69. package/dist/components/sandbox/guardian/guardian-playground.js +45 -0
  70. package/dist/components/sandbox/guardian/guardian-style-wrapper.js +47 -0
  71. package/dist/components/sandbox/guardian/guardian-upload-spec.d.ts +14 -0
  72. package/dist/components/sandbox/guardian/guardian-upload-spec.js +160 -0
  73. package/dist/components/sandbox/guardian/header/glassmorphic-combobox.js +30 -0
  74. package/dist/components/sandbox/guardian/header.js +61 -0
  75. package/dist/components/sandbox/guardian/hooks/use-frame-messages.js +65 -0
  76. package/dist/components/sandbox/guardian/hooks/use-frame-params.js +44 -0
  77. package/dist/components/sandbox/guardian/hooks/use-sandbox-url-loader.js +125 -0
  78. package/dist/components/sandbox/guardian/ide/browser.js +538 -0
  79. package/dist/components/sandbox/guardian/index.js +8 -0
  80. package/dist/components/sandbox/guardian/right-view/code-view.js +60 -0
  81. package/dist/components/sandbox/guardian/right-view/pill-file-selector.js +246 -0
  82. package/dist/components/sandbox/guardian/right-view/preview-control-bar.js +25 -0
  83. package/dist/components/sandbox/guardian/right-view/right-panel-view.js +51 -0
  84. package/dist/components/sandbox/guardian/right-view/right-top-down-view.js +281 -0
  85. package/dist/components/sandbox/guardian/right-view/right-view.js +28 -0
  86. package/dist/components/sandbox/guardian/right-view/simplified-editor.js +234 -0
  87. package/dist/components/sandbox/guardian/types/ide-types.js +162 -0
  88. package/dist/components/sandbox/guardian/types.js +3 -0
  89. package/dist/components/sandbox/guardian/ui/ai-loader.js +91 -0
  90. package/dist/components/sandbox/guardian/ui/badge.js +24 -0
  91. package/dist/components/sandbox/guardian/ui/button.js +45 -0
  92. package/dist/components/sandbox/guardian/ui/command.js +63 -0
  93. package/dist/components/sandbox/guardian/ui/console-with-app.js +17 -0
  94. package/dist/components/sandbox/guardian/ui/dialog.js +57 -0
  95. package/dist/components/sandbox/guardian/ui/download-and-open-buttons.js +117 -0
  96. package/dist/components/sandbox/guardian/ui/dropdown-menu.js +82 -0
  97. package/dist/components/sandbox/guardian/ui/markdown/accordion-group/accordion.js +62 -0
  98. package/dist/components/sandbox/guardian/ui/markdown/accordion-group.js +23 -0
  99. package/dist/components/sandbox/guardian/ui/markdown/callout/callout-check.js +4 -0
  100. package/dist/components/sandbox/guardian/ui/markdown/callout/callout-error.js +4 -0
  101. package/dist/components/sandbox/guardian/ui/markdown/callout/callout-info.js +4 -0
  102. package/dist/components/sandbox/guardian/ui/markdown/callout/callout-note.js +4 -0
  103. package/dist/components/sandbox/guardian/ui/markdown/callout/callout-tip.js +4 -0
  104. package/dist/components/sandbox/guardian/ui/markdown/callout/callout-warning.js +4 -0
  105. package/dist/components/sandbox/guardian/ui/markdown/callout/shared/callout.js +9 -0
  106. package/dist/components/sandbox/guardian/ui/markdown/callout/shared/types.js +1 -0
  107. package/dist/components/sandbox/guardian/ui/markdown/card-group/card.js +18 -0
  108. package/dist/components/sandbox/guardian/ui/markdown/card-group.js +25 -0
  109. package/dist/components/sandbox/guardian/ui/markdown/code-group/code-block.js +54 -0
  110. package/dist/components/sandbox/guardian/ui/markdown/code-group.js +101 -0
  111. package/dist/components/sandbox/guardian/ui/markdown/icon.js +31 -0
  112. package/dist/components/sandbox/guardian/ui/markdown.js +791 -0
  113. package/dist/components/sandbox/guardian/ui/popover.js +25 -0
  114. package/dist/components/sandbox/guardian/ui/tooltip.js +25 -0
  115. package/dist/components/sandbox/guardian/utils.js +89 -0
  116. package/dist/components/sandbox/guardian/zip-to-codebase.js +259 -0
  117. package/dist/components/sandbox/guardian/zip-to-filetree.js +284 -0
  118. package/dist/components/sandbox/index.js +4 -0
  119. package/dist/components/sandbox/sandbox-control-bar.js +91 -0
  120. package/dist/components/sandbox/sandbox-header.js +52 -0
  121. package/dist/components/sandbox/sandbox-home/SandboxCard.js +65 -0
  122. package/dist/components/sandbox/sandbox-home/SandboxHome.js +115 -0
  123. package/dist/components/sandbox/sandbox-home/SearchBar.js +12 -0
  124. package/dist/components/sandbox/sandbox-home/index.js +3 -0
  125. package/dist/components/sandbox/sandbox-left-panel.js +248 -0
  126. package/dist/components/sandbox/sandbox-loading.js +48 -0
  127. package/dist/components/sandbox/sandbox-right-panel.js +247 -0
  128. package/dist/components/sandbox/types.js +1 -0
  129. package/dist/components/sandbox.js +32 -0
  130. package/dist/components/tailwind-example.js +46 -0
  131. package/dist/components/ui/skeleton.js +18 -0
  132. package/dist/index.d.ts +32 -103
  133. package/dist/index.es.js +90529 -423
  134. package/dist/index.js +13 -2
  135. package/dist/index.standalone.js +61 -53
  136. package/dist/index.standalone.umd.js +17 -24
  137. package/dist/lib/api-client.example.js +60 -0
  138. package/dist/lib/api-client.js +140 -0
  139. package/dist/lib/generated-css.js +4 -0
  140. package/dist/lib/inject-styles.js +42 -0
  141. package/dist/lib/shadow-dom-wrapper.js +42 -0
  142. package/dist/lib/utils.js +5 -0
  143. package/dist/sdk.css +1 -1
  144. package/dist/tailwind.css +1 -0
  145. package/package.json +41 -9
@@ -0,0 +1,174 @@
1
+ "use client";
2
+ import React, { useEffect, useMemo, useRef } from "react";
3
+ import { useGuardianContext } from "./context/guardian-context";
4
+ // Helper function to find a node in the file tree by path
5
+ function getTargetNode(fileTree, targetPath) {
6
+ const parts = targetPath.split("/").filter(Boolean);
7
+ let current = fileTree;
8
+ for (const part of parts) {
9
+ if (!current.children || !current.children[part]) {
10
+ return null;
11
+ }
12
+ current = current.children[part];
13
+ }
14
+ return current;
15
+ }
16
+ /**
17
+ * Component that focuses on a specific file and line range in the code editor
18
+ * when it comes into view while scrolling, or when the user clicks "View Code".
19
+ */
20
+ export default function CodeFocusSection({ filePath, lineRange, title, description, children, threshold = 0, themeColor, }) {
21
+ const sectionRef = useRef(null);
22
+ const { generatedCode, fileTree, setActiveFilePath, setActiveFileName, setActiveLineNumber, setActiveLineRange, updateCode, setLanguage, filesEdited, activeFilePath, activeLineRange, } = useGuardianContext();
23
+ // Moves the editor's focus to this file/lines
24
+ const focusCode = () => {
25
+ // Get the file code from generatedCode or fileTree
26
+ // Always search by file_path property first, as that's the source of truth
27
+ let code = "";
28
+ let language;
29
+ let resolvedFilePath;
30
+ let codeOutput;
31
+ // First, search through all code outputs to find one matching file_path
32
+ const matchingCodeOutput = Object.values(generatedCode).find((output) => output.file_path === filePath);
33
+ if (matchingCodeOutput) {
34
+ codeOutput = matchingCodeOutput;
35
+ code = codeOutput.full_code;
36
+ language = codeOutput.code_language;
37
+ resolvedFilePath = codeOutput.file_path;
38
+ }
39
+ else {
40
+ // Fallback: try to get from generatedCode by key, but still use file_path from the object
41
+ if (generatedCode[filePath]) {
42
+ codeOutput = generatedCode[filePath];
43
+ code = codeOutput.full_code;
44
+ language = codeOutput.code_language;
45
+ // Always use the file_path from the code output object as source of truth
46
+ resolvedFilePath = codeOutput.file_path || filePath;
47
+ }
48
+ else {
49
+ // Fallback to fileTree
50
+ try {
51
+ const targetNode = getTargetNode(fileTree, filePath);
52
+ if (targetNode === null || targetNode === void 0 ? void 0 : targetNode.metadata) {
53
+ code = targetNode.metadata.full_code || "";
54
+ language = targetNode.metadata.code_language;
55
+ // Use file_path from metadata if available, otherwise use the provided filePath
56
+ resolvedFilePath = targetNode.metadata.file_path || filePath;
57
+ }
58
+ }
59
+ catch (error) {
60
+ console.warn(`Failed to get code for file ${filePath}:`, error);
61
+ resolvedFilePath = filePath;
62
+ }
63
+ }
64
+ }
65
+ // If we still don't have a resolved file path, use the provided filePath
66
+ if (!resolvedFilePath) {
67
+ resolvedFilePath = filePath;
68
+ }
69
+ // Check if file has been edited - use resolvedFilePath for lookup
70
+ const editedCode = filesEdited[resolvedFilePath] || filesEdited[filePath];
71
+ const finalCode = editedCode ? editedCode.full_code : code;
72
+ if (finalCode) {
73
+ // Extract filename from path - prefer code_file_name from code output
74
+ const fileName = (codeOutput === null || codeOutput === void 0 ? void 0 : codeOutput.code_file_name) ||
75
+ resolvedFilePath.split("/").pop() ||
76
+ resolvedFilePath;
77
+ // Set the active file using the resolved file path
78
+ setActiveFilePath(resolvedFilePath);
79
+ setActiveFileName(fileName);
80
+ updateCode(finalCode);
81
+ // Set language if available
82
+ if (language) {
83
+ setLanguage(language);
84
+ }
85
+ // Set line number/range if provided
86
+ if (lineRange) {
87
+ setActiveLineRange({
88
+ start: lineRange.start,
89
+ end: lineRange.end,
90
+ });
91
+ }
92
+ else {
93
+ setActiveLineRange(undefined);
94
+ setActiveLineNumber(undefined);
95
+ }
96
+ }
97
+ };
98
+ useEffect(() => {
99
+ const element = sectionRef.current;
100
+ if (!element)
101
+ return;
102
+ const observer = new IntersectionObserver((entries) => {
103
+ entries.forEach((entry) => {
104
+ // Trigger when the element enters the middle of the viewport
105
+ if (entry.isIntersecting) {
106
+ focusCode();
107
+ }
108
+ });
109
+ }, {
110
+ threshold,
111
+ rootMargin: "-40% 0px -40% 0px", // Trigger when element enters the middle 20% of viewport
112
+ });
113
+ observer.observe(element);
114
+ return () => {
115
+ observer.disconnect();
116
+ };
117
+ // eslint-disable-next-line react-hooks/exhaustive-deps
118
+ }, [
119
+ filePath,
120
+ lineRange,
121
+ generatedCode,
122
+ fileTree,
123
+ setActiveFilePath,
124
+ setActiveFileName,
125
+ setActiveLineNumber,
126
+ setActiveLineRange,
127
+ updateCode,
128
+ setLanguage,
129
+ filesEdited,
130
+ threshold,
131
+ ]);
132
+ // Get the resolved file path for comparison
133
+ // This ensures we compare against the actual file_path from the code structure
134
+ const resolvedFilePathForComparison = useMemo(() => {
135
+ var _a, _b;
136
+ // Search by file_path property first (this is the source of truth)
137
+ const matchingCodeOutput = Object.values(generatedCode).find((output) => output.file_path === filePath);
138
+ if (matchingCodeOutput) {
139
+ return matchingCodeOutput.file_path;
140
+ }
141
+ // Fallback to key lookup
142
+ if ((_a = generatedCode[filePath]) === null || _a === void 0 ? void 0 : _a.file_path) {
143
+ return generatedCode[filePath].file_path;
144
+ }
145
+ // Fallback to fileTree
146
+ try {
147
+ const targetNode = getTargetNode(fileTree, filePath);
148
+ if ((_b = targetNode === null || targetNode === void 0 ? void 0 : targetNode.metadata) === null || _b === void 0 ? void 0 : _b.file_path) {
149
+ return targetNode.metadata.file_path;
150
+ }
151
+ }
152
+ catch (_c) {
153
+ // Ignore errors
154
+ }
155
+ return filePath;
156
+ }, [filePath, generatedCode, fileTree]);
157
+ return (React.createElement("div", { ref: sectionRef, className: `relative transition-colors py-6 cursor-pointer`, onClick: focusCode },
158
+ React.createElement("div", { className: "pointer-events-none absolute inset-x-[-2rem] top-0 border-t border-border" }),
159
+ React.createElement("div", { className: "pointer-events-none absolute inset-x-[-2rem] bottom-0 border-b border-border" }),
160
+ (activeFilePath === resolvedFilePathForComparison ||
161
+ activeFilePath === filePath) &&
162
+ (activeLineRange
163
+ ? lineRange &&
164
+ activeLineRange.start === lineRange.start &&
165
+ activeLineRange.end === lineRange.end
166
+ : !lineRange) && (React.createElement("div", { className: "absolute left-0 top-0 h-full w-1", style: {
167
+ backgroundColor: themeColor,
168
+ marginLeft: "-2rem",
169
+ } })),
170
+ React.createElement("div", { className: "flex items-center gap-2" },
171
+ React.createElement("h3", { className: "text-md font-semibold text-gray-900 dark:text-gray-100" }, title)),
172
+ description && (React.createElement("p", { className: "text-sm text-gray-400 mt-3" }, description)),
173
+ children && React.createElement("div", { className: "mt-3" }, children)));
174
+ }
@@ -0,0 +1,94 @@
1
+ "use client";
2
+ import React, { createContext, useContext, useState, useCallback, } from "react";
3
+ import { CodeLanguage, } from "../types/ide-types";
4
+ const GuardianContext = createContext(undefined);
5
+ export function GuardianProvider({ children }) {
6
+ const [previewUrl, setPreviewUrlState] = useState("");
7
+ const [isBrowserMaximized, setIsBrowserMaximized] = useState(false);
8
+ const [currentView, setCurrentViewState] = useState("preview");
9
+ // Code state
10
+ const [code, setCode] = useState("");
11
+ const [language, setLanguage] = useState(CodeLanguage.TEXT);
12
+ const [activeFileName, setActiveFileName] = useState("");
13
+ const [activeFilePath, setActiveFilePath] = useState("");
14
+ const [activeLineNumber, setActiveLineNumber] = useState(undefined);
15
+ const [activeLineRange, setActiveLineRange] = useState(undefined);
16
+ const [isGeneratingCode, setIsGeneratingCode] = useState(false);
17
+ // Generated code and file tree
18
+ const [generatedCode, setGeneratedCodeState] = useState({});
19
+ const [fileTree, setFileTree] = useState({
20
+ name: "root",
21
+ children: {},
22
+ type: "folder",
23
+ metadata: {
24
+ response_type: "CodeOutput",
25
+ file_path: "",
26
+ code_file_name: "",
27
+ code_language: CodeLanguage.TEXT,
28
+ dependencies_to_install: [],
29
+ framework: null,
30
+ full_code: "",
31
+ },
32
+ });
33
+ // Dependencies and edited files
34
+ const [activeDependenciesToInstall, setActiveDependenciesToInstall] = useState([]);
35
+ const [filesEdited, setFilesEdited] = useState({});
36
+ const setPreviewUrl = useCallback((url) => {
37
+ setPreviewUrlState(url);
38
+ }, []);
39
+ const setIsBrowserMaximizedState = useCallback((maximized) => {
40
+ setIsBrowserMaximized(maximized);
41
+ }, []);
42
+ const setCurrentView = useCallback((view) => {
43
+ setCurrentViewState(view);
44
+ }, []);
45
+ const updateCode = useCallback((newCode) => {
46
+ setCode(newCode);
47
+ }, []);
48
+ const setGeneratedCode = useCallback((generatedCode) => {
49
+ if (typeof generatedCode === "function") {
50
+ setGeneratedCodeState((prev) => generatedCode(prev));
51
+ }
52
+ else {
53
+ setGeneratedCodeState(generatedCode);
54
+ }
55
+ }, []);
56
+ const value = {
57
+ previewUrl,
58
+ setPreviewUrl,
59
+ isBrowserMaximized,
60
+ setIsBrowserMaximized: setIsBrowserMaximizedState,
61
+ currentView,
62
+ setCurrentView,
63
+ code,
64
+ updateCode,
65
+ language,
66
+ setLanguage,
67
+ activeFileName,
68
+ setActiveFileName,
69
+ activeFilePath,
70
+ setActiveFilePath,
71
+ activeLineNumber,
72
+ setActiveLineNumber,
73
+ activeLineRange,
74
+ setActiveLineRange,
75
+ isGeneratingCode,
76
+ setIsGeneratingCode,
77
+ generatedCode,
78
+ setGeneratedCode,
79
+ fileTree,
80
+ setFileTree,
81
+ activeDependenciesToInstall,
82
+ setActiveDependenciesToInstall,
83
+ filesEdited,
84
+ setFilesEdited,
85
+ };
86
+ return (React.createElement(GuardianContext.Provider, { value: value }, children));
87
+ }
88
+ export function useGuardianContext() {
89
+ const context = useContext(GuardianContext);
90
+ if (!context) {
91
+ throw new Error("useGuardianContext must be used within a GuardianProvider");
92
+ }
93
+ return context;
94
+ }
@@ -0,0 +1,28 @@
1
+ "use client";
2
+ import React, { createContext, useContext, useState } from "react";
3
+ const VmContext = createContext(undefined);
4
+ export const VmProvider = ({ children }) => {
5
+ const [vmUrlMap, setVmUrlMap] = useState({});
6
+ const setVmUrl = (uid, url) => {
7
+ setVmUrlMap((prev) => (Object.assign(Object.assign({}, prev), { [uid]: url })));
8
+ };
9
+ const getVmUrl = (uid) => {
10
+ const value = vmUrlMap[uid];
11
+ // Return undefined if it's an error marker
12
+ return value === "error" ? undefined : value;
13
+ };
14
+ const setVmError = (uid) => {
15
+ setVmUrlMap((prev) => (Object.assign(Object.assign({}, prev), { [uid]: "error" })));
16
+ };
17
+ const hasError = (uid) => {
18
+ return vmUrlMap[uid] === "error";
19
+ };
20
+ return (React.createElement(VmContext.Provider, { value: { vmUrlMap, setVmUrl, getVmUrl, setVmError, hasError } }, children));
21
+ };
22
+ export const useVmContext = () => {
23
+ const context = useContext(VmContext);
24
+ if (!context) {
25
+ throw new Error("useVmContext must be used within a VmProvider");
26
+ }
27
+ return context;
28
+ };
@@ -0,0 +1,34 @@
1
+ "use client";
2
+ import React from "react";
3
+ import { Markdown } from "./ui/markdown";
4
+ export default function DefaultGuideView({ themeColor, }) {
5
+ return (React.createElement("div", { className: "h-full flex flex-col" },
6
+ React.createElement("div", { className: "flex-1 px-8 py-6" },
7
+ React.createElement(Markdown, { className: "text-gray-100", themeColor: themeColor }, `# Guardian Guide
8
+
9
+ Learn how to use Guardian to build and deploy your application with confidence.
10
+
11
+ ## Getting Started
12
+
13
+ Guardian provides a comprehensive development environment with real-time preview, code editing, and AI assistance.
14
+
15
+ ### Features
16
+
17
+ - **Live Preview**: See your changes instantly as you code
18
+ - **Code Editor**: Edit files directly in the browser
19
+ - **AI Assistant**: Get help with your code using the Ask AI feature
20
+
21
+ ### Navigation
22
+
23
+ Use the tabs at the top to switch between:
24
+ - **Guide**: View this documentation
25
+ - **Ask AI**: Get AI-powered assistance with your code
26
+
27
+ ### Code Editing
28
+
29
+ Select files from the file selector to view and edit them. The editor supports syntax highlighting and automatic formatting.
30
+
31
+ ### Preview
32
+
33
+ The preview panel shows your running application. Use the reload button to refresh the preview when needed.`))));
34
+ }
@@ -0,0 +1,35 @@
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 "./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, gitUrl, }) {
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 border-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 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
+ }
@@ -0,0 +1,28 @@
1
+ "use client";
2
+ import React from "react";
3
+ import { motion } from "framer-motion";
4
+ import { cn } from "../../../../../lib/utils";
5
+ export default function SlidingEditPreviewToggle({ playgroundUid, variant = "default", buttonClassName = "", tabs = [
6
+ { id: "editor", label: "Edit" },
7
+ { id: "preview", label: "Preview" },
8
+ ], currentView, setCurrentView, }) {
9
+ // Outer div and button shape depending on variant
10
+ const rootClasses = variant === "pill"
11
+ ? "relative inline-flex items-center bg-muted/30 rounded-full p-1 border border-border/50"
12
+ : "relative inline-flex items-center bg-muted/30 rounded-lg p-1";
13
+ const btnShape = variant === "pill" ? "rounded-full" : "rounded-md";
14
+ const highlightShape = variant === "pill" ? "rounded-full" : "rounded-md";
15
+ // Default button padding if none provided
16
+ const defaultButtonPadding = variant === "pill" ? "px-5 py-2" : "px-4 py-1.5";
17
+ return (React.createElement("div", { className: rootClasses }, tabs.map((tab) => (React.createElement("button", { key: tab.id, onClick: () => setCurrentView(tab.id), className: cn(`relative ${defaultButtonPadding} text-sm font-medium transition-colors duration-150 ${btnShape} ${currentView === tab.id
18
+ ? "text-foreground"
19
+ : "text-muted-foreground hover:text-foreground/80"}`, buttonClassName), style: {
20
+ WebkitTapHighlightColor: "transparent",
21
+ } },
22
+ currentView === tab.id && (React.createElement(motion.div, { layoutId: "activeTabGuide", className: cn(`absolute inset-0 bg-neutral-200 dark:bg-neutral-700 ${highlightShape} shadow-sm border border-border/50`), initial: false, transition: {
23
+ type: "spring",
24
+ stiffness: 500,
25
+ damping: 30,
26
+ } })),
27
+ React.createElement("span", { className: "relative z-10" }, tab.label))))));
28
+ }
@@ -0,0 +1,70 @@
1
+ "use client";
2
+ import React, { useMemo, useState } from "react";
3
+ import SlidingConsoleGuideToggle from "./left-view/toggle";
4
+ // import AskAiView from "../ask-ai-view";
5
+ // import DefaultGuideView from "../default-guide-view";
6
+ import { Markdown } from "../ui/markdown";
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, }) {
15
+ const [currentView, setCurrentView] = useState("console");
16
+ const isConsoleView = useMemo(() => currentView === "console", [currentView]);
17
+ // const isGuideView = useMemo(() => currentView === "guide", [currentView]);
18
+ // const isChatView = useMemo(() => currentView === "chat", [currentView]);
19
+ const renderCustomConsole = () => {
20
+ if (typeof CustomConsole === "string") {
21
+ return (React.createElement("div", { className: "h-full flex flex-col" },
22
+ React.createElement("div", { className: "flex-1 px-8 py-6" },
23
+ React.createElement(Markdown, { className: "text-gray-100", themeColor: themeColor, browserUrl: browserUrl, gitUrl: gitUrl }, CustomConsole))));
24
+ }
25
+ const CustomConsoleComponent = CustomConsole;
26
+ return (React.createElement(CustomConsoleComponent, { onReloadPreview: onReloadPreview !== null && onReloadPreview !== void 0 ? onReloadPreview : (() => { }), onStageChange: onStageChange !== null && onStageChange !== void 0 ? onStageChange : (() => { }), themeColor: themeColor }));
27
+ };
28
+ // Determine which guide view to render
29
+ // const renderGuideView = () => {
30
+ // if (!GuideView) {
31
+ // // If no GuideView provided, render default
32
+ // return (
33
+ // <DefaultGuideView
34
+ // onReloadPreview={onReloadPreview ?? (() => {})}
35
+ // onStageChange={onStageChange ?? (() => {})}
36
+ // themeColor={themeColor}
37
+ // />
38
+ // );
39
+ // }
40
+ // // If GuideView is a string, render as markdown
41
+ // if (typeof GuideView === "string") {
42
+ // return (
43
+ // <div className="h-full flex flex-col">
44
+ // <div className="flex-1 px-8 py-6">
45
+ // <Markdown className="text-gray-100" themeColor={themeColor}>
46
+ // {GuideView}
47
+ // </Markdown>
48
+ // </div>
49
+ // </div>
50
+ // );
51
+ // }
52
+ // // Otherwise, render as React component
53
+ // const GuideComponent = GuideView as ComponentType;
54
+ // return <GuideComponent />;
55
+ // };
56
+ return (React.createElement("div", { className: "flex-1 min-h-0 relative flex flex-col" },
57
+ React.createElement("div", { className: "flex justify-center border-b border-border" },
58
+ React.createElement(SlidingConsoleGuideToggle, { playgroundUid: playgroundUid, variant: "pill", buttonClassName: "text-sm px-4 py-1", currentView: currentView, setCurrentView: setCurrentView, tabs: [
59
+ { id: "console", label: "Guide" },
60
+ // ...(GuideView ? [{id: "guide-og", label: "Guide OG"}] : []),
61
+ // {id: "chat", label: "Ask AI"},
62
+ ] })),
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" })))))));
70
+ }
@@ -0,0 +1,99 @@
1
+ "use client";
2
+ import Header from "./header";
3
+ import AppLayoutNoSidebar from "./app-layout-no-sidebar";
4
+ import GuardianDemo from "./demo/guardian-demo";
5
+ import React, { useEffect, useRef } from "react";
6
+ import { useGuardianContext } from "./context/guardian-context";
7
+ import { useSandboxUrlLoader, } from "./hooks/use-sandbox-url-loader";
8
+ import { useFrameMessages } from "./hooks/use-frame-messages";
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, }) {
12
+ const { previewUrl, setPreviewUrl } = useGuardianContext();
13
+ // Debug: Log the props received for sandbox configuration
14
+ console.log("[GuardianComponent] API config props:", {
15
+ apiKey: apiKey ? `${apiKey.substring(0, 8)}...` : undefined,
16
+ env,
17
+ chatUid,
18
+ hasApiKey: !!apiKey,
19
+ hasEnv: !!env,
20
+ hasChatUid: !!chatUid,
21
+ });
22
+ // Build startSandboxConfig only if all required fields are present and non-empty
23
+ const startSandboxConfig = apiKey && env && chatUid
24
+ ? {
25
+ apiKey,
26
+ env,
27
+ chatUid,
28
+ }
29
+ : undefined;
30
+ console.log("[GuardianComponent] startSandboxConfig:", startSandboxConfig ? "configured" : "undefined (missing required fields)");
31
+ const { getSandboxUrl, loadSandboxUrl, preloadSandboxUrls } = useSandboxUrlLoader(startSandboxConfig);
32
+ // Initialize postMessage listener for iframe communication
33
+ // This sends IFRAME_READY and listens for UPDATE_VIEW messages
34
+ useFrameMessages();
35
+ // Track which console configs we've preloaded to prevent duplicates
36
+ const preloadedConfigsRef = useRef("");
37
+ // Track which main sandbox we've loaded to prevent duplicates
38
+ const loadedSandboxRef = useRef("");
39
+ // Preload console URLs when component mounts
40
+ useEffect(() => {
41
+ if (consoleUrlConfigs && consoleUrlConfigs.length > 0) {
42
+ // Create a key from the configs to detect changes
43
+ const configKey = JSON.stringify(consoleUrlConfigs.map((c) => c.sandboxUid));
44
+ // Only preload if we haven't already preloaded these configs
45
+ if (preloadedConfigsRef.current !== configKey) {
46
+ preloadedConfigsRef.current = configKey;
47
+ preloadSandboxUrls(consoleUrlConfigs).catch((error) => {
48
+ console.error("Failed to preload console URLs:", error);
49
+ });
50
+ }
51
+ }
52
+ // Only re-run if consoleUrlConfigs changes (not when preloadSandboxUrls changes)
53
+ // eslint-disable-next-line react-hooks/exhaustive-deps
54
+ }, [consoleUrlConfigs]);
55
+ useEffect(() => {
56
+ // Create a key for this sandbox load
57
+ const sandboxKey = `${sandboxUid}-${browserUrl}-${useVm}`;
58
+ // Check if we've already initiated a load for this exact sandbox config
59
+ if (loadedSandboxRef.current === sandboxKey) {
60
+ return;
61
+ }
62
+ // Check if URL is already cached for this sandboxUid + browserUrl combination
63
+ const existingUrl = getSandboxUrl(sandboxUid, browserUrl);
64
+ if (existingUrl !== undefined) {
65
+ // Found cached URL for this exact combination, use it immediately
66
+ setPreviewUrl(existingUrl);
67
+ loadedSandboxRef.current = sandboxKey;
68
+ return;
69
+ }
70
+ // Mark as loading to prevent duplicate requests
71
+ loadedSandboxRef.current = sandboxKey;
72
+ // Load the sandbox URL (will be cached by sandboxUid + browserUrl)
73
+ // This allows switching between different browserUrls and reverting back
74
+ // without losing the cached URLs
75
+ setPreviewUrl("");
76
+ loadSandboxUrl({
77
+ sandboxUid,
78
+ browserUrl,
79
+ useVm,
80
+ })
81
+ .then((url) => {
82
+ setPreviewUrl(url);
83
+ })
84
+ .catch((error) => {
85
+ console.error("Failed to load sandbox URL:", error);
86
+ // Keep preview URL empty on error
87
+ });
88
+ // Only re-run if the sandbox parameters change (not when functions change)
89
+ // eslint-disable-next-line react-hooks/exhaustive-deps
90
+ }, [sandboxUid, browserUrl, useVm]);
91
+ // If isFrame, just render GuardianDemo without the header/layout wrapper
92
+ if (isFrame) {
93
+ return (React.createElement("div", { className: "h-[100vh]" },
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 })));
95
+ }
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 }))));
99
+ }
@@ -0,0 +1,35 @@
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
+ }
@@ -0,0 +1,4 @@
1
+ import { GuardianNestedConfig } from "./types";
2
+ export default function GuardianHome({ nestedConfig, }: {
3
+ nestedConfig: GuardianNestedConfig;
4
+ }): import("react").JSX.Element;