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