Spaces:
Running
Running
Update script.js
Browse files
script.js
CHANGED
@@ -54,6 +54,11 @@ let modalThinkingBudgetSliderEl, modalThinkingBudgetValueDisplayEl;
|
|
54 |
let promptDisplayModalOverlayEl, promptDisplayModalContentEl, fullPromptTextEl, promptDisplayModalCloseBtnEl;
|
55 |
let showPromptModalButtonEl; // Added for the new button
|
56 |
|
|
|
|
|
|
|
|
|
|
|
57 |
|
58 |
// --- Constants ---
|
59 |
const API_BASE_URL = 'https://generativelanguage.googleapis.com/v1beta/models/';
|
@@ -282,7 +287,20 @@ async function generateVariations() {
|
|
282 |
return;
|
283 |
}
|
284 |
|
285 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
286 |
const selectedModel = modelSelEl.value;
|
287 |
const currentIsRefinementMode = modalRefinementCheckboxEl.checked;
|
288 |
const currentNumVariations = parseInt(numVariationsSliderEl.value, 10);
|
@@ -290,7 +308,11 @@ async function generateVariations() {
|
|
290 |
|
291 |
if (!apiKey || !userPrompt) {
|
292 |
errorMessageEl.textContent = 'Error: API Key and Prompt (via Alt+P) are required.';
|
293 |
-
if (!
|
|
|
|
|
|
|
|
|
294 |
return;
|
295 |
}
|
296 |
if (!selectedModel) {
|
@@ -320,6 +342,10 @@ async function generateVariations() {
|
|
320 |
console.log(`Refining Evolution ${activeTimelineIndex + 1}. Original context: "${contextPromptForRefinement}"`);
|
321 |
} else if (currentIsRefinementMode) {
|
322 |
errorMessageEl.textContent = 'Error: No active evolution selected to refine. Uncheck "refine" or select an evolution from history.';
|
|
|
|
|
|
|
|
|
323 |
return;
|
324 |
}
|
325 |
|
@@ -339,6 +365,20 @@ async function generateVariations() {
|
|
339 |
fullscreenButtons = Array(numVariationsToGenerate).fill(null);
|
340 |
previewItems = Array(numVariationsToGenerate).fill(null);
|
341 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
342 |
|
343 |
showFourGridPreviewUI();
|
344 |
|
@@ -501,6 +541,20 @@ function showSingleLargePreviewUI(htmlContent, titleText, fullPromptText) {
|
|
501 |
previewGridWrapperEl.className = 'single-mode';
|
502 |
if(perspectiveViewportEl) perspectiveViewportEl.style.perspective = 'none';
|
503 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
504 |
const item = document.createElement('div');
|
505 |
item.className = 'single-preview-item';
|
506 |
|
@@ -533,18 +587,52 @@ function showSingleLargePreviewUI(htmlContent, titleText, fullPromptText) {
|
|
533 |
}
|
534 |
|
535 |
function showInitialPreviewStateUI() {
|
536 |
-
|
537 |
-
previewGridWrapperEl.
|
538 |
-
if(perspectiveViewportEl) perspectiveViewportEl.
|
539 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
540 |
if (codeOutputEl) codeOutputEl.innerHTML = '<code class="language-html">// Select a variation or history item to view its code.</code>';
|
541 |
if (selectedCodeTitleH3El) selectedCodeTitleH3El.textContent = "Selected Code:";
|
542 |
selectedVariationGridIndex = -1;
|
543 |
-
// Reset subtitle state when going back to initial view
|
544 |
if (mainContentSubtitleH2El) {
|
545 |
mainContentSubtitleH2El.classList.remove('prompt-truncated');
|
546 |
delete mainContentSubtitleH2El.dataset.fullPrompt;
|
547 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
548 |
}
|
549 |
|
550 |
function updateMainContentTitles(title, subtitle) {
|
@@ -1196,10 +1284,15 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
1196 |
promptDisplayModalCloseBtnEl = document.getElementById('prompt-display-modal-close-button');
|
1197 |
showPromptModalButtonEl = document.getElementById('show-prompt-modal-button'); // Added
|
1198 |
|
|
|
|
|
|
|
|
|
|
|
1199 |
|
1200 |
// --- Check if all required elements exist ---
|
1201 |
let missingElements = [];
|
1202 |
-
const requiredElements = { apiKeyEl, modelSelEl, codeOutputEl, errorMessageEl, refinementLoadingIndicator, mainContentEl, configButtonEl, intervalSliderEl, intervalValueDisplayEl, fullscreenOverlayEl, fullscreenIframeEl, exitFullscreenBtnEl, perspectiveViewportEl, previewGridWrapperEl, historyPanelEl, historyPanelPlaceholderEl, selectedCodeTitleH3El, mainContentTitleH1El, mainContentSubtitleH2El, fullscreenHistoryNavEl, historyNavPrevBtnEl, historyNavNextBtnEl, promptModalOverlayEl, promptModalContentEl, modalUserPromptEl, modalGenerateBtnEl, modalCancelBtnEl, modalLoadingIndicatorEl, modalRefinementCheckboxEl, numVariationsSliderEl, numVariationsValueDisplayEl, configModalOverlayEl, configModalContentEl, configModalCloseBtnEl, copyCodeButtonEl, exportCodeButtonEl, historyToggleButtonEl, historyArrowDownEl, historyArrowUpEl, newButtonEl, confirmModalOverlayEl, confirmModalMessageEl, confirmModalConfirmBtnEl, confirmModalCancelBtnEl, historyNavLeftBtnEl, historyNavRightBtnEl, modalThinkingBudgetSliderEl, modalThinkingBudgetValueDisplayEl, promptDisplayModalOverlayEl, promptDisplayModalContentEl, fullPromptTextEl, promptDisplayModalCloseBtnEl, showPromptModalButtonEl }; // Added showPromptModalButtonEl
|
1203 |
for (const key in requiredElements) { if (!requiredElements[key]) { missingElements.push(key); } }
|
1204 |
|
1205 |
if (missingElements.length > 0) {
|
|
|
54 |
let promptDisplayModalOverlayEl, promptDisplayModalContentEl, fullPromptTextEl, promptDisplayModalCloseBtnEl;
|
55 |
let showPromptModalButtonEl; // Added for the new button
|
56 |
|
57 |
+
// --- Elements for Initial Setup CTA ---
|
58 |
+
let initialSetupCtaEl;
|
59 |
+
let initialApiKeyInputEl;
|
60 |
+
let examplePromptsContainerEl;
|
61 |
+
|
62 |
|
63 |
// --- Constants ---
|
64 |
const API_BASE_URL = 'https://generativelanguage.googleapis.com/v1beta/models/';
|
|
|
287 |
return;
|
288 |
}
|
289 |
|
290 |
+
// Read API key: Prefer config modal, then initial input, then localStorage
|
291 |
+
let apiKey = apiKeyEl.value.trim();
|
292 |
+
if (!apiKey && initialApiKeyInputEl) {
|
293 |
+
apiKey = initialApiKeyInputEl.value.trim();
|
294 |
+
}
|
295 |
+
if (!apiKey) {
|
296 |
+
apiKey = localStorage.getItem('geminiApiKey') || '';
|
297 |
+
}
|
298 |
+
|
299 |
+
// Update input fields with the resolved API key
|
300 |
+
if (apiKeyEl && apiKeyEl.value !== apiKey) apiKeyEl.value = apiKey;
|
301 |
+
if (initialApiKeyInputEl && initialApiKeyInputEl.value !== apiKey) initialApiKeyInputEl.value = apiKey;
|
302 |
+
|
303 |
+
|
304 |
const selectedModel = modelSelEl.value;
|
305 |
const currentIsRefinementMode = modalRefinementCheckboxEl.checked;
|
306 |
const currentNumVariations = parseInt(numVariationsSliderEl.value, 10);
|
|
|
308 |
|
309 |
if (!apiKey || !userPrompt) {
|
310 |
errorMessageEl.textContent = 'Error: API Key and Prompt (via Alt+P) are required.';
|
311 |
+
if (!apiKey && initialSetupCtaEl && initialSetupCtaEl.classList.contains('flex')) {
|
312 |
+
if(initialApiKeyInputEl) initialApiKeyInputEl.focus();
|
313 |
+
} else if (!userPrompt && !promptModalOverlayEl.classList.contains('visible')) {
|
314 |
+
showPromptModal();
|
315 |
+
}
|
316 |
return;
|
317 |
}
|
318 |
if (!selectedModel) {
|
|
|
342 |
console.log(`Refining Evolution ${activeTimelineIndex + 1}. Original context: "${contextPromptForRefinement}"`);
|
343 |
} else if (currentIsRefinementMode) {
|
344 |
errorMessageEl.textContent = 'Error: No active evolution selected to refine. Uncheck "refine" or select an evolution from history.';
|
345 |
+
// Also hide the initial CTA if it's somehow visible
|
346 |
+
if (initialSetupCtaEl) initialSetupCtaEl.classList.add('hidden');
|
347 |
+
if (initialSetupCtaEl) initialSetupCtaEl.classList.remove('flex');
|
348 |
+
if (previewGridWrapperEl) previewGridWrapperEl.classList.remove('hidden');
|
349 |
return;
|
350 |
}
|
351 |
|
|
|
365 |
fullscreenButtons = Array(numVariationsToGenerate).fill(null);
|
366 |
previewItems = Array(numVariationsToGenerate).fill(null);
|
367 |
|
368 |
+
// Ensure correct layout state for generation
|
369 |
+
if (initialSetupCtaEl) {
|
370 |
+
initialSetupCtaEl.classList.remove('active-cta'); // Start hide animation
|
371 |
+
// Hide example prompt buttons immediately or animate them out too
|
372 |
+
if (examplePromptsContainerEl) {
|
373 |
+
examplePromptsContainerEl.querySelectorAll('.example-prompt-button').forEach(btn => btn.classList.remove('visible'));
|
374 |
+
}
|
375 |
+
setTimeout(() => { // Wait for animation to roughly finish
|
376 |
+
initialSetupCtaEl.style.display = 'none';
|
377 |
+
initialSetupCtaEl.classList.remove('flex', 'flex-grow');
|
378 |
+
}, 500); // Corresponds to CSS transition duration
|
379 |
+
}
|
380 |
+
if (perspectiveViewportEl) perspectiveViewportEl.classList.remove('hidden');
|
381 |
+
// previewGridWrapperEl will be managed by showFourGridPreviewUI
|
382 |
|
383 |
showFourGridPreviewUI();
|
384 |
|
|
|
541 |
previewGridWrapperEl.className = 'single-mode';
|
542 |
if(perspectiveViewportEl) perspectiveViewportEl.style.perspective = 'none';
|
543 |
|
544 |
+
// Ensure correct layout state for single preview
|
545 |
+
if (initialSetupCtaEl) {
|
546 |
+
initialSetupCtaEl.classList.remove('active-cta');
|
547 |
+
if (examplePromptsContainerEl) {
|
548 |
+
examplePromptsContainerEl.querySelectorAll('.example-prompt-button').forEach(btn => btn.classList.remove('visible'));
|
549 |
+
}
|
550 |
+
setTimeout(() => {
|
551 |
+
initialSetupCtaEl.style.display = 'none';
|
552 |
+
initialSetupCtaEl.classList.remove('flex', 'flex-grow');
|
553 |
+
}, 500);
|
554 |
+
}
|
555 |
+
if (perspectiveViewportEl) perspectiveViewportEl.classList.remove('hidden');
|
556 |
+
if (previewGridWrapperEl) previewGridWrapperEl.classList.remove('hidden');
|
557 |
+
|
558 |
const item = document.createElement('div');
|
559 |
item.className = 'single-preview-item';
|
560 |
|
|
|
587 |
}
|
588 |
|
589 |
function showInitialPreviewStateUI() {
|
590 |
+
// Hide the main preview grid and show the initial CTA
|
591 |
+
if (previewGridWrapperEl) previewGridWrapperEl.classList.add('hidden');
|
592 |
+
if (perspectiveViewportEl) perspectiveViewportEl.classList.add('hidden'); // Hide the whole viewport
|
593 |
+
|
594 |
+
if (initialSetupCtaEl) {
|
595 |
+
initialSetupCtaEl.style.display = 'flex'; // Set display before animation
|
596 |
+
initialSetupCtaEl.classList.add('flex-grow');
|
597 |
+
// Use requestAnimationFrame to ensure display:flex is applied before adding class for transition
|
598 |
+
requestAnimationFrame(() => {
|
599 |
+
initialSetupCtaEl.classList.add('active-cta');
|
600 |
+
});
|
601 |
+
}
|
602 |
+
|
603 |
+
updateMainContentTitles("Welcome to Live Previews", "Set up your API Key or try an example below.");
|
604 |
if (codeOutputEl) codeOutputEl.innerHTML = '<code class="language-html">// Select a variation or history item to view its code.</code>';
|
605 |
if (selectedCodeTitleH3El) selectedCodeTitleH3El.textContent = "Selected Code:";
|
606 |
selectedVariationGridIndex = -1;
|
|
|
607 |
if (mainContentSubtitleH2El) {
|
608 |
mainContentSubtitleH2El.classList.remove('prompt-truncated');
|
609 |
delete mainContentSubtitleH2El.dataset.fullPrompt;
|
610 |
}
|
611 |
+
|
612 |
+
// Populate example prompts
|
613 |
+
if (examplePromptsContainerEl) {
|
614 |
+
examplePromptsContainerEl.innerHTML = ''; // Clear existing
|
615 |
+
const prompts = [
|
616 |
+
"A simple landing page for a new SaaS product.",
|
617 |
+
"A responsive image gallery with a lightbox.",
|
618 |
+
"A futuristic login form.",
|
619 |
+
"A personal portfolio website with a blog section."
|
620 |
+
];
|
621 |
+
prompts.forEach((promptText, index) => {
|
622 |
+
const button = document.createElement('button');
|
623 |
+
button.className = 'example-prompt-button';
|
624 |
+
button.textContent = promptText;
|
625 |
+
button.addEventListener('click', () => {
|
626 |
+
if (modalUserPromptEl) modalUserPromptEl.value = promptText;
|
627 |
+
showPromptModal();
|
628 |
+
});
|
629 |
+
examplePromptsContainerEl.appendChild(button);
|
630 |
+
// Staggered animation for buttons
|
631 |
+
setTimeout(() => {
|
632 |
+
button.classList.add('visible');
|
633 |
+
}, 300 + index * 120); // Delay after panel animation starts, then stagger
|
634 |
+
});
|
635 |
+
}
|
636 |
}
|
637 |
|
638 |
function updateMainContentTitles(title, subtitle) {
|
|
|
1284 |
promptDisplayModalCloseBtnEl = document.getElementById('prompt-display-modal-close-button');
|
1285 |
showPromptModalButtonEl = document.getElementById('show-prompt-modal-button'); // Added
|
1286 |
|
1287 |
+
// --- Elements for Initial Setup CTA ---
|
1288 |
+
initialSetupCtaEl = document.getElementById('initial-setup-cta');
|
1289 |
+
initialApiKeyInputEl = document.getElementById('initial-api-key-input');
|
1290 |
+
examplePromptsContainerEl = document.getElementById('example-prompts-container');
|
1291 |
+
|
1292 |
|
1293 |
// --- Check if all required elements exist ---
|
1294 |
let missingElements = [];
|
1295 |
+
const requiredElements = { apiKeyEl, modelSelEl, codeOutputEl, errorMessageEl, refinementLoadingIndicator, mainContentEl, configButtonEl, intervalSliderEl, intervalValueDisplayEl, fullscreenOverlayEl, fullscreenIframeEl, exitFullscreenBtnEl, perspectiveViewportEl, previewGridWrapperEl, historyPanelEl, historyPanelPlaceholderEl, selectedCodeTitleH3El, mainContentTitleH1El, mainContentSubtitleH2El, fullscreenHistoryNavEl, historyNavPrevBtnEl, historyNavNextBtnEl, promptModalOverlayEl, promptModalContentEl, modalUserPromptEl, modalGenerateBtnEl, modalCancelBtnEl, modalLoadingIndicatorEl, modalRefinementCheckboxEl, numVariationsSliderEl, numVariationsValueDisplayEl, configModalOverlayEl, configModalContentEl, configModalCloseBtnEl, copyCodeButtonEl, exportCodeButtonEl, historyToggleButtonEl, historyArrowDownEl, historyArrowUpEl, newButtonEl, confirmModalOverlayEl, confirmModalMessageEl, confirmModalConfirmBtnEl, confirmModalCancelBtnEl, historyNavLeftBtnEl, historyNavRightBtnEl, modalThinkingBudgetSliderEl, modalThinkingBudgetValueDisplayEl, promptDisplayModalOverlayEl, promptDisplayModalContentEl, fullPromptTextEl, promptDisplayModalCloseBtnEl, showPromptModalButtonEl, initialSetupCtaEl, initialApiKeyInputEl, examplePromptsContainerEl }; // Added showPromptModalButtonEl
|
1296 |
for (const key in requiredElements) { if (!requiredElements[key]) { missingElements.push(key); } }
|
1297 |
|
1298 |
if (missingElements.length > 0) {
|