Spaces:
Running
Running
Support json file
Browse files
app/api/me/projects/[namespace]/[repoId]/route.ts
CHANGED
|
@@ -108,7 +108,7 @@ export async function GET(
|
|
| 108 |
const allowedFilesExtensions = ["jpg", "jpeg", "png", "gif", "svg", "webp", "avif", "heic", "heif", "ico", "bmp", "tiff", "tif", "mp4", "webm", "ogg", "avi", "mov", "mp3", "wav", "ogg", "aac", "m4a"];
|
| 109 |
|
| 110 |
for await (const fileInfo of listFiles({repo, accessToken: user.token as string})) {
|
| 111 |
-
if (fileInfo.path.endsWith(".html") || fileInfo.path.endsWith(".css") || fileInfo.path.endsWith(".js")) {
|
| 112 |
const blob = await downloadFile({ repo, accessToken: user.token as string, path: fileInfo.path, raw: true });
|
| 113 |
const html = await blob?.text();
|
| 114 |
if (!html) {
|
|
|
|
| 108 |
const allowedFilesExtensions = ["jpg", "jpeg", "png", "gif", "svg", "webp", "avif", "heic", "heif", "ico", "bmp", "tiff", "tif", "mp4", "webm", "ogg", "avi", "mov", "mp3", "wav", "ogg", "aac", "m4a"];
|
| 109 |
|
| 110 |
for await (const fileInfo of listFiles({repo, accessToken: user.token as string})) {
|
| 111 |
+
if (fileInfo.path.endsWith(".html") || fileInfo.path.endsWith(".css") || fileInfo.path.endsWith(".js") || fileInfo.path.endsWith(".json")) {
|
| 112 |
const blob = await downloadFile({ repo, accessToken: user.token as string, path: fileInfo.path, raw: true });
|
| 113 |
const html = await blob?.text();
|
| 114 |
if (!html) {
|
app/layout.tsx
CHANGED
|
@@ -114,7 +114,7 @@ export default async function RootLayout({
|
|
| 114 |
data-domain="deepsite.hf.co"
|
| 115 |
src="https://plausible.io/js/script.js"
|
| 116 |
/>
|
| 117 |
-
<DomainRedirect />
|
| 118 |
<IframeDetector />
|
| 119 |
<Toaster richColors position="bottom-center" />
|
| 120 |
<TanstackContext>
|
|
|
|
| 114 |
data-domain="deepsite.hf.co"
|
| 115 |
src="https://plausible.io/js/script.js"
|
| 116 |
/>
|
| 117 |
+
{/* <DomainRedirect /> */}
|
| 118 |
<IframeDetector />
|
| 119 |
<Toaster richColors position="bottom-center" />
|
| 120 |
<TanstackContext>
|
components/editor/ask-ai/context.tsx
CHANGED
|
@@ -23,6 +23,8 @@ export const Context = () => {
|
|
| 23 |
return <Braces className={size} />;
|
| 24 |
} else if (filePath.endsWith(".js")) {
|
| 25 |
return <FileCode className={size} />;
|
|
|
|
|
|
|
| 26 |
} else {
|
| 27 |
return <FileText className={size} />;
|
| 28 |
}
|
|
@@ -52,6 +54,8 @@ export const Context = () => {
|
|
| 52 |
selectedFile && selectedFile.endsWith(".html"),
|
| 53 |
"!bg-amber-500/10 !border-amber-500/30 !text-amber-400":
|
| 54 |
selectedFile && selectedFile.endsWith(".js"),
|
|
|
|
|
|
|
| 55 |
})}
|
| 56 |
disabled={
|
| 57 |
globalAiLoading || globalEditorLoading || pages.length === 0
|
|
|
|
| 23 |
return <Braces className={size} />;
|
| 24 |
} else if (filePath.endsWith(".js")) {
|
| 25 |
return <FileCode className={size} />;
|
| 26 |
+
} else if (filePath.endsWith(".json")) {
|
| 27 |
+
return <Braces className={size} />;
|
| 28 |
} else {
|
| 29 |
return <FileText className={size} />;
|
| 30 |
}
|
|
|
|
| 54 |
selectedFile && selectedFile.endsWith(".html"),
|
| 55 |
"!bg-amber-500/10 !border-amber-500/30 !text-amber-400":
|
| 56 |
selectedFile && selectedFile.endsWith(".js"),
|
| 57 |
+
"!bg-yellow-500/10 !border-yellow-500/30 !text-yellow-400":
|
| 58 |
+
selectedFile && selectedFile.endsWith(".json"),
|
| 59 |
})}
|
| 60 |
disabled={
|
| 61 |
globalAiLoading || globalEditorLoading || pages.length === 0
|
components/editor/file-browser/index.tsx
CHANGED
|
@@ -7,6 +7,7 @@ import {
|
|
| 7 |
Folder,
|
| 8 |
ChevronRight,
|
| 9 |
ChevronDown,
|
|
|
|
| 10 |
} from "lucide-react";
|
| 11 |
import classNames from "classnames";
|
| 12 |
|
|
@@ -197,27 +198,7 @@ export function FileBrowser() {
|
|
| 197 |
</svg>
|
| 198 |
);
|
| 199 |
case "json":
|
| 200 |
-
return
|
| 201 |
-
<svg className="size-4 shrink-0" viewBox="0 0 32 32" fill="none">
|
| 202 |
-
<rect width="32" height="32" rx="2" fill="#F7DF1E" />
|
| 203 |
-
<path
|
| 204 |
-
d="M16 2L4 8v16l12 6 12-6V8L16 2zm8.8 20.4l-8.8 4.4-8.8-4.4V9.6l8.8-4.4 8.8 4.4v12.8z"
|
| 205 |
-
fill="#000"
|
| 206 |
-
opacity="0.15"
|
| 207 |
-
/>
|
| 208 |
-
<text
|
| 209 |
-
x="50%"
|
| 210 |
-
y="50%"
|
| 211 |
-
dominantBaseline="middle"
|
| 212 |
-
textAnchor="middle"
|
| 213 |
-
fill="#000"
|
| 214 |
-
fontSize="14"
|
| 215 |
-
fontWeight="600"
|
| 216 |
-
>
|
| 217 |
-
{}
|
| 218 |
-
</text>
|
| 219 |
-
</svg>
|
| 220 |
-
);
|
| 221 |
default:
|
| 222 |
return <FileCode2 className="size-4 shrink-0 text-neutral-400" />;
|
| 223 |
}
|
|
@@ -249,7 +230,7 @@ export function FileBrowser() {
|
|
| 249 |
case "json":
|
| 250 |
return {
|
| 251 |
name: "JSON",
|
| 252 |
-
color: "bg-
|
| 253 |
};
|
| 254 |
default:
|
| 255 |
return {
|
|
@@ -458,6 +439,13 @@ export function FileBrowser() {
|
|
| 458 |
JS: {pages.filter((p) => p.path.endsWith(".js")).length}
|
| 459 |
</span>
|
| 460 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 461 |
</div>
|
| 462 |
</div>
|
| 463 |
</SheetContent>
|
|
|
|
| 7 |
Folder,
|
| 8 |
ChevronRight,
|
| 9 |
ChevronDown,
|
| 10 |
+
FileJson,
|
| 11 |
} from "lucide-react";
|
| 12 |
import classNames from "classnames";
|
| 13 |
|
|
|
|
| 198 |
</svg>
|
| 199 |
);
|
| 200 |
case "json":
|
| 201 |
+
return <FileJson className="size-4 shrink-0 text-amber-400" />;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 202 |
default:
|
| 203 |
return <FileCode2 className="size-4 shrink-0 text-neutral-400" />;
|
| 204 |
}
|
|
|
|
| 230 |
case "json":
|
| 231 |
return {
|
| 232 |
name: "JSON",
|
| 233 |
+
color: "bg-amber-500/20 border-amber-500/30 text-amber-400",
|
| 234 |
};
|
| 235 |
default:
|
| 236 |
return {
|
|
|
|
| 439 |
JS: {pages.filter((p) => p.path.endsWith(".js")).length}
|
| 440 |
</span>
|
| 441 |
</div>
|
| 442 |
+
<div className="flex items-center gap-2 text-neutral-500">
|
| 443 |
+
<div className="size-2 rounded-full bg-yellow-600" />
|
| 444 |
+
<span>
|
| 445 |
+
JSON:{" "}
|
| 446 |
+
{pages.filter((p) => p.path.endsWith(".json")).length}
|
| 447 |
+
</span>
|
| 448 |
+
</div>
|
| 449 |
</div>
|
| 450 |
</div>
|
| 451 |
</SheetContent>
|
components/editor/index.tsx
CHANGED
|
@@ -68,6 +68,7 @@ export const AppEditor = ({
|
|
| 68 |
const path = currentPageData.path;
|
| 69 |
if (path.endsWith(".css")) return "css";
|
| 70 |
if (path.endsWith(".js")) return "javascript";
|
|
|
|
| 71 |
return "html";
|
| 72 |
}, [currentPageData.path]);
|
| 73 |
|
|
@@ -76,6 +77,7 @@ export const AppEditor = ({
|
|
| 76 |
if (editorLanguage === "css") return "CSS copied to clipboard!";
|
| 77 |
if (editorLanguage === "javascript")
|
| 78 |
return "JavaScript copied to clipboard!";
|
|
|
|
| 79 |
return "HTML copied to clipboard!";
|
| 80 |
}, [editorLanguage]);
|
| 81 |
|
|
|
|
| 68 |
const path = currentPageData.path;
|
| 69 |
if (path.endsWith(".css")) return "css";
|
| 70 |
if (path.endsWith(".js")) return "javascript";
|
| 71 |
+
if (path.endsWith(".json")) return "json";
|
| 72 |
return "html";
|
| 73 |
}, [currentPageData.path]);
|
| 74 |
|
|
|
|
| 77 |
if (editorLanguage === "css") return "CSS copied to clipboard!";
|
| 78 |
if (editorLanguage === "javascript")
|
| 79 |
return "JavaScript copied to clipboard!";
|
| 80 |
+
if (editorLanguage === "json") return "JSON copied to clipboard!";
|
| 81 |
return "HTML copied to clipboard!";
|
| 82 |
}, [editorLanguage]);
|
| 83 |
|
components/editor/preview/index.tsx
CHANGED
|
@@ -78,6 +78,9 @@ export const Preview = ({ isNew }: { isNew: boolean }) => {
|
|
| 78 |
const jsFiles = pages.filter(
|
| 79 |
(p) => p.path.endsWith(".js") && p.path !== previewPageData?.path
|
| 80 |
);
|
|
|
|
|
|
|
|
|
|
| 81 |
|
| 82 |
let modifiedHtml = html;
|
| 83 |
|
|
@@ -147,6 +150,42 @@ export const Preview = ({ isNew }: { isNew: boolean }) => {
|
|
| 147 |
});
|
| 148 |
}
|
| 149 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 150 |
return modifiedHtml;
|
| 151 |
},
|
| 152 |
[pages, previewPageData?.path]
|
|
|
|
| 78 |
const jsFiles = pages.filter(
|
| 79 |
(p) => p.path.endsWith(".js") && p.path !== previewPageData?.path
|
| 80 |
);
|
| 81 |
+
const jsonFiles = pages.filter(
|
| 82 |
+
(p) => p.path.endsWith(".json") && p.path !== previewPageData?.path
|
| 83 |
+
);
|
| 84 |
|
| 85 |
let modifiedHtml = html;
|
| 86 |
|
|
|
|
| 150 |
});
|
| 151 |
}
|
| 152 |
|
| 153 |
+
// Inject all JSON files as script tags with type="application/json"
|
| 154 |
+
if (jsonFiles.length > 0) {
|
| 155 |
+
const allJsonContent = jsonFiles
|
| 156 |
+
.map(
|
| 157 |
+
(file) =>
|
| 158 |
+
`<script type="application/json" data-injected-from="${
|
| 159 |
+
file.path
|
| 160 |
+
}" id="${file.path.replace(/[^a-zA-Z0-9]/g, "-")}">\n${
|
| 161 |
+
file.html
|
| 162 |
+
}\n</script>`
|
| 163 |
+
)
|
| 164 |
+
.join("\n");
|
| 165 |
+
|
| 166 |
+
if (modifiedHtml.includes("</body>")) {
|
| 167 |
+
modifiedHtml = modifiedHtml.replace(
|
| 168 |
+
"</body>",
|
| 169 |
+
`${allJsonContent}\n</body>`
|
| 170 |
+
);
|
| 171 |
+
} else if (modifiedHtml.includes("<body>")) {
|
| 172 |
+
modifiedHtml = modifiedHtml + allJsonContent;
|
| 173 |
+
} else {
|
| 174 |
+
modifiedHtml = modifiedHtml + "\n" + allJsonContent;
|
| 175 |
+
}
|
| 176 |
+
|
| 177 |
+
jsonFiles.forEach((file) => {
|
| 178 |
+
const escapedPath = file.path.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
| 179 |
+
modifiedHtml = modifiedHtml.replace(
|
| 180 |
+
new RegExp(
|
| 181 |
+
`<script\\s+[^>]*src=["'][\\.\/]*${escapedPath}["'][^>]*><\\/script>`,
|
| 182 |
+
"gi"
|
| 183 |
+
),
|
| 184 |
+
""
|
| 185 |
+
);
|
| 186 |
+
});
|
| 187 |
+
}
|
| 188 |
+
|
| 189 |
return modifiedHtml;
|
| 190 |
},
|
| 191 |
[pages, previewPageData?.path]
|
lib/prompts.ts
CHANGED
|
@@ -20,7 +20,7 @@ You create website in a way a designer would, using ONLY HTML, CSS and Javascrip
|
|
| 20 |
Try to create the best UI possible. Important: Make the website responsive by using TailwindCSS. Use it as much as you can, if you can't use it, use custom css (make sure to import tailwind with <script src="https://cdn.tailwindcss.com"></script> in the head).
|
| 21 |
Also try to elaborate as much as you can, to create something unique, with a great design.
|
| 22 |
If you want to use ICONS import Feather Icons (Make sure to add <script src="https://unpkg.com/feather-icons"></script> and <script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script> in the head., and <script>feather.replace();</script> in the body. Ex : <i data-feather="user"></i>).
|
| 23 |
-
For interactive animations you can use: Vanta.js (Make sure to add <script src="https://cdn.jsdelivr.net/npm/vanta@latest/dist/vanta.globe.min.js"></script> and <script>VANTA.GLOBE({...</script> in the body.).
|
| 24 |
Don't hesitate to use real public API for the datas, you can find good ones here https://github.com/public-apis/public-apis depending on what the user asks for.
|
| 25 |
You can create multiple pages website at once (following the format rules below) or a Single Page Application. But make sure to create multiple pages if the user asks for different pages.
|
| 26 |
IMPORTANT: To avoid duplicate code across pages, you MUST create separate style.css and script.js files for shared CSS and JavaScript code. Each HTML file should link to these files using <link rel="stylesheet" href="style.css"> and <script src="script.js"></script>.
|
|
|
|
| 20 |
Try to create the best UI possible. Important: Make the website responsive by using TailwindCSS. Use it as much as you can, if you can't use it, use custom css (make sure to import tailwind with <script src="https://cdn.tailwindcss.com"></script> in the head).
|
| 21 |
Also try to elaborate as much as you can, to create something unique, with a great design.
|
| 22 |
If you want to use ICONS import Feather Icons (Make sure to add <script src="https://unpkg.com/feather-icons"></script> and <script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script> in the head., and <script>feather.replace();</script> in the body. Ex : <i data-feather="user"></i>).
|
| 23 |
+
For interactive animations you can use: Vanta.js (Make sure to add <script src="https://cdn.jsdelivr.net/npm/vanta@latest/dist/vanta.globe.min.js"></script> and <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script> and <script>VANTA.GLOBE({...</script> in the body.).
|
| 24 |
Don't hesitate to use real public API for the datas, you can find good ones here https://github.com/public-apis/public-apis depending on what the user asks for.
|
| 25 |
You can create multiple pages website at once (following the format rules below) or a Single Page Application. But make sure to create multiple pages if the user asks for different pages.
|
| 26 |
IMPORTANT: To avoid duplicate code across pages, you MUST create separate style.css and script.js files for shared CSS and JavaScript code. Each HTML file should link to these files using <link rel="stylesheet" href="style.css"> and <script src="script.js"></script>.
|