FREE STORE POS - free

#156
index.html CHANGED
@@ -11,29 +11,6 @@
11
  helps you build websites with AI, no code required. Let's deploy your
12
  website with DeepSite and enjoy the magic of AI."
13
  />
14
- <meta name="theme-color" content="#000000" />
15
- <meta name="apple-mobile-web-app-capable" content="yes" />
16
- <meta name="apple-mobile-web-app-status-bar-style" content="black" />
17
- <meta name="apple-mobile-web-app-title" content="DeepSite" />
18
- <meta name="msapplication-TileColor" content="#000000" />
19
- <meta name="twitter:card" content="summary_large_image" />
20
- <meta name="twitter:title" content="DeepSite | Build with AI ✨" />
21
- <meta
22
- name="twitter:description"
23
- content="DeepSite is a web development tool that
24
- helps you build websites with AI, no code required. Let's deploy your
25
- website with DeepSite and enjoy the magic of AI."
26
- />
27
- <meta name="twitter:image" content="/banner.png" />
28
- <meta property="og:type" content="website" />
29
- <meta property="og:title" content="DeepSite | Build with AI ✨" />
30
- <meta
31
- property="og:description"
32
- content="DeepSite is a web development tool that
33
- helps you build websites with AI, no code required. Let's deploy your
34
- website with DeepSite and enjoy the magic of AI."
35
- />
36
- <meta property="og:image" content="/banner.png" />
37
  <link rel="preconnect" href="https://fonts.googleapis.com" />
38
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
39
  <link
 
11
  helps you build websites with AI, no code required. Let's deploy your
12
  website with DeepSite and enjoy the magic of AI."
13
  />
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
  <link rel="preconnect" href="https://fonts.googleapis.com" />
15
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
16
  <link
package-lock.json CHANGED
@@ -9,10 +9,9 @@
9
  "version": "0.0.0",
10
  "dependencies": {
11
  "@huggingface/hub": "^1.1.1",
12
- "@huggingface/inference": "^4.0.2",
13
  "@monaco-editor/react": "^4.7.0",
14
  "@radix-ui/react-avatar": "^1.1.10",
15
- "@radix-ui/react-dialog": "^1.1.14",
16
  "@radix-ui/react-dropdown-menu": "^2.1.15",
17
  "@radix-ui/react-popover": "^1.1.14",
18
  "@radix-ui/react-select": "^2.2.5",
@@ -21,7 +20,6 @@
21
  "@radix-ui/react-tabs": "^1.1.12",
22
  "@radix-ui/react-toggle": "^1.1.9",
23
  "@radix-ui/react-toggle-group": "^1.1.10",
24
- "@radix-ui/react-tooltip": "^1.2.7",
25
  "@tailwindcss/vite": "^4.0.15",
26
  "@xenova/transformers": "^2.17.2",
27
  "body-parser": "^1.20.3",
@@ -191,11 +189,10 @@
191
  }
192
  },
193
  "node_modules/@babel/helper-plugin-utils": {
194
- "version": "7.27.1",
195
- "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz",
196
- "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==",
197
  "dev": true,
198
- "license": "MIT",
199
  "engines": {
200
  "node": ">=6.9.0"
201
  }
@@ -920,32 +917,29 @@
920
  "integrity": "sha512-HK6JTVB/nrgjOnbe77HFSENftfAp67AI4mHMR2x64Os1hvchuTT88M8fKEiyESSvqKFKwW4lQKkHva07p05AXw=="
921
  },
922
  "node_modules/@huggingface/inference": {
923
- "version": "4.0.2",
924
- "resolved": "https://registry.npmjs.org/@huggingface/inference/-/inference-4.0.2.tgz",
925
- "integrity": "sha512-XuWb8ocH7lA5kSdXrGnqshtRz3ocSBzEzxcp5xeAXLjgM1ocoIHq+RW8/Ti0xq3MeRGQWgUkYPCgDV/xgs8p4g==",
926
- "license": "MIT",
927
  "dependencies": {
928
- "@huggingface/jinja": "^0.5.0",
929
- "@huggingface/tasks": "^0.19.11"
930
  },
931
  "engines": {
932
  "node": ">=18"
933
  }
934
  },
935
  "node_modules/@huggingface/jinja": {
936
- "version": "0.5.0",
937
- "resolved": "https://registry.npmjs.org/@huggingface/jinja/-/jinja-0.5.0.tgz",
938
- "integrity": "sha512-Ptc03/jGRiYRoi0bUYKZ14MkDslsBRT24oxmsvUlfYrvQMldrxCevhPnT+hfX8awKTT8/f/0ZBBWldoeAcMHdQ==",
939
- "license": "MIT",
940
  "engines": {
941
  "node": ">=18"
942
  }
943
  },
944
  "node_modules/@huggingface/tasks": {
945
- "version": "0.19.11",
946
- "resolved": "https://registry.npmjs.org/@huggingface/tasks/-/tasks-0.19.11.tgz",
947
- "integrity": "sha512-oBhSgVlg7Pp643MsH8BiI3OAXIMJNxdSiMtv4mApRZV8dmAz8oasKhg6CVKIplO7vAO7F6dkmMn4bYM64I2A9w==",
948
- "license": "MIT"
949
  },
950
  "node_modules/@humanfs/core": {
951
  "version": "0.19.1",
@@ -1283,42 +1277,6 @@
1283
  }
1284
  }
1285
  },
1286
- "node_modules/@radix-ui/react-dialog": {
1287
- "version": "1.1.14",
1288
- "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.14.tgz",
1289
- "integrity": "sha512-+CpweKjqpzTmwRwcYECQcNYbI8V9VSQt0SNFKeEBLgfucbsLssU6Ppq7wUdNXEGb573bMjFhVjKVll8rmV6zMw==",
1290
- "license": "MIT",
1291
- "dependencies": {
1292
- "@radix-ui/primitive": "1.1.2",
1293
- "@radix-ui/react-compose-refs": "1.1.2",
1294
- "@radix-ui/react-context": "1.1.2",
1295
- "@radix-ui/react-dismissable-layer": "1.1.10",
1296
- "@radix-ui/react-focus-guards": "1.1.2",
1297
- "@radix-ui/react-focus-scope": "1.1.7",
1298
- "@radix-ui/react-id": "1.1.1",
1299
- "@radix-ui/react-portal": "1.1.9",
1300
- "@radix-ui/react-presence": "1.1.4",
1301
- "@radix-ui/react-primitive": "2.1.3",
1302
- "@radix-ui/react-slot": "1.2.3",
1303
- "@radix-ui/react-use-controllable-state": "1.2.2",
1304
- "aria-hidden": "^1.2.4",
1305
- "react-remove-scroll": "^2.6.3"
1306
- },
1307
- "peerDependencies": {
1308
- "@types/react": "*",
1309
- "@types/react-dom": "*",
1310
- "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
1311
- "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
1312
- },
1313
- "peerDependenciesMeta": {
1314
- "@types/react": {
1315
- "optional": true
1316
- },
1317
- "@types/react-dom": {
1318
- "optional": true
1319
- }
1320
- }
1321
- },
1322
  "node_modules/@radix-ui/react-direction": {
1323
  "version": "1.1.1",
1324
  "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.1.tgz",
@@ -1833,40 +1791,6 @@
1833
  }
1834
  }
1835
  },
1836
- "node_modules/@radix-ui/react-tooltip": {
1837
- "version": "1.2.7",
1838
- "resolved": "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.2.7.tgz",
1839
- "integrity": "sha512-Ap+fNYwKTYJ9pzqW+Xe2HtMRbQ/EeWkj2qykZ6SuEV4iS/o1bZI5ssJbk4D2r8XuDuOBVz/tIx2JObtuqU+5Zw==",
1840
- "license": "MIT",
1841
- "dependencies": {
1842
- "@radix-ui/primitive": "1.1.2",
1843
- "@radix-ui/react-compose-refs": "1.1.2",
1844
- "@radix-ui/react-context": "1.1.2",
1845
- "@radix-ui/react-dismissable-layer": "1.1.10",
1846
- "@radix-ui/react-id": "1.1.1",
1847
- "@radix-ui/react-popper": "1.2.7",
1848
- "@radix-ui/react-portal": "1.1.9",
1849
- "@radix-ui/react-presence": "1.1.4",
1850
- "@radix-ui/react-primitive": "2.1.3",
1851
- "@radix-ui/react-slot": "1.2.3",
1852
- "@radix-ui/react-use-controllable-state": "1.2.2",
1853
- "@radix-ui/react-visually-hidden": "1.2.3"
1854
- },
1855
- "peerDependencies": {
1856
- "@types/react": "*",
1857
- "@types/react-dom": "*",
1858
- "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
1859
- "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
1860
- },
1861
- "peerDependenciesMeta": {
1862
- "@types/react": {
1863
- "optional": true
1864
- },
1865
- "@types/react-dom": {
1866
- "optional": true
1867
- }
1868
- }
1869
- },
1870
  "node_modules/@radix-ui/react-use-callback-ref": {
1871
  "version": "1.1.1",
1872
  "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.1.tgz",
 
9
  "version": "0.0.0",
10
  "dependencies": {
11
  "@huggingface/hub": "^1.1.1",
12
+ "@huggingface/inference": "^3.6.1",
13
  "@monaco-editor/react": "^4.7.0",
14
  "@radix-ui/react-avatar": "^1.1.10",
 
15
  "@radix-ui/react-dropdown-menu": "^2.1.15",
16
  "@radix-ui/react-popover": "^1.1.14",
17
  "@radix-ui/react-select": "^2.2.5",
 
20
  "@radix-ui/react-tabs": "^1.1.12",
21
  "@radix-ui/react-toggle": "^1.1.9",
22
  "@radix-ui/react-toggle-group": "^1.1.10",
 
23
  "@tailwindcss/vite": "^4.0.15",
24
  "@xenova/transformers": "^2.17.2",
25
  "body-parser": "^1.20.3",
 
189
  }
190
  },
