Spaces:
Running
Running
Update app/(main)/page.tsx
Browse files- app/(main)/page.tsx +34 -101
app/(main)/page.tsx
CHANGED
|
@@ -41,9 +41,7 @@ export default function Home() {
|
|
| 41 |
model: "",
|
| 42 |
});
|
| 43 |
let [ref, scrollTo] = useScrollTo();
|
| 44 |
-
let [messages, setMessages] = useState<{ role: string; content: string }[]>(
|
| 45 |
-
[],
|
| 46 |
-
);
|
| 47 |
|
| 48 |
let loading = status === "creating" || status === "updating";
|
| 49 |
|
|
@@ -57,41 +55,44 @@ export default function Home() {
|
|
| 57 |
setStatus("creating");
|
| 58 |
setGeneratedCode("");
|
| 59 |
|
| 60 |
-
|
| 61 |
-
|
| 62 |
-
|
| 63 |
-
|
| 64 |
-
|
| 65 |
-
|
| 66 |
-
|
| 67 |
-
|
| 68 |
-
|
| 69 |
-
|
| 70 |
-
|
| 71 |
-
|
| 72 |
-
|
| 73 |
-
|
|
|
|
| 74 |
|
| 75 |
-
|
| 76 |
-
|
| 77 |
-
|
| 78 |
|
| 79 |
-
|
| 80 |
-
|
| 81 |
|
| 82 |
-
|
| 83 |
-
|
| 84 |
-
|
| 85 |
-
|
|
|
|
|
|
|
| 86 |
}
|
| 87 |
-
receivedData += new TextDecoder().decode(value);
|
| 88 |
-
const cleanedData = removeCodeFormatting(receivedData);
|
| 89 |
-
setGeneratedCode(cleanedData);
|
| 90 |
-
}
|
| 91 |
|
| 92 |
-
|
| 93 |
-
|
| 94 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 95 |
}
|
| 96 |
|
| 97 |
useEffect(() => {
|
|
@@ -147,54 +148,9 @@ export default function Home() {
|
|
| 147 |
</button>
|
| 148 |
</div>
|
| 149 |
</div>
|
| 150 |
-
<div className="mt-6 flex flex-col justify-center gap-4 sm:flex-row sm:items-center sm:gap-8">
|
| 151 |
-
<div className="flex items-center justify-between gap-3 sm:justify-center">
|
| 152 |
-
<p className="text-gray-500 dark:text-gray-400 sm:text-xs">Model:</p>
|
| 153 |
-
<Select.Root
|
| 154 |
-
name="model"
|
| 155 |
-
disabled={loading}
|
| 156 |
-
value={model}
|
| 157 |
-
onValueChange={(value) => setModel(value)}
|
| 158 |
-
>
|
| 159 |
-
<Select.Trigger className="group flex w-60 max-w-xs items-center rounded-2xl border-[6px] border-gray-300 dark:border-gray-700 bg-white dark:bg-[#1E293B] px-4 py-2 text-sm focus-visible:outline focus-visible:outline-2 focus-visible:outline-blue-500">
|
| 160 |
-
<Select.Value />
|
| 161 |
-
<Select.Icon className="ml-auto">
|
| 162 |
-
<ChevronDownIcon className="size-6 text-gray-300 group-focus-visible:text-gray-500 group-enabled:group-hover:text-gray-500 dark:text-gray-600 dark:group-focus-visible:text-gray-400 dark:group-enabled:group-hover:text-gray-400" />
|
| 163 |
-
</Select.Icon>
|
| 164 |
-
</Select.Trigger>
|
| 165 |
-
<Select.Portal>
|
| 166 |
-
<Select.Content className="overflow-hidden rounded-md bg-white dark:bg-[#1E293B] shadow-lg">
|
| 167 |
-
<Select.Viewport className="p-2">
|
| 168 |
-
{models.map((model) => (
|
| 169 |
-
<Select.Item
|
| 170 |
-
key={model.value}
|
| 171 |
-
value={model.value}
|
| 172 |
-
className="flex cursor-pointer items-center rounded-md px-3 py-2 text-sm data-[highlighted]:bg-gray-100 dark:data-[highlighted]:bg-gray-800 data-[highlighted]:outline-none"
|
| 173 |
-
>
|
| 174 |
-
<Select.ItemText asChild>
|
| 175 |
-
<span className="inline-flex items-center gap-2 text-gray-500 dark:text-gray-400">
|
| 176 |
-
<div className="size-2 rounded-full bg-green-500" />
|
| 177 |
-
{model.label}
|
| 178 |
-
</span>
|
| 179 |
-
</Select.ItemText>
|
| 180 |
-
<Select.ItemIndicator className="ml-auto">
|
| 181 |
-
<CheckIcon className="size-5 text-blue-600" />
|
| 182 |
-
</Select.ItemIndicator>
|
| 183 |
-
</Select.Item>
|
| 184 |
-
))}
|
| 185 |
-
</Select.Viewport>
|
| 186 |
-
<Select.ScrollDownButton />
|
| 187 |
-
<Select.Arrow />
|
| 188 |
-
</Select.Content>
|
| 189 |
-
</Select.Portal>
|
| 190 |
-
</Select.Root>
|
| 191 |
-
</div>
|
| 192 |
-
</div>
|
| 193 |
</fieldset>
|
| 194 |
</form>
|
| 195 |
|
| 196 |
-
<hr className="border-1 mb-20 h-px bg-gray-700 dark:bg-gray-700/30" />
|
| 197 |
-
|
| 198 |
{status !== "initial" && (
|
| 199 |
<motion.div
|
| 200 |
initial={{ height: 0 }}
|
|
@@ -212,29 +168,6 @@ export default function Home() {
|
|
| 212 |
<div className="isolate">
|
| 213 |
<CodeViewer code={generatedCode} showEditor />
|
| 214 |
</div>
|
| 215 |
-
|
| 216 |
-
<AnimatePresence>
|
| 217 |
-
{loading && (
|
| 218 |
-
<motion.div
|
| 219 |
-
initial={status === "updating" ? { x: "100%" } : undefined}
|
| 220 |
-
animate={status === "updating" ? { x: "0%" } : undefined}
|
| 221 |
-
exit={{ x: "100%" }}
|
| 222 |
-
transition={{
|
| 223 |
-
type: "spring",
|
| 224 |
-
bounce: 0,
|
| 225 |
-
duration: 0.85,
|
| 226 |
-
delay: 0.5,
|
| 227 |
-
}}
|
| 228 |
-
className="absolute inset-x-0 bottom-0 top-1/2 flex items-center justify-center rounded-r border border-gray-400 dark:border-gray-700 bg-gradient-to-br from-gray-100 to-gray-300 dark:from-[#1E293B] dark:to-gray-800 md:inset-y-0 md:left-1/2 md:right-0"
|
| 229 |
-
>
|
| 230 |
-
<p className="animate-pulse text-3xl font-bold dark:text-gray-100">
|
| 231 |
-
{status === "creating"
|
| 232 |
-
? "Building your app..."
|
| 233 |
-
: "Updating your app..."}
|
| 234 |
-
</p>
|
| 235 |
-
</motion.div>
|
| 236 |
-
)}
|
| 237 |
-
</AnimatePresence>
|
| 238 |
</div>
|
| 239 |
</motion.div>
|
| 240 |
)}
|
|
|
|
| 41 |
model: "",
|
| 42 |
});
|
| 43 |
let [ref, scrollTo] = useScrollTo();
|
| 44 |
+
let [messages, setMessages] = useState<{ role: string; content: string }[]>([]);
|
|
|
|
|
|
|
| 45 |
|
| 46 |
let loading = status === "creating" || status === "updating";
|
| 47 |
|
|
|
|
| 55 |
setStatus("creating");
|
| 56 |
setGeneratedCode("");
|
| 57 |
|
| 58 |
+
try {
|
| 59 |
+
let res = await fetch("/api/generateCode", {
|
| 60 |
+
method: "POST",
|
| 61 |
+
headers: {
|
| 62 |
+
"Content-Type": "application/json",
|
| 63 |
+
},
|
| 64 |
+
body: JSON.stringify({
|
| 65 |
+
model,
|
| 66 |
+
messages: [{ role: "user", content: prompt }],
|
| 67 |
+
}),
|
| 68 |
+
});
|
| 69 |
+
|
| 70 |
+
if (!res.ok) {
|
| 71 |
+
throw new Error(res.statusText || `HTTP error: ${res.status}`);
|
| 72 |
+
}
|
| 73 |
|
| 74 |
+
if (!res.body) {
|
| 75 |
+
throw new Error("No response body");
|
| 76 |
+
}
|
| 77 |
|
| 78 |
+
const reader = res.body.getReader();
|
| 79 |
+
let receivedData = "";
|
| 80 |
|
| 81 |
+
while (true) {
|
| 82 |
+
const { done, value } = await reader.read();
|
| 83 |
+
if (done) break;
|
| 84 |
+
receivedData += new TextDecoder().decode(value);
|
| 85 |
+
const cleanedData = removeCodeFormatting(receivedData);
|
| 86 |
+
setGeneratedCode(cleanedData);
|
| 87 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
| 88 |
|
| 89 |
+
setMessages([{ role: "user", content: prompt }]);
|
| 90 |
+
setInitialAppConfig({ model });
|
| 91 |
+
setStatus("created");
|
| 92 |
+
} catch (error) {
|
| 93 |
+
console.error("Error al generar la aplicaci贸n:", error);
|
| 94 |
+
setStatus("initial");
|
| 95 |
+
}
|
| 96 |
}
|
| 97 |
|
| 98 |
useEffect(() => {
|
|
|
|
| 148 |
</button>
|
| 149 |
</div>
|
| 150 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 151 |
</fieldset>
|
| 152 |
</form>
|
| 153 |
|
|
|
|
|
|
|
| 154 |
{status !== "initial" && (
|
| 155 |
<motion.div
|
| 156 |
initial={{ height: 0 }}
|
|
|
|
| 168 |
<div className="isolate">
|
| 169 |
<CodeViewer code={generatedCode} showEditor />
|
| 170 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 171 |
</div>
|
| 172 |
</motion.div>
|
| 173 |
)}
|