.gitattributes ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ CakezyWebsite/images/Chocolate_Truffle_Cake.jpg.jpg filter=lfs diff=lfs merge=lfs -text
2
+ CakezyWebsite/images/Red_Velvet_Cake.jpg.jpg filter=lfs diff=lfs merge=lfs -text
CakezyWebsite/images/Chocolate_Truffle_Cake.jpg.jpg ADDED

Git LFS Details

  • SHA256: c421e73443952e93755c66164d729f97c33f996d3929d4257fe8b203f4c6015c
  • Pointer size: 131 Bytes
  • Size of remote file: 128 kB
CakezyWebsite/images/Red_Velvet_Cake.jpg.jpg ADDED

Git LFS Details

  • SHA256: 364d0f49ac19c903d17d10fc62da54c1910468477f0d29129214978c96cca5fc
  • Pointer size: 131 Bytes
  • Size of remote file: 179 kB
CakezyWebsite/images/black_forest_cake.jpg.jpg ADDED
CakezyWebsite/images/fresh_lime_soda.jpg.jpg ADDED
CakezyWebsite/images/iced_mocha_frappe.jpg.jpg ADDED
CakezyWebsite/images/mango_smoothie.jpg.jpg ADDED
CakezyWebsite/index.html.html ADDED
@@ -0,0 +1,121 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Cakezy Delights - Premium Cakes & Beverages</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ <script src="https://unpkg.com/feather-icons"></script>
9
+ <style>
10
+ .hero-gradient {
11
+ background: linear-gradient(135deg, #f3e8ff 0%, #fce4ec 50%, #fff0f6 100%);
12
+ }
13
+ .cake-card:hover, .beverage-card:hover {
14
+ transform: translateY(-5px);
15
+ box-shadow: 0 20px 25px -5px rgba(0,0,0,0.1), 0 10px 10px -5px rgba(0,0,0,0.04);
16
+ }
17
+ </style>
18
+ </head>
19
+ <body class="font-sans antialiased text-gray-800">
20
+
21
+ <!-- Navigation -->
22
+ <nav class="bg-white shadow-sm">
23
+ <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
24
+ <div class="flex justify-between h-16">
25
+ <div class="flex items-center">
26
+ <i data-feather="cake" class="h-8 w-8 text-pink-500"></i>
27
+ <span class="ml-2 text-xl font-bold text-gray-900">Cakezy Delights</span>
28
+ </div>
29
+ <div class="hidden sm:flex sm:items-center sm:space-x-8">
30
+ <a href="#cakes" class="text-gray-900 border-b-2 border-pink-500 px-1 pt-1 text-sm font-medium">Cakes</a>
31
+ <a href="#beverages" class="text-gray-500 hover:text-gray-700 px-1 pt-1 text-sm font-medium">Beverages</a>
32
+ <a href="#contact" class="text-gray-500 hover:text-gray-700 px-1 pt-1 text-sm font-medium">Contact</a>
33
+ </div>
34
+ </div>
35
+ </div>
36
+ </nav>
37
+
38
+ <!-- Hero Section -->
39
+ <section class="hero-gradient">
40
+ <div class="max-w-7xl mx-auto py-16 px-4 text-center">
41
+ <h1 class="text-4xl font-extrabold text-gray-900 sm:text-5xl md:text-6xl">
42
+ Sip. Slice. Smile.
43
+ </h1>
44
+ <span class="block text-pink-500 text-4xl md:text-5xl font-bold">Cakezy Delights</span>
45
+ <p class="mt-4 text-gray-500 text-lg md:text-xl">
46
+ Freshly baked cakes & refreshing beverages delivered to your doorstep.
47
+ </p>
48
+ </div>
49
+ </section>
50
+
51
+ <!-- Cakes Section -->
52
+ <section id="cakes" class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-12">
53
+ <h2 class="text-3xl font-extrabold text-gray-900 text-center mb-10">Our Best-Selling Cakes 🍰</h2>
54
+ <div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-8">
55
+ <!-- Cake 1 -->
56
+ <div class="cake-card bg-white rounded-lg overflow-hidden shadow-md transition-all duration-300">
57
+ <img src="images/Chocolate_Truffle_Cake.jpg" alt="Chocolate Truffle Cake" class="w-full h-64 object-cover">
58
+ <div class="p-4">
59
+ <h3 class="text-lg font-medium text-gray-900">Chocolate Truffle Cake</h3>
60
+ <p class="text-gray-500 text-sm mt-1">Rich chocolate layers with truffle cream</p>
61
+ </div>
62
+ </div>
63
+
64
+ <!-- Cake 2 -->
65
+ <div class="cake-card bg-white rounded-lg overflow-hidden shadow-md transition-all duration-300">
66
+ <img src="images/Red_Velvet_Cake.jpg" alt="Red Velvet Cake" class="w-full h-64 object-cover">
67
+ <div class="p-4">
68
+ <h3 class="text-lg font-medium text-gray-900">Red Velvet Cake</h3>
69
+ <p class="text-gray-500 text-sm mt-1">Classic velvet with cream cheese frosting</p>
70
+ </div>
71
+ </div>
72
+
73
+ <!-- Cake 3 -->
74
+ <div class="cake-card bg-white rounded-lg overflow-hidden shadow-md transition-all duration-300">
75
+ <img src="images/black_forest_cake.jpg" alt="Black Forest Cake" class="w-full h-64 object-cover">
76
+ <div class="p-4">
77
+ <h3 class="text-lg font-medium text-gray-900">Black Forest Cake</h3>
78
+ <p class="text-gray-500 text-sm mt-1">Chocolate layers with cherry filling</p>
79
+ </div>
80
+ </div>
81
+ </div>
82
+ </section>
83
+
84
+ <!-- Beverages Section -->
85
+ <section id="beverages" class="bg-gray-100 py-12">
86
+ <h2 class="text-3xl font-extrabold text-gray-900 text-center mb-10">Refreshing Beverages 🥤</h2>
87
+ <div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-8 max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
88
+ <!-- Beverage 1 -->
89
+ <div class="beverage-card bg-white rounded-lg overflow-hidden shadow-md transition-all duration-300">
90
+ <img src="images/mango_smoothie.jpg" alt="Mango Smoothie" class="w-full h-64 object-cover">
91
+ <div class="p-4">
92
+ <h3 class="text-lg font-medium text-gray-900">Mango Smoothie</h3>
93
+ <p class="text-gray-500 text-sm mt-1">350ml</p>
94
+ </div>
95
+ </div>
96
+
97
+ <!-- Beverage 2 -->
98
+ <div class="beverage-card bg-white rounded-lg overflow-hidden shadow-md transition-all duration-300">
99
+ <img src="images/iced_mocha_frappe.jpg" alt="Cold Coffee Frappe" class="w-full h-64 object-cover">
100
+ <div class="p-4">
101
+ <h3 class="text-lg font-medium text-gray-900">Cold Coffee Frappe</h3>
102
+ <p class="text-gray-500 text-sm mt-1">400ml</p>
103
+ </div>
104
+ </div>
105
+
106
+ <!-- Beverage 3 -->
107
+ <div class="beverage-card bg-white rounded-lg overflow-hidden shadow-md transition-all duration-300">
108
+ <img src="images/fresh_lime_soda.jpg" alt="Fresh Lime Soda" class="w-full h-64 object-cover">
109
+ <div class="p-4">
110
+ <h3 class="text-lg font-medium text-gray-900">Fresh Lime Soda</h3>
111
+ <p class="text-gray-500 text-sm mt-1">300ml</p>
112
+ </div>
113
+ </div>
114
+ </div>
115
+ </section>
116
+
117
+ <script>
118
+ feather.replace()
119
+ </script>
120
+ </body>
121
+ </html>
Dockerfile CHANGED
@@ -1,19 +1,16 @@
1
- FROM node:20-alpine
2
- USER root
3
 
4
- USER 1000
5
- WORKDIR /usr/src/app
6
- # Copy package.json and package-lock.json to the container
7
- COPY --chown=1000 package.json package-lock.json ./
8
 
9
- # Copy the rest of the application files to the container
10
- COPY --chown=1000 . .
11
 
12
- RUN npm install
13
- RUN npm run build
14
 
15
- # Expose the application port (assuming your app runs on port 3000)
16
- EXPOSE 3000
17
 
18
- # Start the application
19
- CMD ["npm", "start"]
 
1
+ FROM registry.hf.space/enzostvs-deepsite:cpu-bbc7882
2
+ # FROM node:22
3
 
4
+ # USER 1000
5
+ # WORKDIR /usr/src/app
 
 
6
 
7
+ # # Copy the rest of the application files to the container
8
+ # COPY --chown=1000 . .
9
 
10
+ # RUN npm ci && npm run build
 
11
 
12
+ # # Expose the application port (assuming your app runs on port 3000)
13
+ # EXPOSE 3000
14
 
15
+ # # Start the application
16
+ # CMD ["npm", "start"]
app/api/ask/route.ts CHANGED
@@ -285,11 +285,35 @@ export async function PUT(request: NextRequest) {
285
  return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
286
  };
287
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
288
  const createFlexibleHtmlRegex = (searchBlock: string) => {
289
- let searchRegex = escapeRegExp(searchBlock)
290
- .replace(/\s+/g, '\\s*')
 
 
 
 
291
  .replace(/>\s*</g, '>\\s*<')
292
- .replace(/\s*>/g, '\\s*>');
 
293
 
294
  return new RegExp(searchRegex, 'g');
295
  };
@@ -300,41 +324,9 @@ export async function PUT(request: NextRequest) {
300
  const systemPrompt = FOLLOW_UP_SYSTEM_PROMPT + (isNew ? PROMPT_FOR_PROJECT_NAME : "");
301
  const userContext = "You are modifying the HTML file based on the user's request.";
302
 
303
- const getRelevantPages = (pages: Page[], prompt: string, maxPages: number = 2): Page[] => {
304
- if (pages.length <= maxPages) return pages;
305
-
306
- const indexPage = pages.find(p => p.path === '/' || p.path === '/index' || p.path === 'index');
307
- const otherPages = pages.filter(p => p !== indexPage);
308
-
309
- if (selectedElementHtml) {
310
- const elementKeywords = selectedElementHtml.toLowerCase().match(/class=["']([^"']*)["']|id=["']([^"']*)["']/g) || [];
311
- const relevantPages = otherPages.filter(page => {
312
- const pageContent = page.html.toLowerCase();
313
- return elementKeywords.some((keyword: string) => pageContent.includes(keyword.toLowerCase()));
314
- });
315
-
316
- return indexPage ? [indexPage, ...relevantPages.slice(0, maxPages - 1)] : relevantPages.slice(0, maxPages);
317
- }
318
-
319
- const keywords = prompt.toLowerCase().split(/\s+/).filter(word => word.length > 3);
320
- const scoredPages = otherPages.map(page => {
321
- const pageContent = (page.path + ' ' + page.html).toLowerCase();
322
- const score = keywords.reduce((acc, keyword) => {
323
- return acc + (pageContent.includes(keyword) ? 1 : 0);
324
- }, 0);
325
- return { page, score };
326
- });
327
-
328
- const topPages = scoredPages
329
- .sort((a, b) => b.score - a.score)
330
- .slice(0, maxPages - (indexPage ? 1 : 0))
331
- .map(item => item.page);
332
-
333
- return indexPage ? [indexPage, ...topPages] : topPages;
334
- };
335
-
336
- const relevantPages = getRelevantPages(pages || [], prompt);
337
- const pagesContext = relevantPages
338
  .map((p: Page) => `- ${p.path}\n${p.html}`)
339
  .join("\n\n");
340
 
@@ -342,7 +334,7 @@ export async function PUT(request: NextRequest) {
342
  selectedElementHtml
343
  ? `\n\nYou have to update ONLY the following element, NOTHING ELSE: \n\n\`\`\`html\n${selectedElementHtml}\n\`\`\` Could be in multiple pages, if so, update all the pages.`
344
  : ""
345
- }. Current pages (${relevantPages.length}/${pages?.length || 0} shown): ${pagesContext}. ${files?.length > 0 ? `Available images: ${files?.map((f: string) => f).join(', ')}.` : ""}`;
346
 
347
  const estimatedInputTokens = estimateInputTokens(systemPrompt, prompt, userContext + assistantContext);
348
  const dynamicMaxTokens = calculateMaxTokens(selectedProvider, estimatedInputTokens, false);
@@ -450,17 +442,49 @@ export async function PUT(request: NextRequest) {
450
  updatedLines.push([1, replaceBlock.split("\n").length]);
451
  } else {
452
  const regex = createFlexibleHtmlRegex(searchBlock);
453
- const match = regex.exec(pageHtml);
 
 
 
454
 
455
  if (match) {
456
- const matchedText = match[0];
457
- const beforeText = pageHtml.substring(0, match.index);
458
- const startLineNumber = beforeText.split("\n").length;
459
- const replaceLines = replaceBlock.split("\n").length;
460
- const endLineNumber = startLineNumber + replaceLines - 1;
461
-
462
- updatedLines.push([startLineNumber, endLineNumber]);
463
- pageHtml = pageHtml.replace(matchedText, replaceBlock);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
464
  }
465
  }
466
 
@@ -539,17 +563,54 @@ export async function PUT(request: NextRequest) {
539
  updatedLines.push([1, replaceBlock.split("\n").length]);
540
  } else {
541
  const regex = createFlexibleHtmlRegex(searchBlock);
542
- const match = regex.exec(newHtml);
 
 
 
 
 
 
 
 
 
543
 
544
  if (match) {
545
- const matchedText = match[0];
546
- const beforeText = newHtml.substring(0, match.index);
547
- const startLineNumber = beforeText.split("\n").length;
548
- const replaceLines = replaceBlock.split("\n").length;
549
- const endLineNumber = startLineNumber + replaceLines - 1;
550
-
551
- updatedLines.push([startLineNumber, endLineNumber]);
552
- newHtml = newHtml.replace(matchedText, replaceBlock);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
553
  }
554
  }
555
 
@@ -598,7 +659,6 @@ pinned: false
598
  tags:
599
  - deepsite-v3
600
  ---
601
-
602
  # Welcome to your new DeepSite project!
603
  This project was created with [DeepSite](https://deepsite.hf.co).
604
  `;
@@ -652,5 +712,4 @@ This project was created with [DeepSite](https://deepsite.hf.co).
652
  { status: 500 }
653
  );
654
  }
655
- }
656
-
 