191
  "node_modules/@babel/helper-plugin-utils": {
192
+ "version": "7.26.5",
193
+ "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.26.5.tgz",
194
+ "integrity": "sha512-RS+jZcRdZdRFzMyr+wcsaqOmld1/EqTghfaBGQQd/WnRdzdlvSZ//kF7U8VQTxf1ynZ4cjUcYgjVGx13ewNPMg==",
195
  "dev": true,
 
196
  "engines": {
197
  "node": ">=6.9.0"
198
  }
 
917
  "integrity": "sha512-HK6JTVB/nrgjOnbe77HFSENftfAp67AI4mHMR2x64Os1hvchuTT88M8fKEiyESSvqKFKwW4lQKkHva07p05AXw=="
918
  },
919
  "node_modules/@huggingface/inference": {
920
+ "version": "3.6.1",
921
+ "resolved": "https://registry.npmjs.org/@huggingface/inference/-/inference-3.6.1.tgz",
922
+ "integrity": "sha512-EtQlbBqcZycPe+qiTEFI+wNHOMpG0gwNTaZSvYu1juN1p/1dEgqAb2GO31dxLgNev2PzH9d+9nm8GngOsIepJg==",
 
923
  "dependencies": {
924
+ "@huggingface/jinja": "^0.3.3",
925
+ "@huggingface/tasks": "^0.17.8"
926
  },
927
  "engines": {
928
  "node": ">=18"
929
  }
930
  },
931
  "node_modules/@huggingface/jinja": {
932
+ "version": "0.3.3",
933
+ "resolved": "https://registry.npmjs.org/@huggingface/jinja/-/jinja-0.3.3.tgz",
934
+ "integrity": "sha512-vQQr2JyWvVFba3Lj9es4q9vCl1sAc74fdgnEMoX8qHrXtswap9ge9uO3ONDzQB0cQ0PUyaKY2N6HaVbTBvSXvw==",
 
935
  "engines": {
936
  "node": ">=18"
937
  }
938
  },
939
  "node_modules/@huggingface/tasks": {
940
+ "version": "0.17.9",
941
+ "resolved": "https://registry.npmjs.org/@huggingface/tasks/-/tasks-0.17.9.tgz",
942
+ "integrity": "sha512-lV6RgCJkqy3p93FFxP9H4SGJmFcHAwr1FO+Zk56q/JWsf7Tdsel1DEo1Xfd3An7ZPWpc2Y9ldRecGo9efDYghg=="
 
943
  },
944
  "node_modules/@humanfs/core": {
945
  "version": "0.19.1",
 
1277
  }
1278
  }
1279
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1280
  "node_modules/@radix-ui/react-direction": {
1281
  "version": "1.1.1",
1282
  "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.1.tgz",
 
1791
  }
1792
  }
1793
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1794
  "node_modules/@radix-ui/react-use-callback-ref": {
1795
  "version": "1.1.1",
1796
  "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.1.tgz",
package.json CHANGED
@@ -12,10 +12,9 @@
12
  },
13
  "dependencies": {
14
  "@huggingface/hub": "^1.1.1",
15
- "@huggingface/inference": "^4.0.2",
16
  "@monaco-editor/react": "^4.7.0",
17
  "@radix-ui/react-avatar": "^1.1.10",
18
- "@radix-ui/react-dialog": "^1.1.14",
19
  "@radix-ui/react-dropdown-menu": "^2.1.15",
20
  "@radix-ui/react-popover": "^1.1.14",
21
  "@radix-ui/react-select": "^2.2.5",
@@ -24,7 +23,6 @@
24
  "@radix-ui/react-tabs": "^1.1.12",
25
  "@radix-ui/react-toggle": "^1.1.9",
26
  "@radix-ui/react-toggle-group": "^1.1.10",
27
- "@radix-ui/react-tooltip": "^1.2.7",
28
  "@tailwindcss/vite": "^4.0.15",
29
  "@xenova/transformers": "^2.17.2",
30
  "body-parser": "^1.20.3",
 
12
  },
13
  "dependencies": {
14
  "@huggingface/hub": "^1.1.1",
15
+ "@huggingface/inference": "^3.6.1",
16
  "@monaco-editor/react": "^4.7.0",
17
  "@radix-ui/react-avatar": "^1.1.10",
 
18
  "@radix-ui/react-dropdown-menu": "^2.1.15",
19
  "@radix-ui/react-popover": "^1.1.14",
20
  "@radix-ui/react-select": "^2.2.5",
 
23
  "@radix-ui/react-tabs": "^1.1.12",
24
  "@radix-ui/react-toggle": "^1.1.9",
25
  "@radix-ui/react-toggle-group": "^1.1.10",
 
26
  "@tailwindcss/vite": "^4.0.15",
27
  "@xenova/transformers": "^2.17.2",
28
  "body-parser": "^1.20.3",
public/banner.png CHANGED

Git LFS Details

  • SHA256: 88e110c7da99a0d6d17f1e301de3f6b77f1a2e3ea46fec3f4caed8334b0f0ba7
  • Pointer size: 130 Bytes
  • Size of remote file: 97.2 kB

Git LFS Details

  • SHA256: f4132f4892c92b395e1274a9d0c33134bd93fbe5d1364f23d7883cbc753f02c6
  • Pointer size: 131 Bytes
  • Size of remote file: 116 kB
server.js CHANGED
@@ -204,9 +204,6 @@ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-
204
  await uploadFiles({
205
  repo,
206
  files,
207
- commitTitle: `${prompts[prompts.length - 1]} - ${
208
- prompts.length > 1 ? "Follow Up" : "Initial"
209
- } Deployment`,
210
  accessToken: hf_token,
211
  });
212
  return res.status(200).send({ ok: true, path: repo.name });
@@ -219,14 +216,8 @@ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-
219
  });
220
 
