@innovastudio/contentbox 1.6.176 → 1.6.177
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -115892,6 +115892,10 @@ class CodeChat$1 {
|
|
|
115892
115892
|
this.builder = builder;
|
|
115893
115893
|
const builderStuff = this.builder.builderStuff;
|
|
115894
115894
|
this.builderStuff = builderStuff;
|
|
115895
|
+
|
|
115896
|
+
// Check if demo mode is enabled
|
|
115897
|
+
this.isDemoMode = this.builder.demoMode || false;
|
|
115898
|
+
this.demoConversations = this.builder.demoConversations || [];
|
|
115895
115899
|
const out = s => this.out(s);
|
|
115896
115900
|
|
|
115897
115901
|
// Load saved settings or use defaults
|
|
@@ -116231,6 +116235,12 @@ class CodeChat$1 {
|
|
|
116231
116235
|
// backward
|
|
116232
116236
|
this.imageModels = this.builder.imageGenerationModels;
|
|
116233
116237
|
}
|
|
116238
|
+
let inputPlaceholderText;
|
|
116239
|
+
if (this.builder.editor) {
|
|
116240
|
+
inputPlaceholderText = out('e.g., Create a landing page for a creative studio');
|
|
116241
|
+
} else {
|
|
116242
|
+
inputPlaceholderText = out('e.g., Create an article about a productive home workspace');
|
|
116243
|
+
}
|
|
116234
116244
|
let html = `
|
|
116235
116245
|
<style>
|
|
116236
116246
|
#chatPanel {
|
|
@@ -116562,10 +116572,12 @@ class CodeChat$1 {
|
|
|
116562
116572
|
box-shadow: 6px 14px 20px 0px rgba(95, 95, 95, 0.11);
|
|
116563
116573
|
z-index: 10005;
|
|
116564
116574
|
display: none;
|
|
116575
|
+
pointer-events: auto; /* Reset cursor to default to prevent it from getting stuck */
|
|
116565
116576
|
}
|
|
116566
116577
|
|
|
116567
116578
|
#settingsDialog.open {
|
|
116568
116579
|
display: block;
|
|
116580
|
+
pointer-events: auto; /* Reset cursor to default to prevent it from getting stuck */
|
|
116569
116581
|
}
|
|
116570
116582
|
|
|
116571
116583
|
#settingsDialog .settings-header {
|
|
@@ -116826,9 +116838,118 @@ class CodeChat$1 {
|
|
|
116826
116838
|
body.dark #chatPanel .copy-button:hover {
|
|
116827
116839
|
background: rgba(255, 255, 255, 0.2);
|
|
116828
116840
|
}
|
|
116841
|
+
|
|
116842
|
+
|
|
116843
|
+
/* Quick Image Size Button */
|
|
116844
|
+
#chatPanel .quick-image-size-button {
|
|
116845
|
+
width: 48px;
|
|
116846
|
+
height: 48px;
|
|
116847
|
+
border: none;
|
|
116848
|
+
border-radius: 8px;
|
|
116849
|
+
font-size: 13px;
|
|
116850
|
+
font-weight: 500;
|
|
116851
|
+
cursor: pointer;
|
|
116852
|
+
transition: background 0.2s;
|
|
116853
|
+
display: flex;
|
|
116854
|
+
align-items: center;
|
|
116855
|
+
justify-content: center;
|
|
116856
|
+
}
|
|
116857
|
+
|
|
116858
|
+
#chatPanel .quick-image-size-button:hover:not(:disabled) {
|
|
116859
|
+
background: rgba(0, 0, 0, 0.05);
|
|
116860
|
+
}
|
|
116861
|
+
|
|
116862
|
+
#chatPanel .quick-image-size-button:disabled {
|
|
116863
|
+
opacity: 0.6;
|
|
116864
|
+
cursor: not-allowed;
|
|
116865
|
+
}
|
|
116866
|
+
|
|
116867
|
+
body.dark #chatPanel .quick-image-size-button {
|
|
116868
|
+
background: #484848;
|
|
116869
|
+
}
|
|
116870
|
+
|
|
116871
|
+
body.dark #chatPanel .quick-image-size-button:hover:not(:disabled) {
|
|
116872
|
+
background: #4c4c4c;
|
|
116873
|
+
}
|
|
116874
|
+
|
|
116875
|
+
/* Image Size Popover */
|
|
116876
|
+
#chatPanel .image-size-popover {
|
|
116877
|
+
position: absolute;
|
|
116878
|
+
bottom: 72px;
|
|
116879
|
+
right: 68px;
|
|
116880
|
+
background: white;
|
|
116881
|
+
border: 1px solid #e5e5e5;
|
|
116882
|
+
border-radius: 8px;
|
|
116883
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
|
116884
|
+
z-index: 10006;
|
|
116885
|
+
min-width: 160px;
|
|
116886
|
+
max-height: 300px;
|
|
116887
|
+
overflow-y: auto;
|
|
116888
|
+
}
|
|
116889
|
+
|
|
116890
|
+
body.dark #chatPanel .image-size-popover {
|
|
116891
|
+
background: #3a3a3a;
|
|
116892
|
+
border-color: #555;
|
|
116893
|
+
}
|
|
116894
|
+
|
|
116895
|
+
#chatPanel .size-options {
|
|
116896
|
+
padding: 8px;
|
|
116897
|
+
}
|
|
116898
|
+
|
|
116899
|
+
#chatPanel .size-option {
|
|
116900
|
+
display: flex;
|
|
116901
|
+
align-items: center;
|
|
116902
|
+
padding: 10px 12px;
|
|
116903
|
+
cursor: pointer;
|
|
116904
|
+
border-radius: 6px;
|
|
116905
|
+
transition: background 0.2s;
|
|
116906
|
+
font-size: 14px;
|
|
116907
|
+
}
|
|
116908
|
+
#chatPanel .size-option label,
|
|
116909
|
+
#chatPanel .size-option input {
|
|
116910
|
+
cursor: pointer;
|
|
116911
|
+
}
|
|
116912
|
+
|
|
116913
|
+
#chatPanel .size-option:hover {
|
|
116914
|
+
background: rgba(0, 0, 0, 0.05);
|
|
116915
|
+
}
|
|
116916
|
+
|
|
116917
|
+
#chatPanel .size-option.selected {
|
|
116918
|
+
background: rgba(62, 147, 247, 0.1);
|
|
116919
|
+
font-weight: 500;
|
|
116920
|
+
}
|
|
116921
|
+
|
|
116922
|
+
#chatPanel .size-option input[type="radio"] {
|
|
116923
|
+
margin-right: 8px;
|
|
116924
|
+
}
|
|
116925
|
+
|
|
116926
|
+
body.dark #chatPanel .size-option:hover {
|
|
116927
|
+
background: rgba(255, 255, 255, 0.1);
|
|
116928
|
+
}
|
|
116929
|
+
|
|
116930
|
+
body.dark #chatPanel .size-option.selected {
|
|
116931
|
+
background: rgba(62, 147, 247, 0.2);
|
|
116932
|
+
}
|
|
116933
|
+
|
|
116934
|
+
#chatPanel .image-size-popover::-webkit-scrollbar {
|
|
116935
|
+
width: 6px;
|
|
116936
|
+
}
|
|
116937
|
+
|
|
116938
|
+
#chatPanel .image-size-popover::-webkit-scrollbar-track {
|
|
116939
|
+
background: transparent;
|
|
116940
|
+
}
|
|
116941
|
+
|
|
116942
|
+
#chatPanel .image-size-popover::-webkit-scrollbar-thumb {
|
|
116943
|
+
background: #e5e5e5;
|
|
116944
|
+
border-radius: 3px;
|
|
116945
|
+
}
|
|
116946
|
+
|
|
116947
|
+
body.dark #chatPanel .image-size-popover::-webkit-scrollbar-thumb {
|
|
116948
|
+
background: #555;
|
|
116949
|
+
}
|
|
116829
116950
|
</style>
|
|
116830
116951
|
<div
|
|
116831
|
-
class="hidden"
|
|
116952
|
+
class="hidden keep-selection"
|
|
116832
116953
|
id="chatPanel"
|
|
116833
116954
|
role="dialog"
|
|
116834
116955
|
aria-labelledby="chatPanelTitle"
|
|
@@ -116878,10 +116999,24 @@ class CodeChat$1 {
|
|
|
116878
116999
|
<label for="promptInput" class="sr-only">${out('Message input')}</label>
|
|
116879
117000
|
<textarea
|
|
116880
117001
|
id="promptInput"
|
|
116881
|
-
placeholder="${
|
|
117002
|
+
placeholder="${inputPlaceholderText}"
|
|
116882
117003
|
rows="1"
|
|
116883
117004
|
aria-label="${out('Type your message')}"
|
|
116884
117005
|
></textarea>
|
|
117006
|
+
|
|
117007
|
+
<!-- NEW: Quick image size button -->
|
|
117008
|
+
<button
|
|
117009
|
+
id="quickImageSizeButton"
|
|
117010
|
+
type="button"
|
|
117011
|
+
class="quick-image-size-button"
|
|
117012
|
+
aria-label="${out('Select image size')}"
|
|
117013
|
+
aria-haspopup="true"
|
|
117014
|
+
aria-expanded="false"
|
|
117015
|
+
style="display: none;"
|
|
117016
|
+
>
|
|
117017
|
+
□
|
|
117018
|
+
</button>
|
|
117019
|
+
|
|
116885
117020
|
<button
|
|
116886
117021
|
id="sendButton"
|
|
116887
117022
|
type="button"
|
|
@@ -116895,15 +117030,30 @@ class CodeChat$1 {
|
|
|
116895
117030
|
</svg>
|
|
116896
117031
|
</button>
|
|
116897
117032
|
</div>
|
|
117033
|
+
|
|
117034
|
+
<!-- NEW: Size selection popover -->
|
|
117035
|
+
<div
|
|
117036
|
+
id="imageSizePopover"
|
|
117037
|
+
class="image-size-popover"
|
|
117038
|
+
role="menu"
|
|
117039
|
+
aria-hidden="true"
|
|
117040
|
+
style="display: none;"
|
|
117041
|
+
>
|
|
117042
|
+
<div class="size-options" id="sizeOptionsContainer">
|
|
117043
|
+
<!-- Options populated dynamically -->
|
|
117044
|
+
</div>
|
|
117045
|
+
</div>
|
|
117046
|
+
|
|
116898
117047
|
</div>
|
|
116899
117048
|
</div>
|
|
116900
117049
|
|
|
116901
117050
|
<!-- Settings Dialog Overlay -->
|
|
116902
|
-
<div id="settingsOverlay" aria-hidden="true"></div>
|
|
117051
|
+
<div id="settingsOverlay" class="keep-selection" aria-hidden="true"></div>
|
|
116903
117052
|
|
|
116904
117053
|
<!-- Settings Dialog -->
|
|
116905
117054
|
<div
|
|
116906
117055
|
id="settingsDialog"
|
|
117056
|
+
class="keep-selection"
|
|
116907
117057
|
role="dialog"
|
|
116908
117058
|
aria-labelledby="settingsTitle"
|
|
116909
117059
|
aria-modal="true"
|
|
@@ -117037,9 +117187,16 @@ class CodeChat$1 {
|
|
|
117037
117187
|
this.chatModelSelect.value = this.settings.chatModel;
|
|
117038
117188
|
this.imageModelSelect.value = this.settings.imageModel;
|
|
117039
117189
|
this.imageSizeSelect.value = this.settings.imageSize;
|
|
117040
|
-
|
|
117190
|
+
|
|
117191
|
+
// Check saved state - default to closed if never set
|
|
117192
|
+
const savedState = localStorage.getItem('chatPanelVisible');
|
|
117193
|
+
let isChatVisible = savedState === 'true'; // Only open if explicitly set to 'true'
|
|
117041
117194
|
if (!isChatVisible) {
|
|
117042
117195
|
modal.classList.add('hidden');
|
|
117196
|
+
modal.setAttribute('aria-hidden', 'true');
|
|
117197
|
+
} else {
|
|
117198
|
+
modal.classList.remove('hidden');
|
|
117199
|
+
modal.removeAttribute('aria-hidden');
|
|
117043
117200
|
}
|
|
117044
117201
|
const btnClose = modal.querySelector('.close-button');
|
|
117045
117202
|
btnClose.addEventListener('click', () => {
|
|
@@ -117122,7 +117279,45 @@ class CodeChat$1 {
|
|
|
117122
117279
|
this.closeChatButton = closeChatButton;
|
|
117123
117280
|
this.sendButton = sendButton;
|
|
117124
117281
|
this.messagesContainer = messagesContainer;
|
|
117282
|
+
|
|
117283
|
+
// NEW: Quick image size button elements
|
|
117284
|
+
this.quickImageSizeButton = builderStuff.querySelector('#quickImageSizeButton');
|
|
117285
|
+
this.imageSizePopover = builderStuff.querySelector('#imageSizePopover');
|
|
117286
|
+
this.sizeOptionsContainer = builderStuff.querySelector('#sizeOptionsContainer');
|
|
117287
|
+
|
|
117288
|
+
// Quick Image Size Button Handlers
|
|
117289
|
+
this.quickImageSizeButton.addEventListener('click', e => {
|
|
117290
|
+
e.stopPropagation();
|
|
117291
|
+
this.toggleImageSizePopover();
|
|
117292
|
+
});
|
|
117293
|
+
|
|
117294
|
+
// Close popover when clicking outside
|
|
117295
|
+
document.addEventListener('click', e => {
|
|
117296
|
+
if (!this.imageSizePopover.contains(e.target) && !this.quickImageSizeButton.contains(e.target)) {
|
|
117297
|
+
this.closeImageSizePopover();
|
|
117298
|
+
}
|
|
117299
|
+
});
|
|
117300
|
+
|
|
117301
|
+
// Close popover on Escape
|
|
117302
|
+
this.imageSizePopover.addEventListener('keydown', e => {
|
|
117303
|
+
if (e.key === 'Escape') {
|
|
117304
|
+
this.closeImageSizePopover();
|
|
117305
|
+
this.quickImageSizeButton.focus();
|
|
117306
|
+
}
|
|
117307
|
+
});
|
|
117125
117308
|
this.renderImageOptions();
|
|
117309
|
+
if (this.demoConversations) {
|
|
117310
|
+
this.loadConversations();
|
|
117311
|
+
}
|
|
117312
|
+
if (this.isDemoMode) {
|
|
117313
|
+
this.addDemoBanner();
|
|
117314
|
+
|
|
117315
|
+
// Disable input in demo mode
|
|
117316
|
+
this.promptInput.disabled = true;
|
|
117317
|
+
// this.promptInput.placeholder = out('Demo mode - Chat is read-only');
|
|
117318
|
+
this.sendButton.disabled = true;
|
|
117319
|
+
this.messagesContainer.scrollTop = this.messagesContainer.scrollHeight;
|
|
117320
|
+
}
|
|
117126
117321
|
}
|
|
117127
117322
|
renderImageOptions() {
|
|
117128
117323
|
const out = s => this.out(s);
|
|
@@ -117229,6 +117424,9 @@ class CodeChat$1 {
|
|
|
117229
117424
|
// Trigger initial render with defaults
|
|
117230
117425
|
modelSelect.value = defaultModelId;
|
|
117231
117426
|
renderSizes(defaultModelId, false);
|
|
117427
|
+
|
|
117428
|
+
// NEW: Initialize quick size button
|
|
117429
|
+
this.updateQuickImageSizeButton();
|
|
117232
117430
|
}
|
|
117233
117431
|
|
|
117234
117432
|
/**
|
|
@@ -117294,6 +117492,9 @@ class CodeChat$1 {
|
|
|
117294
117492
|
this.settingsOverlay.setAttribute('aria-hidden', 'true');
|
|
117295
117493
|
this.settingsDialog.classList.remove('open');
|
|
117296
117494
|
this.settingsDialog.setAttribute('aria-hidden', 'true');
|
|
117495
|
+
|
|
117496
|
+
// Reset cursor to default to prevent it from getting stuck
|
|
117497
|
+
document.body.style.cursor = '';
|
|
117297
117498
|
if (this.settingsLastFocusedElement) {
|
|
117298
117499
|
this.settingsLastFocusedElement.focus();
|
|
117299
117500
|
}
|
|
@@ -117305,6 +117506,9 @@ class CodeChat$1 {
|
|
|
117305
117506
|
this.settings.imageModel = this.imageModelSelect.value;
|
|
117306
117507
|
this.settings.imageSize = this.imageSizeSelect.value;
|
|
117307
117508
|
this.saveSettingsToStorage();
|
|
117509
|
+
|
|
117510
|
+
// NEW: Update quick button when settings change
|
|
117511
|
+
this.updateQuickImageSizeButton();
|
|
117308
117512
|
this.closeSettings();
|
|
117309
117513
|
}
|
|
117310
117514
|
|
|
@@ -117338,6 +117542,106 @@ Your job:
|
|
|
117338
117542
|
3. Determine what each image should depict based on surrounding content and context
|
|
117339
117543
|
4. Create detailed image generation prompts for each image
|
|
117340
117544
|
|
|
117545
|
+
📸 EDITORIAL STYLE GUIDE - Apply to all image prompts:
|
|
117546
|
+
|
|
117547
|
+
- Default aesthetic: Minimalist magazine-style (Kinfolk, Cereal, Vogue Living)
|
|
117548
|
+
- Composition: Clean, lots of negative space, well-balanced
|
|
117549
|
+
|
|
117550
|
+
|
|
117551
|
+
CREATIVE PROMPT ENHANCEMENT:
|
|
117552
|
+
When constructing image prompts, intelligently enrich basic descriptions using these proven cinematic stylers:
|
|
117553
|
+
|
|
117554
|
+
1. **Golden Hour Cinematic**
|
|
117555
|
+
"Warm sunlight, golden-hour lighting. Low contrast with lifted shadows, ethereal glow throughout. Overall vibe: relaxed, coastal, sun-kissed, carefree, West Coast lifestyle, evoking warmth and endless summer."
|
|
117556
|
+
→ Best for: Landscapes, architecture, outdoor scenes, lifestyle content
|
|
117557
|
+
|
|
117558
|
+
2. **Morning Halo Effect**
|
|
117559
|
+
"The lighting is soft, morning sunlight coming, creating a 'halo' effect. Vibrant cinematic shot"
|
|
117560
|
+
→ Best for: Portraits, people in action, outdoor activities
|
|
117561
|
+
|
|
117562
|
+
3. **Natural Forest Serenity**
|
|
117563
|
+
"in a lush, green forest. The sunlight should be filtering through the trees, creating a serene and natural atmosphere"
|
|
117564
|
+
→ Best for: Nature scenes, outdoor activities, wellness content
|
|
117565
|
+
|
|
117566
|
+
4. **Coastal Summer Drama**
|
|
117567
|
+
"on a dramatic windswept coastline. The overall atmosphere is cheerful, breezy, and full of summer warmth"
|
|
117568
|
+
→ Best for: Beach/coastal scenes, adventure, travel content
|
|
117569
|
+
|
|
117570
|
+
5. **Modern Interior Elegance**
|
|
117571
|
+
"illuminated by warm, natural lighting. The background features a softly blurred modern interior with subtle lights and cool tones, adding depth without distraction"
|
|
117572
|
+
→ Best for: Indoor portraits, product shots, professional/business settings
|
|
117573
|
+
|
|
117574
|
+
ENHANCEMENT STRATEGY:
|
|
117575
|
+
- Analyze the subject matter and context from the HTML/request
|
|
117576
|
+
- Select the most appropriate styler that matches the scene type
|
|
117577
|
+
- Check if user has specified lighting/time → DO NOT apply contradicting styler elements
|
|
117578
|
+
* Example: User says "daylight" → DO NOT add "golden-hour" or "sunset"
|
|
117579
|
+
- Aim for creative elevation while maintaining the core subject integrity
|
|
117580
|
+
- Blend the styler naturally into the prompt (adapt grammar, pronouns, context)
|
|
117581
|
+
- IF user is vague (no specific lighting/mood) → Apply full styler enhancement
|
|
117582
|
+
- User's explicit details ALWAYS take precedence over styler recommendations
|
|
117583
|
+
` +
|
|
117584
|
+
/*
|
|
117585
|
+
ENHANCEMENT STRATEGY:
|
|
117586
|
+
- Analyze the subject matter and context from the HTML/request
|
|
117587
|
+
- Select the most appropriate styler that matches the scene type
|
|
117588
|
+
- Blend the styler naturally into the prompt (adapt grammar, pronouns, context)
|
|
117589
|
+
- If the subject already has specific lighting/atmosphere details, complement rather than override
|
|
117590
|
+
- Aim for creative elevation while maintaining the core subject integrity
|
|
117591
|
+
*/
|
|
117592
|
+
`
|
|
117593
|
+
Examples of enriched prompts:
|
|
117594
|
+
- Basic: "a house with mountain view"
|
|
117595
|
+
→ Enhanced: "a house with beautiful mountain view. Warm sunlight, golden-hour lighting. Low contrast with lifted shadows, ethereal glow throughout. Overall vibe: relaxed, coastal, sun-kissed, carefree, West Coast lifestyle, evoking warmth and endless summer."
|
|
117596
|
+
|
|
117597
|
+
- Basic: "person hiking"
|
|
117598
|
+
→ Enhanced: "a person hiking in nature. The lighting is soft, morning sunlight coming, creating a 'halo' effect. Vibrant cinematic shot"
|
|
117599
|
+
|
|
117600
|
+
- Basic: "woman reading"
|
|
117601
|
+
→ Enhanced: "a woman sitting comfortably and reading. Her face is illuminated by warm, natural lighting. The background features a softly blurred modern interior with subtle lights and cool tones, adding depth without distraction"
|
|
117602
|
+
|
|
117603
|
+
- Already detailed: "dramatic headshot with bokeh and rim lighting"
|
|
117604
|
+
→ No enhancement needed (preserve user's vision)
|
|
117605
|
+
|
|
117606
|
+
|
|
117607
|
+
CONTEXT-SPECIFIC GUIDELINES:
|
|
117608
|
+
|
|
117609
|
+
Interior/Indoor scenes:
|
|
117610
|
+
- Lighting: Soft natural window light
|
|
117611
|
+
- Backdrop: white walls or neutral tones
|
|
117612
|
+
- Mood: Calm, serene, inviting, uncluttered
|
|
117613
|
+
- Reference: "Kinfolk interior photography"
|
|
117614
|
+
|
|
117615
|
+
People/Portraits/Activities:
|
|
117616
|
+
- Lighting: Natural diffused light, flattering and soft
|
|
117617
|
+
- Styling: Effortlessly elegant, contemporary casual
|
|
117618
|
+
- Pose: Candid, authentic moments, relaxed
|
|
117619
|
+
- Reference: "modern lifestyle editorial photography"
|
|
117620
|
+
|
|
117621
|
+
Products/Objects:
|
|
117622
|
+
- Lighting: Clean studio or soft natural light
|
|
117623
|
+
- Backdrop: Minimalist neutral, lots of breathing room
|
|
117624
|
+
- Mood: Refined simplicity, premium feel
|
|
117625
|
+
- Reference: "high-end editorial product photography"
|
|
117626
|
+
|
|
117627
|
+
Food/Culinary:
|
|
117628
|
+
- Lighting: Soft daylight, gentle overhead or 45° angle
|
|
117629
|
+
- Styling: Minimal props, artisan ceramics, linen
|
|
117630
|
+
- Mood: Fresh, appetizing, rustic-modern
|
|
117631
|
+
- Reference: "Bon Appétit editorial food styling"
|
|
117632
|
+
|
|
117633
|
+
Outdoor/Landscape:
|
|
117634
|
+
- Composition: Serene, contemplative, minimal
|
|
117635
|
+
- Mood: Calm atmosphere, breathing space, lifted brightness
|
|
117636
|
+
- Colors: Vibrant cinematic shot.
|
|
117637
|
+
- Reference: "editorial travel photography"
|
|
117638
|
+
|
|
117639
|
+
CRITICAL RULES:
|
|
117640
|
+
1. If user specifies a style (cinematic, vintage, vibrant, etc.) → RESPECT IT, only add quality markers
|
|
117641
|
+
2. If user is vague → APPLY FULL EDITORIAL TREATMENT based on subject category
|
|
117642
|
+
3. Always maintain cohesive aesthetic across all images
|
|
117643
|
+
4. Every prompt should feel like it belongs in a high-end lifestyle magazine
|
|
117644
|
+
|
|
117341
117645
|
Respond with a JSON array with one entry per image to generate:
|
|
117342
117646
|
[
|
|
117343
117647
|
{
|
|
@@ -117448,6 +117752,11 @@ Response: [
|
|
|
117448
117752
|
*/
|
|
117449
117753
|
async sendMessage() {
|
|
117450
117754
|
const out = s => this.out(s);
|
|
117755
|
+
|
|
117756
|
+
// Prevent sending messages in demo mode
|
|
117757
|
+
if (this.isDemoMode) {
|
|
117758
|
+
return;
|
|
117759
|
+
}
|
|
117451
117760
|
const prompt = this.promptInput.value.trim();
|
|
117452
117761
|
if (!prompt) return;
|
|
117453
117762
|
this.addMessage('user', prompt);
|
|
@@ -117515,14 +117824,42 @@ Response: [
|
|
|
117515
117824
|
} else if (result.type === 'image') {
|
|
117516
117825
|
if (result.imageDetails && result.imageDetails.length > 1) {
|
|
117517
117826
|
this.addMessage('assistant', `✓ Generated ${result.imageDetails.length} images successfully`);
|
|
117827
|
+
// this.addMessage('assistant', `✓ ${out('Generated {count} images successfully').replace('{count}', result.imageDetails.length)}`);
|
|
117518
117828
|
this.addImagePreview(result.imageDetails);
|
|
117519
117829
|
} else {
|
|
117520
|
-
this.addMessage('assistant', '✓
|
|
117830
|
+
this.addMessage('assistant', '✓ Image generated successfully');
|
|
117831
|
+
// this.addMessage('assistant', `✓ ${out('Image generated successfully')}`);
|
|
117521
117832
|
if (result.generatedUrls && result.generatedUrls[0]) {
|
|
117522
117833
|
this.addImagePreview([{
|
|
117523
117834
|
url: result.generatedUrls[0],
|
|
117524
117835
|
context: result.description
|
|
117525
117836
|
}]);
|
|
117837
|
+
|
|
117838
|
+
// If there is a selected image, replace with the new image
|
|
117839
|
+
const url = result.generatedUrls[0];
|
|
117840
|
+
if (this.builder.editor) {
|
|
117841
|
+
// ContentBox
|
|
117842
|
+
const img = this.builder.editor.activeImage;
|
|
117843
|
+
if (img) {
|
|
117844
|
+
this.builder.editor.saveForUndo();
|
|
117845
|
+
img.addEventListener('load', () => {
|
|
117846
|
+
this.builder.editor.element.image.repositionImageTool();
|
|
117847
|
+
this.builder.editor.elmTool.repositionElementTool();
|
|
117848
|
+
});
|
|
117849
|
+
this.builder.editor.activeImage.setAttribute('src', url);
|
|
117850
|
+
}
|
|
117851
|
+
} else {
|
|
117852
|
+
// ContentBuilder
|
|
117853
|
+
const img = this.builder.activeImage;
|
|
117854
|
+
if (img) {
|
|
117855
|
+
this.builder.uo.saveForUndo();
|
|
117856
|
+
img.addEventListener('load', () => {
|
|
117857
|
+
this.builder.element.image.repositionImageTool();
|
|
117858
|
+
this.builder.elmTool.repositionElementTool();
|
|
117859
|
+
});
|
|
117860
|
+
this.builder.activeImage.setAttribute('src', url);
|
|
117861
|
+
}
|
|
117862
|
+
}
|
|
117526
117863
|
}
|
|
117527
117864
|
}
|
|
117528
117865
|
}
|
|
@@ -117576,15 +117913,16 @@ Response: [
|
|
|
117576
117913
|
`;
|
|
117577
117914
|
images.forEach(img => {
|
|
117578
117915
|
previewHTML += `
|
|
117579
|
-
<div style="border-radius:
|
|
117580
|
-
<img src="${img.url}" alt="${img.context || 'Generated image'}" style="width: 100%;
|
|
117916
|
+
<div style="border-radius: 6px; overflow: hidden; background: rgba(255,255,255,0.05);">
|
|
117917
|
+
<img src="${img.url}" alt="${img.context || 'Generated image'}" style="width: 100%;" />
|
|
117581
117918
|
<div style="padding: 8px; font-size: 11px; opacity: 0.8;">
|
|
117582
117919
|
${img.context || ''}
|
|
117583
117920
|
<a href="${img.url}" target="_blank" rel="noopener noreferrer" style="display: block; margin-top: 4px;">View</a>
|
|
117584
117921
|
</div>
|
|
117585
117922
|
</div>
|
|
117586
|
-
`;
|
|
117923
|
+
`; // height: 150px; object-fit: cover;
|
|
117587
117924
|
});
|
|
117925
|
+
|
|
117588
117926
|
previewHTML += '</div>';
|
|
117589
117927
|
previewDiv.innerHTML = previewHTML;
|
|
117590
117928
|
this.messagesContainer.appendChild(previewDiv);
|
|
@@ -117605,6 +117943,32 @@ Response: [
|
|
|
117605
117943
|
|
|
117606
117944
|
// Check if image generation is enabled
|
|
117607
117945
|
const imageGenEnabled = this.builder.generateMediaUrl_Fal ? true : false;
|
|
117946
|
+
|
|
117947
|
+
// Build context about previously generated images
|
|
117948
|
+
let imageHistoryContext = '';
|
|
117949
|
+
const previousImageResults = this.conversationResults.filter(r => r.type === 'image' && r.generatedUrls && r.generatedUrls.length > 0);
|
|
117950
|
+
if (previousImageResults.length > 0) {
|
|
117951
|
+
imageHistoryContext = '\n\n=== PREVIOUSLY GENERATED IMAGES IN THIS CONVERSATION ===\n';
|
|
117952
|
+
imageHistoryContext += 'The following images were generated earlier in this conversation:\n\n';
|
|
117953
|
+
previousImageResults.forEach((result, idx) => {
|
|
117954
|
+
if (result.imageDetails && result.imageDetails.length > 0) {
|
|
117955
|
+
result.imageDetails.forEach((img, imgIdx) => {
|
|
117956
|
+
imageHistoryContext += `Generated Image ${idx + 1}.${imgIdx + 1}:\n`;
|
|
117957
|
+
imageHistoryContext += ` URL: ${img.url}\n`;
|
|
117958
|
+
imageHistoryContext += ` Context: ${img.context}\n`;
|
|
117959
|
+
imageHistoryContext += ` Description: ${result.description}\n\n`;
|
|
117960
|
+
});
|
|
117961
|
+
} else {
|
|
117962
|
+
result.generatedUrls.forEach((url, urlIdx) => {
|
|
117963
|
+
imageHistoryContext += `Generated Image ${idx + 1}.${urlIdx + 1}:\n`;
|
|
117964
|
+
imageHistoryContext += ` URL: ${url}\n`;
|
|
117965
|
+
imageHistoryContext += ` Description: ${result.description}\n\n`;
|
|
117966
|
+
});
|
|
117967
|
+
}
|
|
117968
|
+
});
|
|
117969
|
+
imageHistoryContext += '⚠️ IMPORTANT: If the user refers to "the generated image", "this image", "the image", or "previous image", they are referring to these images above.\n';
|
|
117970
|
+
imageHistoryContext += '⚠️ DO NOT create a new image task. Instead, create a CODE task that uses these existing URLs.\n\n';
|
|
117971
|
+
}
|
|
117608
117972
|
const classificationPrompt = `Analyze this user message and break it down into tasks.
|
|
117609
117973
|
|
|
117610
117974
|
CURRENT HTML CONTEXT (use this to understand the page structure):
|
|
@@ -117612,11 +117976,19 @@ CURRENT HTML CONTEXT (use this to understand the page structure):
|
|
|
117612
117976
|
${this.builder.html()}
|
|
117613
117977
|
\`\`\`
|
|
117614
117978
|
|
|
117979
|
+
${imageHistoryContext}
|
|
117980
|
+
|
|
117615
117981
|
IMPORTANT: This is a WEB BUILDER tool with chat capabilities. Valid requests are:
|
|
117616
117982
|
- Creating/editing/removing HTML content (code tasks)
|
|
117617
117983
|
${imageGenEnabled ? '- Generating images for the webpage (image tasks)' : ''}
|
|
117618
117984
|
- Asking questions or having conversations (chat tasks) - THIS CAN BE ABOUT ANYTHING
|
|
117619
117985
|
|
|
117986
|
+
CRITICAL CONTEXT RULE:
|
|
117987
|
+
- In a web builder, "create an article/blog/story/content" means CREATE A WEBPAGE (CODE task)
|
|
117988
|
+
- Only use CHAT task for questions, explanations, or requests for advice
|
|
117989
|
+
- If user says "create", "write", "make", "build" followed by content → CODE task
|
|
117990
|
+
- If user says "explain", "how do I", "what is", "tell me about" → CHAT task
|
|
117991
|
+
|
|
117620
117992
|
${imageGenEnabled ? '' : `
|
|
117621
117993
|
⚠️ AI IMAGE GENERATION IS CURRENTLY DISABLED
|
|
117622
117994
|
- If user requests AI image generation/creation, explain that it's disabled
|
|
@@ -117686,6 +118058,18 @@ IMAGE TASK RULES:
|
|
|
117686
118058
|
- IMPORTANT: Look at the HTML context to understand if multiple images are involved
|
|
117687
118059
|
- If the target section has multiple images, indicate this in targetElement (e.g., "all 3 images in Culinary Delights section")
|
|
117688
118060
|
- Image tasks should come BEFORE code tasks that depend on them
|
|
118061
|
+
|
|
118062
|
+
- CRITICAL: DO NOT create image task for these phrases (they mean REUSE existing):
|
|
118063
|
+
* "use the generated image" / "use the image"
|
|
118064
|
+
* "use this image" / "use existing image"
|
|
118065
|
+
* "with the generated image" / "with this image"
|
|
118066
|
+
* "with the previous image" / "with the last image"
|
|
118067
|
+
* "using the image I just created/generated"
|
|
118068
|
+
* Any reference to a PREVIOUS image from conversation history
|
|
118069
|
+
- Decision logic:
|
|
118070
|
+
* "Generate a new image of X" → CREATE image task (new generation)
|
|
118071
|
+
* "Create article using the generated image" → NO image task (reuse existing)
|
|
118072
|
+
|
|
117689
118073
|
` : ''}
|
|
117690
118074
|
|
|
117691
118075
|
Examples:
|
|
@@ -117723,6 +118107,17 @@ Input: "Create a landing page about wood furniture workshop"
|
|
|
117723
118107
|
Output: {"is_valid": true, "tasks": [{"type": "code", "description": "Create a landing page for a wood furniture workshop", "order": 1}], "is_mixed": false}
|
|
117724
118108
|
Note: No image task created because user did not explicitly request AI image generation
|
|
117725
118109
|
|
|
118110
|
+
Input: "Create an inspiring article and use the generated image"
|
|
118111
|
+
Output: {"is_valid": true, "tasks": [{"type": "code", "description": "Create article using previously generated image from conversation history", "order": 1}], "is_mixed": false}
|
|
118112
|
+
Note: No image task because user wants to REUSE existing image
|
|
118113
|
+
|
|
118114
|
+
Input: "Write a blog post about productivity and use this image"
|
|
118115
|
+
Output: {"is_valid": true, "tasks": [{"type": "code", "description": "Create blog post using previously generated image", "order": 1}], "is_mixed": false}
|
|
118116
|
+
|
|
118117
|
+
Input: "Generate another mountain image and create a landing page"
|
|
118118
|
+
Output: {"tasks": [{"type": "image", "description": "Generate new mountain image", "imagePrompt": "...", "order": 1}, {"type": "code", "description": "Create landing page with new image", "order": 2}], "is_mixed": true}
|
|
118119
|
+
Note: "another" and "generate" indicate NEW image generation
|
|
118120
|
+
|
|
117726
118121
|
` : `
|
|
117727
118122
|
Input: "Generate an AI image of a mountain"
|
|
117728
118123
|
Output: {"is_valid": false, "reason": "AI image generation is currently disabled.", "tasks": [], "is_mixed": false}
|
|
@@ -117806,7 +118201,9 @@ Output: {"is_valid": false, "reason": "AI image generation is currently disabled
|
|
|
117806
118201
|
if (imageTasksFromThisRequest.length > 0) {
|
|
117807
118202
|
hasGeneratedImages = true;
|
|
117808
118203
|
imageContext = '\n\n=== GENERATED IMAGE URLS (USE THESE FOR YOUR TASK) ===\n';
|
|
117809
|
-
|
|
118204
|
+
|
|
118205
|
+
// ⭐ REVERSE to show most recent first
|
|
118206
|
+
imageTasksFromThisRequest.reverse().forEach(imageTask => {
|
|
117810
118207
|
if (imageTask.imageDetails && imageTask.imageDetails.length > 0) {
|
|
117811
118208
|
// Multiple images with context
|
|
117812
118209
|
imageTask.imageDetails.forEach((img, idx) => {
|
|
@@ -117821,7 +118218,8 @@ Output: {"is_valid": false, "reason": "AI image generation is currently disabled
|
|
|
117821
118218
|
});
|
|
117822
118219
|
}
|
|
117823
118220
|
});
|
|
117824
|
-
imageContext += '\n⚠️ IMPORTANT: Use
|
|
118221
|
+
imageContext += '\n⚠️ IMPORTANT: Use the FIRST image URL listed above (most recent) unless the task specifically asks for a different image.\n';
|
|
118222
|
+
imageContext += '⚠️ The first image is the MOST RECENTLY GENERATED and should be used by default.\n';
|
|
117825
118223
|
imageContext += '⚠️ Your task description specifies WHICH images to update - follow it precisely.\n';
|
|
117826
118224
|
}
|
|
117827
118225
|
|
|
@@ -118374,6 +118772,319 @@ ${this.builder.html()}
|
|
|
118374
118772
|
document.body.removeChild(announcement);
|
|
118375
118773
|
}, 1000);
|
|
118376
118774
|
}
|
|
118775
|
+
|
|
118776
|
+
/**
|
|
118777
|
+
* ============================================================================
|
|
118778
|
+
* DEMO MODE
|
|
118779
|
+
* ============================================================================
|
|
118780
|
+
*/
|
|
118781
|
+
loadConversations() {
|
|
118782
|
+
// Load demo conversations
|
|
118783
|
+
if (this.demoConversations && this.demoConversations.length > 0) {
|
|
118784
|
+
this.demoConversations.forEach(msg => {
|
|
118785
|
+
if (msg.role === 'user') {
|
|
118786
|
+
this.addMessage('user', msg.content);
|
|
118787
|
+
} else if (msg.role === 'assistant') {
|
|
118788
|
+
this.addMessage('assistant', msg.content, true);
|
|
118789
|
+
|
|
118790
|
+
// Add image preview if available
|
|
118791
|
+
if (msg.imagePreview && msg.imagePreview.length > 0) {
|
|
118792
|
+
this.addImagePreview(msg.imagePreview);
|
|
118793
|
+
|
|
118794
|
+
// Include in conversationResults with correct structure
|
|
118795
|
+
this.conversationResults.push({
|
|
118796
|
+
type: 'image',
|
|
118797
|
+
description: 'Previously generated image from demo',
|
|
118798
|
+
content: `Generated ${msg.imagePreview.length} images`,
|
|
118799
|
+
generatedUrls: msg.imagePreview.map(img => img.url),
|
|
118800
|
+
// Array of URLs
|
|
118801
|
+
imageDetails: msg.imagePreview.map(img => ({
|
|
118802
|
+
// Array of objects
|
|
118803
|
+
url: img.url,
|
|
118804
|
+
context: img.context,
|
|
118805
|
+
prompt: img.context || '' // Use context as prompt if no prompt available
|
|
118806
|
+
})),
|
|
118807
|
+
|
|
118808
|
+
targetElement: 'demo images'
|
|
118809
|
+
});
|
|
118810
|
+
}
|
|
118811
|
+
}
|
|
118812
|
+
});
|
|
118813
|
+
}
|
|
118814
|
+
}
|
|
118815
|
+
addDemoBanner() {
|
|
118816
|
+
const out = s => this.out(s);
|
|
118817
|
+
const banner = document.createElement('div');
|
|
118818
|
+
banner.className = 'demo-banner';
|
|
118819
|
+
banner.innerHTML = `
|
|
118820
|
+
<div style="
|
|
118821
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
118822
|
+
color: white;
|
|
118823
|
+
padding: 12px 16px;
|
|
118824
|
+
border-radius: 8px;
|
|
118825
|
+
font-size: 13px;
|
|
118826
|
+
display: flex;
|
|
118827
|
+
align-items: center;
|
|
118828
|
+
gap: 8px;
|
|
118829
|
+
box-shadow: 0 4px 12px rgba(102, 126, 234, 0.3);
|
|
118830
|
+
">
|
|
118831
|
+
<span style="font-size: 18px;">📖</span>
|
|
118832
|
+
<div>
|
|
118833
|
+
<strong>${out('Read-Only Demo')}</strong>
|
|
118834
|
+
<div style="font-size: 11px; opacity: 0.9; margin-top: 2px;">
|
|
118835
|
+
${out('Full AI chat available in the complete version.')}
|
|
118836
|
+
</div>
|
|
118837
|
+
</div>
|
|
118838
|
+
</div>
|
|
118839
|
+
`;
|
|
118840
|
+
|
|
118841
|
+
// Insert banner at the top of messages container
|
|
118842
|
+
// this.messagesContainer.insertBefore(banner, this.messagesContainer.firstChild);
|
|
118843
|
+
this.messagesContainer.appendChild(banner);
|
|
118844
|
+
}
|
|
118845
|
+
|
|
118846
|
+
/**
|
|
118847
|
+
* Update the quick image size button based on current model and settings
|
|
118848
|
+
*/
|
|
118849
|
+
updateQuickImageSizeButton() {
|
|
118850
|
+
const imageGenEnabled = this.builder.generateMediaUrl_Fal ? true : false;
|
|
118851
|
+
if (!imageGenEnabled) {
|
|
118852
|
+
this.quickImageSizeButton.style.display = 'none';
|
|
118853
|
+
return;
|
|
118854
|
+
}
|
|
118855
|
+
const currentModelId = this.settings.imageModel;
|
|
118856
|
+
const availableSizes = this.getSizesForModel(currentModelId);
|
|
118857
|
+
|
|
118858
|
+
// Hide button if model has no size options
|
|
118859
|
+
if (!availableSizes || availableSizes.length === 0) {
|
|
118860
|
+
this.quickImageSizeButton.style.display = 'none';
|
|
118861
|
+
return;
|
|
118862
|
+
}
|
|
118863
|
+
|
|
118864
|
+
// Show button
|
|
118865
|
+
this.quickImageSizeButton.style.display = 'flex';
|
|
118866
|
+
|
|
118867
|
+
// Smart selection: check if current size is available
|
|
118868
|
+
let selectedSize = this.settings.imageSize;
|
|
118869
|
+
if (!availableSizes.includes(selectedSize)) {
|
|
118870
|
+
// Current size not available, find best fallback
|
|
118871
|
+
selectedSize = this.findBestFallback(selectedSize, availableSizes);
|
|
118872
|
+
this.settings.imageSize = selectedSize;
|
|
118873
|
+
|
|
118874
|
+
// Sync with settings dialog
|
|
118875
|
+
this.imageSizeSelect.value = selectedSize;
|
|
118876
|
+
|
|
118877
|
+
// Save to storage
|
|
118878
|
+
this.saveSettingsToStorage();
|
|
118879
|
+
}
|
|
118880
|
+
|
|
118881
|
+
// Update button label
|
|
118882
|
+
this.updateButtonLabel(selectedSize);
|
|
118883
|
+
|
|
118884
|
+
// Populate popover options
|
|
118885
|
+
this.populateSizePopover(availableSizes, selectedSize);
|
|
118886
|
+
}
|
|
118887
|
+
|
|
118888
|
+
/**
|
|
118889
|
+
* Get available sizes for a model (reuse existing logic)
|
|
118890
|
+
*/
|
|
118891
|
+
getSizesForModel(modelId) {
|
|
118892
|
+
const model = this.imageModels.find(m => m.id === modelId);
|
|
118893
|
+
if (!model) return null;
|
|
118894
|
+
|
|
118895
|
+
// if sizes explicitly empty array → means no size options
|
|
118896
|
+
if (Array.isArray(model.sizes) && model.sizes.length === 0) {
|
|
118897
|
+
return null;
|
|
118898
|
+
}
|
|
118899
|
+
const defaultSizes = ['square', 'square_hd', 'landscape_4_3', 'landscape_16_9', 'portrait_4_3', 'portrait_16_9'];
|
|
118900
|
+
return model.sizes || defaultSizes;
|
|
118901
|
+
}
|
|
118902
|
+
|
|
118903
|
+
/**
|
|
118904
|
+
* Find best fallback size when current selection is not available
|
|
118905
|
+
*/
|
|
118906
|
+
findBestFallback(preferredSize, availableSizes) {
|
|
118907
|
+
// Strategy 1: Try to match orientation
|
|
118908
|
+
const orientation = this.getOrientation(preferredSize);
|
|
118909
|
+
const matchingOrientation = availableSizes.find(size => this.getOrientation(size) === orientation);
|
|
118910
|
+
if (matchingOrientation) return matchingOrientation;
|
|
118911
|
+
|
|
118912
|
+
// Strategy 2: Common defaults
|
|
118913
|
+
if (availableSizes.includes('16:9')) return '16:9';
|
|
118914
|
+
if (availableSizes.includes('landscape_16_9')) return 'landscape_16_9';
|
|
118915
|
+
if (availableSizes.includes('1:1')) return '1:1';
|
|
118916
|
+
if (availableSizes.includes('square')) return 'square';
|
|
118917
|
+
|
|
118918
|
+
// Strategy 3: First available
|
|
118919
|
+
return availableSizes[0];
|
|
118920
|
+
}
|
|
118921
|
+
|
|
118922
|
+
/**
|
|
118923
|
+
* Determine orientation from size value
|
|
118924
|
+
*/
|
|
118925
|
+
getOrientation(size) {
|
|
118926
|
+
const landscape = ['16:9', '21:9', '4:3', '3:2', '5:4', 'landscape_16_9', 'landscape_4_3'];
|
|
118927
|
+
const portrait = ['9:16', '9:21', '3:4', '2:3', '4:5', 'portrait_16_9', 'portrait_4_3'];
|
|
118928
|
+
if (landscape.includes(size)) return 'landscape';
|
|
118929
|
+
if (portrait.includes(size)) return 'portrait';
|
|
118930
|
+
return 'square';
|
|
118931
|
+
}
|
|
118932
|
+
|
|
118933
|
+
/**
|
|
118934
|
+
* Update button label to show current size
|
|
118935
|
+
*/
|
|
118936
|
+
updateButtonLabel(sizeValue) {
|
|
118937
|
+
if (!sizeValue) {
|
|
118938
|
+
this.quickImageSizeButton.textContent = '□';
|
|
118939
|
+
this.quickImageSizeButton.setAttribute('aria-label', this.out('Select image size'));
|
|
118940
|
+
return;
|
|
118941
|
+
}
|
|
118942
|
+
|
|
118943
|
+
// Convert verbose labels to short form
|
|
118944
|
+
const labelMap = {
|
|
118945
|
+
'landscape_16_9': '16:9',
|
|
118946
|
+
'landscape_4_3': '4:3',
|
|
118947
|
+
'portrait_16_9': '9:16',
|
|
118948
|
+
'portrait_4_3': '3:4',
|
|
118949
|
+
'square': '1:1',
|
|
118950
|
+
'square_hd': '1:1 HD'
|
|
118951
|
+
};
|
|
118952
|
+
const displayLabel = labelMap[sizeValue] || sizeValue;
|
|
118953
|
+
this.quickImageSizeButton.textContent = displayLabel;
|
|
118954
|
+
this.quickImageSizeButton.setAttribute('aria-label', `${this.out('Image size')}: ${displayLabel}`);
|
|
118955
|
+
}
|
|
118956
|
+
|
|
118957
|
+
/**
|
|
118958
|
+
* Populate the size popover with available options
|
|
118959
|
+
*/
|
|
118960
|
+
populateSizePopover(sizes, selectedSize) {
|
|
118961
|
+
const out = s => this.out(s);
|
|
118962
|
+
const sizeDefs = {
|
|
118963
|
+
'square_hd': out('Square HD'),
|
|
118964
|
+
'square': out('Square'),
|
|
118965
|
+
'landscape_4_3': out('Landscape 4x3'),
|
|
118966
|
+
'landscape_16_9': out('Landscape 16x9'),
|
|
118967
|
+
'portrait_4_3': out('Portrait 3x4'),
|
|
118968
|
+
'portrait_16_9': out('Portrait 9x16'),
|
|
118969
|
+
'1:1': out('Square'),
|
|
118970
|
+
'3:2': out('Landscape 3x2'),
|
|
118971
|
+
'4:3': out('Landscape 4x3'),
|
|
118972
|
+
'5:4': out('Landscape 5x4'),
|
|
118973
|
+
'16:9': out('Landscape 16x9'),
|
|
118974
|
+
'21:9': out('Landscape 21:9'),
|
|
118975
|
+
'2:3': out('Portrait 2x3'),
|
|
118976
|
+
'3:4': out('Portrait 3x4'),
|
|
118977
|
+
'4:5': out('Portrait 4x5'),
|
|
118978
|
+
'9:16': out('Portrait 9x16'),
|
|
118979
|
+
'9:21': out('Portrait 9:21')
|
|
118980
|
+
};
|
|
118981
|
+
this.sizeOptionsContainer.innerHTML = '';
|
|
118982
|
+
sizes.forEach(size => {
|
|
118983
|
+
const option = document.createElement('div');
|
|
118984
|
+
option.className = 'size-option' + (size === selectedSize ? ' selected' : '');
|
|
118985
|
+
option.setAttribute('role', 'menuitem');
|
|
118986
|
+
option.setAttribute('tabindex', '0');
|
|
118987
|
+
const radio = document.createElement('input');
|
|
118988
|
+
radio.type = 'radio';
|
|
118989
|
+
radio.name = 'quickImageSize';
|
|
118990
|
+
radio.value = size;
|
|
118991
|
+
radio.checked = size === selectedSize;
|
|
118992
|
+
radio.id = `quick-size-${size}`;
|
|
118993
|
+
const label = document.createElement('label');
|
|
118994
|
+
label.htmlFor = `quick-size-${size}`;
|
|
118995
|
+
label.textContent = sizeDefs[size] || size;
|
|
118996
|
+
// label.style.cursor = 'pointer';
|
|
118997
|
+
label.style.flex = '1';
|
|
118998
|
+
option.appendChild(radio);
|
|
118999
|
+
option.appendChild(label);
|
|
119000
|
+
|
|
119001
|
+
// Click handler
|
|
119002
|
+
option.addEventListener('click', () => {
|
|
119003
|
+
this.selectImageSize(size);
|
|
119004
|
+
});
|
|
119005
|
+
|
|
119006
|
+
// Keyboard handler
|
|
119007
|
+
option.addEventListener('keydown', e => {
|
|
119008
|
+
if (e.key === 'Enter' || e.key === ' ') {
|
|
119009
|
+
e.preventDefault();
|
|
119010
|
+
this.selectImageSize(size);
|
|
119011
|
+
}
|
|
119012
|
+
});
|
|
119013
|
+
this.sizeOptionsContainer.appendChild(option);
|
|
119014
|
+
});
|
|
119015
|
+
}
|
|
119016
|
+
|
|
119017
|
+
/**
|
|
119018
|
+
* Handle size selection
|
|
119019
|
+
*/
|
|
119020
|
+
selectImageSize(size) {
|
|
119021
|
+
// Update settings
|
|
119022
|
+
this.settings.imageSize = size;
|
|
119023
|
+
|
|
119024
|
+
// Sync with settings dialog
|
|
119025
|
+
this.imageSizeSelect.value = size;
|
|
119026
|
+
|
|
119027
|
+
// Update button label
|
|
119028
|
+
this.updateButtonLabel(size);
|
|
119029
|
+
|
|
119030
|
+
// Update popover selection
|
|
119031
|
+
this.sizeOptionsContainer.querySelectorAll('.size-option').forEach(opt => {
|
|
119032
|
+
opt.classList.remove('selected');
|
|
119033
|
+
opt.querySelector('input[type="radio"]').checked = false;
|
|
119034
|
+
});
|
|
119035
|
+
|
|
119036
|
+
// const selectedOption = this.sizeOptionsContainer.querySelector(`#quick-size-${size}`);
|
|
119037
|
+
const selectedOption = Array.from(this.sizeOptionsContainer.querySelectorAll('input[type="radio"]')).find(radio => radio.value === size);
|
|
119038
|
+
if (selectedOption) {
|
|
119039
|
+
selectedOption.closest('.size-option').classList.add('selected');
|
|
119040
|
+
selectedOption.checked = true;
|
|
119041
|
+
}
|
|
119042
|
+
|
|
119043
|
+
// Save to storage
|
|
119044
|
+
this.saveSettingsToStorage();
|
|
119045
|
+
|
|
119046
|
+
// Close popover
|
|
119047
|
+
this.closeImageSizePopover();
|
|
119048
|
+
|
|
119049
|
+
// Focus back to input
|
|
119050
|
+
this.promptInput.focus();
|
|
119051
|
+
}
|
|
119052
|
+
|
|
119053
|
+
/**
|
|
119054
|
+
* Toggle popover visibility
|
|
119055
|
+
*/
|
|
119056
|
+
toggleImageSizePopover() {
|
|
119057
|
+
const isVisible = this.imageSizePopover.style.display !== 'none';
|
|
119058
|
+
if (isVisible) {
|
|
119059
|
+
this.closeImageSizePopover();
|
|
119060
|
+
} else {
|
|
119061
|
+
this.openImageSizePopover();
|
|
119062
|
+
}
|
|
119063
|
+
}
|
|
119064
|
+
|
|
119065
|
+
/**
|
|
119066
|
+
* Open the size popover
|
|
119067
|
+
*/
|
|
119068
|
+
openImageSizePopover() {
|
|
119069
|
+
this.imageSizePopover.style.display = 'block';
|
|
119070
|
+
this.imageSizePopover.setAttribute('aria-hidden', 'false');
|
|
119071
|
+
this.quickImageSizeButton.setAttribute('aria-expanded', 'true');
|
|
119072
|
+
|
|
119073
|
+
// Focus first option
|
|
119074
|
+
const firstOption = this.sizeOptionsContainer.querySelector('.size-option');
|
|
119075
|
+
if (firstOption) {
|
|
119076
|
+
firstOption.focus();
|
|
119077
|
+
}
|
|
119078
|
+
}
|
|
119079
|
+
|
|
119080
|
+
/**
|
|
119081
|
+
* Close the size popover
|
|
119082
|
+
*/
|
|
119083
|
+
closeImageSizePopover() {
|
|
119084
|
+
this.imageSizePopover.style.display = 'none';
|
|
119085
|
+
this.imageSizePopover.setAttribute('aria-hidden', 'true');
|
|
119086
|
+
this.quickImageSizeButton.setAttribute('aria-expanded', 'false');
|
|
119087
|
+
}
|
|
118377
119088
|
out(s) {
|
|
118378
119089
|
let result = this.builder.lang[s];
|
|
118379
119090
|
if (result) return result;else return s;
|
|
@@ -118799,7 +119510,7 @@ Classes: transition-none, transition, transition-colors, transition-opacity, tra
|
|
|
118799
119510
|
|
|
118800
119511
|
**Duration**
|
|
118801
119512
|
|
|
118802
|
-
Classes: duration-75, duration-100, duration-150, duration-200, duration-300, duration-500, duration-700, duration-1000
|
|
119513
|
+
Classes: duration-75, duration-100, duration-150, duration-200, duration-300, duration-500, duration-700, duration-1000, duration-1500
|
|
118803
119514
|
|
|
118804
119515
|
**Timing**
|
|
118805
119516
|
|
|
@@ -118813,6 +119524,10 @@ Classes: delay-75, delay-100, delay-150, delay-200, delay-300, delay-500
|
|
|
118813
119524
|
|
|
118814
119525
|
Classes: scale-0, scale-50, scale-75, scale-90, scale-95, scale-100, scale-105, scale-110, scale-125, scale-150
|
|
118815
119526
|
|
|
119527
|
+
**Hover Effect**
|
|
119528
|
+
|
|
119529
|
+
Classes: hover:scale-105
|
|
119530
|
+
|
|
118816
119531
|
**Rotate**
|
|
118817
119532
|
|
|
118818
119533
|
Classes: rotate-0, rotate-45, rotate-90, rotate-180
|
|
@@ -119146,6 +119861,31 @@ When creating icon-based features, benefits, or service sections: use Bootstrap
|
|
|
119146
119861
|
<h4 class="size-18 font-medium text-center pb-3">Lightning Fast</h4>
|
|
119147
119862
|
<p class="size-14 leading-16 text-gray-600 text-center">Description...</p>
|
|
119148
119863
|
|
|
119864
|
+
### 9. Image Layout with Hover Effect
|
|
119865
|
+
|
|
119866
|
+
Use this pattern for all images (galleries, featured images, portfolio items):
|
|
119867
|
+
|
|
119868
|
+
<div class="w-full overflow-hidden relative bg-gray-50" style="aspect-ratio:16/9">
|
|
119869
|
+
<img src="..." alt="..." class="w-full h-full object-cover transition-transform duration-1500 hover:scale-105">
|
|
119870
|
+
</div>
|
|
119871
|
+
|
|
119872
|
+
**Key elements:**
|
|
119873
|
+
- 'aspect-ratio:16/9' - maintains proportions (adjust as needed: 1/1, 4/3, 3/2, 16/9, etc.)
|
|
119874
|
+
- 'overflow-hidden' - keeps scaled image contained
|
|
119875
|
+
- 'bg-gray-50' - placeholder while image loads
|
|
119876
|
+
- 'transition-transform duration-1000' - smooth 1-second animation
|
|
119877
|
+
- 'hover:scale-105' - subtle 5% scale on hover
|
|
119878
|
+
- 'object-cover' - ensures image fills container
|
|
119879
|
+
|
|
119880
|
+
**Common aspect ratios:**
|
|
119881
|
+
- Square: 'aspect-ratio:1/1'
|
|
119882
|
+
- Portrait: 'aspect-ratio:3/4' or 'aspect-ratio:2/3'
|
|
119883
|
+
- Landscape: 'aspect-ratio:4/3' or 'aspect-ratio:3/2'
|
|
119884
|
+
- Wide: 'aspect-ratio:16/9' or 'aspect-ratio:21/9'
|
|
119885
|
+
- Tall portrait: 'aspect-ratio:9/16'
|
|
119886
|
+
|
|
119887
|
+
Always include this hover effect for a polished, interactive feel.
|
|
119888
|
+
|
|
119149
119889
|
`;
|
|
119150
119890
|
|
|
119151
119891
|
const contextCodeBlock$1 = `
|
|
@@ -119345,6 +120085,17 @@ The frameworks provide utility classes for structure and typography. To create r
|
|
|
119345
120085
|
|
|
119346
120086
|
**Example <style>: When needed for animations, transitions, or reusable patterns**
|
|
119347
120087
|
|
|
120088
|
+
<div class="row">
|
|
120089
|
+
<div class="column">
|
|
120090
|
+
|
|
120091
|
+
<!-- GUIDANCE: Use this layout to show images at any aspect ratio with a hover scale effect -->
|
|
120092
|
+
<div class="w-full overflow-hidden relative bg-gray-50" style="aspect-ratio:16/9">
|
|
120093
|
+
<img src="https://placehold.co/1200x1200/f5f5f5/999?text=Featured" alt="Featured Project" class="w-full h-full object-cover transition-transform duration-1500 hover:scale-105">
|
|
120094
|
+
</div>
|
|
120095
|
+
|
|
120096
|
+
</div>
|
|
120097
|
+
</div>
|
|
120098
|
+
|
|
119348
120099
|
<div class="row">
|
|
119349
120100
|
<div class="column">
|
|
119350
120101
|
|
|
@@ -119519,6 +120270,33 @@ class ContentBuilder {
|
|
|
119519
120270
|
'snippets': []
|
|
119520
120271
|
},
|
|
119521
120272
|
screenMode: 'desktop',
|
|
120273
|
+
demoMode: false,
|
|
120274
|
+
/*
|
|
120275
|
+
demoConversations: [
|
|
120276
|
+
{
|
|
120277
|
+
role: 'user',
|
|
120278
|
+
content: 'Generate an image: "a house with beautiful mountain view. warm sunlight, golden-hour lighting, filmic teal-orange color grade".',
|
|
120279
|
+
// timestamp: Date.now() - 180000 // 3 minutes ago
|
|
120280
|
+
},
|
|
120281
|
+
{
|
|
120282
|
+
role: 'assistant',
|
|
120283
|
+
content: '✓ Image generated successfully',
|
|
120284
|
+
imagePreview: [
|
|
120285
|
+
{ url: 'uploads/ai-8vnqv.png', context: 'Generate image of a house with a beautiful mountain view' },
|
|
120286
|
+
]
|
|
120287
|
+
},
|
|
120288
|
+
{
|
|
120289
|
+
role: 'user',
|
|
120290
|
+
content: `Create a thoughtful article about finding home in extraordinary landscapes. Write vivid prose about mountain dwellings and how our environments shape the way we live.
|
|
120291
|
+
Use the generated image for this article, and present it as a premium design magazine feature.`,
|
|
120292
|
+
},
|
|
120293
|
+
{
|
|
120294
|
+
role: 'assistant',
|
|
120295
|
+
content: '✓ Create a thoughtful article about finding home in extraordinary landscapes with vivid prose about mountain dwellings and their impact on our lives, formatted as a premium design magazine feature.',
|
|
120296
|
+
}
|
|
120297
|
+
],
|
|
120298
|
+
*/
|
|
120299
|
+
|
|
119522
120300
|
// Live Preview
|
|
119523
120301
|
// previewURL: 'preview.html',
|
|
119524
120302
|
onPreviewOpen: () => {
|
|
@@ -143636,7 +144414,10 @@ class CodeChat {
|
|
|
143636
144414
|
};
|
|
143637
144415
|
this.builder = builder;
|
|
143638
144416
|
const builderStuff = this.builder.builderStuff;
|
|
143639
|
-
this.builderStuff = builderStuff;
|
|
144417
|
+
this.builderStuff = builderStuff; // Check if demo mode is enabled
|
|
144418
|
+
|
|
144419
|
+
this.isDemoMode = this.builder.demoMode || false;
|
|
144420
|
+
this.demoConversations = this.builder.demoConversations || [];
|
|
143640
144421
|
|
|
143641
144422
|
const out = s => this.out(s); // Load saved settings or use defaults
|
|
143642
144423
|
|
|
@@ -143983,6 +144764,14 @@ class CodeChat {
|
|
|
143983
144764
|
this.imageModels = this.builder.imageGenerationModels;
|
|
143984
144765
|
}
|
|
143985
144766
|
|
|
144767
|
+
let inputPlaceholderText;
|
|
144768
|
+
|
|
144769
|
+
if (this.builder.editor) {
|
|
144770
|
+
inputPlaceholderText = out('e.g., Create a landing page for a creative studio');
|
|
144771
|
+
} else {
|
|
144772
|
+
inputPlaceholderText = out('e.g., Create an article about a productive home workspace');
|
|
144773
|
+
}
|
|
144774
|
+
|
|
143986
144775
|
let html = `
|
|
143987
144776
|
<style>
|
|
143988
144777
|
#chatPanel {
|
|
@@ -144314,10 +145103,12 @@ class CodeChat {
|
|
|
144314
145103
|
box-shadow: 6px 14px 20px 0px rgba(95, 95, 95, 0.11);
|
|
144315
145104
|
z-index: 10005;
|
|
144316
145105
|
display: none;
|
|
145106
|
+
pointer-events: auto; /* Reset cursor to default to prevent it from getting stuck */
|
|
144317
145107
|
}
|
|
144318
145108
|
|
|
144319
145109
|
#settingsDialog.open {
|
|
144320
145110
|
display: block;
|
|
145111
|
+
pointer-events: auto; /* Reset cursor to default to prevent it from getting stuck */
|
|
144321
145112
|
}
|
|
144322
145113
|
|
|
144323
145114
|
#settingsDialog .settings-header {
|
|
@@ -144578,9 +145369,118 @@ class CodeChat {
|
|
|
144578
145369
|
body.dark #chatPanel .copy-button:hover {
|
|
144579
145370
|
background: rgba(255, 255, 255, 0.2);
|
|
144580
145371
|
}
|
|
145372
|
+
|
|
145373
|
+
|
|
145374
|
+
/* Quick Image Size Button */
|
|
145375
|
+
#chatPanel .quick-image-size-button {
|
|
145376
|
+
width: 48px;
|
|
145377
|
+
height: 48px;
|
|
145378
|
+
border: none;
|
|
145379
|
+
border-radius: 8px;
|
|
145380
|
+
font-size: 13px;
|
|
145381
|
+
font-weight: 500;
|
|
145382
|
+
cursor: pointer;
|
|
145383
|
+
transition: background 0.2s;
|
|
145384
|
+
display: flex;
|
|
145385
|
+
align-items: center;
|
|
145386
|
+
justify-content: center;
|
|
145387
|
+
}
|
|
145388
|
+
|
|
145389
|
+
#chatPanel .quick-image-size-button:hover:not(:disabled) {
|
|
145390
|
+
background: rgba(0, 0, 0, 0.05);
|
|
145391
|
+
}
|
|
145392
|
+
|
|
145393
|
+
#chatPanel .quick-image-size-button:disabled {
|
|
145394
|
+
opacity: 0.6;
|
|
145395
|
+
cursor: not-allowed;
|
|
145396
|
+
}
|
|
145397
|
+
|
|
145398
|
+
body.dark #chatPanel .quick-image-size-button {
|
|
145399
|
+
background: #484848;
|
|
145400
|
+
}
|
|
145401
|
+
|
|
145402
|
+
body.dark #chatPanel .quick-image-size-button:hover:not(:disabled) {
|
|
145403
|
+
background: #4c4c4c;
|
|
145404
|
+
}
|
|
145405
|
+
|
|
145406
|
+
/* Image Size Popover */
|
|
145407
|
+
#chatPanel .image-size-popover {
|
|
145408
|
+
position: absolute;
|
|
145409
|
+
bottom: 72px;
|
|
145410
|
+
right: 68px;
|
|
145411
|
+
background: white;
|
|
145412
|
+
border: 1px solid #e5e5e5;
|
|
145413
|
+
border-radius: 8px;
|
|
145414
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
|
145415
|
+
z-index: 10006;
|
|
145416
|
+
min-width: 160px;
|
|
145417
|
+
max-height: 300px;
|
|
145418
|
+
overflow-y: auto;
|
|
145419
|
+
}
|
|
145420
|
+
|
|
145421
|
+
body.dark #chatPanel .image-size-popover {
|
|
145422
|
+
background: #3a3a3a;
|
|
145423
|
+
border-color: #555;
|
|
145424
|
+
}
|
|
145425
|
+
|
|
145426
|
+
#chatPanel .size-options {
|
|
145427
|
+
padding: 8px;
|
|
145428
|
+
}
|
|
145429
|
+
|
|
145430
|
+
#chatPanel .size-option {
|
|
145431
|
+
display: flex;
|
|
145432
|
+
align-items: center;
|
|
145433
|
+
padding: 10px 12px;
|
|
145434
|
+
cursor: pointer;
|
|
145435
|
+
border-radius: 6px;
|
|
145436
|
+
transition: background 0.2s;
|
|
145437
|
+
font-size: 14px;
|
|
145438
|
+
}
|
|
145439
|
+
#chatPanel .size-option label,
|
|
145440
|
+
#chatPanel .size-option input {
|
|
145441
|
+
cursor: pointer;
|
|
145442
|
+
}
|
|
145443
|
+
|
|
145444
|
+
#chatPanel .size-option:hover {
|
|
145445
|
+
background: rgba(0, 0, 0, 0.05);
|
|
145446
|
+
}
|
|
145447
|
+
|
|
145448
|
+
#chatPanel .size-option.selected {
|
|
145449
|
+
background: rgba(62, 147, 247, 0.1);
|
|
145450
|
+
font-weight: 500;
|
|
145451
|
+
}
|
|
145452
|
+
|
|
145453
|
+
#chatPanel .size-option input[type="radio"] {
|
|
145454
|
+
margin-right: 8px;
|
|
145455
|
+
}
|
|
145456
|
+
|
|
145457
|
+
body.dark #chatPanel .size-option:hover {
|
|
145458
|
+
background: rgba(255, 255, 255, 0.1);
|
|
145459
|
+
}
|
|
145460
|
+
|
|
145461
|
+
body.dark #chatPanel .size-option.selected {
|
|
145462
|
+
background: rgba(62, 147, 247, 0.2);
|
|
145463
|
+
}
|
|
145464
|
+
|
|
145465
|
+
#chatPanel .image-size-popover::-webkit-scrollbar {
|
|
145466
|
+
width: 6px;
|
|
145467
|
+
}
|
|
145468
|
+
|
|
145469
|
+
#chatPanel .image-size-popover::-webkit-scrollbar-track {
|
|
145470
|
+
background: transparent;
|
|
145471
|
+
}
|
|
145472
|
+
|
|
145473
|
+
#chatPanel .image-size-popover::-webkit-scrollbar-thumb {
|
|
145474
|
+
background: #e5e5e5;
|
|
145475
|
+
border-radius: 3px;
|
|
145476
|
+
}
|
|
145477
|
+
|
|
145478
|
+
body.dark #chatPanel .image-size-popover::-webkit-scrollbar-thumb {
|
|
145479
|
+
background: #555;
|
|
145480
|
+
}
|
|
144581
145481
|
</style>
|
|
144582
145482
|
<div
|
|
144583
|
-
class="hidden"
|
|
145483
|
+
class="hidden keep-selection"
|
|
144584
145484
|
id="chatPanel"
|
|
144585
145485
|
role="dialog"
|
|
144586
145486
|
aria-labelledby="chatPanelTitle"
|
|
@@ -144630,10 +145530,24 @@ class CodeChat {
|
|
|
144630
145530
|
<label for="promptInput" class="sr-only">${out('Message input')}</label>
|
|
144631
145531
|
<textarea
|
|
144632
145532
|
id="promptInput"
|
|
144633
|
-
placeholder="${
|
|
145533
|
+
placeholder="${inputPlaceholderText}"
|
|
144634
145534
|
rows="1"
|
|
144635
145535
|
aria-label="${out('Type your message')}"
|
|
144636
145536
|
></textarea>
|
|
145537
|
+
|
|
145538
|
+
<!-- NEW: Quick image size button -->
|
|
145539
|
+
<button
|
|
145540
|
+
id="quickImageSizeButton"
|
|
145541
|
+
type="button"
|
|
145542
|
+
class="quick-image-size-button"
|
|
145543
|
+
aria-label="${out('Select image size')}"
|
|
145544
|
+
aria-haspopup="true"
|
|
145545
|
+
aria-expanded="false"
|
|
145546
|
+
style="display: none;"
|
|
145547
|
+
>
|
|
145548
|
+
□
|
|
145549
|
+
</button>
|
|
145550
|
+
|
|
144637
145551
|
<button
|
|
144638
145552
|
id="sendButton"
|
|
144639
145553
|
type="button"
|
|
@@ -144647,15 +145561,30 @@ class CodeChat {
|
|
|
144647
145561
|
</svg>
|
|
144648
145562
|
</button>
|
|
144649
145563
|
</div>
|
|
145564
|
+
|
|
145565
|
+
<!-- NEW: Size selection popover -->
|
|
145566
|
+
<div
|
|
145567
|
+
id="imageSizePopover"
|
|
145568
|
+
class="image-size-popover"
|
|
145569
|
+
role="menu"
|
|
145570
|
+
aria-hidden="true"
|
|
145571
|
+
style="display: none;"
|
|
145572
|
+
>
|
|
145573
|
+
<div class="size-options" id="sizeOptionsContainer">
|
|
145574
|
+
<!-- Options populated dynamically -->
|
|
145575
|
+
</div>
|
|
145576
|
+
</div>
|
|
145577
|
+
|
|
144650
145578
|
</div>
|
|
144651
145579
|
</div>
|
|
144652
145580
|
|
|
144653
145581
|
<!-- Settings Dialog Overlay -->
|
|
144654
|
-
<div id="settingsOverlay" aria-hidden="true"></div>
|
|
145582
|
+
<div id="settingsOverlay" class="keep-selection" aria-hidden="true"></div>
|
|
144655
145583
|
|
|
144656
145584
|
<!-- Settings Dialog -->
|
|
144657
145585
|
<div
|
|
144658
145586
|
id="settingsDialog"
|
|
145587
|
+
class="keep-selection"
|
|
144659
145588
|
role="dialog"
|
|
144660
145589
|
aria-labelledby="settingsTitle"
|
|
144661
145590
|
aria-modal="true"
|
|
@@ -144785,11 +145714,17 @@ class CodeChat {
|
|
|
144785
145714
|
this.codeModelSelect.value = this.settings.codeModel;
|
|
144786
145715
|
this.chatModelSelect.value = this.settings.chatModel;
|
|
144787
145716
|
this.imageModelSelect.value = this.settings.imageModel;
|
|
144788
|
-
this.imageSizeSelect.value = this.settings.imageSize;
|
|
144789
|
-
|
|
145717
|
+
this.imageSizeSelect.value = this.settings.imageSize; // Check saved state - default to closed if never set
|
|
145718
|
+
|
|
145719
|
+
const savedState = localStorage.getItem('chatPanelVisible');
|
|
145720
|
+
let isChatVisible = savedState === 'true'; // Only open if explicitly set to 'true'
|
|
144790
145721
|
|
|
144791
145722
|
if (!isChatVisible) {
|
|
144792
145723
|
modal.classList.add('hidden');
|
|
145724
|
+
modal.setAttribute('aria-hidden', 'true');
|
|
145725
|
+
} else {
|
|
145726
|
+
modal.classList.remove('hidden');
|
|
145727
|
+
modal.removeAttribute('aria-hidden');
|
|
144793
145728
|
}
|
|
144794
145729
|
|
|
144795
145730
|
const btnClose = modal.querySelector('.close-button');
|
|
@@ -144873,8 +145808,43 @@ class CodeChat {
|
|
|
144873
145808
|
this.promptInput = promptInput;
|
|
144874
145809
|
this.closeChatButton = closeChatButton;
|
|
144875
145810
|
this.sendButton = sendButton;
|
|
144876
|
-
this.messagesContainer = messagesContainer;
|
|
145811
|
+
this.messagesContainer = messagesContainer; // NEW: Quick image size button elements
|
|
145812
|
+
|
|
145813
|
+
this.quickImageSizeButton = builderStuff.querySelector('#quickImageSizeButton');
|
|
145814
|
+
this.imageSizePopover = builderStuff.querySelector('#imageSizePopover');
|
|
145815
|
+
this.sizeOptionsContainer = builderStuff.querySelector('#sizeOptionsContainer'); // Quick Image Size Button Handlers
|
|
145816
|
+
|
|
145817
|
+
this.quickImageSizeButton.addEventListener('click', e => {
|
|
145818
|
+
e.stopPropagation();
|
|
145819
|
+
this.toggleImageSizePopover();
|
|
145820
|
+
}); // Close popover when clicking outside
|
|
145821
|
+
|
|
145822
|
+
document.addEventListener('click', e => {
|
|
145823
|
+
if (!this.imageSizePopover.contains(e.target) && !this.quickImageSizeButton.contains(e.target)) {
|
|
145824
|
+
this.closeImageSizePopover();
|
|
145825
|
+
}
|
|
145826
|
+
}); // Close popover on Escape
|
|
145827
|
+
|
|
145828
|
+
this.imageSizePopover.addEventListener('keydown', e => {
|
|
145829
|
+
if (e.key === 'Escape') {
|
|
145830
|
+
this.closeImageSizePopover();
|
|
145831
|
+
this.quickImageSizeButton.focus();
|
|
145832
|
+
}
|
|
145833
|
+
});
|
|
144877
145834
|
this.renderImageOptions();
|
|
145835
|
+
|
|
145836
|
+
if (this.demoConversations) {
|
|
145837
|
+
this.loadConversations();
|
|
145838
|
+
}
|
|
145839
|
+
|
|
145840
|
+
if (this.isDemoMode) {
|
|
145841
|
+
this.addDemoBanner(); // Disable input in demo mode
|
|
145842
|
+
|
|
145843
|
+
this.promptInput.disabled = true; // this.promptInput.placeholder = out('Demo mode - Chat is read-only');
|
|
145844
|
+
|
|
145845
|
+
this.sendButton.disabled = true;
|
|
145846
|
+
this.messagesContainer.scrollTop = this.messagesContainer.scrollHeight;
|
|
145847
|
+
}
|
|
144878
145848
|
}
|
|
144879
145849
|
|
|
144880
145850
|
renderImageOptions() {
|
|
@@ -144977,7 +145947,9 @@ class CodeChat {
|
|
|
144977
145947
|
}); // Trigger initial render with defaults
|
|
144978
145948
|
|
|
144979
145949
|
modelSelect.value = defaultModelId;
|
|
144980
|
-
renderSizes(defaultModelId, false);
|
|
145950
|
+
renderSizes(defaultModelId, false); // NEW: Initialize quick size button
|
|
145951
|
+
|
|
145952
|
+
this.updateQuickImageSizeButton();
|
|
144981
145953
|
}
|
|
144982
145954
|
/**
|
|
144983
145955
|
* ============================================================================
|
|
@@ -145049,7 +146021,9 @@ class CodeChat {
|
|
|
145049
146021
|
this.settingsOverlay.classList.remove('open');
|
|
145050
146022
|
this.settingsOverlay.setAttribute('aria-hidden', 'true');
|
|
145051
146023
|
this.settingsDialog.classList.remove('open');
|
|
145052
|
-
this.settingsDialog.setAttribute('aria-hidden', 'true');
|
|
146024
|
+
this.settingsDialog.setAttribute('aria-hidden', 'true'); // Reset cursor to default to prevent it from getting stuck
|
|
146025
|
+
|
|
146026
|
+
document.body.style.cursor = '';
|
|
145053
146027
|
|
|
145054
146028
|
if (this.settingsLastFocusedElement) {
|
|
145055
146029
|
this.settingsLastFocusedElement.focus();
|
|
@@ -145063,7 +146037,9 @@ class CodeChat {
|
|
|
145063
146037
|
this.settings.chatModel = this.chatModelSelect.value;
|
|
145064
146038
|
this.settings.imageModel = this.imageModelSelect.value;
|
|
145065
146039
|
this.settings.imageSize = this.imageSizeSelect.value;
|
|
145066
|
-
this.saveSettingsToStorage();
|
|
146040
|
+
this.saveSettingsToStorage(); // NEW: Update quick button when settings change
|
|
146041
|
+
|
|
146042
|
+
this.updateQuickImageSizeButton();
|
|
145067
146043
|
this.closeSettings();
|
|
145068
146044
|
}
|
|
145069
146045
|
/**
|
|
@@ -145098,6 +146074,106 @@ Your job:
|
|
|
145098
146074
|
3. Determine what each image should depict based on surrounding content and context
|
|
145099
146075
|
4. Create detailed image generation prompts for each image
|
|
145100
146076
|
|
|
146077
|
+
📸 EDITORIAL STYLE GUIDE - Apply to all image prompts:
|
|
146078
|
+
|
|
146079
|
+
- Default aesthetic: Minimalist magazine-style (Kinfolk, Cereal, Vogue Living)
|
|
146080
|
+
- Composition: Clean, lots of negative space, well-balanced
|
|
146081
|
+
|
|
146082
|
+
|
|
146083
|
+
CREATIVE PROMPT ENHANCEMENT:
|
|
146084
|
+
When constructing image prompts, intelligently enrich basic descriptions using these proven cinematic stylers:
|
|
146085
|
+
|
|
146086
|
+
1. **Golden Hour Cinematic**
|
|
146087
|
+
"Warm sunlight, golden-hour lighting. Low contrast with lifted shadows, ethereal glow throughout. Overall vibe: relaxed, coastal, sun-kissed, carefree, West Coast lifestyle, evoking warmth and endless summer."
|
|
146088
|
+
→ Best for: Landscapes, architecture, outdoor scenes, lifestyle content
|
|
146089
|
+
|
|
146090
|
+
2. **Morning Halo Effect**
|
|
146091
|
+
"The lighting is soft, morning sunlight coming, creating a 'halo' effect. Vibrant cinematic shot"
|
|
146092
|
+
→ Best for: Portraits, people in action, outdoor activities
|
|
146093
|
+
|
|
146094
|
+
3. **Natural Forest Serenity**
|
|
146095
|
+
"in a lush, green forest. The sunlight should be filtering through the trees, creating a serene and natural atmosphere"
|
|
146096
|
+
→ Best for: Nature scenes, outdoor activities, wellness content
|
|
146097
|
+
|
|
146098
|
+
4. **Coastal Summer Drama**
|
|
146099
|
+
"on a dramatic windswept coastline. The overall atmosphere is cheerful, breezy, and full of summer warmth"
|
|
146100
|
+
→ Best for: Beach/coastal scenes, adventure, travel content
|
|
146101
|
+
|
|
146102
|
+
5. **Modern Interior Elegance**
|
|
146103
|
+
"illuminated by warm, natural lighting. The background features a softly blurred modern interior with subtle lights and cool tones, adding depth without distraction"
|
|
146104
|
+
→ Best for: Indoor portraits, product shots, professional/business settings
|
|
146105
|
+
|
|
146106
|
+
ENHANCEMENT STRATEGY:
|
|
146107
|
+
- Analyze the subject matter and context from the HTML/request
|
|
146108
|
+
- Select the most appropriate styler that matches the scene type
|
|
146109
|
+
- Check if user has specified lighting/time → DO NOT apply contradicting styler elements
|
|
146110
|
+
* Example: User says "daylight" → DO NOT add "golden-hour" or "sunset"
|
|
146111
|
+
- Aim for creative elevation while maintaining the core subject integrity
|
|
146112
|
+
- Blend the styler naturally into the prompt (adapt grammar, pronouns, context)
|
|
146113
|
+
- IF user is vague (no specific lighting/mood) → Apply full styler enhancement
|
|
146114
|
+
- User's explicit details ALWAYS take precedence over styler recommendations
|
|
146115
|
+
` +
|
|
146116
|
+
/*
|
|
146117
|
+
ENHANCEMENT STRATEGY:
|
|
146118
|
+
- Analyze the subject matter and context from the HTML/request
|
|
146119
|
+
- Select the most appropriate styler that matches the scene type
|
|
146120
|
+
- Blend the styler naturally into the prompt (adapt grammar, pronouns, context)
|
|
146121
|
+
- If the subject already has specific lighting/atmosphere details, complement rather than override
|
|
146122
|
+
- Aim for creative elevation while maintaining the core subject integrity
|
|
146123
|
+
*/
|
|
146124
|
+
`
|
|
146125
|
+
Examples of enriched prompts:
|
|
146126
|
+
- Basic: "a house with mountain view"
|
|
146127
|
+
→ Enhanced: "a house with beautiful mountain view. Warm sunlight, golden-hour lighting. Low contrast with lifted shadows, ethereal glow throughout. Overall vibe: relaxed, coastal, sun-kissed, carefree, West Coast lifestyle, evoking warmth and endless summer."
|
|
146128
|
+
|
|
146129
|
+
- Basic: "person hiking"
|
|
146130
|
+
→ Enhanced: "a person hiking in nature. The lighting is soft, morning sunlight coming, creating a 'halo' effect. Vibrant cinematic shot"
|
|
146131
|
+
|
|
146132
|
+
- Basic: "woman reading"
|
|
146133
|
+
→ Enhanced: "a woman sitting comfortably and reading. Her face is illuminated by warm, natural lighting. The background features a softly blurred modern interior with subtle lights and cool tones, adding depth without distraction"
|
|
146134
|
+
|
|
146135
|
+
- Already detailed: "dramatic headshot with bokeh and rim lighting"
|
|
146136
|
+
→ No enhancement needed (preserve user's vision)
|
|
146137
|
+
|
|
146138
|
+
|
|
146139
|
+
CONTEXT-SPECIFIC GUIDELINES:
|
|
146140
|
+
|
|
146141
|
+
Interior/Indoor scenes:
|
|
146142
|
+
- Lighting: Soft natural window light
|
|
146143
|
+
- Backdrop: white walls or neutral tones
|
|
146144
|
+
- Mood: Calm, serene, inviting, uncluttered
|
|
146145
|
+
- Reference: "Kinfolk interior photography"
|
|
146146
|
+
|
|
146147
|
+
People/Portraits/Activities:
|
|
146148
|
+
- Lighting: Natural diffused light, flattering and soft
|
|
146149
|
+
- Styling: Effortlessly elegant, contemporary casual
|
|
146150
|
+
- Pose: Candid, authentic moments, relaxed
|
|
146151
|
+
- Reference: "modern lifestyle editorial photography"
|
|
146152
|
+
|
|
146153
|
+
Products/Objects:
|
|
146154
|
+
- Lighting: Clean studio or soft natural light
|
|
146155
|
+
- Backdrop: Minimalist neutral, lots of breathing room
|
|
146156
|
+
- Mood: Refined simplicity, premium feel
|
|
146157
|
+
- Reference: "high-end editorial product photography"
|
|
146158
|
+
|
|
146159
|
+
Food/Culinary:
|
|
146160
|
+
- Lighting: Soft daylight, gentle overhead or 45° angle
|
|
146161
|
+
- Styling: Minimal props, artisan ceramics, linen
|
|
146162
|
+
- Mood: Fresh, appetizing, rustic-modern
|
|
146163
|
+
- Reference: "Bon Appétit editorial food styling"
|
|
146164
|
+
|
|
146165
|
+
Outdoor/Landscape:
|
|
146166
|
+
- Composition: Serene, contemplative, minimal
|
|
146167
|
+
- Mood: Calm atmosphere, breathing space, lifted brightness
|
|
146168
|
+
- Colors: Vibrant cinematic shot.
|
|
146169
|
+
- Reference: "editorial travel photography"
|
|
146170
|
+
|
|
146171
|
+
CRITICAL RULES:
|
|
146172
|
+
1. If user specifies a style (cinematic, vintage, vibrant, etc.) → RESPECT IT, only add quality markers
|
|
146173
|
+
2. If user is vague → APPLY FULL EDITORIAL TREATMENT based on subject category
|
|
146174
|
+
3. Always maintain cohesive aesthetic across all images
|
|
146175
|
+
4. Every prompt should feel like it belongs in a high-end lifestyle magazine
|
|
146176
|
+
|
|
145101
146177
|
Respond with a JSON array with one entry per image to generate:
|
|
145102
146178
|
[
|
|
145103
146179
|
{
|
|
@@ -145202,7 +146278,12 @@ Response: [
|
|
|
145202
146278
|
|
|
145203
146279
|
|
|
145204
146280
|
async sendMessage() {
|
|
145205
|
-
const out = s => this.out(s);
|
|
146281
|
+
const out = s => this.out(s); // Prevent sending messages in demo mode
|
|
146282
|
+
|
|
146283
|
+
|
|
146284
|
+
if (this.isDemoMode) {
|
|
146285
|
+
return;
|
|
146286
|
+
}
|
|
145206
146287
|
|
|
145207
146288
|
const prompt = this.promptInput.value.trim();
|
|
145208
146289
|
if (!prompt) return;
|
|
@@ -145269,16 +146350,45 @@ Response: [
|
|
|
145269
146350
|
this.addMessage('assistant', `✓ ${result.description}`);
|
|
145270
146351
|
} else if (result.type === 'image') {
|
|
145271
146352
|
if (result.imageDetails && result.imageDetails.length > 1) {
|
|
145272
|
-
this.addMessage('assistant', `✓ Generated ${result.imageDetails.length} images successfully`);
|
|
146353
|
+
this.addMessage('assistant', `✓ Generated ${result.imageDetails.length} images successfully`); // this.addMessage('assistant', `✓ ${out('Generated {count} images successfully').replace('{count}', result.imageDetails.length)}`);
|
|
146354
|
+
|
|
145273
146355
|
this.addImagePreview(result.imageDetails);
|
|
145274
146356
|
} else {
|
|
145275
|
-
this.addMessage('assistant', '✓
|
|
146357
|
+
this.addMessage('assistant', '✓ Image generated successfully'); // this.addMessage('assistant', `✓ ${out('Image generated successfully')}`);
|
|
145276
146358
|
|
|
145277
146359
|
if (result.generatedUrls && result.generatedUrls[0]) {
|
|
145278
146360
|
this.addImagePreview([{
|
|
145279
146361
|
url: result.generatedUrls[0],
|
|
145280
146362
|
context: result.description
|
|
145281
|
-
}]);
|
|
146363
|
+
}]); // If there is a selected image, replace with the new image
|
|
146364
|
+
|
|
146365
|
+
const url = result.generatedUrls[0];
|
|
146366
|
+
|
|
146367
|
+
if (this.builder.editor) {
|
|
146368
|
+
// ContentBox
|
|
146369
|
+
const img = this.builder.editor.activeImage;
|
|
146370
|
+
|
|
146371
|
+
if (img) {
|
|
146372
|
+
this.builder.editor.saveForUndo();
|
|
146373
|
+
img.addEventListener('load', () => {
|
|
146374
|
+
this.builder.editor.element.image.repositionImageTool();
|
|
146375
|
+
this.builder.editor.elmTool.repositionElementTool();
|
|
146376
|
+
});
|
|
146377
|
+
this.builder.editor.activeImage.setAttribute('src', url);
|
|
146378
|
+
}
|
|
146379
|
+
} else {
|
|
146380
|
+
// ContentBuilder
|
|
146381
|
+
const img = this.builder.activeImage;
|
|
146382
|
+
|
|
146383
|
+
if (img) {
|
|
146384
|
+
this.builder.uo.saveForUndo();
|
|
146385
|
+
img.addEventListener('load', () => {
|
|
146386
|
+
this.builder.element.image.repositionImageTool();
|
|
146387
|
+
this.builder.elmTool.repositionElementTool();
|
|
146388
|
+
});
|
|
146389
|
+
this.builder.activeImage.setAttribute('src', url);
|
|
146390
|
+
}
|
|
146391
|
+
}
|
|
145282
146392
|
}
|
|
145283
146393
|
}
|
|
145284
146394
|
}
|
|
@@ -145336,14 +146446,14 @@ Response: [
|
|
|
145336
146446
|
`;
|
|
145337
146447
|
images.forEach(img => {
|
|
145338
146448
|
previewHTML += `
|
|
145339
|
-
<div style="border-radius:
|
|
145340
|
-
<img src="${img.url}" alt="${img.context || 'Generated image'}" style="width: 100%;
|
|
146449
|
+
<div style="border-radius: 6px; overflow: hidden; background: rgba(255,255,255,0.05);">
|
|
146450
|
+
<img src="${img.url}" alt="${img.context || 'Generated image'}" style="width: 100%;" />
|
|
145341
146451
|
<div style="padding: 8px; font-size: 11px; opacity: 0.8;">
|
|
145342
146452
|
${img.context || ''}
|
|
145343
146453
|
<a href="${img.url}" target="_blank" rel="noopener noreferrer" style="display: block; margin-top: 4px;">View</a>
|
|
145344
146454
|
</div>
|
|
145345
146455
|
</div>
|
|
145346
|
-
`;
|
|
146456
|
+
`; // height: 150px; object-fit: cover;
|
|
145347
146457
|
});
|
|
145348
146458
|
previewHTML += '</div>';
|
|
145349
146459
|
previewDiv.innerHTML = previewHTML;
|
|
@@ -145363,7 +146473,34 @@ Response: [
|
|
|
145363
146473
|
...this.builder.defaultHeaders
|
|
145364
146474
|
}; // Check if image generation is enabled
|
|
145365
146475
|
|
|
145366
|
-
const imageGenEnabled = this.builder.generateMediaUrl_Fal ? true : false;
|
|
146476
|
+
const imageGenEnabled = this.builder.generateMediaUrl_Fal ? true : false; // Build context about previously generated images
|
|
146477
|
+
|
|
146478
|
+
let imageHistoryContext = '';
|
|
146479
|
+
const previousImageResults = this.conversationResults.filter(r => r.type === 'image' && r.generatedUrls && r.generatedUrls.length > 0);
|
|
146480
|
+
|
|
146481
|
+
if (previousImageResults.length > 0) {
|
|
146482
|
+
imageHistoryContext = '\n\n=== PREVIOUSLY GENERATED IMAGES IN THIS CONVERSATION ===\n';
|
|
146483
|
+
imageHistoryContext += 'The following images were generated earlier in this conversation:\n\n';
|
|
146484
|
+
previousImageResults.forEach((result, idx) => {
|
|
146485
|
+
if (result.imageDetails && result.imageDetails.length > 0) {
|
|
146486
|
+
result.imageDetails.forEach((img, imgIdx) => {
|
|
146487
|
+
imageHistoryContext += `Generated Image ${idx + 1}.${imgIdx + 1}:\n`;
|
|
146488
|
+
imageHistoryContext += ` URL: ${img.url}\n`;
|
|
146489
|
+
imageHistoryContext += ` Context: ${img.context}\n`;
|
|
146490
|
+
imageHistoryContext += ` Description: ${result.description}\n\n`;
|
|
146491
|
+
});
|
|
146492
|
+
} else {
|
|
146493
|
+
result.generatedUrls.forEach((url, urlIdx) => {
|
|
146494
|
+
imageHistoryContext += `Generated Image ${idx + 1}.${urlIdx + 1}:\n`;
|
|
146495
|
+
imageHistoryContext += ` URL: ${url}\n`;
|
|
146496
|
+
imageHistoryContext += ` Description: ${result.description}\n\n`;
|
|
146497
|
+
});
|
|
146498
|
+
}
|
|
146499
|
+
});
|
|
146500
|
+
imageHistoryContext += '⚠️ IMPORTANT: If the user refers to "the generated image", "this image", "the image", or "previous image", they are referring to these images above.\n';
|
|
146501
|
+
imageHistoryContext += '⚠️ DO NOT create a new image task. Instead, create a CODE task that uses these existing URLs.\n\n';
|
|
146502
|
+
}
|
|
146503
|
+
|
|
145367
146504
|
const classificationPrompt = `Analyze this user message and break it down into tasks.
|
|
145368
146505
|
|
|
145369
146506
|
CURRENT HTML CONTEXT (use this to understand the page structure):
|
|
@@ -145371,11 +146508,19 @@ CURRENT HTML CONTEXT (use this to understand the page structure):
|
|
|
145371
146508
|
${this.builder.html()}
|
|
145372
146509
|
\`\`\`
|
|
145373
146510
|
|
|
146511
|
+
${imageHistoryContext}
|
|
146512
|
+
|
|
145374
146513
|
IMPORTANT: This is a WEB BUILDER tool with chat capabilities. Valid requests are:
|
|
145375
146514
|
- Creating/editing/removing HTML content (code tasks)
|
|
145376
146515
|
${imageGenEnabled ? '- Generating images for the webpage (image tasks)' : ''}
|
|
145377
146516
|
- Asking questions or having conversations (chat tasks) - THIS CAN BE ABOUT ANYTHING
|
|
145378
146517
|
|
|
146518
|
+
CRITICAL CONTEXT RULE:
|
|
146519
|
+
- In a web builder, "create an article/blog/story/content" means CREATE A WEBPAGE (CODE task)
|
|
146520
|
+
- Only use CHAT task for questions, explanations, or requests for advice
|
|
146521
|
+
- If user says "create", "write", "make", "build" followed by content → CODE task
|
|
146522
|
+
- If user says "explain", "how do I", "what is", "tell me about" → CHAT task
|
|
146523
|
+
|
|
145379
146524
|
${imageGenEnabled ? '' : `
|
|
145380
146525
|
⚠️ AI IMAGE GENERATION IS CURRENTLY DISABLED
|
|
145381
146526
|
- If user requests AI image generation/creation, explain that it's disabled
|
|
@@ -145445,6 +146590,18 @@ IMAGE TASK RULES:
|
|
|
145445
146590
|
- IMPORTANT: Look at the HTML context to understand if multiple images are involved
|
|
145446
146591
|
- If the target section has multiple images, indicate this in targetElement (e.g., "all 3 images in Culinary Delights section")
|
|
145447
146592
|
- Image tasks should come BEFORE code tasks that depend on them
|
|
146593
|
+
|
|
146594
|
+
- CRITICAL: DO NOT create image task for these phrases (they mean REUSE existing):
|
|
146595
|
+
* "use the generated image" / "use the image"
|
|
146596
|
+
* "use this image" / "use existing image"
|
|
146597
|
+
* "with the generated image" / "with this image"
|
|
146598
|
+
* "with the previous image" / "with the last image"
|
|
146599
|
+
* "using the image I just created/generated"
|
|
146600
|
+
* Any reference to a PREVIOUS image from conversation history
|
|
146601
|
+
- Decision logic:
|
|
146602
|
+
* "Generate a new image of X" → CREATE image task (new generation)
|
|
146603
|
+
* "Create article using the generated image" → NO image task (reuse existing)
|
|
146604
|
+
|
|
145448
146605
|
` : ''}
|
|
145449
146606
|
|
|
145450
146607
|
Examples:
|
|
@@ -145482,6 +146639,17 @@ Input: "Create a landing page about wood furniture workshop"
|
|
|
145482
146639
|
Output: {"is_valid": true, "tasks": [{"type": "code", "description": "Create a landing page for a wood furniture workshop", "order": 1}], "is_mixed": false}
|
|
145483
146640
|
Note: No image task created because user did not explicitly request AI image generation
|
|
145484
146641
|
|
|
146642
|
+
Input: "Create an inspiring article and use the generated image"
|
|
146643
|
+
Output: {"is_valid": true, "tasks": [{"type": "code", "description": "Create article using previously generated image from conversation history", "order": 1}], "is_mixed": false}
|
|
146644
|
+
Note: No image task because user wants to REUSE existing image
|
|
146645
|
+
|
|
146646
|
+
Input: "Write a blog post about productivity and use this image"
|
|
146647
|
+
Output: {"is_valid": true, "tasks": [{"type": "code", "description": "Create blog post using previously generated image", "order": 1}], "is_mixed": false}
|
|
146648
|
+
|
|
146649
|
+
Input: "Generate another mountain image and create a landing page"
|
|
146650
|
+
Output: {"tasks": [{"type": "image", "description": "Generate new mountain image", "imagePrompt": "...", "order": 1}, {"type": "code", "description": "Create landing page with new image", "order": 2}], "is_mixed": true}
|
|
146651
|
+
Note: "another" and "generate" indicate NEW image generation
|
|
146652
|
+
|
|
145485
146653
|
` : `
|
|
145486
146654
|
Input: "Generate an AI image of a mountain"
|
|
145487
146655
|
Output: {"is_valid": false, "reason": "AI image generation is currently disabled.", "tasks": [], "is_mixed": false}
|
|
@@ -145564,8 +146732,9 @@ Output: {"is_valid": false, "reason": "AI image generation is currently disabled
|
|
|
145564
146732
|
|
|
145565
146733
|
if (imageTasksFromThisRequest.length > 0) {
|
|
145566
146734
|
hasGeneratedImages = true;
|
|
145567
|
-
imageContext = '\n\n=== GENERATED IMAGE URLS (USE THESE FOR YOUR TASK) ===\n';
|
|
145568
|
-
|
|
146735
|
+
imageContext = '\n\n=== GENERATED IMAGE URLS (USE THESE FOR YOUR TASK) ===\n'; // ⭐ REVERSE to show most recent first
|
|
146736
|
+
|
|
146737
|
+
imageTasksFromThisRequest.reverse().forEach(imageTask => {
|
|
145569
146738
|
if (imageTask.imageDetails && imageTask.imageDetails.length > 0) {
|
|
145570
146739
|
// Multiple images with context
|
|
145571
146740
|
imageTask.imageDetails.forEach((img, idx) => {
|
|
@@ -145580,7 +146749,8 @@ Output: {"is_valid": false, "reason": "AI image generation is currently disabled
|
|
|
145580
146749
|
});
|
|
145581
146750
|
}
|
|
145582
146751
|
});
|
|
145583
|
-
imageContext += '\n⚠️ IMPORTANT: Use
|
|
146752
|
+
imageContext += '\n⚠️ IMPORTANT: Use the FIRST image URL listed above (most recent) unless the task specifically asks for a different image.\n';
|
|
146753
|
+
imageContext += '⚠️ The first image is the MOST RECENTLY GENERATED and should be used by default.\n';
|
|
145584
146754
|
imageContext += '⚠️ Your task description specifies WHICH images to update - follow it precisely.\n';
|
|
145585
146755
|
} // ⭐ ALSO CHECK FOR CHAT RESULTS FROM PREVIOUS TASKS
|
|
145586
146756
|
|
|
@@ -146163,6 +147333,320 @@ ${this.builder.html()}
|
|
|
146163
147333
|
document.body.removeChild(announcement);
|
|
146164
147334
|
}, 1000);
|
|
146165
147335
|
}
|
|
147336
|
+
/**
|
|
147337
|
+
* ============================================================================
|
|
147338
|
+
* DEMO MODE
|
|
147339
|
+
* ============================================================================
|
|
147340
|
+
*/
|
|
147341
|
+
|
|
147342
|
+
|
|
147343
|
+
loadConversations() {
|
|
147344
|
+
// Load demo conversations
|
|
147345
|
+
if (this.demoConversations && this.demoConversations.length > 0) {
|
|
147346
|
+
this.demoConversations.forEach(msg => {
|
|
147347
|
+
if (msg.role === 'user') {
|
|
147348
|
+
this.addMessage('user', msg.content);
|
|
147349
|
+
} else if (msg.role === 'assistant') {
|
|
147350
|
+
this.addMessage('assistant', msg.content, true); // Add image preview if available
|
|
147351
|
+
|
|
147352
|
+
if (msg.imagePreview && msg.imagePreview.length > 0) {
|
|
147353
|
+
this.addImagePreview(msg.imagePreview); // Include in conversationResults with correct structure
|
|
147354
|
+
|
|
147355
|
+
this.conversationResults.push({
|
|
147356
|
+
type: 'image',
|
|
147357
|
+
description: 'Previously generated image from demo',
|
|
147358
|
+
content: `Generated ${msg.imagePreview.length} images`,
|
|
147359
|
+
generatedUrls: msg.imagePreview.map(img => img.url),
|
|
147360
|
+
// Array of URLs
|
|
147361
|
+
imageDetails: msg.imagePreview.map(img => ({
|
|
147362
|
+
// Array of objects
|
|
147363
|
+
url: img.url,
|
|
147364
|
+
context: img.context,
|
|
147365
|
+
prompt: img.context || '' // Use context as prompt if no prompt available
|
|
147366
|
+
|
|
147367
|
+
})),
|
|
147368
|
+
targetElement: 'demo images'
|
|
147369
|
+
});
|
|
147370
|
+
}
|
|
147371
|
+
}
|
|
147372
|
+
});
|
|
147373
|
+
}
|
|
147374
|
+
}
|
|
147375
|
+
|
|
147376
|
+
addDemoBanner() {
|
|
147377
|
+
const out = s => this.out(s);
|
|
147378
|
+
|
|
147379
|
+
const banner = document.createElement('div');
|
|
147380
|
+
banner.className = 'demo-banner';
|
|
147381
|
+
banner.innerHTML = `
|
|
147382
|
+
<div style="
|
|
147383
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
147384
|
+
color: white;
|
|
147385
|
+
padding: 12px 16px;
|
|
147386
|
+
border-radius: 8px;
|
|
147387
|
+
font-size: 13px;
|
|
147388
|
+
display: flex;
|
|
147389
|
+
align-items: center;
|
|
147390
|
+
gap: 8px;
|
|
147391
|
+
box-shadow: 0 4px 12px rgba(102, 126, 234, 0.3);
|
|
147392
|
+
">
|
|
147393
|
+
<span style="font-size: 18px;">📖</span>
|
|
147394
|
+
<div>
|
|
147395
|
+
<strong>${out('Read-Only Demo')}</strong>
|
|
147396
|
+
<div style="font-size: 11px; opacity: 0.9; margin-top: 2px;">
|
|
147397
|
+
${out('Full AI chat available in the complete version.')}
|
|
147398
|
+
</div>
|
|
147399
|
+
</div>
|
|
147400
|
+
</div>
|
|
147401
|
+
`; // Insert banner at the top of messages container
|
|
147402
|
+
// this.messagesContainer.insertBefore(banner, this.messagesContainer.firstChild);
|
|
147403
|
+
|
|
147404
|
+
this.messagesContainer.appendChild(banner);
|
|
147405
|
+
}
|
|
147406
|
+
/**
|
|
147407
|
+
* Update the quick image size button based on current model and settings
|
|
147408
|
+
*/
|
|
147409
|
+
|
|
147410
|
+
|
|
147411
|
+
updateQuickImageSizeButton() {
|
|
147412
|
+
const imageGenEnabled = this.builder.generateMediaUrl_Fal ? true : false;
|
|
147413
|
+
|
|
147414
|
+
if (!imageGenEnabled) {
|
|
147415
|
+
this.quickImageSizeButton.style.display = 'none';
|
|
147416
|
+
return;
|
|
147417
|
+
}
|
|
147418
|
+
|
|
147419
|
+
const currentModelId = this.settings.imageModel;
|
|
147420
|
+
const availableSizes = this.getSizesForModel(currentModelId); // Hide button if model has no size options
|
|
147421
|
+
|
|
147422
|
+
if (!availableSizes || availableSizes.length === 0) {
|
|
147423
|
+
this.quickImageSizeButton.style.display = 'none';
|
|
147424
|
+
return;
|
|
147425
|
+
} // Show button
|
|
147426
|
+
|
|
147427
|
+
|
|
147428
|
+
this.quickImageSizeButton.style.display = 'flex'; // Smart selection: check if current size is available
|
|
147429
|
+
|
|
147430
|
+
let selectedSize = this.settings.imageSize;
|
|
147431
|
+
|
|
147432
|
+
if (!availableSizes.includes(selectedSize)) {
|
|
147433
|
+
// Current size not available, find best fallback
|
|
147434
|
+
selectedSize = this.findBestFallback(selectedSize, availableSizes);
|
|
147435
|
+
this.settings.imageSize = selectedSize; // Sync with settings dialog
|
|
147436
|
+
|
|
147437
|
+
this.imageSizeSelect.value = selectedSize; // Save to storage
|
|
147438
|
+
|
|
147439
|
+
this.saveSettingsToStorage();
|
|
147440
|
+
} // Update button label
|
|
147441
|
+
|
|
147442
|
+
|
|
147443
|
+
this.updateButtonLabel(selectedSize); // Populate popover options
|
|
147444
|
+
|
|
147445
|
+
this.populateSizePopover(availableSizes, selectedSize);
|
|
147446
|
+
}
|
|
147447
|
+
/**
|
|
147448
|
+
* Get available sizes for a model (reuse existing logic)
|
|
147449
|
+
*/
|
|
147450
|
+
|
|
147451
|
+
|
|
147452
|
+
getSizesForModel(modelId) {
|
|
147453
|
+
const model = this.imageModels.find(m => m.id === modelId);
|
|
147454
|
+
if (!model) return null; // if sizes explicitly empty array → means no size options
|
|
147455
|
+
|
|
147456
|
+
if (Array.isArray(model.sizes) && model.sizes.length === 0) {
|
|
147457
|
+
return null;
|
|
147458
|
+
}
|
|
147459
|
+
|
|
147460
|
+
const defaultSizes = ['square', 'square_hd', 'landscape_4_3', 'landscape_16_9', 'portrait_4_3', 'portrait_16_9'];
|
|
147461
|
+
return model.sizes || defaultSizes;
|
|
147462
|
+
}
|
|
147463
|
+
/**
|
|
147464
|
+
* Find best fallback size when current selection is not available
|
|
147465
|
+
*/
|
|
147466
|
+
|
|
147467
|
+
|
|
147468
|
+
findBestFallback(preferredSize, availableSizes) {
|
|
147469
|
+
// Strategy 1: Try to match orientation
|
|
147470
|
+
const orientation = this.getOrientation(preferredSize);
|
|
147471
|
+
const matchingOrientation = availableSizes.find(size => this.getOrientation(size) === orientation);
|
|
147472
|
+
if (matchingOrientation) return matchingOrientation; // Strategy 2: Common defaults
|
|
147473
|
+
|
|
147474
|
+
if (availableSizes.includes('16:9')) return '16:9';
|
|
147475
|
+
if (availableSizes.includes('landscape_16_9')) return 'landscape_16_9';
|
|
147476
|
+
if (availableSizes.includes('1:1')) return '1:1';
|
|
147477
|
+
if (availableSizes.includes('square')) return 'square'; // Strategy 3: First available
|
|
147478
|
+
|
|
147479
|
+
return availableSizes[0];
|
|
147480
|
+
}
|
|
147481
|
+
/**
|
|
147482
|
+
* Determine orientation from size value
|
|
147483
|
+
*/
|
|
147484
|
+
|
|
147485
|
+
|
|
147486
|
+
getOrientation(size) {
|
|
147487
|
+
const landscape = ['16:9', '21:9', '4:3', '3:2', '5:4', 'landscape_16_9', 'landscape_4_3'];
|
|
147488
|
+
const portrait = ['9:16', '9:21', '3:4', '2:3', '4:5', 'portrait_16_9', 'portrait_4_3'];
|
|
147489
|
+
if (landscape.includes(size)) return 'landscape';
|
|
147490
|
+
if (portrait.includes(size)) return 'portrait';
|
|
147491
|
+
return 'square';
|
|
147492
|
+
}
|
|
147493
|
+
/**
|
|
147494
|
+
* Update button label to show current size
|
|
147495
|
+
*/
|
|
147496
|
+
|
|
147497
|
+
|
|
147498
|
+
updateButtonLabel(sizeValue) {
|
|
147499
|
+
if (!sizeValue) {
|
|
147500
|
+
this.quickImageSizeButton.textContent = '□';
|
|
147501
|
+
this.quickImageSizeButton.setAttribute('aria-label', this.out('Select image size'));
|
|
147502
|
+
return;
|
|
147503
|
+
} // Convert verbose labels to short form
|
|
147504
|
+
|
|
147505
|
+
|
|
147506
|
+
const labelMap = {
|
|
147507
|
+
'landscape_16_9': '16:9',
|
|
147508
|
+
'landscape_4_3': '4:3',
|
|
147509
|
+
'portrait_16_9': '9:16',
|
|
147510
|
+
'portrait_4_3': '3:4',
|
|
147511
|
+
'square': '1:1',
|
|
147512
|
+
'square_hd': '1:1 HD'
|
|
147513
|
+
};
|
|
147514
|
+
const displayLabel = labelMap[sizeValue] || sizeValue;
|
|
147515
|
+
this.quickImageSizeButton.textContent = displayLabel;
|
|
147516
|
+
this.quickImageSizeButton.setAttribute('aria-label', `${this.out('Image size')}: ${displayLabel}`);
|
|
147517
|
+
}
|
|
147518
|
+
/**
|
|
147519
|
+
* Populate the size popover with available options
|
|
147520
|
+
*/
|
|
147521
|
+
|
|
147522
|
+
|
|
147523
|
+
populateSizePopover(sizes, selectedSize) {
|
|
147524
|
+
const out = s => this.out(s);
|
|
147525
|
+
|
|
147526
|
+
const sizeDefs = {
|
|
147527
|
+
'square_hd': out('Square HD'),
|
|
147528
|
+
'square': out('Square'),
|
|
147529
|
+
'landscape_4_3': out('Landscape 4x3'),
|
|
147530
|
+
'landscape_16_9': out('Landscape 16x9'),
|
|
147531
|
+
'portrait_4_3': out('Portrait 3x4'),
|
|
147532
|
+
'portrait_16_9': out('Portrait 9x16'),
|
|
147533
|
+
'1:1': out('Square'),
|
|
147534
|
+
'3:2': out('Landscape 3x2'),
|
|
147535
|
+
'4:3': out('Landscape 4x3'),
|
|
147536
|
+
'5:4': out('Landscape 5x4'),
|
|
147537
|
+
'16:9': out('Landscape 16x9'),
|
|
147538
|
+
'21:9': out('Landscape 21:9'),
|
|
147539
|
+
'2:3': out('Portrait 2x3'),
|
|
147540
|
+
'3:4': out('Portrait 3x4'),
|
|
147541
|
+
'4:5': out('Portrait 4x5'),
|
|
147542
|
+
'9:16': out('Portrait 9x16'),
|
|
147543
|
+
'9:21': out('Portrait 9:21')
|
|
147544
|
+
};
|
|
147545
|
+
this.sizeOptionsContainer.innerHTML = '';
|
|
147546
|
+
sizes.forEach(size => {
|
|
147547
|
+
const option = document.createElement('div');
|
|
147548
|
+
option.className = 'size-option' + (size === selectedSize ? ' selected' : '');
|
|
147549
|
+
option.setAttribute('role', 'menuitem');
|
|
147550
|
+
option.setAttribute('tabindex', '0');
|
|
147551
|
+
const radio = document.createElement('input');
|
|
147552
|
+
radio.type = 'radio';
|
|
147553
|
+
radio.name = 'quickImageSize';
|
|
147554
|
+
radio.value = size;
|
|
147555
|
+
radio.checked = size === selectedSize;
|
|
147556
|
+
radio.id = `quick-size-${size}`;
|
|
147557
|
+
const label = document.createElement('label');
|
|
147558
|
+
label.htmlFor = `quick-size-${size}`;
|
|
147559
|
+
label.textContent = sizeDefs[size] || size; // label.style.cursor = 'pointer';
|
|
147560
|
+
|
|
147561
|
+
label.style.flex = '1';
|
|
147562
|
+
option.appendChild(radio);
|
|
147563
|
+
option.appendChild(label); // Click handler
|
|
147564
|
+
|
|
147565
|
+
option.addEventListener('click', () => {
|
|
147566
|
+
this.selectImageSize(size);
|
|
147567
|
+
}); // Keyboard handler
|
|
147568
|
+
|
|
147569
|
+
option.addEventListener('keydown', e => {
|
|
147570
|
+
if (e.key === 'Enter' || e.key === ' ') {
|
|
147571
|
+
e.preventDefault();
|
|
147572
|
+
this.selectImageSize(size);
|
|
147573
|
+
}
|
|
147574
|
+
});
|
|
147575
|
+
this.sizeOptionsContainer.appendChild(option);
|
|
147576
|
+
});
|
|
147577
|
+
}
|
|
147578
|
+
/**
|
|
147579
|
+
* Handle size selection
|
|
147580
|
+
*/
|
|
147581
|
+
|
|
147582
|
+
|
|
147583
|
+
selectImageSize(size) {
|
|
147584
|
+
// Update settings
|
|
147585
|
+
this.settings.imageSize = size; // Sync with settings dialog
|
|
147586
|
+
|
|
147587
|
+
this.imageSizeSelect.value = size; // Update button label
|
|
147588
|
+
|
|
147589
|
+
this.updateButtonLabel(size); // Update popover selection
|
|
147590
|
+
|
|
147591
|
+
this.sizeOptionsContainer.querySelectorAll('.size-option').forEach(opt => {
|
|
147592
|
+
opt.classList.remove('selected');
|
|
147593
|
+
opt.querySelector('input[type="radio"]').checked = false;
|
|
147594
|
+
}); // const selectedOption = this.sizeOptionsContainer.querySelector(`#quick-size-${size}`);
|
|
147595
|
+
|
|
147596
|
+
const selectedOption = Array.from(this.sizeOptionsContainer.querySelectorAll('input[type="radio"]')).find(radio => radio.value === size);
|
|
147597
|
+
|
|
147598
|
+
if (selectedOption) {
|
|
147599
|
+
selectedOption.closest('.size-option').classList.add('selected');
|
|
147600
|
+
selectedOption.checked = true;
|
|
147601
|
+
} // Save to storage
|
|
147602
|
+
|
|
147603
|
+
|
|
147604
|
+
this.saveSettingsToStorage(); // Close popover
|
|
147605
|
+
|
|
147606
|
+
this.closeImageSizePopover(); // Focus back to input
|
|
147607
|
+
|
|
147608
|
+
this.promptInput.focus();
|
|
147609
|
+
}
|
|
147610
|
+
/**
|
|
147611
|
+
* Toggle popover visibility
|
|
147612
|
+
*/
|
|
147613
|
+
|
|
147614
|
+
|
|
147615
|
+
toggleImageSizePopover() {
|
|
147616
|
+
const isVisible = this.imageSizePopover.style.display !== 'none';
|
|
147617
|
+
|
|
147618
|
+
if (isVisible) {
|
|
147619
|
+
this.closeImageSizePopover();
|
|
147620
|
+
} else {
|
|
147621
|
+
this.openImageSizePopover();
|
|
147622
|
+
}
|
|
147623
|
+
}
|
|
147624
|
+
/**
|
|
147625
|
+
* Open the size popover
|
|
147626
|
+
*/
|
|
147627
|
+
|
|
147628
|
+
|
|
147629
|
+
openImageSizePopover() {
|
|
147630
|
+
this.imageSizePopover.style.display = 'block';
|
|
147631
|
+
this.imageSizePopover.setAttribute('aria-hidden', 'false');
|
|
147632
|
+
this.quickImageSizeButton.setAttribute('aria-expanded', 'true'); // Focus first option
|
|
147633
|
+
|
|
147634
|
+
const firstOption = this.sizeOptionsContainer.querySelector('.size-option');
|
|
147635
|
+
|
|
147636
|
+
if (firstOption) {
|
|
147637
|
+
firstOption.focus();
|
|
147638
|
+
}
|
|
147639
|
+
}
|
|
147640
|
+
/**
|
|
147641
|
+
* Close the size popover
|
|
147642
|
+
*/
|
|
147643
|
+
|
|
147644
|
+
|
|
147645
|
+
closeImageSizePopover() {
|
|
147646
|
+
this.imageSizePopover.style.display = 'none';
|
|
147647
|
+
this.imageSizePopover.setAttribute('aria-hidden', 'true');
|
|
147648
|
+
this.quickImageSizeButton.setAttribute('aria-expanded', 'false');
|
|
147649
|
+
}
|
|
146166
147650
|
|
|
146167
147651
|
out(s) {
|
|
146168
147652
|
let result = this.builder.lang[s];
|
|
@@ -146590,7 +148074,7 @@ Classes: transition-none, transition, transition-colors, transition-opacity, tra
|
|
|
146590
148074
|
|
|
146591
148075
|
**Duration**
|
|
146592
148076
|
|
|
146593
|
-
Classes: duration-75, duration-100, duration-150, duration-200, duration-300, duration-500, duration-700, duration-1000
|
|
148077
|
+
Classes: duration-75, duration-100, duration-150, duration-200, duration-300, duration-500, duration-700, duration-1000, duration-1500
|
|
146594
148078
|
|
|
146595
148079
|
**Timing**
|
|
146596
148080
|
|
|
@@ -146604,6 +148088,10 @@ Classes: delay-75, delay-100, delay-150, delay-200, delay-300, delay-500
|
|
|
146604
148088
|
|
|
146605
148089
|
Classes: scale-0, scale-50, scale-75, scale-90, scale-95, scale-100, scale-105, scale-110, scale-125, scale-150
|
|
146606
148090
|
|
|
148091
|
+
**Hover Effect**
|
|
148092
|
+
|
|
148093
|
+
Classes: hover:scale-105
|
|
148094
|
+
|
|
146607
148095
|
**Rotate**
|
|
146608
148096
|
|
|
146609
148097
|
Classes: rotate-0, rotate-45, rotate-90, rotate-180
|
|
@@ -146937,6 +148425,31 @@ When creating icon-based features, benefits, or service sections: use Bootstrap
|
|
|
146937
148425
|
<h4 class="size-18 font-medium text-center pb-3">Lightning Fast</h4>
|
|
146938
148426
|
<p class="size-14 leading-16 text-gray-600 text-center">Description...</p>
|
|
146939
148427
|
|
|
148428
|
+
### 9. Image Layout with Hover Effect
|
|
148429
|
+
|
|
148430
|
+
Use this pattern for all images (galleries, featured images, portfolio items):
|
|
148431
|
+
|
|
148432
|
+
<div class="w-full overflow-hidden relative bg-gray-50" style="aspect-ratio:16/9">
|
|
148433
|
+
<img src="..." alt="..." class="w-full h-full object-cover transition-transform duration-1500 hover:scale-105">
|
|
148434
|
+
</div>
|
|
148435
|
+
|
|
148436
|
+
**Key elements:**
|
|
148437
|
+
- 'aspect-ratio:16/9' - maintains proportions (adjust as needed: 1/1, 4/3, 3/2, 16/9, etc.)
|
|
148438
|
+
- 'overflow-hidden' - keeps scaled image contained
|
|
148439
|
+
- 'bg-gray-50' - placeholder while image loads
|
|
148440
|
+
- 'transition-transform duration-1000' - smooth 1-second animation
|
|
148441
|
+
- 'hover:scale-105' - subtle 5% scale on hover
|
|
148442
|
+
- 'object-cover' - ensures image fills container
|
|
148443
|
+
|
|
148444
|
+
**Common aspect ratios:**
|
|
148445
|
+
- Square: 'aspect-ratio:1/1'
|
|
148446
|
+
- Portrait: 'aspect-ratio:3/4' or 'aspect-ratio:2/3'
|
|
148447
|
+
- Landscape: 'aspect-ratio:4/3' or 'aspect-ratio:3/2'
|
|
148448
|
+
- Wide: 'aspect-ratio:16/9' or 'aspect-ratio:21/9'
|
|
148449
|
+
- Tall portrait: 'aspect-ratio:9/16'
|
|
148450
|
+
|
|
148451
|
+
Always include this hover effect for a polished, interactive feel.
|
|
148452
|
+
|
|
146940
148453
|
`;
|
|
146941
148454
|
|
|
146942
148455
|
const contextBoxFramework = `
|
|
@@ -147710,6 +149223,17 @@ The frameworks provide utility classes for structure and typography. To create r
|
|
|
147710
149223
|
|
|
147711
149224
|
<div class="is-container leading-14 size-18 is-content-1100">
|
|
147712
149225
|
|
|
149226
|
+
<div class="row">
|
|
149227
|
+
<div class="column">
|
|
149228
|
+
|
|
149229
|
+
<!-- GUIDANCE: Use this layout to show images at any aspect ratio with a hover scale effect -->
|
|
149230
|
+
<div class="w-full overflow-hidden relative bg-gray-50" style="aspect-ratio:16/9">
|
|
149231
|
+
<img src="https://placehold.co/1200x1200/f5f5f5/999?text=Featured" alt="Featured Project" class="w-full h-full object-cover transition-transform duration-1500 hover:scale-105">
|
|
149232
|
+
</div>
|
|
149233
|
+
|
|
149234
|
+
</div>
|
|
149235
|
+
</div>
|
|
149236
|
+
|
|
147713
149237
|
<div class="row">
|
|
147714
149238
|
<div class="column">
|
|
147715
149239
|
|
|
@@ -154480,6 +156004,33 @@ Add an image for each feature.`, 'Create a new block showcasing a photo gallery
|
|
|
154480
156004
|
*/
|
|
154481
156005
|
|
|
154482
156006
|
},
|
|
156007
|
+
demoMode: false,
|
|
156008
|
+
|
|
156009
|
+
/*
|
|
156010
|
+
demoConversations: [
|
|
156011
|
+
{
|
|
156012
|
+
role: 'user',
|
|
156013
|
+
content: 'Generate an image: "a house with beautiful mountain view. warm sunlight, golden-hour lighting, filmic teal-orange color grade".',
|
|
156014
|
+
// timestamp: Date.now() - 180000 // 3 minutes ago
|
|
156015
|
+
},
|
|
156016
|
+
{
|
|
156017
|
+
role: 'assistant',
|
|
156018
|
+
content: '✓ Image generated successfully',
|
|
156019
|
+
imagePreview: [
|
|
156020
|
+
{ url: 'uploads/ai-8vnqv.png', context: 'Generate image of a house with a beautiful mountain view' },
|
|
156021
|
+
]
|
|
156022
|
+
},
|
|
156023
|
+
{
|
|
156024
|
+
role: 'user',
|
|
156025
|
+
content: `Create a thoughtful article about finding home in extraordinary landscapes. Write vivid prose about mountain dwellings and how our environments shape the way we live.
|
|
156026
|
+
Use the generated image for this article, and present it as a premium design magazine feature.`,
|
|
156027
|
+
},
|
|
156028
|
+
{
|
|
156029
|
+
role: 'assistant',
|
|
156030
|
+
content: '✓ Create a thoughtful article about finding home in extraordinary landscapes with vivid prose about mountain dwellings and their impact on our lives, formatted as a premium design magazine feature.',
|
|
156031
|
+
}
|
|
156032
|
+
],
|
|
156033
|
+
*/
|
|
154483
156034
|
|
|
154484
156035
|
/* Old Version (backward compatible) */
|
|
154485
156036
|
onAddSectionOpen: function () {},
|