285
  return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
286
  };
287
 
288
+ const normalizeHtml = (html: string): string => {
289
+ return html
290
+ // Normalize whitespace within tags
291
+ .replace(/\s+/g, ' ')
292
+ // Remove spaces before closing >
293
+ .replace(/\s+>/g, '>')
294
+ // Remove spaces before />
295
+ .replace(/\s+\/>/g, '/>')
296
+ // Normalize spaces around = in attributes
297
+ .replace(/\s*=\s*/g, '=')
298
+ // Normalize quotes (convert single to double)
299
+ .replace(/='([^']*)'/g, '="$1"')
300
+ // Remove trailing spaces in opening/closing tags
301
+ .replace(/<([^>]*?)\s+>/g, '<$1>')
302
+ // Normalize self-closing tags
303
+ .replace(/\/\s*>/g, '/>')
304
+ .trim();
305
+ };
306
+
307
  const createFlexibleHtmlRegex = (searchBlock: string) => {
308
+ // Normalize both the search block for comparison
309
+ const normalizedSearch = normalizeHtml(searchBlock);
310
+
311
+ // Escape regex special characters
312
+ let searchRegex = escapeRegExp(normalizedSearch)
313
+ // Make whitespace flexible (but only between elements, not within tags)
314
  .replace(/>\s*</g, '>\\s*<')
315
+ // Make line breaks and spaces around content flexible
316
+ .replace(/>\s*([^<]+)\s*</g, '>\\s*$1\\s*<');
317
 
318
  return new RegExp(searchRegex, 'g');
319
  };
 