221
  app.post("/api/ask-ai", async (req, res) => {
222
- const { prompt, provider, model, redesignMarkdown } = req.body;
223
- if (!model) {
224
- return res.status(400).send({
225
- ok: false,
226
- message: "Missing required fields",
227
- });
228
- }
229
- if (!redesignMarkdown && !prompt) {
230
  return res.status(400).send({
231
  ok: false,
232
  message: "Missing required fields",
@@ -254,7 +245,6 @@ app.post("/api/ask-ai", async (req, res) => {
254
 
255
  let { hf_token } = req.cookies;
256
  let token = hf_token;
257
- let billTo = null;
258
 
259
  if (process.env.HF_TOKEN && process.env.HF_TOKEN !== "") {
260
  token = process.env.HF_TOKEN;
@@ -278,7 +268,6 @@ app.post("/api/ask-ai", async (req, res) => {
278
  }
279
 
280
  token = process.env.DEFAULT_HF_TOKEN;
281
- billTo = "huggingface";
282
  }
283
 
284
  // Set up response headers for streaming
@@ -304,27 +293,23 @@ app.post("/api/ask-ai", async (req, res) => {
304
  message: `Context is too long. ${selectedProvider.name} allow ${selectedProvider.max_tokens} max tokens.`,
305
  });
306
  }
 
307
  try {
308
- const chatCompletion = client.chatCompletionStream(
309
- {
310
- model: selectedModel.value,
311
- provider: selectedProvider.id,
312
- messages: [
313
- {
314
- role: "system",
315
- content: initialSystemPrompt,
316
- },
317
- {
318
- role: "user",
319
- content: redesignMarkdown
320
- ? `Here is my current design as a markdown:\n\n${redesignMarkdown}\n\nNow, please create a new design based on this markdown.`
321
- : prompt,
322
- },
323
- ],
324
- max_tokens: selectedProvider.max_tokens,
325
- },
326
- billTo ? { billTo } : {}
327
- );
328
 
329
  while (true) {
330
  const { done, value } = await chatCompletion.next();
@@ -442,7 +427,6 @@ ${REPLACE_END}
442
 
443
  let { hf_token } = req.cookies;
444
  let token = hf_token;
445
- let billTo = null;
446
 
447
  if (process.env.HF_TOKEN && process.env.HF_TOKEN !== "") {
448
  token = process.env.HF_TOKEN;
@@ -466,45 +450,42 @@ ${REPLACE_END}
466
  }
467
 
468
  token = process.env.DEFAULT_HF_TOKEN;
469
- billTo = "huggingface";
470
  }
471
 
472
  const client = new InferenceClient(token);
473
 
474
  const selectedProvider = PROVIDERS[selectedModel.autoProvider];
 
475
  try {
476
- const response = await client.chatCompletion(
477
- {
478
- model: selectedModel.value,
479
- provider: selectedProvider.id,
480
- messages: [
481
- {
482
- role: "system",
483
- content: followUpSystemPrompt,
484
- },
485
- {
486
- role: "user",
487
- content: previousPrompt
488
- ? previousPrompt
489
- : "You are modifying the HTML file based on the user's request.",
490
- },
491
- {
492
- role: "assistant",
493
- content: `The current code is: \n\`\`\`html\n${html}\n\`\`\``,
494
- },
495
- {
496
- role: "user",
497
- content: prompt,
498
- },
499
- ],
500
- ...(selectedProvider.id !== "sambanova"
501
- ? {
502
- max_tokens: selectedProvider.max_tokens,
503
- }
504
- : {}),
505
- },
506
- billTo ? { billTo } : {}
507
- );
508
 
509
  const chunk = response.choices[0]?.message?.content;
510
  // TO DO: handle the case where there are multiple SEARCH/REPLACE blocks
@@ -517,8 +498,6 @@ ${REPLACE_END}
517
 
518
  if (chunk) {
519
  let newHtml = html;
520
- // array of arrays to hold updated lines (start and end line numbers)
521
- const updatedLines = [];
522
 
523
  // Find all search/replace blocks in the chunk
524
  let position = 0;
@@ -557,29 +536,9 @@ ${REPLACE_END}
557
  if (searchBlock.trim() === "") {
558
  // Inserting at the beginning
559
  newHtml = `${replaceBlock}\n${newHtml}`;
560
-
561
- // Track first line as updated
562
- updatedLines.push([1, replaceBlock.split("\n").length]);
563
  } else {
564
- // Find the position of the search block in the HTML
565
- const blockPosition = newHtml.indexOf(searchBlock);
566
- if (blockPosition !== -1) {
567
- // Count lines before the search block
568
- const beforeText = newHtml.substring(0, blockPosition);
569
- const startLineNumber = beforeText.split("\n").length;
570
-
571
- // Count lines in search and replace blocks
572
- const replaceLines = replaceBlock.split("\n").length;
573
-
574
- // Calculate end line (start + length of replaced content)
575
- const endLineNumber = startLineNumber + replaceLines - 1;
576
-
577
- // Track the line numbers that were updated
578
- updatedLines.push([startLineNumber, endLineNumber]);
579
-
580
- // Perform the replacement
581
- newHtml = newHtml.replace(searchBlock, replaceBlock);
582
- }
583
  }
584
 
585
  // Move position to after this block to find the next one
@@ -589,7 +548,6 @@ ${REPLACE_END}
589
  return res.status(200).send({
590
  ok: true,
591
  html: newHtml,
592
- updatedLines,
593
  });
594
  } else {
595
  return res.status(400).send({
@@ -683,43 +641,6 @@ app.get("/api/remix/:username/:repo", async (req, res) => {
683
  });
684
  }
685
  });
686
-
687
- app.post("/api/re-design", async (req, res) => {
688
- const { url } = req.body;
689
- if (!url) {
690
- return res.status(400).send({
691
- ok: false,
692
- message: "Missing required fields",
693
- });
694
- }
695
-
696
- // call the api https://r.jina.ai/{url} and return the response
697
- try {
698
- const response = await fetch(
699
- `https://r.jina.ai/${encodeURIComponent(url)}`,
700
- {
701
- method: "POST",
702
- }
703
- );
704
- if (!response.ok) {
705
- return res.status(500).send({
706
- ok: false,
707
- message: "Failed to fetch redesign",
708
- });
709
- }
710
- // return the html response
711
- const markdown = await response.text();
712
- return res.status(200).send({
713
- ok: true,
714
- markdown,
715
- });
716
- } catch (error) {
717
- return res.status(500).send({
718
- ok: false,
719
- message: error.message,
720
- });
721
- }
722
- });
723
  app.get("*", (_req, res) => {
724
  res.sendFile(path.join(__dirname, "dist", "index.html"));
725
  });
 
204
  await uploadFiles({
205
  repo,
206
  files,
 
 
 
207
  accessToken: hf_token,
208
  });
209
  return res.status(200).send({ ok: true, path: repo.name });
 
216
  });
217
 
218
  app.post("/api/ask-ai", async (req, res) => {
219
+ const { prompt, provider, model } = req.body;
220
+ if (!prompt || !model) {
 
 
 
 
 
 
221
  return res.status(400).send({
222
  ok: false,
223
  message: "Missing required fields",
 
245
 
246
  let { hf_token } = req.cookies;
247
  let token = hf_token;
 
248
 
249
  if (process.env.HF_TOKEN && process.env.HF_TOKEN !== "") {
250
  token = process.env.HF_TOKEN;
 
268
  }
269
 
270
  token = process.env.DEFAULT_HF_TOKEN;
 
271
  }
272
 
273
  // Set up response headers for streaming
 
293
  message: `Context is too long. ${selectedProvider.name} allow ${selectedProvider.max_tokens} max tokens.`,
294
  });
295
  }
296
+
297
  try {
298
+ const chatCompletion = client.chatCompletionStream({
299
+ model: selectedModel.value,
300
+ provider: selectedProvider.id,
301
+ messages: [
302
+ {
303
+ role: "system",
304
+ content: initialSystemPrompt,
305
+ },
306
+ {
307
+ role: "user",
308
+ content: prompt,
309
+ },
310
+ ],
311
+ max_tokens: selectedProvider.max_tokens,
312
+ });
 
 
 
 
 
313
 
314
  while (true) {
315
  const { done, value } = await chatCompletion.next();
 
427
 
428
  let { hf_token } = req.cookies;
429
  let token = hf_token;
 
430
 
431
  if (process.env.HF_TOKEN && process.env.HF_TOKEN !== "") {
432
  token = process.env.HF_TOKEN;
 
450
  }
451
 
452
  token = process.env.DEFAULT_HF_TOKEN;
 
453
  }
454
 
455
  const client = new InferenceClient(token);
456
 
457
  const selectedProvider = PROVIDERS[selectedModel.autoProvider];
458
+
459
  try {
460
+ const response = await client.chatCompletion({
461
+ model: selectedModel.value,
462
+ provider: selectedProvider.id,
463
+ messages: [
464
+ {
465
+ role: "system",
466
+ content: followUpSystemPrompt,
467
+ },
468
+ {
469
+ role: "user",
470
+ content: previousPrompt
471
+ ? previousPrompt
472
+ : "You are modifying the HTML file based on the user's request.",
473
+ },
474
+ {
475
+ role: "assistant",
476
+ content: `The current code is: \n\`\`\`html\n${html}\n\`\`\``,
477
+ },
478
+ {
479
+ role: "user",
480
+ content: prompt,
481
+ },
482
+ ],
483
+ ...(selectedProvider.id !== "sambanova"
484
+ ? {
485
+ max_tokens: selectedProvider.max_tokens,
486
+ }
487
+ : {}),
488
+ });
 
 
 
489
 
490
  const chunk = response.choices[0]?.message?.content;
491
  // TO DO: handle the case where there are multiple SEARCH/REPLACE blocks
 
498
 
499
  if (chunk) {
500
  let newHtml = html;
 
 
501
 
502
  // Find all search/replace blocks in the chunk
503
  let position = 0;
 
536
  if (searchBlock.trim() === "") {
537
  // Inserting at the beginning
538
  newHtml = `${replaceBlock}\n${newHtml}`;
 
 
 
539
  } else {
540
+ // Replacing existing code
541
+ newHtml = newHtml.replace(searchBlock, replaceBlock);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
542
  }
543
 
544
  // Move position to after this block to find the next one
 
548
  return res.status(200).send({
549
  ok: true,
550
  html: newHtml,
 
551
  });
552
  } else {
553
  return res.status(400).send({
 
641
  });
642
  }
643
  });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
644
  app.get("*", (_req, res) => {
645
  res.sendFile(path.join(__dirname, "dist", "index.html"));
646
  });
src/assets/index.css CHANGED
@@ -136,7 +136,3 @@
136
  .monaco-editor .line-numbers {
137
  @apply !text-neutral-500;
138
  }
139
-
140
- .matched-line {
141
- @apply bg-sky-500/30;
142
- }
 
136
  .monaco-editor .line-numbers {
137
  @apply !text-neutral-500;
138
  }
 
 
 
 
src/assets/linux.png DELETED
Binary file (8.63 kB)
 
src/components/ask-ai/ask-ai.tsx CHANGED
@@ -1,10 +1,11 @@
1
  /* eslint-disable @typescript-eslint/no-explicit-any */
2
  import { useState, useRef } from "react";
 
 
3
  import classNames from "classnames";
4
  import { toast } from "sonner";
5
  import { useLocalStorage, useUpdateEffect } from "react-use";
6
- import { ArrowUp, ChevronDown } from "lucide-react";
7
- import { FaStopCircle } from "react-icons/fa";
8
 
9
  import Login from "../login/login";
10
  import { defaultHTML } from "../../../utils/consts";
@@ -13,11 +14,7 @@ import Settings from "../settings/settings";
13
  import ProModal from "../pro-modal/pro-modal";
14
  import { Button } from "../ui/button";
15
  // @ts-expect-error not needed
16
- import { MODELS } from "../../../utils/providers";
17
- import Loading from "../loading/loading";
18
- import { HtmlHistory } from "../../../utils/types";
19
- import InviteFriends from "../invite-friends/invite-friends";
20
- import ReImagine from "../re-imagine/re-imagine";
21
 
22
  function AskAI({
23
  html,
@@ -33,9 +30,8 @@ function AskAI({
33
  onScrollToBottom: () => void;
34
  isAiWorking: boolean;
35
  onNewPrompt: (prompt: string) => void;
36
- htmlHistory?: HtmlHistory[];
37
  setisAiWorking: React.Dispatch<React.SetStateAction<boolean>>;
38
- onSuccess: (h: string, p: string, n?: number[][]) => void;
39
  }) {
40
  const refThink = useRef<HTMLDivElement | null>(null);
41
 
@@ -51,14 +47,12 @@ function AskAI({
51
  const [think, setThink] = useState<string | undefined>(undefined);
52
  const [openThink, setOpenThink] = useState(false);
53
  const [isThinking, setIsThinking] = useState(true);
54
- const [controller, setController] = useState<AbortController | null>(null);
55
 
56
  const audio = new Audio(SuccessSound);
57
  audio.volume = 0.5;
58
 
59
- const callAi = async (redesignMarkdown?: string) => {
60
- if (isAiWorking) return;
61
- if (!redesignMarkdown && !prompt.trim()) return;
62
  setisAiWorking(true);
63
  setProviderError("");
64
  setThink("");
@@ -70,11 +64,9 @@ function AskAI({
70
  let lastRenderTime = 0;
71
 
72
  const isFollowUp = html !== defaultHTML;
73
- const abortController = new AbortController();
74
- setController(abortController);
75
  try {
76
  onNewPrompt(prompt);
77
- if (isFollowUp && !redesignMarkdown) {
78
  const request = await fetch("/api/ask-ai", {
79
  method: "PUT",
80
  body: JSON.stringify({
@@ -86,7 +78,6 @@ function AskAI({
86
  headers: {
87
  "Content-Type": "application/json",
88
  },
89
- signal: abortController.signal,
90
  });
91
  if (request && request.body) {
92
  const res = await request.json();
@@ -109,7 +100,7 @@ function AskAI({
109
  setPreviousPrompt(prompt);
110
  setPrompt("");
111
  setisAiWorking(false);
112
- onSuccess(res.html, prompt, res.updatedLines);
113
  audio.play();
114
  }
115
  } else {
@@ -119,12 +110,10 @@ function AskAI({
119
  prompt,
120
  provider,
121
  model,
122
- redesignMarkdown,
123
  }),
124
  headers: {
125
  "Content-Type": "application/json",
126
  },
127
- signal: abortController.signal,
128
  });
129
  if (request && request.body) {
130
  if (!request.ok) {
@@ -234,17 +223,6 @@ function AskAI({
234
  }
235
  };
236
 
237
- const stopController = () => {
238
- if (controller) {
239
- controller.abort();
240
- setController(null);
241
- setisAiWorking(false);
242
- setThink("");
243
- setOpenThink(false);
244
- setIsThinking(false);
245
- }
246
- };
247
-
248
  useUpdateEffect(() => {
249
  if (refThink.current) {
250
  refThink.current.scrollTop = refThink.current.scrollHeight;
@@ -257,8 +235,10 @@ function AskAI({
257
  }
258
  }, [isThinking]);
259
 
 
 
260
  return (
261
- <div className="bg-neutral-800 border border-neutral-700 rounded-2xl ring-[4px] focus-within:ring-neutral-500/30 focus-within:border-neutral-600 ring-transparent z-10 absolute bottom-3 left-3 w-[calc(100%-20px)] group">
262
  {think && (
263
  <div className="w-full border-b border-neutral-700 relative overflow-hidden">
264
  <header
@@ -268,7 +248,7 @@ function AskAI({
268
  }}
269
  >
270
  <p className="text-sm font-medium text-neutral-300 group-hover:text-neutral-200 transition-colors duration-200">
271
- {isThinking ? "DeepSite is thinking..." : "DeepSite's plan"}
272
  </p>
273
  <ChevronDown
274
  className={classNames(
@@ -296,46 +276,37 @@ function AskAI({
296
  </main>
297
  </div>
298
  )}
299
- <div className="w-full relative flex items-center justify-between">
 
 
 
 
 
 
 
300
  {isAiWorking && (
301
- <div className="absolute bg-neutral-800 rounded-lg bottom-0 left-4 w-[calc(100%-30px)] h-full z-1 flex items-center justify-between max-lg:text-sm">
302
- <div className="flex items-center justify-start gap-2">
303
- <Loading overlay={false} className="!size-4" />
304
- <p className="text-neutral-400 text-sm">
305
- AI is {isThinking ? "thinking" : "coding"}...{" "}
306
- </p>
307
- </div>
308
- <div
309
- className="text-xs text-neutral-400 px-1 py-0.5 rounded-md border border-neutral-600 flex items-center justify-center gap-1.5 bg-neutral-800 hover:brightness-110 transition-all duration-200 cursor-pointer"
310
- onClick={stopController}
311
- >
312
- <FaStopCircle />
313
- Stop generation
314
- </div>
315
  </div>
316
  )}
 
317
  <input
318
  type="text"
319
  disabled={isAiWorking}
320
- className="w-full bg-transparent text-sm outline-none text-white placeholder:text-neutral-400 p-4"
321
- placeholder={
322
- hasAsked ? "Ask DeepSite for edits" : "Ask DeepSite anything..."
323
- }
324
  value={prompt}
325
  onChange={(e) => setPrompt(e.target.value)}
326
  onKeyDown={(e) => {
327
- if (e.key === "Enter" && !e.shiftKey) {
328
  callAi();
329
  }
330
  }}
331
  />
332
- </div>
333
- <div className="flex items-center justify-between gap-2 px-4 pb-3">
334
- <div className="flex-1 flex items-center justify-start gap-1.5">
335
- <ReImagine onRedesign={(md) => callAi(md)} />
336
- <InviteFriends />
337
- </div>
338
  <div className="flex items-center justify-end gap-2">
 
339
  <Settings
340
  provider={provider as string}
341
  model={model as string}
@@ -346,11 +317,12 @@ function AskAI({
346
  onClose={setOpenProvider}
347
  />
348
  <Button
349
- size="iconXs"
 
350
  disabled={isAiWorking || !prompt.trim()}
351
- onClick={() => callAi()}
352
  >
353
- <ArrowUp className="size-4" />
354
  </Button>
355
  </div>
356
  </div>
@@ -365,7 +337,7 @@ function AskAI({
365
  ></div>
366
  <div
367
  className={classNames(
368
- "absolute top-0 -translate-y-[calc(100%+8px)] right-0 z-10 w-80 border border-neutral-800 !bg-neutral-900 rounded-lg shadow-lg transition-all duration-75 overflow-hidden",
369
  {
370
  "opacity-0 pointer-events-none": !open,
371
  }
 
1
  /* eslint-disable @typescript-eslint/no-explicit-any */
2
  import { useState, useRef } from "react";
3
+ import { RiSparkling2Fill } from "react-icons/ri";
4
+ import { GrSend } from "react-icons/gr";
5
  import classNames from "classnames";
6
  import { toast } from "sonner";
7
  import { useLocalStorage, useUpdateEffect } from "react-use";
8
+ import { ChevronDown } from "lucide-react";
 
9
 
10
  import Login from "../login/login";
11
  import { defaultHTML } from "../../../utils/consts";
 
14
  import ProModal from "../pro-modal/pro-modal";
15
  import { Button } from "../ui/button";
16
  // @ts-expect-error not needed
17
+ import { MODELS } from "./../../../utils/providers";
 
 
 
 
18
 
19
  function AskAI({
20
  html,
 
30
  onScrollToBottom: () => void;
31
  isAiWorking: boolean;
32
  onNewPrompt: (prompt: string) => void;
 
33
  setisAiWorking: React.Dispatch<React.SetStateAction<boolean>>;
34
+ onSuccess: (h: string, p: string) => void;
35
  }) {
36
  const refThink = useRef<HTMLDivElement | null>(null);
37
 
 
47
  const [think, setThink] = useState<string | undefined>(undefined);
48
  const [openThink, setOpenThink] = useState(false);
49
  const [isThinking, setIsThinking] = useState(true);
 
50
 
51
  const audio = new Audio(SuccessSound);
52
  audio.volume = 0.5;
53
 
54
+ const callAi = async () => {
55
+ if (isAiWorking || !prompt.trim()) return;
 
56
  setisAiWorking(true);
57
  setProviderError("");
58
  setThink("");
 
64
  let lastRenderTime = 0;
65
 
66
  const isFollowUp = html !== defaultHTML;
 
 
67
  try {
68
  onNewPrompt(prompt);
69
+ if (isFollowUp) {
70
  const request = await fetch("/api/ask-ai", {
71
  method: "PUT",
72
  body: JSON.stringify({
 
78
  headers: {
79
  "Content-Type": "application/json",
80
  },
 
81
  });
82
  if (request && request.body) {
83
  const res = await request.json();
 
100
  setPreviousPrompt(prompt);
101
  setPrompt("");
102
  setisAiWorking(false);
103
+ onSuccess(res.html, prompt);
104
  audio.play();
105
  }
106
  } else {
 
110
  prompt,
111
  provider,
112
  model,
 
113
  }),
114
  headers: {
115
  "Content-Type": "application/json",
116
  },
 
117
  });
118
  if (request && request.body) {
119
  if (!request.ok) {
 
223
  }
224
  };
225
 
 
 
 
 
 
 
 
 
 
 
 
226
  useUpdateEffect(() => {
227
  if (refThink.current) {
228
  refThink.current.scrollTop = refThink.current.scrollHeight;
 
235
  }
236
  }, [isThinking]);
237
 
238
+ // TODO: auto scroll is not working properly, fix it
239
+
240
  return (
241
+ <div className="bg-neutral-800 border border-neutral-700 rounded-lg ring-[5px] focus-within:ring-sky-500/50 ring-transparent z-10 absolute bottom-3 left-3 w-[calc(100%-20px)] group">
242
  {think && (
243
  <div className="w-full border-b border-neutral-700 relative overflow-hidden">
244
  <header
 
248
  }}
249
  >
250
  <p className="text-sm font-medium text-neutral-300 group-hover:text-neutral-200 transition-colors duration-200">
251
+ {isThinking ? "AI is thinking..." : "AI's plan"}
252
  </p>
253
  <ChevronDown
254
  className={classNames(
 
276
  </main>
277
  </div>
278
  )}
279
+ <div
280
+ className={classNames(
281
+ "w-full relative flex items-center justify-between pl-3.5 p-2 lg:p-2 lg:pl-4",
282
+ {
283
+ "animate-pulse": isAiWorking,
284
+ }
285
+ )}
286
+ >
287
  {isAiWorking && (
288
+ <div className="absolute bg-neutral-800 rounded-lg bottom-0 left-11 w-[calc(100%-92px)] h-full z-1 flex items-center justify-start max-lg:text-sm">
289
+ <p className="text-neutral-400 font-code">
290
+ AI is {isThinking ? "thinking" : "coding"}...
291
+ </p>
 
 
 
 
 
 
 
 
 
 
292
  </div>
293
  )}
294
+ <RiSparkling2Fill className="size-5 text-neutral-400 group-focus-within:text-sky-500" />
295
  <input
296
  type="text"
297
  disabled={isAiWorking}
298
+ className="w-full bg-transparent max-lg:text-sm outline-none px-3 text-white placeholder:text-neutral-400 font-code"
299
+ placeholder={hasAsked ? "Ask AI for edits" : "Ask AI anything..."}
 
 
300
  value={prompt}
301
  onChange={(e) => setPrompt(e.target.value)}
302
  onKeyDown={(e) => {
303
+ if (e.key === "Enter") {
304
  callAi();
305
  }
306
  }}
307
  />
 
 
 
 
 
 
308
  <div className="flex items-center justify-end gap-2">
309
+ {/* <SpeechPrompt setPrompt={setPrompt} /> */}
310
  <Settings
311
  provider={provider as string}
312
  model={model as string}
 
317
  onClose={setOpenProvider}
318
  />
319
  <Button
320
+ variant="pink"
321
+ size="icon"
322
  disabled={isAiWorking || !prompt.trim()}
323
+ onClick={callAi}
324
  >
325
+ <GrSend className="-translate-x-[1px]" />
326
  </Button>
327
  </div>
328
  </div>
 
337
  ></div>
338
  <div
339
  className={classNames(
340
+ "absolute top-0 -translate-y-[calc(100%+8px)] right-0 z-10 w-80 bg-white border border-gray-200 rounded-lg shadow-lg transition-all duration-75 overflow-hidden",
341
  {
342
  "opacity-0 pointer-events-none": !open,
343
  }
src/components/deploy-button/deploy-button.tsx CHANGED
@@ -10,6 +10,20 @@ import LoadButton from "../load-button/load-button";
10
  import { Button } from "../ui/button";
11
  import { Popover, PopoverContent, PopoverTrigger } from "../ui/popover";
12
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
  function DeployButton({
14
  html,
15
  auth,
@@ -46,17 +60,11 @@ function DeployButton({
46
  });
47
  const response = await request.json();
48
  if (response.ok) {
49
- toast.success("Your space is live! 🎉", {
50
- action: {
51
- label: "See Space",
52
- onClick: () => {
53
- window.open(
54
- `https://huggingface.co/spaces/${response.path ?? path}`,
55
- "_blank"
56
- );
57
- },
58
- },
59
- });
60
  setPath(response.path);
61
  } else {
62
  toast.error(response.message);
@@ -84,7 +92,7 @@ function DeployButton({
84
  </div>
85
  </PopoverTrigger>
86
  <PopoverContent
87
- className="!rounded-2xl p-0 overflow-hidden !bg-neutral-900"
88
  align="end"
89
  >
90
  {!auth ? (
 
10
  import { Button } from "../ui/button";
11
  import { Popover, PopoverContent, PopoverTrigger } from "../ui/popover";
12
 
13
+ const MsgToast = ({ url }: { url: string }) => (
14
+ <div className="w-full flex items-center justify-center gap-3">
15
+ Your space is live!
16
+ <button
17
+ className="bg-black text-sm block text-white rounded-md px-3 py-1.5 hover:bg-gray-900 cursor-pointer"
18
+ onClick={() => {
19
+ window.open(url, "_blank");
20
+ }}
21
+ >
22
+ See Space
23
+ </button>
24
+ </div>
25
+ );
26
+
27
  function DeployButton({
28
  html,
29
  auth,
 
60
  });
61
  const response = await request.json();
62
  if (response.ok) {
63
+ toast.success(
64
+ <MsgToast
65
+ url={`https://huggingface.co/spaces/${response.path ?? path}`}
66
+ />
67
+ );
 
 
 
 
 
 
68
  setPath(response.path);
69
  } else {
70
  toast.error(response.message);
 
92
  </div>
93
  </PopoverTrigger>
94
  <PopoverContent
95
+ className="p-0 overflow-hidden !bg-neutral-900"
96
  align="end"
97
  >
98
  {!auth ? (
src/components/history/history.tsx CHANGED
@@ -13,11 +13,11 @@ export default function History({
13
  <Popover>
14
  <PopoverTrigger asChild>
15
  <Button variant="ghost" size="sm" className="max-lg:hidden">
16
- {history?.length} edit{history.length !== 1 ? "s" : ""}
17
  </Button>
18
  </PopoverTrigger>
19
  <PopoverContent
20
- className="!rounded-2xl !p-0 overflow-hidden !bg-neutral-900"
21
  align="start"
22
  >
23
  <header className="text-sm px-4 py-3 border-b gap-2 bg-neutral-950 border-neutral-800 font-semibold text-neutral-200">
 
13
  <Popover>
14
  <PopoverTrigger asChild>
15
  <Button variant="ghost" size="sm" className="max-lg:hidden">
16
+ {history?.length} edits
17
  </Button>
18
  </PopoverTrigger>
19
  <PopoverContent
20
+ className="!p-0 overflow-hidden !bg-neutral-900"
21
  align="start"
22
  >
23
  <header className="text-sm px-4 py-3 border-b gap-2 bg-neutral-950 border-neutral-800 font-semibold text-neutral-200">
src/components/invite-friends/invite-friends.tsx DELETED
@@ -1,78 +0,0 @@
1
- import { TiUserAdd } from "react-icons/ti";
2
- import { Link } from "lucide-react";
3
- import { FaXTwitter } from "react-icons/fa6";
4
-
5
- import { Button } from "../ui/button";
6
- import { Dialog, DialogContent, DialogTrigger } from "../ui/dialog";
7
- import { useCopyToClipboard } from "react-use";
8
- import { toast } from "sonner";
9
- export default function InviteFriends() {
10
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
11
- const [_, copyToClipboard] = useCopyToClipboard();
12
-
13
- return (
14
- <Dialog>
15
- <form>
16
- <DialogTrigger asChild>
17
- <Button
18
- size="iconXs"
19
- variant="outline"
20
- className="!border-neutral-600 !text-neutral-400 !hover:!border-neutral-500 hover:!text-neutral-300"
21
- >
22
- <TiUserAdd className="size-4" />
23
- </Button>
24
- </DialogTrigger>
25
- <DialogContent className="sm:max-w-lg lg:!p-8 !rounded-3xl !bg-white !border-neutral-100">
26
- <main>
27
- <div className="flex items-center justify-start -space-x-4 mb-5">
28
- <div className="size-11 rounded-full bg-pink-300 shadow-2xs flex items-center justify-center text-2xl">
29
- 😎
30
- </div>
31
- <div className="size-11 rounded-full bg-amber-300 shadow-2xs flex items-center justify-center text-2xl z-2">
32
- 😇
33
- </div>
34
- <div className="size-11 rounded-full bg-sky-300 shadow-2xs flex items-center justify-center text-2xl">
35
- 😜
36
- </div>
37
- </div>
38
- <p className="text-xl font-semibold text-neutral-950 max-w-[200px]">
39
- Invite your friends to join us!
40
- </p>
41
- <p className="text-sm text-neutral-500 mt-2 max-w-sm">
42
- Support us and share the love and let them know about our awesome
43
- platform.
44
- </p>
45
- <div className="mt-4 space-x-3.5">
46
- <a
47
- href="https://x.com/intent/post?url=https://enzostvs-deepsite.hf.space/&text=Checkout%20this%20awesome%20Ai%20Tool!%20Vibe%20coding%20has%20never%20been%20so%20easy✨"
48
- target="_blank"
49
- rel="noopener noreferrer"
50
- >
51
- <Button
52
- variant="ghostWhite"
53
- size="sm"
54
- className="!text-neutral-700"
55
- >
56
- <FaXTwitter className="size-4" />
57
- Share on
58
- </Button>
59
- </a>
60
- <Button
61
- variant="ghostWhite"
62
- size="sm"
63
- className="!text-neutral-700"
64
- onClick={() => {
65
- copyToClipboard("https://enzostvs-deepsite.hf.space/");
66
- toast.success("Invite link copied to clipboard!");
67
- }}
68
- >
69
- <Link className="size-4" />
70
- Copy Invite Link
71
- </Button>
72
- </div>
73
- </main>
74
- </DialogContent>
75
- </form>
76
- </Dialog>
77
- );
78
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/components/load-button/load-button.tsx CHANGED
@@ -64,7 +64,7 @@ function LoadButton({
64
  </p>
65
  </PopoverTrigger>
66
  <PopoverContent
67
- className="!rounded-2xl p-0 overflow-hidden !bg-neutral-900"
68
  align="end"
69
  >
70
  <header className="flex items-center text-sm px-4 py-3 border-b gap-2 bg-neutral-950 border-neutral-800 font-semibold text-neutral-200">
 
64
  </p>
65
  </PopoverTrigger>
66
  <PopoverContent
67
+ className="p-0 overflow-hidden !bg-neutral-900"
68
  align="end"
69
  >
70
  <header className="flex items-center text-sm px-4 py-3 border-b gap-2 bg-neutral-950 border-neutral-800 font-semibold text-neutral-200">
src/components/loading/loading.tsx CHANGED
@@ -1,21 +1,8 @@
1
- import classNames from "classnames";
2
-
3
- function Loading({
4
- overlay = true,
5
- className,
6
- }: {
7
- overlay?: boolean;
8
- className?: string;
9
- }) {
10
  return (
11
- <div
12
- className={classNames("", {
13
- "absolute left-0 top-0 h-full w-full flex items-center justify-center z-20 bg-black/50 rounded-full":
14
- overlay,
15
- })}
16
- >
17
  <svg
18
- className={`size-5 animate-spin text-white ${className}`}
19
  xmlns="http://www.w3.org/2000/svg"
20
  fill="none"
21
  viewBox="0 0 24 24"
 
1
+ function Loading() {
 
 
 
 
 
 
 
 
2
  return (
3
+ <div className="absolute left-0 top-0 h-full w-full flex items-center justify-center z-20 bg-black/50 rounded-full">
 
 
 
 
 
4
  <svg
5
+ className="size-5 animate-spin text-white"
6
  xmlns="http://www.w3.org/2000/svg"
7
  fill="none"
8
  viewBox="0 0 24 24"
src/components/pro-modal/pro-modal.tsx CHANGED
@@ -1,8 +1,6 @@
 
1
  import { useLocalStorage } from "react-use";
2
  import { defaultHTML } from "../../../utils/consts";
3
- import { Dialog, DialogContent } from "../ui/dialog";
4
- import { Button } from "../ui/button";
5
- import { CheckCheck } from "lucide-react";
6
 
7
  function ProModal({
8
  open,
@@ -22,73 +20,51 @@ function ProModal({
22
  };
23
 
24
  return (
25
- <Dialog open={open} onOpenChange={onClose}>
26
- <DialogContent className="sm:max-w-lg lg:!p-8 !rounded-3xl !bg-white !border-neutral-100">
27
- <main className="flex flex-col items-start text-left relative pt-2">
28
- <div className="flex items-center justify-start -space-x-4 mb-5">
29
- <div className="size-14 rounded-full bg-pink-200 shadow-2xs flex items-center justify-center text-3xl opacity-50">
30
- 🚀
31
- </div>
32
- <div className="size-16 rounded-full bg-amber-200 shadow-2xl flex items-center justify-center text-4xl z-2">
33
- 🤩
34
- </div>
35
- <div className="size-14 rounded-full bg-sky-200 shadow-2xs flex items-center justify-center text-3xl opacity-50">
36
- 🥳
37
- </div>
38
- </div>
39
- <p className="text-2xl font-bold text-neutral-950">
40
- Only 9$ for unlimited access!
 
 
 
 
 
 
 
 
 
 
 
 
41
  </p>
42
- <p className="text-neutral-500 text-base mt-2 max-w-sm">
43
- It seems like you have reached the monthly free limit of DeepSite.
 
44
  </p>
45
- <hr className="bg-neutral-200 w-full max-w-[150px] my-6" />
46
- <p className="text-lg mt-3 text-neutral-900 font-semibold">
47
- Upgrade to a <ProTag className="mx-1" /> Account, and unlock:
48
- </p>
49
- <ul className="mt-3 space-y-1 text-neutral-500">
50
- <li className="text-sm space-x-2 flex items-center justify-start gap-2">
51
- <CheckCheck className="text-emerald-500 size-4" />
52
- DeepSite unlimited access to all Inference Providers
53
- </li>
54
- <li className="text-sm space-x-2 flex items-center justify-start gap-2">
55
- <CheckCheck className="text-emerald-500 size-4" />
56
- Get highest priority and 8x more quota on Spaces ZeroGPU
57
- </li>
58
- <li className="text-sm space-x-2 flex items-center justify-start gap-2">
59
- <CheckCheck className="text-emerald-500 size-4" />
60
- Activate Dataset Viewer on private datasets
61
- </li>
62
- <li className="text-sm space-x-2 flex items-center justify-start gap-2">
63
- <CheckCheck className="text-emerald-500 size-4" />
64
- Get exclusive early access to new features and updates
65
- </li>
66
- <li className="text-sm space-x-2 flex items-center justify-start gap-2">
67
- <CheckCheck className="text-emerald-500 size-4" />
68
- Get free credits across all Inference Providers
69
- </li>
70
- <li className="text-sm text-neutral-500 space-x-2 flex items-center justify-start gap-2 mt-3">
71
- ... and much more!
72
- </li>
73
- </ul>
74
- <Button
75
- variant="gray"
76
- size="lg"
77
- className="w-full !text-base !h-11 mt-8"
78
  onClick={handleProClick}
79
  >
80
  Subscribe to PRO ($9/month)
81
- </Button>
82
  </main>
83
- </DialogContent>
84
- </Dialog>
85
  );
86
  }
87
- const ProTag = ({ className }: { className?: string }) => (
88
- <span
89
- className={`${className} bg-linear-to-br shadow-green-500/10 dark:shadow-green-500/20 inline-block -skew-x-12 border border-gray-200 from-pink-300 via-green-200 to-yellow-200 text-xs font-bold text-black shadow-lg rounded-md px-2.5 py-0.5`}
90
- >
91
- PRO
92
- </span>
93
- );
94
  export default ProModal;
 
1
+ import classNames from "classnames";
2
  import { useLocalStorage } from "react-use";
3
  import { defaultHTML } from "../../../utils/consts";
 
 
 
4
 
5
  function ProModal({
6
  open,
 
20
  };
21
 
22
  return (
23
+ <>
24
+ <div
25
+ className={classNames(
26
+ "h-screen w-screen bg-black/20 fixed left-0 top-0 z-40",
27
+ {
28
+ "opacity-0 pointer-events-none": !open,
29
+ }
30
+ )}
31
+ onClick={() => onClose(false)}
32
+ ></div>
33
+ <div
34
+ className={classNames(
35
+ "absolute top-0 -translate-y-[calc(100%+16px)] right-0 z-40 w-96 bg-white border border-gray-200 rounded-lg shadow-lg transition-all duration-75 overflow-hidden",
36
+ {
37
+ "opacity-0 pointer-events-none": !open,
38
+ }
39
+ )}
40
+ >
41
+ <header className="flex items-center text-sm px-4 py-2 border-b border-gray-200 gap-2 bg-gray-100 font-semibold text-gray-700">
42
+ <span className="bg-linear-to-br shadow-green-500/10 dark:shadow-green-500/20 inline-block -skew-x-12 border border-gray-200 from-pink-300 via-green-200 to-yellow-200 text-xs font-bold text-black shadow-lg dark:from-pink-500 dark:via-green-500 dark:to-yellow-500 dark:text-black rounded-lg px-2.5 py-0.5 ">
43
+ PRO
44
+ </span>
45
+ Your free inference quota is exhausted
46
+ </header>
47
+ <main className="px-4 pt-3 pb-4">
48
+ <p className="text-gray-950 text-sm font-semibold flex items-center justify-between">
49
+ Upgrade to a PRO account to activate Inference Providers and
50
+ continue using DeepSite.
51
  </p>
52
+ <p className="text-sm text-pretty text-gray-500 mt-2">
53
+ It also unlocks thousands of Space apps powered by ZeroGPU for 3d,
54
+ audio, music, video and more!
55
  </p>
56
+ <a
57
+ href="https://huggingface.co/subscribe/pro"
58
+ target="_blank"
59
+ className="mt-4 bg-black text-white cursor-pointer rounded-full py-2 px-3 text-sm font-medium w-full block text-center hover:bg-gray-800 transition duration-200 ease-in-out"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
60
  onClick={handleProClick}
61
  >
62
  Subscribe to PRO ($9/month)
63
+ </a>
64
  </main>
65
+ </div>
66
+ </>
67
  );
68
  }
69
+
 
 
 
 
 
 
70
  export default ProModal;
src/components/re-imagine/re-imagine.tsx DELETED
@@ -1,136 +0,0 @@
1
- import { useState } from "react";
2
- import { Paintbrush } from "lucide-react";
3
- import { toast } from "sonner";
4
-
5
- import { Button } from "../ui/button";
6
- import { Popover, PopoverContent, PopoverTrigger } from "../ui/popover";
7
- import { Input } from "../ui/input";
8
- import Loading from "../loading/loading";
9
-
10
- export default function ReImagine({
11
- onRedesign,
12
- }: {
13
- onRedesign: (md: string) => void;
14
- }) {
15
- const [url, setUrl] = useState<string>("");
16
- const [open, setOpen] = useState(false);
17
- const [isLoading, setIsLoading] = useState(false);
18
-
19
- const checkIfUrlIsValid = (url: string) => {
20
- const urlPattern = new RegExp(
21
- /^(https?:\/\/)?([\da-z.-]+)\.([a-z.]{2,6})([/\w .-]*)*\/?$/,
22
- "i"
23
- );
24
- return urlPattern.test(url);
25
- };
26
-
27
- const handleClick = async () => {
28
- if (!url) {
29
- toast.error("Please enter a URL.");
30
- return;
31
- }
32
- if (!checkIfUrlIsValid(url)) {
33
- toast.error("Please enter a valid URL.");
34
- return;
35
- }
36
- // Here you would typically handle the re-design logic
37
- setIsLoading(true);
38
- const request = await fetch("/api/re-design", {
39
- method: "POST",
40
- body: JSON.stringify({ url }),
41
- headers: {
42
- "Content-Type": "application/json",
43
- },
44
- });
45
- const response = await request.json();
46
- if (response.ok) {
47
- setOpen(false);
48
- setUrl("");
49
- onRedesign(response.markdown);
50
- toast.success("DeepSite is re-designing your site! Let him cook... 🔥");
51
- } else {
52
- toast.error(response.message || "Failed to re-design the site.");
53
- }
54
- setIsLoading(false);
55
- };
56
-
57
- return (
58
- <Popover open={open} onOpenChange={setOpen}>
59
- <form>
60
- <PopoverTrigger asChild>
61
- <Button
62
- size="iconXs"
63
- variant="outline"
64
- className="!border-neutral-600 !text-neutral-400 !hover:!border-neutral-500 hover:!text-neutral-300"
65
- >
66
- <Paintbrush className="size-4" />
67
- </Button>
68
- </PopoverTrigger>
69
- <PopoverContent
70
- align="start"
71
- className="!rounded-2xl !p-0 !bg-white !border-neutral-100 min-w-xs text-center overflow-hidden"
72
- >
73
- <header className="bg-neutral-50 p-6 border-b border-neutral-200/60">
74
- <div className="flex items-center justify-center -space-x-4 mb-3">
75
- <div className="size-9 rounded-full bg-pink-200 shadow-2xs flex items-center justify-center text-xl opacity-50">
76
- 🎨
77
- </div>
78
- <div className="size-11 rounded-full bg-amber-200 shadow-2xl flex items-center justify-center text-2xl z-2">
79
- 🥳
80
- </div>
81
- <div className="size-9 rounded-full bg-sky-200 shadow-2xs flex items-center justify-center text-xl opacity-50">
82
- 💎
83
- </div>
84
- </div>
85
- <p className="text-xl font-semibold text-neutral-950">
86
- Redesign your Site!
87
- </p>
88
- <p className="text-sm text-neutral-500 mt-1.5">
89
- Try our new Redesign feature to give your site a fresh look.
90
- </p>
91
- </header>
92
- <main className="space-y-4 p-6">
93
- <div>
94
- <p className="text-sm text-neutral-700 mb-2">
95
- Enter your website URL to get started:
96
- </p>
97
- <Input
98
- type="text"
99
- placeholder="https://example.com"
100
- value={url}
101
- onChange={(e) => setUrl(e.target.value)}
102
- onBlur={(e) => {
103
- const inputUrl = e.target.value.trim();
104
- if (!inputUrl) {
105
- setUrl("");
106
- return;
107
- }
108
- if (!checkIfUrlIsValid(inputUrl)) {
109
- toast.error("Please enter a valid URL.");
110
- return;
111
- }
112
- setUrl(inputUrl);
113
- }}
114
- className="!bg-white !border-neutral-300 !text-neutral-800 !placeholder:text-neutral-400 selection:!bg-blue-100"
115
- />
116
- </div>
117
- <div>
118
- <p className="text-sm text-neutral-700 mb-2">
119
- Then, let's redesign it!
120
- </p>
121
- <Button
122
- variant="gray"
123
- onClick={handleClick}
124
- className="relative w-full"
125
- disabled={isLoading}
126
- >
127
- Redesign <Paintbrush className="size-4" />
128
- {isLoading && <Loading className="ml-2 size-4 animate-spin" />}
129
- </Button>
130
- </div>
131
- </main>
132
- </PopoverContent>
133
- </form>
134
- </Popover>
135
- );
136
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/components/settings/settings.tsx CHANGED
@@ -56,13 +56,12 @@ function Settings({
56
  <div className="">
57
  <Popover open={open} onOpenChange={onClose}>
58
  <PopoverTrigger asChild>
59
- <Button variant="gray" size="sm">
60
- <PiGearSixFill className="size-4" />
61
- Settings
62
  </Button>
63
  </PopoverTrigger>
64
  <PopoverContent
65
- className="!rounded-2xl p-0 !w-96 overflow-hidden !bg-neutral-900"
66
  align="center"
67
  >
68
  <header className="flex items-center text-sm px-4 py-3 border-b gap-2 bg-neutral-950 border-neutral-800 font-semibold text-neutral-200">
@@ -106,7 +105,7 @@ function Settings({
106
  label: string;
107
  isNew?: boolean;
108
  }) => (
109
- <SelectItem key={value} value={value} className="">
110
  {label}
111
  {isNew && (
112
  <span className="text-xs bg-gradient-to-br from-sky-400 to-sky-600 text-white rounded-full px-1.5 py-0.5">
 
56
  <div className="">
57
  <Popover open={open} onOpenChange={onClose}>
58
  <PopoverTrigger asChild>
59
+ <Button variant="gray" size="icon">
60
+ <PiGearSixFill className="size-5" />
 
61
  </Button>
62
  </PopoverTrigger>
63
  <PopoverContent
64
+ className="p-0 !w-96 overflow-hidden !bg-neutral-900"
65
  align="center"
66
  >
67
  <header className="flex items-center text-sm px-4 py-3 border-b gap-2 bg-neutral-950 border-neutral-800 font-semibold text-neutral-200">
 
105
  label: string;
106
  isNew?: boolean;
107
  }) => (
108
+ <SelectItem value={value} className="">
109
  {label}
110
  {isNew && (
111
  <span className="text-xs bg-gradient-to-br from-sky-400 to-sky-600 text-white rounded-full px-1.5 py-0.5">
src/components/ui/button.tsx CHANGED
@@ -11,7 +11,8 @@ const buttonVariants = cva(
11
  variant: {
12
  default:
13
  "bg-neutral-900 text-neutral-50 shadow-xs hover:bg-neutral-900/90 dark:bg-neutral-50 dark:text-neutral-900 dark:hover:bg-neutral-50/90",
14
- destructive: "bg-red-600 text-white shadow-xs hover:bg-red-500",
 
15
  outline:
16
  "border bg-white shadow-xs hover:bg-neutral-100 hover:text-neutral-900 dark:bg-neutral-200/30 dark:border-neutral-200 dark:hover:bg-neutral-200/50 dark:bg-neutral-950 dark:hover:bg-neutral-800 dark:hover:text-neutral-50 dark:dark:bg-neutral-800/30 dark:dark:border-neutral-800 dark:dark:hover:bg-neutral-800/50",
17
  secondary:
@@ -21,7 +22,6 @@ const buttonVariants = cva(
21
  link: "text-neutral-900 underline-offset-4 hover:underline dark:text-neutral-50",
22
  pink: "bg-sky-500 text-white hover:brightness-110",
23
  gray: "bg-neutral-900 text-neutral-300 hover:brightness-110",
24
- ghostWhite: "bg-neutral-200/60 text-neutral-900 hover:bg-neutral-200",
25
  },
26
  size: {
27
  default: "h-9 px-4 py-2 has-[>svg]:px-3",
@@ -29,7 +29,6 @@ const buttonVariants = cva(
29
  lg: "h-10 rounded-full px-6 has-[>svg]:px-4",
30
  icon: "size-9",
31
  iconXs: "size-7",
32
- iconXss: "size-6",
33
  xs: "h-6 text-xs rounded-full pl-2 pr-2 gap-1",
34
  },
35
  },
 
11
  variant: {
12
  default:
13
  "bg-neutral-900 text-neutral-50 shadow-xs hover:bg-neutral-900/90 dark:bg-neutral-50 dark:text-neutral-900 dark:hover:bg-neutral-50/90",
14
+ destructive:
15
+ "bg-red-500 text-white shadow-xs hover:bg-red-500/90 focus-visible:ring-red-500/20 dark:focus-visible:ring-red-500/40 dark:bg-red-500/60 dark:bg-red-900 dark:hover:bg-red-900/90 dark:focus-visible:ring-red-900/20 dark:dark:focus-visible:ring-red-900/40 dark:dark:bg-red-900/60",
16
  outline:
17
  "border bg-white shadow-xs hover:bg-neutral-100 hover:text-neutral-900 dark:bg-neutral-200/30 dark:border-neutral-200 dark:hover:bg-neutral-200/50 dark:bg-neutral-950 dark:hover:bg-neutral-800 dark:hover:text-neutral-50 dark:dark:bg-neutral-800/30 dark:dark:border-neutral-800 dark:dark:hover:bg-neutral-800/50",
18
  secondary:
 
22
  link: "text-neutral-900 underline-offset-4 hover:underline dark:text-neutral-50",
23
  pink: "bg-sky-500 text-white hover:brightness-110",
24
  gray: "bg-neutral-900 text-neutral-300 hover:brightness-110",
 
25
  },
26
  size: {
27
  default: "h-9 px-4 py-2 has-[>svg]:px-3",
 
29
  lg: "h-10 rounded-full px-6 has-[>svg]:px-4",
30
  icon: "size-9",
31
  iconXs: "size-7",
 
32
  xs: "h-6 text-xs rounded-full pl-2 pr-2 gap-1",
33
  },
34
  },
src/components/ui/dialog.tsx DELETED
@@ -1,144 +0,0 @@
1
- import * as React from "react";
2
- import * as DialogPrimitive from "@radix-ui/react-dialog";
3
- import { XIcon } from "lucide-react";
4
-
5
- import { cn } from "./../../lib/utils";
6
-
7
- function Dialog({
8
- ...props
9
- }: React.ComponentProps<typeof DialogPrimitive.Root>) {
10
- return <DialogPrimitive.Root data-slot="dialog" {...props} />;
11
- }
12
-
13
- function DialogTrigger({
14
- ...props
15
- }: React.ComponentProps<typeof DialogPrimitive.Trigger>) {
16
- return <DialogPrimitive.Trigger data-slot="dialog-trigger" {...props} />;
17
- }
18
-
19
- function DialogPortal({
20
- ...props
21
- }: React.ComponentProps<typeof DialogPrimitive.Portal>) {
22
- return <DialogPrimitive.Portal data-slot="dialog-portal" {...props} />;
23
- }
24
-
25
- function DialogClose({
26
- ...props
27
- }: React.ComponentProps<typeof DialogPrimitive.Close>) {
28
- return <DialogPrimitive.Close data-slot="dialog-close" {...props} />;
29
- }
30
-
31
- function DialogOverlay({
32
- className,
33
- ...props
34
- }: React.ComponentProps<typeof DialogPrimitive.Overlay>) {
35
- return (
36
- <DialogPrimitive.Overlay
37
- data-slot="dialog-overlay"
38
- className={cn(
39
- "data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50",
40
- className
41
- )}
42
- {...props}
43
- />
44
- );
45
- }
46
-
47
- function DialogContent({
48
- className,
49
- children,
50
- showCloseButton = true,
51
- ...props
52
- }: React.ComponentProps<typeof DialogPrimitive.Content> & {
53
- showCloseButton?: boolean;
54
- }) {
55
- return (
56
- <DialogPortal data-slot="dialog-portal">
57
- <DialogOverlay />
58
- <DialogPrimitive.Content
59
- data-slot="dialog-content"
60
- className={cn(
61
- "bg-white data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border border-neutral-200 p-6 shadow-lg duration-200 sm:max-w-lg dark:bg-neutral-950 dark:border-neutral-800",
62
- className
63
- )}
64
- {...props}
65
- >
66
- {children}
67
- {showCloseButton && (
68
- <DialogPrimitive.Close
69
- data-slot="dialog-close"
70
- className="ring-offset-white focus:ring-neutral-950 data-[state=open]:bg-neutral-100 data-[state=open]:text-neutral-500 absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 dark:ring-offset-neutral-950 dark:focus:ring-neutral-300 dark:data-[state=open]:bg-neutral-800 dark:data-[state=open]:text-neutral-400"
71
- >
72
- <XIcon />
73
- <span className="sr-only">Close</span>
74
- </DialogPrimitive.Close>
75
- )}
76
- </DialogPrimitive.Content>
77
- </DialogPortal>
78
- );
79
- }
80
-
81
- function DialogHeader({ className, ...props }: React.ComponentProps<"div">) {
82
- return (
83
- <div
84
- data-slot="dialog-header"
85
- className={cn("flex flex-col gap-2 text-center sm:text-left", className)}
86
- {...props}
87
- />
88
- );
89
- }
90
-
91
- function DialogFooter({ className, ...props }: React.ComponentProps<"div">) {
92
- return (
93
- <div
94
- data-slot="dialog-footer"
95
- className={cn(
96
- "flex flex-col-reverse gap-2 sm:flex-row sm:justify-end",
97
- className
98
- )}
99
- {...props}
100
- />
101
- );
102
- }
103
-
104
- function DialogTitle({
105
- className,
106
- ...props
107
- }: React.ComponentProps<typeof DialogPrimitive.Title>) {
108
- return (
109
- <DialogPrimitive.Title
110
- data-slot="dialog-title"
111
- className={cn("text-lg leading-none font-semibold", className)}
112
- {...props}
113
- />
114
- );
115
- }
116
-
117
- function DialogDescription({
118
- className,
119
- ...props
120
- }: React.ComponentProps<typeof DialogPrimitive.Description>) {
121
- return (
122
- <DialogPrimitive.Description
123
- data-slot="dialog-description"
124
- className={cn(
125
- "text-neutral-500 text-sm dark:text-neutral-400",
126
- className
127
- )}
128
- {...props}
129
- />
130
- );
131
- }
132
-
133
- export {
134
- Dialog,
135
- DialogClose,
136
- DialogContent,
137
- DialogDescription,
138
- DialogFooter,
139
- DialogHeader,
140
- DialogOverlay,
141
- DialogPortal,
142
- DialogTitle,
143
- DialogTrigger,
144
- };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/components/ui/tooltip.tsx DELETED
@@ -1,59 +0,0 @@
1
- import * as React from "react";
2
- import * as TooltipPrimitive from "@radix-ui/react-tooltip";
3
-
4
- import { cn } from "./../../lib/utils";
5
-
6
- function TooltipProvider({
7
- delayDuration = 0,
8
- ...props
9
- }: React.ComponentProps<typeof TooltipPrimitive.Provider>) {
10
- return (
11
- <TooltipPrimitive.Provider
12
- data-slot="tooltip-provider"
13
- delayDuration={delayDuration}
14
- {...props}
15
- />
16
- );
17
- }
18
-
19
- function Tooltip({
20
- ...props
21
- }: React.ComponentProps<typeof TooltipPrimitive.Root>) {
22
- return (
23
- <TooltipProvider>
24
- <TooltipPrimitive.Root data-slot="tooltip" {...props} />
25
- </TooltipProvider>
26
- );
27
- }
28
-
29
- function TooltipTrigger({
30
- ...props
31
- }: React.ComponentProps<typeof TooltipPrimitive.Trigger>) {
32
- return <TooltipPrimitive.Trigger data-slot="tooltip-trigger" {...props} />;
33
- }
34
-
35
- function TooltipContent({
36
- className,
37
- sideOffset = 0,
38
- children,
39
- ...props
40
- }: React.ComponentProps<typeof TooltipPrimitive.Content>) {
41
- return (
42
- <TooltipPrimitive.Portal>
43
- <TooltipPrimitive.Content
44
- data-slot="tooltip-content"
45
- sideOffset={sideOffset}
46
- className={cn(
47
- "bg-black text-neutral-50 animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-fit origin-(--radix-tooltip-content-transform-origin) rounded-md px-3 py-1.5 text-xs text-balance",
48
- className
49
- )}
50
- {...props}
51
- >
52
- {children}
53
- <TooltipPrimitive.Arrow className="bg-black fill-black z-50 size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-[2px]" />
54
- </TooltipPrimitive.Content>
55
- </TooltipPrimitive.Portal>
56
- );
57
- }
58
-
59
- export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/views/App.tsx CHANGED
@@ -34,8 +34,6 @@ export default function App() {
34
  const resizer = useRef<HTMLDivElement>(null);
35
  const editorRef = useRef<editor.IStandaloneCodeEditor | null>(null);
36
  const iframeRef = useRef<HTMLIFrameElement | null>(null);
37
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
38
- const monacoRef = useRef<any>(null);
39
 
40
  const [html, setHtml] = useState((htmlStorage as string) ?? defaultHTML);
41
  const [isAiWorking, setisAiWorking] = useState(false);
@@ -218,31 +216,20 @@ export default function App() {
218
  fontLigatures: true,
219
  theme: "vs-dark",
220
  minimap: { enabled: false },
221
- scrollbar: {
222
- horizontal: "hidden",
223
- },
224
  }}
225
  value={html}
226
  onChange={(value) => {
227
  const newValue = value ?? "";
228
  setHtml(newValue);
229
  }}
230
- onMount={(editor, monaco) => {
231
- editorRef.current = editor;
232
- monacoRef.current = monaco;
233
- }}
234
  />
235
  <AskAI
236
  html={html}
237
  setHtml={(newHtml: string) => {
238
  setHtml(newHtml);
239
  }}
240
- htmlHistory={htmlHistory}
241
- onSuccess={(
242
- finalHtml: string,
243
- p: string,
244
- updatedLines?: number[][]
245
- ) => {
246
  const currentHistory = [...htmlHistory];
247
  currentHistory.unshift({
248
  html: finalHtml,
@@ -254,26 +241,6 @@ export default function App() {
254
  if (window.innerWidth <= 1024) {
255
  setCurrentTab("preview");
256
  }
257
- if (updatedLines && updatedLines?.length > 0) {
258
- const decorations = updatedLines.map((line) => ({
259
- range: new monacoRef.current.Range(
260
- line[0],
261
- 1,
262
- line[1],
263
- 1
264
- ),
265
- options: {
266
- inlineClassName: "matched-line",
267
- },
268
- }));
269
- setTimeout(() => {
270
- editorRef?.current
271
- ?.getModel()
272
- ?.deltaDecorations([], decorations);
273
-
274
- editorRef.current?.revealLine(updatedLines[0][0]);
275
- }, 100);
276
- }
277
  }}
278
  isAiWorking={isAiWorking}
279
  setisAiWorking={setisAiWorking}
 
34
  const resizer = useRef<HTMLDivElement>(null);
35
  const editorRef = useRef<editor.IStandaloneCodeEditor | null>(null);
36
  const iframeRef = useRef<HTMLIFrameElement | null>(null);
 
 
37
 
38
  const [html, setHtml] = useState((htmlStorage as string) ?? defaultHTML);
39
  const [isAiWorking, setisAiWorking] = useState(false);
 
216
  fontLigatures: true,
217
  theme: "vs-dark",
218
  minimap: { enabled: false },
 
 
 
219
  }}
220
  value={html}
221
  onChange={(value) => {
222
  const newValue = value ?? "";
223
  setHtml(newValue);
224
  }}
225
+ onMount={(editor) => (editorRef.current = editor)}
 
 
 
226
  />
227
  <AskAI
228
  html={html}
229
  setHtml={(newHtml: string) => {
230
  setHtml(newHtml);
231
  }}
232
+ onSuccess={(finalHtml: string, p: string) => {
 
 
 
 
 
233
  const currentHistory = [...htmlHistory];
234
  currentHistory.unshift({
235
  html: finalHtml,
 
241
  if (window.innerWidth <= 1024) {
242
  setCurrentTab("preview");
243
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
244
  }}
245
  isAiWorking={isAiWorking}
246
  setisAiWorking={setisAiWorking}
utils/providers.js CHANGED
@@ -36,19 +36,12 @@ export const MODELS = [
36
  value: "deepseek-ai/DeepSeek-V3-0324",
37
  label: "DeepSeek V3 O324",
38
  providers: ["fireworks-ai", "nebius", "sambanova", "novita", "hyperbolic"],
39
- autoProvider: "fireworks-ai",
40
  },
41
  {
42
  value: "deepseek-ai/DeepSeek-R1-0528",
43
  label: "DeepSeek R1 0528",
44
- providers: [
45
- "fireworks-ai",
46
- "novita",
47
- "hyperbolic",
48
- "nebius",
49
- "together",
50
- "sambanova",
51
- ],
52
  autoProvider: "novita",
53
  isNew: true,
54
  isThinker: true,
 
36
  value: "deepseek-ai/DeepSeek-V3-0324",
37
  label: "DeepSeek V3 O324",
38
  providers: ["fireworks-ai", "nebius", "sambanova", "novita", "hyperbolic"],
39
+ autoProvider: "sambanova",
40
  },
41
  {
42
  value: "deepseek-ai/DeepSeek-R1-0528",
43
  label: "DeepSeek R1 0528",
44
+ providers: ["fireworks-ai", "novita", "hyperbolic", "nebius", "together"],
 
 
 
 
 
 
 
45
  autoProvider: "novita",
46
  isNew: true,
47
  isThinker: true,