word-to-code / pages /index.js
tinazone's picture
Upload 44 files
21d7fc3 verified
raw
history blame
6.17 kB
import { useState } from 'react';
import Script from 'next/script';
import { Inter } from 'next/font/google';
import SketchRenderer from '../components/SketchRenderer';
import GenerationForm from '../components/GenerationForm';
import CodePanel from '../components/CodePanel';
import { initialSketch, examples, exampleReasonings } from '../sketches';
const inter = Inter({
subsets: ['latin'],
variable: '--font-inter',
});
export default function Home() {
const [word, setWord] = useState('');
const [instructions, setInstructions] = useState('');
const [isGenerating, setIsGenerating] = useState(false);
const [generatedCode, setGeneratedCode] = useState(initialSketch);
const [showCodePanel, setShowCodePanel] = useState(false);
const [error, setError] = useState(null);
const [activeExample, setActiveExample] = useState(null);
const [showExamples, setShowExamples] = useState(false);
const [modelResponse, setModelResponse] = useState('');
const [showSystemPrompt, setShowSystemPrompt] = useState(false);
const [isCapturingGif, setIsCapturingGif] = useState(false);
const handleExampleClick = (example) => {
setActiveExample(example);
setGeneratedCode(examples[example]);
setShowCodePanel(true);
setModelResponse(exampleReasonings[example]);
};
const handleSubmit = async (e) => {
e.preventDefault();
setIsGenerating(true);
setError(null);
setActiveExample(null);
try {
const response = await fetch('/api/generate', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ word, instructions }),
});
const data = await response.json();
if (!response.ok) {
throw new Error(data.message || `API error: ${response.status}`);
}
if (!data || data.error) {
throw new Error(data.error || 'No data received from API');
}
if (!data.code || !data.code.includes('function setup()')) {
throw new Error('Generated code is not in the correct format');
}
setGeneratedCode(data.code);
setModelResponse(data.fullResponse || '');
setShowCodePanel(true);
} catch (error) {
console.error('Generation error:', error);
setError(error.message);
} finally {
setIsGenerating(false);
}
};
const handleReplay = () => {
setGeneratedCode(prevCode => prevCode + ' ');
requestAnimationFrame(() => {
setGeneratedCode(prevCode => prevCode.slice(0, -1));
});
};
const handleGifCapture = async (startCapture) => {
if (startCapture) {
setIsCapturingGif(true);
try {
const iframe = document.getElementById('sketch-iframe');
if (iframe) {
iframe.contentWindow.postMessage({ type: 'startGifCapture' }, '*');
}
} catch (error) {
console.error('GIF capture error:', error);
setIsCapturingGif(false);
}
} else {
setIsCapturingGif(false);
}
};
return (
<div className={`min-h-screen bg-white text-black flex flex-col items-center p-4 sm:p-8 ${inter.variable}`}>
<Script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.9.0/p5.js" strategy="beforeInteractive" />
<header className="w-full flex items-center mb-8 pl-4 sm:pl-8">
<div className="flex items-center gap-2">
<h1
className="text-xl font-medium cursor-pointer hover:opacity-80 transition-opacity"
onClick={() => window.location.reload()}
>
Word to Code
</h1>
<div className="text-sm text-gray-500">
Built with <a href="https://ai.google.dev/docs" target="_blank" rel="noopener noreferrer" className="underline hover:text-black">Gemini 2.0</a>
</div>
</div>
</header>
<main className={`w-full max-w-[1200px] flex flex-col gap-6 mx-auto transition-all duration-500 ease-in-out ${showCodePanel ? '' : 'items-center'}`}>
<div className={`flex flex-col lg:flex-row gap-8 items-start w-full transition-all duration-500 ease-in-out ${
showCodePanel ? 'justify-center translate-x-0' : 'justify-center'
}`}>
<div className={`flex flex-col gap-6 w-full max-w-[500px] transition-all duration-500 ease-in-out ${showCodePanel ? '' : 'items-center'}`}>
<SketchRenderer
generatedCode={generatedCode}
isGenerating={isGenerating}
error={error}
showCodePanel={showCodePanel}
onReplay={handleReplay}
onGifCapture={handleGifCapture}
isCapturingGif={isCapturingGif}
isInitialSketch={generatedCode === initialSketch}
/>
<GenerationForm
word={word}
setWord={setWord}
instructions={instructions}
setInstructions={setInstructions}
isGenerating={isGenerating}
showSystemPrompt={showSystemPrompt}
setShowSystemPrompt={setShowSystemPrompt}
showExamples={showExamples}
setShowExamples={setShowExamples}
activeExample={activeExample}
handleExampleClick={handleExampleClick}
onSubmit={handleSubmit}
/>
</div>
{showCodePanel && (
<CodePanel
modelResponse={modelResponse}
generatedCode={generatedCode}
/>
)}
</div>
</main>
<style jsx global>{`
::-webkit-scrollbar {
display: none;
}
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@media (min-width: 1024px) {
@keyframes fadeIn {
from {
opacity: 0;
transform: translateX(10px);
}
to {
opacity: 1;
transform: translateX(0);
}
}
}
`}</style>
</div>
);
}