324
  const systemPrompt = FOLLOW_UP_SYSTEM_PROMPT + (isNew ? PROMPT_FOR_PROJECT_NAME : "");
325
  const userContext = "You are modifying the HTML file based on the user's request.";
326
 
327
+ // Send all pages without filtering
328
+ const allPages = pages || [];
329
+ const pagesContext = allPages
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
330
  .map((p: Page) => `- ${p.path}\n${p.html}`)
331
  .join("\n\n");
332
 
 
334
  selectedElementHtml
335
  ? `\n\nYou have to update ONLY the following element, NOTHING ELSE: \n\n\`\`\`html\n${selectedElementHtml}\n\`\`\` Could be in multiple pages, if so, update all the pages.`
336
  : ""
337
+ }. Current pages (${allPages.length} total): ${pagesContext}. ${files?.length > 0 ? `Available images: ${files?.map((f: string) => f).join(', ')}.` : ""}`;
338
 
339
  const estimatedInputTokens = estimateInputTokens(systemPrompt, prompt, userContext + assistantContext);
340
  const dynamicMaxTokens = calculateMaxTokens(selectedProvider, estimatedInputTokens, false);
 
442
  updatedLines.push([1, replaceBlock.split("\n").length]);
443
  } else {
444
  const regex = createFlexibleHtmlRegex(searchBlock);
445
+
446
+ // Normalize the pageHtml for matching
447
+ const normalizedPageHtml = normalizeHtml(pageHtml);
448
+ const match = regex.exec(normalizedPageHtml);
449
 
450
  if (match) {
451
+ // Find the original match in the non-normalized HTML
452
+ const normalizedSearch = normalizeHtml(searchBlock);
453
+ const originalMatchIndex = pageHtml.indexOf(searchBlock);
454
+
455
+ if (originalMatchIndex !== -1) {
456
+ const beforeText = pageHtml.substring(0, originalMatchIndex);
457
+ const startLineNumber = beforeText.split("\n").length;
458
+ const replaceLines = replaceBlock.split("\n").length;
459
+ const endLineNumber = startLineNumber + replaceLines - 1;
460
+
461
+ updatedLines.push([startLineNumber, endLineNumber]);
462
+ pageHtml = pageHtml.replace(searchBlock, replaceBlock);
463
+ } else {
464
+ // Fallback: try to find similar pattern in the original HTML
465
+ const flexibleRegex = new RegExp(
466
+ escapeRegExp(searchBlock)
467
+ .replace(/\s+/g, '\\s+')
468
+ .replace(/\s*=\s*/g, '\\s*=\\s*')
469
+ .replace(/'\s*([^']*)\s*'/g, "'\\s*$1\\s*'")
470
+ .replace(/"\s*([^"]*)\s*"/g, '"\\s*$1\\s*"')
471
+ .replace(/\s*>/g, '\\s*>')
472
+ .replace(/\s*\/>/g, '\\s*/>'),
473
+ 'g'
474
+ );
475
+
476
+ const flexibleMatch = flexibleRegex.exec(pageHtml);
477
+ if (flexibleMatch) {
478
+ const matchedText = flexibleMatch[0];
479
+ const beforeText = pageHtml.substring(0, flexibleMatch.index);
480
+ const startLineNumber = beforeText.split("\n").length;
481
+ const replaceLines = replaceBlock.split("\n").length;
482
+ const endLineNumber = startLineNumber + replaceLines - 1;
483
+
484
+ updatedLines.push([startLineNumber, endLineNumber]);
485
+ pageHtml = pageHtml.replace(matchedText, replaceBlock);
486
+ }
487
+ }
488
  }
489
  }
490
 
 
563
  updatedLines.push([1, replaceBlock.split("\n").length]);
564
  } else {
565
  const regex = createFlexibleHtmlRegex(searchBlock);
566
+
567
+ // Get the main page HTML (first page or index page)
568
+ const mainPage = updatedPages.find(p => p.path === '/' || p.path === '/index' || p.path === 'index') || updatedPages[0];
569
+ if (!mainPage) continue;
570
+
571
+ newHtml = mainPage.html;
572
+
573
+ // Normalize the newHtml for matching
574
+ const normalizedNewHtml = normalizeHtml(newHtml);
575
+ const match = regex.exec(normalizedNewHtml);
576
 
577
  if (match) {
578
+ // Find the original match in the non-normalized HTML
579
+ const originalMatchIndex = newHtml.indexOf(searchBlock);
580
+
581
+ if (originalMatchIndex !== -1) {
582
+ const beforeText = newHtml.substring(0, originalMatchIndex);
583
+ const startLineNumber = beforeText.split("\n").length;
584
+ const replaceLines = replaceBlock.split("\n").length;
585
+ const endLineNumber = startLineNumber + replaceLines - 1;
586
+
587
+ updatedLines.push([startLineNumber, endLineNumber]);
588
+ newHtml = newHtml.replace(searchBlock, replaceBlock);
589
+ } else {
590
+ // Fallback: try to find similar pattern in the original HTML
591
+ const flexibleRegex = new RegExp(
592
+ escapeRegExp(searchBlock)
593
+ .replace(/\s+/g, '\\s+')
594
+ .replace(/\s*=\s*/g, '\\s*=\\s*')
595
+ .replace(/'\s*([^']*)\s*'/g, "'\\s*$1\\s*'")
596
+ .replace(/"\s*([^"]*)\s*"/g, '"\\s*$1\\s*"')
597
+ .replace(/\s*>/g, '\\s*>')
598
+ .replace(/\s*\/>/g, '\\s*/>'),
599
+ 'g'
600
+ );
601
+
602
+ const flexibleMatch = flexibleRegex.exec(newHtml);
603
+ if (flexibleMatch) {
604
+ const matchedText = flexibleMatch[0];
605
+ const beforeText = newHtml.substring(0, flexibleMatch.index);
606
+ const startLineNumber = beforeText.split("\n").length;
607
+ const replaceLines = replaceBlock.split("\n").length;
608
+ const endLineNumber = startLineNumber + replaceLines - 1;
609
+
610
+ updatedLines.push([startLineNumber, endLineNumber]);
611
+ newHtml = newHtml.replace(matchedText, replaceBlock);
612
+ }
613
+ }
614
  }
615
  }
616
 
 
659
  tags:
660
  - deepsite-v3
661
  ---
 
662
  # Welcome to your new DeepSite project!
663
  This project was created with [DeepSite](https://deepsite.hf.co).
664
  `;
 
