Select a component, customize it with AI, and copy the code to your website in seconds.
Live Preview
Generated Code
`;iframe.srcdoc = iframeContent;
previewContainer.appendChild(iframe);// Resize iframe after content is loaded to fit content
iframe.onload = () => {
try {
const body = iframe.contentDocument.body;
const html = iframe.contentDocument.documentElement;
const height = Math.max( body.scrollHeight, body.offsetHeight,
html.clientHeight, html.scrollHeight, html.offsetHeight );
previewContainer.style.height = `${height}px`;
} catch (e) {
console.error("Error resizing iframe:", e);
// Provide a fallback height if calculation fails
previewContainer.style.height = '400px';
}
};
}
// --- Core Functions ---
function generateComponent(componentKey) {
const template = componentTemplates[componentKey].trim();
updateDisplay(template);
}async function fetchWithRetry(url, options, retries = 3, delay = 1000) {
for (let i = 0; i < retries; i++) {
try {
const response = await fetch(url, options);
if (!response.ok) {
// Don't retry on client-side errors (4xx), only server-side (5xx) or network errors
if (response.status >= 400 && response.status < 500) {
throw new Error(`Client Error: ${response.status} ${response.statusText}`);
}
// Otherwise, it's a server error, so we can retry
throw new Error(`Server Error: ${response.status} ${response.statusText}`);
}
return response;
} catch (error) {
if (i === retries - 1) throw error; // Last attempt, rethrow
console.log(`Attempt ${i + 1} failed. Retrying in ${delay}ms...`);
await new Promise(res => setTimeout(res, delay));
delay *= 2; // Exponential backoff
}
}
}async function generateWithAI() {
const userPrompt = aiPrompt.value;
if (!userPrompt.trim()) {
aiError.textContent = "Please enter a description.";
aiError.classList.remove('hidden');
return;
}const currentCode = codeOutput.textContent;
setLoadingState(true);const systemPrompt = `You are an expert web developer specializing in Tailwind CSS. Your task is to modify the provided HTML code based on the user's request.
- ONLY respond with the updated HTML code block.
- Do NOT add any explanations, introductions, or extra text.
- Maintain the existing structure and Tailwind CSS classes as much as possible, only changing the content (text, image placeholders, etc.) as requested.
- For images, use placehold.co for placeholders, like 'https://placehold.co/600x400/1e293b/ffffff?text=My+Image'.`;const payload = {
contents: [{
parts: [{ text: `User request: "${userPrompt}"\n\nExisting HTML:\n\`\`\`html\n${currentCode}\n\`\`\`` }]
}],
systemInstruction: {
parts: [{ text: systemPrompt }]
}
};try {
const response = await fetchWithRetry(API_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload)
});const result = await response.json();
const candidate = result.candidates?.[0];if (candidate && candidate.content?.parts?.[0]?.text) {
let generatedText = candidate.content.parts[0].text;
// Clean the response to get only the HTML
const htmlMatch = generatedText.match(/```html([\s\S]*?)```/);
if(htmlMatch && htmlMatch[1]) {
generatedText = htmlMatch[1].trim();
} else {
// If no code block found, assume the whole response is code, but remove backticks
generatedText = generatedText.replace(/```/g, "").trim();
}// Validate the cleaned response to ensure it looks like a valid component
if (!generatedText || !generatedText.startsWith(')?$/gm,"$1")],{type:"text/javascript"}))}catch(e){d="data:text/javascript;base64,"+btoa(t.replace(/^(?:)?$/gm,"$1"))}return d}