712
  { status: 500 }
713
  );
714
  }
715
+ }
 
hooks/useAi.ts CHANGED
@@ -10,7 +10,6 @@ import { api } from "@/lib/api";
10
  import { useRouter } from "next/navigation";
11
  import { useUser } from "./useUser";
12
  import { LivePreviewRef } from "@/components/editor/live-preview";
13
- import { isTheSameHtml } from "@/lib/compare-html-diff";
14
 
15
  export const useAi = (onScrollToBottom?: () => void, livePreviewRef?: React.RefObject<LivePreviewRef | null>) => {
16
  const client = useQueryClient();
@@ -199,15 +198,10 @@ export const useAi = (onScrollToBottom?: () => void, livePreviewRef?: React.RefO
199
  }
200
 
201
  const newPages = formatPages(contentResponse);
202
- let projectName = contentResponse.match(/<<<<<<< PROJECT_NAME_START ([\s\S]*?) >>>>>>> PROJECT_NAME_END/)?.[1]?.trim();
203
- if (!projectName) {
204
- projectName = prompt.substring(0, 40).replace(/[^a-zA-Z0-9]/g, "-").slice(0, 40);
205
- }
206
  setPages(newPages);
207
- setLastSavedPages([...newPages]);
208
- if (newPages.length > 0 && !isTheSameHtml(newPages[0].html)) {
209
- createNewProject(prompt, newPages, projectName, isLoggedIn);
210
- }
211
  setPrompts([...prompts, prompt]);
212
 
213
  return { success: true, pages: newPages };
 
10
  import { useRouter } from "next/navigation";
11
  import { useUser } from "./useUser";
12
  import { LivePreviewRef } from "@/components/editor/live-preview";
 
13
 
14
  export const useAi = (onScrollToBottom?: () => void, livePreviewRef?: React.RefObject<LivePreviewRef | null>) => {
15
  const client = useQueryClient();
 
198
  }
199
 
200
  const newPages = formatPages(contentResponse);
201
+ const projectName = contentResponse.match(/<<<<<<< PROJECT_NAME_START ([\s\S]*?) >>>>>>> PROJECT_NAME_END/)?.[1]?.trim();
 
 
 
202
  setPages(newPages);
203
+ setLastSavedPages([...newPages]); // Mark initial pages as saved
204
+ createNewProject(prompt, newPages, projectName, isLoggedIn);
 
 
205
  setPrompts([...prompts, prompt]);
206
 
207
  return { success: true, pages: newPages };