@innovastudio/contentbox 1.6.175 → 1.6.177
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -115892,6 +115892,10 @@ class CodeChat$1 {
|
|
|
115892
115892
|
this.builder = builder;
|
|
115893
115893
|
const builderStuff = this.builder.builderStuff;
|
|
115894
115894
|
this.builderStuff = builderStuff;
|
|
115895
|
+
|
|
115896
|
+
// Check if demo mode is enabled
|
|
115897
|
+
this.isDemoMode = this.builder.demoMode || false;
|
|
115898
|
+
this.demoConversations = this.builder.demoConversations || [];
|
|
115895
115899
|
const out = s => this.out(s);
|
|
115896
115900
|
|
|
115897
115901
|
// Load saved settings or use defaults
|
|
@@ -115901,6 +115905,9 @@ class CodeChat$1 {
|
|
|
115901
115905
|
this.systemModel = this.builder.systemModel;
|
|
115902
115906
|
}
|
|
115903
115907
|
this.codeModels = [{
|
|
115908
|
+
id: 'anthropic/claude-opus-4.5',
|
|
115909
|
+
label: 'Claude Opus 4.5'
|
|
115910
|
+
}, {
|
|
115904
115911
|
id: 'google/gemini-3-pro-preview',
|
|
115905
115912
|
label: 'Google Gemini 3 Pro Preview'
|
|
115906
115913
|
}, {
|
|
@@ -116228,6 +116235,12 @@ class CodeChat$1 {
|
|
|
116228
116235
|
// backward
|
|
116229
116236
|
this.imageModels = this.builder.imageGenerationModels;
|
|
116230
116237
|
}
|
|
116238
|
+
let inputPlaceholderText;
|
|
116239
|
+
if (this.builder.editor) {
|
|
116240
|
+
inputPlaceholderText = out('e.g., Create a landing page for a creative studio');
|
|
116241
|
+
} else {
|
|
116242
|
+
inputPlaceholderText = out('e.g., Create an article about a productive home workspace');
|
|
116243
|
+
}
|
|
116231
116244
|
let html = `
|
|
116232
116245
|
<style>
|
|
116233
116246
|
#chatPanel {
|
|
@@ -116559,10 +116572,12 @@ class CodeChat$1 {
|
|
|
116559
116572
|
box-shadow: 6px 14px 20px 0px rgba(95, 95, 95, 0.11);
|
|
116560
116573
|
z-index: 10005;
|
|
116561
116574
|
display: none;
|
|
116575
|
+
pointer-events: auto; /* Reset cursor to default to prevent it from getting stuck */
|
|
116562
116576
|
}
|
|
116563
116577
|
|
|
116564
116578
|
#settingsDialog.open {
|
|
116565
116579
|
display: block;
|
|
116580
|
+
pointer-events: auto; /* Reset cursor to default to prevent it from getting stuck */
|
|
116566
116581
|
}
|
|
116567
116582
|
|
|
116568
116583
|
#settingsDialog .settings-header {
|
|
@@ -116823,9 +116838,118 @@ class CodeChat$1 {
|
|
|
116823
116838
|
body.dark #chatPanel .copy-button:hover {
|
|
116824
116839
|
background: rgba(255, 255, 255, 0.2);
|
|
116825
116840
|
}
|
|
116841
|
+
|
|
116842
|
+
|
|
116843
|
+
/* Quick Image Size Button */
|
|
116844
|
+
#chatPanel .quick-image-size-button {
|
|
116845
|
+
width: 48px;
|
|
116846
|
+
height: 48px;
|
|
116847
|
+
border: none;
|
|
116848
|
+
border-radius: 8px;
|
|
116849
|
+
font-size: 13px;
|
|
116850
|
+
font-weight: 500;
|
|
116851
|
+
cursor: pointer;
|
|
116852
|
+
transition: background 0.2s;
|
|
116853
|
+
display: flex;
|
|
116854
|
+
align-items: center;
|
|
116855
|
+
justify-content: center;
|
|
116856
|
+
}
|
|
116857
|
+
|
|
116858
|
+
#chatPanel .quick-image-size-button:hover:not(:disabled) {
|
|
116859
|
+
background: rgba(0, 0, 0, 0.05);
|
|
116860
|
+
}
|
|
116861
|
+
|
|
116862
|
+
#chatPanel .quick-image-size-button:disabled {
|
|
116863
|
+
opacity: 0.6;
|
|
116864
|
+
cursor: not-allowed;
|
|
116865
|
+
}
|
|
116866
|
+
|
|
116867
|
+
body.dark #chatPanel .quick-image-size-button {
|
|
116868
|
+
background: #484848;
|
|
116869
|
+
}
|
|
116870
|
+
|
|
116871
|
+
body.dark #chatPanel .quick-image-size-button:hover:not(:disabled) {
|
|
116872
|
+
background: #4c4c4c;
|
|
116873
|
+
}
|
|
116874
|
+
|
|
116875
|
+
/* Image Size Popover */
|
|
116876
|
+
#chatPanel .image-size-popover {
|
|
116877
|
+
position: absolute;
|
|
116878
|
+
bottom: 72px;
|
|
116879
|
+
right: 68px;
|
|
116880
|
+
background: white;
|
|
116881
|
+
border: 1px solid #e5e5e5;
|
|
116882
|
+
border-radius: 8px;
|
|
116883
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
|
116884
|
+
z-index: 10006;
|
|
116885
|
+
min-width: 160px;
|
|
116886
|
+
max-height: 300px;
|
|
116887
|
+
overflow-y: auto;
|
|
116888
|
+
}
|
|
116889
|
+
|
|
116890
|
+
body.dark #chatPanel .image-size-popover {
|
|
116891
|
+
background: #3a3a3a;
|
|
116892
|
+
border-color: #555;
|
|
116893
|
+
}
|
|
116894
|
+
|
|
116895
|
+
#chatPanel .size-options {
|
|
116896
|
+
padding: 8px;
|
|
116897
|
+
}
|
|
116898
|
+
|
|
116899
|
+
#chatPanel .size-option {
|
|
116900
|
+
display: flex;
|
|
116901
|
+
align-items: center;
|
|
116902
|
+
padding: 10px 12px;
|
|
116903
|
+
cursor: pointer;
|
|
116904
|
+
border-radius: 6px;
|
|
116905
|
+
transition: background 0.2s;
|
|
116906
|
+
font-size: 14px;
|
|
116907
|
+
}
|
|
116908
|
+
#chatPanel .size-option label,
|
|
116909
|
+
#chatPanel .size-option input {
|
|
116910
|
+
cursor: pointer;
|
|
116911
|
+
}
|
|
116912
|
+
|
|
116913
|
+
#chatPanel .size-option:hover {
|
|
116914
|
+
background: rgba(0, 0, 0, 0.05);
|
|
116915
|
+
}
|
|
116916
|
+
|
|
116917
|
+
#chatPanel .size-option.selected {
|
|
116918
|
+
background: rgba(62, 147, 247, 0.1);
|
|
116919
|
+
font-weight: 500;
|
|
116920
|
+
}
|
|
116921
|
+
|
|
116922
|
+
#chatPanel .size-option input[type="radio"] {
|
|
116923
|
+
margin-right: 8px;
|
|
116924
|
+
}
|
|
116925
|
+
|
|
116926
|
+
body.dark #chatPanel .size-option:hover {
|
|
116927
|
+
background: rgba(255, 255, 255, 0.1);
|
|
116928
|
+
}
|
|
116929
|
+
|
|
116930
|
+
body.dark #chatPanel .size-option.selected {
|
|
116931
|
+
background: rgba(62, 147, 247, 0.2);
|
|
116932
|
+
}
|
|
116933
|
+
|
|
116934
|
+
#chatPanel .image-size-popover::-webkit-scrollbar {
|
|
116935
|
+
width: 6px;
|
|
116936
|
+
}
|
|
116937
|
+
|
|
116938
|
+
#chatPanel .image-size-popover::-webkit-scrollbar-track {
|
|
116939
|
+
background: transparent;
|
|
116940
|
+
}
|
|
116941
|
+
|
|
116942
|
+
#chatPanel .image-size-popover::-webkit-scrollbar-thumb {
|
|
116943
|
+
background: #e5e5e5;
|
|
116944
|
+
border-radius: 3px;
|
|
116945
|
+
}
|
|
116946
|
+
|
|
116947
|
+
body.dark #chatPanel .image-size-popover::-webkit-scrollbar-thumb {
|
|
116948
|
+
background: #555;
|
|
116949
|
+
}
|
|
116826
116950
|
</style>
|
|
116827
116951
|
<div
|
|
116828
|
-
class="hidden"
|
|
116952
|
+
class="hidden keep-selection"
|
|
116829
116953
|
id="chatPanel"
|
|
116830
116954
|
role="dialog"
|
|
116831
116955
|
aria-labelledby="chatPanelTitle"
|
|
@@ -116875,10 +116999,24 @@ class CodeChat$1 {
|
|
|
116875
116999
|
<label for="promptInput" class="sr-only">${out('Message input')}</label>
|
|
116876
117000
|
<textarea
|
|
116877
117001
|
id="promptInput"
|
|
116878
|
-
placeholder="${
|
|
117002
|
+
placeholder="${inputPlaceholderText}"
|
|
116879
117003
|
rows="1"
|
|
116880
117004
|
aria-label="${out('Type your message')}"
|
|
116881
117005
|
></textarea>
|
|
117006
|
+
|
|
117007
|
+
<!-- NEW: Quick image size button -->
|
|
117008
|
+
<button
|
|
117009
|
+
id="quickImageSizeButton"
|
|
117010
|
+
type="button"
|
|
117011
|
+
class="quick-image-size-button"
|
|
117012
|
+
aria-label="${out('Select image size')}"
|
|
117013
|
+
aria-haspopup="true"
|
|
117014
|
+
aria-expanded="false"
|
|
117015
|
+
style="display: none;"
|
|
117016
|
+
>
|
|
117017
|
+
□
|
|
117018
|
+
</button>
|
|
117019
|
+
|
|
116882
117020
|
<button
|
|
116883
117021
|
id="sendButton"
|
|
116884
117022
|
type="button"
|
|
@@ -116892,15 +117030,30 @@ class CodeChat$1 {
|
|
|
116892
117030
|
</svg>
|
|
116893
117031
|
</button>
|
|
116894
117032
|
</div>
|
|
117033
|
+
|
|
117034
|
+
<!-- NEW: Size selection popover -->
|
|
117035
|
+
<div
|
|
117036
|
+
id="imageSizePopover"
|
|
117037
|
+
class="image-size-popover"
|
|
117038
|
+
role="menu"
|
|
117039
|
+
aria-hidden="true"
|
|
117040
|
+
style="display: none;"
|
|
117041
|
+
>
|
|
117042
|
+
<div class="size-options" id="sizeOptionsContainer">
|
|
117043
|
+
<!-- Options populated dynamically -->
|
|
117044
|
+
</div>
|
|
117045
|
+
</div>
|
|
117046
|
+
|
|
116895
117047
|
</div>
|
|
116896
117048
|
</div>
|
|
116897
117049
|
|
|
116898
117050
|
<!-- Settings Dialog Overlay -->
|
|
116899
|
-
<div id="settingsOverlay" aria-hidden="true"></div>
|
|
117051
|
+
<div id="settingsOverlay" class="keep-selection" aria-hidden="true"></div>
|
|
116900
117052
|
|
|
116901
117053
|
<!-- Settings Dialog -->
|
|
116902
117054
|
<div
|
|
116903
117055
|
id="settingsDialog"
|
|
117056
|
+
class="keep-selection"
|
|
116904
117057
|
role="dialog"
|
|
116905
117058
|
aria-labelledby="settingsTitle"
|
|
116906
117059
|
aria-modal="true"
|
|
@@ -117034,9 +117187,16 @@ class CodeChat$1 {
|
|
|
117034
117187
|
this.chatModelSelect.value = this.settings.chatModel;
|
|
117035
117188
|
this.imageModelSelect.value = this.settings.imageModel;
|
|
117036
117189
|
this.imageSizeSelect.value = this.settings.imageSize;
|
|
117037
|
-
|
|
117190
|
+
|
|
117191
|
+
// Check saved state - default to closed if never set
|
|
117192
|
+
const savedState = localStorage.getItem('chatPanelVisible');
|
|
117193
|
+
let isChatVisible = savedState === 'true'; // Only open if explicitly set to 'true'
|
|
117038
117194
|
if (!isChatVisible) {
|
|
117039
117195
|
modal.classList.add('hidden');
|
|
117196
|
+
modal.setAttribute('aria-hidden', 'true');
|
|
117197
|
+
} else {
|
|
117198
|
+
modal.classList.remove('hidden');
|
|
117199
|
+
modal.removeAttribute('aria-hidden');
|
|
117040
117200
|
}
|
|
117041
117201
|
const btnClose = modal.querySelector('.close-button');
|
|
117042
117202
|
btnClose.addEventListener('click', () => {
|
|
@@ -117119,7 +117279,45 @@ class CodeChat$1 {
|
|
|
117119
117279
|
this.closeChatButton = closeChatButton;
|
|
117120
117280
|
this.sendButton = sendButton;
|
|
117121
117281
|
this.messagesContainer = messagesContainer;
|
|
117282
|
+
|
|
117283
|
+
// NEW: Quick image size button elements
|
|
117284
|
+
this.quickImageSizeButton = builderStuff.querySelector('#quickImageSizeButton');
|
|
117285
|
+
this.imageSizePopover = builderStuff.querySelector('#imageSizePopover');
|
|
117286
|
+
this.sizeOptionsContainer = builderStuff.querySelector('#sizeOptionsContainer');
|
|
117287
|
+
|
|
117288
|
+
// Quick Image Size Button Handlers
|
|
117289
|
+
this.quickImageSizeButton.addEventListener('click', e => {
|
|
117290
|
+
e.stopPropagation();
|
|
117291
|
+
this.toggleImageSizePopover();
|
|
117292
|
+
});
|
|
117293
|
+
|
|
117294
|
+
// Close popover when clicking outside
|
|
117295
|
+
document.addEventListener('click', e => {
|
|
117296
|
+
if (!this.imageSizePopover.contains(e.target) && !this.quickImageSizeButton.contains(e.target)) {
|
|
117297
|
+
this.closeImageSizePopover();
|
|
117298
|
+
}
|
|
117299
|
+
});
|
|
117300
|
+
|
|
117301
|
+
// Close popover on Escape
|
|
117302
|
+
this.imageSizePopover.addEventListener('keydown', e => {
|
|
117303
|
+
if (e.key === 'Escape') {
|
|
117304
|
+
this.closeImageSizePopover();
|
|
117305
|
+
this.quickImageSizeButton.focus();
|
|
117306
|
+
}
|
|
117307
|
+
});
|
|
117122
117308
|
this.renderImageOptions();
|
|
117309
|
+
if (this.demoConversations) {
|
|
117310
|
+
this.loadConversations();
|
|
117311
|
+
}
|
|
117312
|
+
if (this.isDemoMode) {
|
|
117313
|
+
this.addDemoBanner();
|
|
117314
|
+
|
|
117315
|
+
// Disable input in demo mode
|
|
117316
|
+
this.promptInput.disabled = true;
|
|
117317
|
+
// this.promptInput.placeholder = out('Demo mode - Chat is read-only');
|
|
117318
|
+
this.sendButton.disabled = true;
|
|
117319
|
+
this.messagesContainer.scrollTop = this.messagesContainer.scrollHeight;
|
|
117320
|
+
}
|
|
117123
117321
|
}
|
|
117124
117322
|
renderImageOptions() {
|
|
117125
117323
|
const out = s => this.out(s);
|
|
@@ -117226,6 +117424,9 @@ class CodeChat$1 {
|
|
|
117226
117424
|
// Trigger initial render with defaults
|
|
117227
117425
|
modelSelect.value = defaultModelId;
|
|
117228
117426
|
renderSizes(defaultModelId, false);
|
|
117427
|
+
|
|
117428
|
+
// NEW: Initialize quick size button
|
|
117429
|
+
this.updateQuickImageSizeButton();
|
|
117229
117430
|
}
|
|
117230
117431
|
|
|
117231
117432
|
/**
|
|
@@ -117291,6 +117492,9 @@ class CodeChat$1 {
|
|
|
117291
117492
|
this.settingsOverlay.setAttribute('aria-hidden', 'true');
|
|
117292
117493
|
this.settingsDialog.classList.remove('open');
|
|
117293
117494
|
this.settingsDialog.setAttribute('aria-hidden', 'true');
|
|
117495
|
+
|
|
117496
|
+
// Reset cursor to default to prevent it from getting stuck
|
|
117497
|
+
document.body.style.cursor = '';
|
|
117294
117498
|
if (this.settingsLastFocusedElement) {
|
|
117295
117499
|
this.settingsLastFocusedElement.focus();
|
|
117296
117500
|
}
|
|
@@ -117302,6 +117506,9 @@ class CodeChat$1 {
|
|
|
117302
117506
|
this.settings.imageModel = this.imageModelSelect.value;
|
|
117303
117507
|
this.settings.imageSize = this.imageSizeSelect.value;
|
|
117304
117508
|
this.saveSettingsToStorage();
|
|
117509
|
+
|
|
117510
|
+
// NEW: Update quick button when settings change
|
|
117511
|
+
this.updateQuickImageSizeButton();
|
|
117305
117512
|
this.closeSettings();
|
|
117306
117513
|
}
|
|
117307
117514
|
|
|
@@ -117335,6 +117542,106 @@ Your job:
|
|
|
117335
117542
|
3. Determine what each image should depict based on surrounding content and context
|
|
117336
117543
|
4. Create detailed image generation prompts for each image
|
|
117337
117544
|
|
|
117545
|
+
📸 EDITORIAL STYLE GUIDE - Apply to all image prompts:
|
|
117546
|
+
|
|
117547
|
+
- Default aesthetic: Minimalist magazine-style (Kinfolk, Cereal, Vogue Living)
|
|
117548
|
+
- Composition: Clean, lots of negative space, well-balanced
|
|
117549
|
+
|
|
117550
|
+
|
|
117551
|
+
CREATIVE PROMPT ENHANCEMENT:
|
|
117552
|
+
When constructing image prompts, intelligently enrich basic descriptions using these proven cinematic stylers:
|
|
117553
|
+
|
|
117554
|
+
1. **Golden Hour Cinematic**
|
|
117555
|
+
"Warm sunlight, golden-hour lighting. Low contrast with lifted shadows, ethereal glow throughout. Overall vibe: relaxed, coastal, sun-kissed, carefree, West Coast lifestyle, evoking warmth and endless summer."
|
|
117556
|
+
→ Best for: Landscapes, architecture, outdoor scenes, lifestyle content
|
|
117557
|
+
|
|
117558
|
+
2. **Morning Halo Effect**
|
|
117559
|
+
"The lighting is soft, morning sunlight coming, creating a 'halo' effect. Vibrant cinematic shot"
|
|
117560
|
+
→ Best for: Portraits, people in action, outdoor activities
|
|
117561
|
+
|
|
117562
|
+
3. **Natural Forest Serenity**
|
|
117563
|
+
"in a lush, green forest. The sunlight should be filtering through the trees, creating a serene and natural atmosphere"
|
|
117564
|
+
→ Best for: Nature scenes, outdoor activities, wellness content
|
|
117565
|
+
|
|
117566
|
+
4. **Coastal Summer Drama**
|
|
117567
|
+
"on a dramatic windswept coastline. The overall atmosphere is cheerful, breezy, and full of summer warmth"
|
|
117568
|
+
→ Best for: Beach/coastal scenes, adventure, travel content
|
|
117569
|
+
|
|
117570
|
+
5. **Modern Interior Elegance**
|
|
117571
|
+
"illuminated by warm, natural lighting. The background features a softly blurred modern interior with subtle lights and cool tones, adding depth without distraction"
|
|
117572
|
+
→ Best for: Indoor portraits, product shots, professional/business settings
|
|
117573
|
+
|
|
117574
|
+
ENHANCEMENT STRATEGY:
|
|
117575
|
+
- Analyze the subject matter and context from the HTML/request
|
|
117576
|
+
- Select the most appropriate styler that matches the scene type
|
|
117577
|
+
- Check if user has specified lighting/time → DO NOT apply contradicting styler elements
|
|
117578
|
+
* Example: User says "daylight" → DO NOT add "golden-hour" or "sunset"
|
|
117579
|
+
- Aim for creative elevation while maintaining the core subject integrity
|
|
117580
|
+
- Blend the styler naturally into the prompt (adapt grammar, pronouns, context)
|
|
117581
|
+
- IF user is vague (no specific lighting/mood) → Apply full styler enhancement
|
|
117582
|
+
- User's explicit details ALWAYS take precedence over styler recommendations
|
|
117583
|
+
` +
|
|
117584
|
+
/*
|
|
117585
|
+
ENHANCEMENT STRATEGY:
|
|
117586
|
+
- Analyze the subject matter and context from the HTML/request
|
|
117587
|
+
- Select the most appropriate styler that matches the scene type
|
|
117588
|
+
- Blend the styler naturally into the prompt (adapt grammar, pronouns, context)
|
|
117589
|
+
- If the subject already has specific lighting/atmosphere details, complement rather than override
|
|
117590
|
+
- Aim for creative elevation while maintaining the core subject integrity
|
|
117591
|
+
*/
|
|
117592
|
+
`
|
|
117593
|
+
Examples of enriched prompts:
|
|
117594
|
+
- Basic: "a house with mountain view"
|
|
117595
|
+
→ Enhanced: "a house with beautiful mountain view. Warm sunlight, golden-hour lighting. Low contrast with lifted shadows, ethereal glow throughout. Overall vibe: relaxed, coastal, sun-kissed, carefree, West Coast lifestyle, evoking warmth and endless summer."
|
|
117596
|
+
|
|
117597
|
+
- Basic: "person hiking"
|
|
117598
|
+
→ Enhanced: "a person hiking in nature. The lighting is soft, morning sunlight coming, creating a 'halo' effect. Vibrant cinematic shot"
|
|
117599
|
+
|
|
117600
|
+
- Basic: "woman reading"
|
|
117601
|
+
→ Enhanced: "a woman sitting comfortably and reading. Her face is illuminated by warm, natural lighting. The background features a softly blurred modern interior with subtle lights and cool tones, adding depth without distraction"
|
|
117602
|
+
|
|
117603
|
+
- Already detailed: "dramatic headshot with bokeh and rim lighting"
|
|
117604
|
+
→ No enhancement needed (preserve user's vision)
|
|
117605
|
+
|
|
117606
|
+
|
|
117607
|
+
CONTEXT-SPECIFIC GUIDELINES:
|
|
117608
|
+
|
|
117609
|
+
Interior/Indoor scenes:
|
|
117610
|
+
- Lighting: Soft natural window light
|
|
117611
|
+
- Backdrop: white walls or neutral tones
|
|
117612
|
+
- Mood: Calm, serene, inviting, uncluttered
|
|
117613
|
+
- Reference: "Kinfolk interior photography"
|
|
117614
|
+
|
|
117615
|
+
People/Portraits/Activities:
|
|
117616
|
+
- Lighting: Natural diffused light, flattering and soft
|
|
117617
|
+
- Styling: Effortlessly elegant, contemporary casual
|
|
117618
|
+
- Pose: Candid, authentic moments, relaxed
|
|
117619
|
+
- Reference: "modern lifestyle editorial photography"
|
|
117620
|
+
|
|
117621
|
+
Products/Objects:
|
|
117622
|
+
- Lighting: Clean studio or soft natural light
|
|
117623
|
+
- Backdrop: Minimalist neutral, lots of breathing room
|
|
117624
|
+
- Mood: Refined simplicity, premium feel
|
|
117625
|
+
- Reference: "high-end editorial product photography"
|
|
117626
|
+
|
|
117627
|
+
Food/Culinary:
|
|
117628
|
+
- Lighting: Soft daylight, gentle overhead or 45° angle
|
|
117629
|
+
- Styling: Minimal props, artisan ceramics, linen
|
|
117630
|
+
- Mood: Fresh, appetizing, rustic-modern
|
|
117631
|
+
- Reference: "Bon Appétit editorial food styling"
|
|
117632
|
+
|
|
117633
|
+
Outdoor/Landscape:
|
|
117634
|
+
- Composition: Serene, contemplative, minimal
|
|
117635
|
+
- Mood: Calm atmosphere, breathing space, lifted brightness
|
|
117636
|
+
- Colors: Vibrant cinematic shot.
|
|
117637
|
+
- Reference: "editorial travel photography"
|
|
117638
|
+
|
|
117639
|
+
CRITICAL RULES:
|
|
117640
|
+
1. If user specifies a style (cinematic, vintage, vibrant, etc.) → RESPECT IT, only add quality markers
|
|
117641
|
+
2. If user is vague → APPLY FULL EDITORIAL TREATMENT based on subject category
|
|
117642
|
+
3. Always maintain cohesive aesthetic across all images
|
|
117643
|
+
4. Every prompt should feel like it belongs in a high-end lifestyle magazine
|
|
117644
|
+
|
|
117338
117645
|
Respond with a JSON array with one entry per image to generate:
|
|
117339
117646
|
[
|
|
117340
117647
|
{
|
|
@@ -117445,6 +117752,11 @@ Response: [
|
|
|
117445
117752
|
*/
|
|
117446
117753
|
async sendMessage() {
|
|
117447
117754
|
const out = s => this.out(s);
|
|
117755
|
+
|
|
117756
|
+
// Prevent sending messages in demo mode
|
|
117757
|
+
if (this.isDemoMode) {
|
|
117758
|
+
return;
|
|
117759
|
+
}
|
|
117448
117760
|
const prompt = this.promptInput.value.trim();
|
|
117449
117761
|
if (!prompt) return;
|
|
117450
117762
|
this.addMessage('user', prompt);
|
|
@@ -117512,14 +117824,42 @@ Response: [
|
|
|
117512
117824
|
} else if (result.type === 'image') {
|
|
117513
117825
|
if (result.imageDetails && result.imageDetails.length > 1) {
|
|
117514
117826
|
this.addMessage('assistant', `✓ Generated ${result.imageDetails.length} images successfully`);
|
|
117827
|
+
// this.addMessage('assistant', `✓ ${out('Generated {count} images successfully').replace('{count}', result.imageDetails.length)}`);
|
|
117515
117828
|
this.addImagePreview(result.imageDetails);
|
|
117516
117829
|
} else {
|
|
117517
|
-
this.addMessage('assistant', '✓
|
|
117830
|
+
this.addMessage('assistant', '✓ Image generated successfully');
|
|
117831
|
+
// this.addMessage('assistant', `✓ ${out('Image generated successfully')}`);
|
|
117518
117832
|
if (result.generatedUrls && result.generatedUrls[0]) {
|
|
117519
117833
|
this.addImagePreview([{
|
|
117520
117834
|
url: result.generatedUrls[0],
|
|
117521
117835
|
context: result.description
|
|
117522
117836
|
}]);
|
|
117837
|
+
|
|
117838
|
+
// If there is a selected image, replace with the new image
|
|
117839
|
+
const url = result.generatedUrls[0];
|
|
117840
|
+
if (this.builder.editor) {
|
|
117841
|
+
// ContentBox
|
|
117842
|
+
const img = this.builder.editor.activeImage;
|
|
117843
|
+
if (img) {
|
|
117844
|
+
this.builder.editor.saveForUndo();
|
|
117845
|
+
img.addEventListener('load', () => {
|
|
117846
|
+
this.builder.editor.element.image.repositionImageTool();
|
|
117847
|
+
this.builder.editor.elmTool.repositionElementTool();
|
|
117848
|
+
});
|
|
117849
|
+
this.builder.editor.activeImage.setAttribute('src', url);
|
|
117850
|
+
}
|
|
117851
|
+
} else {
|
|
117852
|
+
// ContentBuilder
|
|
117853
|
+
const img = this.builder.activeImage;
|
|
117854
|
+
if (img) {
|
|
117855
|
+
this.builder.uo.saveForUndo();
|
|
117856
|
+
img.addEventListener('load', () => {
|
|
117857
|
+
this.builder.element.image.repositionImageTool();
|
|
117858
|
+
this.builder.elmTool.repositionElementTool();
|
|
117859
|
+
});
|
|
117860
|
+
this.builder.activeImage.setAttribute('src', url);
|
|
117861
|
+
}
|
|
117862
|
+
}
|
|
117523
117863
|
}
|
|
117524
117864
|
}
|
|
117525
117865
|
}
|
|
@@ -117573,15 +117913,16 @@ Response: [
|
|
|
117573
117913
|
`;
|
|
117574
117914
|
images.forEach(img => {
|
|
117575
117915
|
previewHTML += `
|
|
117576
|
-
<div style="border-radius:
|
|
117577
|
-
<img src="${img.url}" alt="${img.context || 'Generated image'}" style="width: 100%;
|
|
117916
|
+
<div style="border-radius: 6px; overflow: hidden; background: rgba(255,255,255,0.05);">
|
|
117917
|
+
<img src="${img.url}" alt="${img.context || 'Generated image'}" style="width: 100%;" />
|
|
117578
117918
|
<div style="padding: 8px; font-size: 11px; opacity: 0.8;">
|
|
117579
117919
|
${img.context || ''}
|
|
117580
117920
|
<a href="${img.url}" target="_blank" rel="noopener noreferrer" style="display: block; margin-top: 4px;">View</a>
|
|
117581
117921
|
</div>
|
|
117582
117922
|
</div>
|
|
117583
|
-
`;
|
|
117923
|
+
`; // height: 150px; object-fit: cover;
|
|
117584
117924
|
});
|
|
117925
|
+
|
|
117585
117926
|
previewHTML += '</div>';
|
|
117586
117927
|
previewDiv.innerHTML = previewHTML;
|
|
117587
117928
|
this.messagesContainer.appendChild(previewDiv);
|
|
@@ -117602,6 +117943,32 @@ Response: [
|
|
|
117602
117943
|
|
|
117603
117944
|
// Check if image generation is enabled
|
|
117604
117945
|
const imageGenEnabled = this.builder.generateMediaUrl_Fal ? true : false;
|
|
117946
|
+
|
|
117947
|
+
// Build context about previously generated images
|
|
117948
|
+
let imageHistoryContext = '';
|
|
117949
|
+
const previousImageResults = this.conversationResults.filter(r => r.type === 'image' && r.generatedUrls && r.generatedUrls.length > 0);
|
|
117950
|
+
if (previousImageResults.length > 0) {
|
|
117951
|
+
imageHistoryContext = '\n\n=== PREVIOUSLY GENERATED IMAGES IN THIS CONVERSATION ===\n';
|
|
117952
|
+
imageHistoryContext += 'The following images were generated earlier in this conversation:\n\n';
|
|
117953
|
+
previousImageResults.forEach((result, idx) => {
|
|
117954
|
+
if (result.imageDetails && result.imageDetails.length > 0) {
|
|
117955
|
+
result.imageDetails.forEach((img, imgIdx) => {
|
|
117956
|
+
imageHistoryContext += `Generated Image ${idx + 1}.${imgIdx + 1}:\n`;
|
|
117957
|
+
imageHistoryContext += ` URL: ${img.url}\n`;
|
|
117958
|
+
imageHistoryContext += ` Context: ${img.context}\n`;
|
|
117959
|
+
imageHistoryContext += ` Description: ${result.description}\n\n`;
|
|
117960
|
+
});
|
|
117961
|
+
} else {
|
|
117962
|
+
result.generatedUrls.forEach((url, urlIdx) => {
|
|
117963
|
+
imageHistoryContext += `Generated Image ${idx + 1}.${urlIdx + 1}:\n`;
|
|
117964
|
+
imageHistoryContext += ` URL: ${url}\n`;
|
|
117965
|
+
imageHistoryContext += ` Description: ${result.description}\n\n`;
|
|
117966
|
+
});
|
|
117967
|
+
}
|
|
117968
|
+
});
|
|
117969
|
+
imageHistoryContext += '⚠️ IMPORTANT: If the user refers to "the generated image", "this image", "the image", or "previous image", they are referring to these images above.\n';
|
|
117970
|
+
imageHistoryContext += '⚠️ DO NOT create a new image task. Instead, create a CODE task that uses these existing URLs.\n\n';
|
|
117971
|
+
}
|
|
117605
117972
|
const classificationPrompt = `Analyze this user message and break it down into tasks.
|
|
117606
117973
|
|
|
117607
117974
|
CURRENT HTML CONTEXT (use this to understand the page structure):
|
|
@@ -117609,11 +117976,19 @@ CURRENT HTML CONTEXT (use this to understand the page structure):
|
|
|
117609
117976
|
${this.builder.html()}
|
|
117610
117977
|
\`\`\`
|
|
117611
117978
|
|
|
117979
|
+
${imageHistoryContext}
|
|
117980
|
+
|
|
117612
117981
|
IMPORTANT: This is a WEB BUILDER tool with chat capabilities. Valid requests are:
|
|
117613
117982
|
- Creating/editing/removing HTML content (code tasks)
|
|
117614
117983
|
${imageGenEnabled ? '- Generating images for the webpage (image tasks)' : ''}
|
|
117615
117984
|
- Asking questions or having conversations (chat tasks) - THIS CAN BE ABOUT ANYTHING
|
|
117616
117985
|
|
|
117986
|
+
CRITICAL CONTEXT RULE:
|
|
117987
|
+
- In a web builder, "create an article/blog/story/content" means CREATE A WEBPAGE (CODE task)
|
|
117988
|
+
- Only use CHAT task for questions, explanations, or requests for advice
|
|
117989
|
+
- If user says "create", "write", "make", "build" followed by content → CODE task
|
|
117990
|
+
- If user says "explain", "how do I", "what is", "tell me about" → CHAT task
|
|
117991
|
+
|
|
117617
117992
|
${imageGenEnabled ? '' : `
|
|
117618
117993
|
⚠️ AI IMAGE GENERATION IS CURRENTLY DISABLED
|
|
117619
117994
|
- If user requests AI image generation/creation, explain that it's disabled
|
|
@@ -117683,6 +118058,18 @@ IMAGE TASK RULES:
|
|
|
117683
118058
|
- IMPORTANT: Look at the HTML context to understand if multiple images are involved
|
|
117684
118059
|
- If the target section has multiple images, indicate this in targetElement (e.g., "all 3 images in Culinary Delights section")
|
|
117685
118060
|
- Image tasks should come BEFORE code tasks that depend on them
|
|
118061
|
+
|
|
118062
|
+
- CRITICAL: DO NOT create image task for these phrases (they mean REUSE existing):
|
|
118063
|
+
* "use the generated image" / "use the image"
|
|
118064
|
+
* "use this image" / "use existing image"
|
|
118065
|
+
* "with the generated image" / "with this image"
|
|
118066
|
+
* "with the previous image" / "with the last image"
|
|
118067
|
+
* "using the image I just created/generated"
|
|
118068
|
+
* Any reference to a PREVIOUS image from conversation history
|
|
118069
|
+
- Decision logic:
|
|
118070
|
+
* "Generate a new image of X" → CREATE image task (new generation)
|
|
118071
|
+
* "Create article using the generated image" → NO image task (reuse existing)
|
|
118072
|
+
|
|
117686
118073
|
` : ''}
|
|
117687
118074
|
|
|
117688
118075
|
Examples:
|
|
@@ -117720,6 +118107,17 @@ Input: "Create a landing page about wood furniture workshop"
|
|
|
117720
118107
|
Output: {"is_valid": true, "tasks": [{"type": "code", "description": "Create a landing page for a wood furniture workshop", "order": 1}], "is_mixed": false}
|
|
117721
118108
|
Note: No image task created because user did not explicitly request AI image generation
|
|
117722
118109
|
|
|
118110
|
+
Input: "Create an inspiring article and use the generated image"
|
|
118111
|
+
Output: {"is_valid": true, "tasks": [{"type": "code", "description": "Create article using previously generated image from conversation history", "order": 1}], "is_mixed": false}
|
|
118112
|
+
Note: No image task because user wants to REUSE existing image
|
|
118113
|
+
|
|
118114
|
+
Input: "Write a blog post about productivity and use this image"
|
|
118115
|
+
Output: {"is_valid": true, "tasks": [{"type": "code", "description": "Create blog post using previously generated image", "order": 1}], "is_mixed": false}
|
|
118116
|
+
|
|
118117
|
+
Input: "Generate another mountain image and create a landing page"
|
|
118118
|
+
Output: {"tasks": [{"type": "image", "description": "Generate new mountain image", "imagePrompt": "...", "order": 1}, {"type": "code", "description": "Create landing page with new image", "order": 2}], "is_mixed": true}
|
|
118119
|
+
Note: "another" and "generate" indicate NEW image generation
|
|
118120
|
+
|
|
117723
118121
|
` : `
|
|
117724
118122
|
Input: "Generate an AI image of a mountain"
|
|
117725
118123
|
Output: {"is_valid": false, "reason": "AI image generation is currently disabled.", "tasks": [], "is_mixed": false}
|
|
@@ -117803,7 +118201,9 @@ Output: {"is_valid": false, "reason": "AI image generation is currently disabled
|
|
|
117803
118201
|
if (imageTasksFromThisRequest.length > 0) {
|
|
117804
118202
|
hasGeneratedImages = true;
|
|
117805
118203
|
imageContext = '\n\n=== GENERATED IMAGE URLS (USE THESE FOR YOUR TASK) ===\n';
|
|
117806
|
-
|
|
118204
|
+
|
|
118205
|
+
// ⭐ REVERSE to show most recent first
|
|
118206
|
+
imageTasksFromThisRequest.reverse().forEach(imageTask => {
|
|
117807
118207
|
if (imageTask.imageDetails && imageTask.imageDetails.length > 0) {
|
|
117808
118208
|
// Multiple images with context
|
|
117809
118209
|
imageTask.imageDetails.forEach((img, idx) => {
|
|
@@ -117818,7 +118218,8 @@ Output: {"is_valid": false, "reason": "AI image generation is currently disabled
|
|
|
117818
118218
|
});
|
|
117819
118219
|
}
|
|
117820
118220
|
});
|
|
117821
|
-
imageContext += '\n⚠️ IMPORTANT: Use
|
|
118221
|
+
imageContext += '\n⚠️ IMPORTANT: Use the FIRST image URL listed above (most recent) unless the task specifically asks for a different image.\n';
|
|
118222
|
+
imageContext += '⚠️ The first image is the MOST RECENTLY GENERATED and should be used by default.\n';
|
|
117822
118223
|
imageContext += '⚠️ Your task description specifies WHICH images to update - follow it precisely.\n';
|
|
117823
118224
|
}
|
|
117824
118225
|
|
|
@@ -117915,6 +118316,10 @@ ${this.builder.html()}
|
|
|
117915
118316
|
TASK: ${task.description}
|
|
117916
118317
|
|
|
117917
118318
|
IMPORTANT: Follow the Best Practices in Content framework.
|
|
118319
|
+
${this.builder.editor ? `CRITICAL: This project uses the Content.css and Box framework, NOT Tailwind. ONLY use classes explicitly documented in this framework guide.
|
|
118320
|
+
DO NOT use Tailwind classes like gap-4, w-1/2, top-4, hover:scale-120, etc.` : `CRITICAL: This project uses the Content.css framework, NOT Tailwind. ONLY use classes explicitly documented in this framework guide.
|
|
118321
|
+
DO NOT use Tailwind classes like gap-4, w-1/2, top-4, hover:scale-120, etc.`}
|
|
118322
|
+
For flexibility, you can use inline styles or embedded <style> at the end of the generated HTML.
|
|
117918
118323
|
|
|
117919
118324
|
${imageContext}
|
|
117920
118325
|
${chatContext}
|
|
@@ -118367,6 +118772,319 @@ ${this.builder.html()}
|
|
|
118367
118772
|
document.body.removeChild(announcement);
|
|
118368
118773
|
}, 1000);
|
|
118369
118774
|
}
|
|
118775
|
+
|
|
118776
|
+
/**
|
|
118777
|
+
* ============================================================================
|
|
118778
|
+
* DEMO MODE
|
|
118779
|
+
* ============================================================================
|
|
118780
|
+
*/
|
|
118781
|
+
loadConversations() {
|
|
118782
|
+
// Load demo conversations
|
|
118783
|
+
if (this.demoConversations && this.demoConversations.length > 0) {
|
|
118784
|
+
this.demoConversations.forEach(msg => {
|
|
118785
|
+
if (msg.role === 'user') {
|
|
118786
|
+
this.addMessage('user', msg.content);
|
|
118787
|
+
} else if (msg.role === 'assistant') {
|
|
118788
|
+
this.addMessage('assistant', msg.content, true);
|
|
118789
|
+
|
|
118790
|
+
// Add image preview if available
|
|
118791
|
+
if (msg.imagePreview && msg.imagePreview.length > 0) {
|
|
118792
|
+
this.addImagePreview(msg.imagePreview);
|
|
118793
|
+
|
|
118794
|
+
// Include in conversationResults with correct structure
|
|
118795
|
+
this.conversationResults.push({
|
|
118796
|
+
type: 'image',
|
|
118797
|
+
description: 'Previously generated image from demo',
|
|
118798
|
+
content: `Generated ${msg.imagePreview.length} images`,
|
|
118799
|
+
generatedUrls: msg.imagePreview.map(img => img.url),
|
|
118800
|
+
// Array of URLs
|
|
118801
|
+
imageDetails: msg.imagePreview.map(img => ({
|
|
118802
|
+
// Array of objects
|
|
118803
|
+
url: img.url,
|
|
118804
|
+
context: img.context,
|
|
118805
|
+
prompt: img.context || '' // Use context as prompt if no prompt available
|
|
118806
|
+
})),
|
|
118807
|
+
|
|
118808
|
+
targetElement: 'demo images'
|
|
118809
|
+
});
|
|
118810
|
+
}
|
|
118811
|
+
}
|
|
118812
|
+
});
|
|
118813
|
+
}
|
|
118814
|
+
}
|
|
118815
|
+
addDemoBanner() {
|
|
118816
|
+
const out = s => this.out(s);
|
|
118817
|
+
const banner = document.createElement('div');
|
|
118818
|
+
banner.className = 'demo-banner';
|
|
118819
|
+
banner.innerHTML = `
|
|
118820
|
+
<div style="
|
|
118821
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
118822
|
+
color: white;
|
|
118823
|
+
padding: 12px 16px;
|
|
118824
|
+
border-radius: 8px;
|
|
118825
|
+
font-size: 13px;
|
|
118826
|
+
display: flex;
|
|
118827
|
+
align-items: center;
|
|
118828
|
+
gap: 8px;
|
|
118829
|
+
box-shadow: 0 4px 12px rgba(102, 126, 234, 0.3);
|
|
118830
|
+
">
|
|
118831
|
+
<span style="font-size: 18px;">📖</span>
|
|
118832
|
+
<div>
|
|
118833
|
+
<strong>${out('Read-Only Demo')}</strong>
|
|
118834
|
+
<div style="font-size: 11px; opacity: 0.9; margin-top: 2px;">
|
|
118835
|
+
${out('Full AI chat available in the complete version.')}
|
|
118836
|
+
</div>
|
|
118837
|
+
</div>
|
|
118838
|
+
</div>
|
|
118839
|
+
`;
|
|
118840
|
+
|
|
118841
|
+
// Insert banner at the top of messages container
|
|
118842
|
+
// this.messagesContainer.insertBefore(banner, this.messagesContainer.firstChild);
|
|
118843
|
+
this.messagesContainer.appendChild(banner);
|
|
118844
|
+
}
|
|
118845
|
+
|
|
118846
|
+
/**
|
|
118847
|
+
* Update the quick image size button based on current model and settings
|
|
118848
|
+
*/
|
|
118849
|
+
updateQuickImageSizeButton() {
|
|
118850
|
+
const imageGenEnabled = this.builder.generateMediaUrl_Fal ? true : false;
|
|
118851
|
+
if (!imageGenEnabled) {
|
|
118852
|
+
this.quickImageSizeButton.style.display = 'none';
|
|
118853
|
+
return;
|
|
118854
|
+
}
|
|
118855
|
+
const currentModelId = this.settings.imageModel;
|
|
118856
|
+
const availableSizes = this.getSizesForModel(currentModelId);
|
|
118857
|
+
|
|
118858
|
+
// Hide button if model has no size options
|
|
118859
|
+
if (!availableSizes || availableSizes.length === 0) {
|
|
118860
|
+
this.quickImageSizeButton.style.display = 'none';
|
|
118861
|
+
return;
|
|
118862
|
+
}
|
|
118863
|
+
|
|
118864
|
+
// Show button
|
|
118865
|
+
this.quickImageSizeButton.style.display = 'flex';
|
|
118866
|
+
|
|
118867
|
+
// Smart selection: check if current size is available
|
|
118868
|
+
let selectedSize = this.settings.imageSize;
|
|
118869
|
+
if (!availableSizes.includes(selectedSize)) {
|
|
118870
|
+
// Current size not available, find best fallback
|
|
118871
|
+
selectedSize = this.findBestFallback(selectedSize, availableSizes);
|
|
118872
|
+
this.settings.imageSize = selectedSize;
|
|
118873
|
+
|
|
118874
|
+
// Sync with settings dialog
|
|
118875
|
+
this.imageSizeSelect.value = selectedSize;
|
|
118876
|
+
|
|
118877
|
+
// Save to storage
|
|
118878
|
+
this.saveSettingsToStorage();
|
|
118879
|
+
}
|
|
118880
|
+
|
|
118881
|
+
// Update button label
|
|
118882
|
+
this.updateButtonLabel(selectedSize);
|
|
118883
|
+
|
|
118884
|
+
// Populate popover options
|
|
118885
|
+
this.populateSizePopover(availableSizes, selectedSize);
|
|
118886
|
+
}
|
|
118887
|
+
|
|
118888
|
+
/**
|
|
118889
|
+
* Get available sizes for a model (reuse existing logic)
|
|
118890
|
+
*/
|
|
118891
|
+
getSizesForModel(modelId) {
|
|
118892
|
+
const model = this.imageModels.find(m => m.id === modelId);
|
|
118893
|
+
if (!model) return null;
|
|
118894
|
+
|
|
118895
|
+
// if sizes explicitly empty array → means no size options
|
|
118896
|
+
if (Array.isArray(model.sizes) && model.sizes.length === 0) {
|
|
118897
|
+
return null;
|
|
118898
|
+
}
|
|
118899
|
+
const defaultSizes = ['square', 'square_hd', 'landscape_4_3', 'landscape_16_9', 'portrait_4_3', 'portrait_16_9'];
|
|
118900
|
+
return model.sizes || defaultSizes;
|
|
118901
|
+
}
|
|
118902
|
+
|
|
118903
|
+
/**
|
|
118904
|
+
* Find best fallback size when current selection is not available
|
|
118905
|
+
*/
|
|
118906
|
+
findBestFallback(preferredSize, availableSizes) {
|
|
118907
|
+
// Strategy 1: Try to match orientation
|
|
118908
|
+
const orientation = this.getOrientation(preferredSize);
|
|
118909
|
+
const matchingOrientation = availableSizes.find(size => this.getOrientation(size) === orientation);
|
|
118910
|
+
if (matchingOrientation) return matchingOrientation;
|
|
118911
|
+
|
|
118912
|
+
// Strategy 2: Common defaults
|
|
118913
|
+
if (availableSizes.includes('16:9')) return '16:9';
|
|
118914
|
+
if (availableSizes.includes('landscape_16_9')) return 'landscape_16_9';
|
|
118915
|
+
if (availableSizes.includes('1:1')) return '1:1';
|
|
118916
|
+
if (availableSizes.includes('square')) return 'square';
|
|
118917
|
+
|
|
118918
|
+
// Strategy 3: First available
|
|
118919
|
+
return availableSizes[0];
|
|
118920
|
+
}
|
|
118921
|
+
|
|
118922
|
+
/**
|
|
118923
|
+
* Determine orientation from size value
|
|
118924
|
+
*/
|
|
118925
|
+
getOrientation(size) {
|
|
118926
|
+
const landscape = ['16:9', '21:9', '4:3', '3:2', '5:4', 'landscape_16_9', 'landscape_4_3'];
|
|
118927
|
+
const portrait = ['9:16', '9:21', '3:4', '2:3', '4:5', 'portrait_16_9', 'portrait_4_3'];
|
|
118928
|
+
if (landscape.includes(size)) return 'landscape';
|
|
118929
|
+
if (portrait.includes(size)) return 'portrait';
|
|
118930
|
+
return 'square';
|
|
118931
|
+
}
|
|
118932
|
+
|
|
118933
|
+
/**
|
|
118934
|
+
* Update button label to show current size
|
|
118935
|
+
*/
|
|
118936
|
+
updateButtonLabel(sizeValue) {
|
|
118937
|
+
if (!sizeValue) {
|
|
118938
|
+
this.quickImageSizeButton.textContent = '□';
|
|
118939
|
+
this.quickImageSizeButton.setAttribute('aria-label', this.out('Select image size'));
|
|
118940
|
+
return;
|
|
118941
|
+
}
|
|
118942
|
+
|
|
118943
|
+
// Convert verbose labels to short form
|
|
118944
|
+
const labelMap = {
|
|
118945
|
+
'landscape_16_9': '16:9',
|
|
118946
|
+
'landscape_4_3': '4:3',
|
|
118947
|
+
'portrait_16_9': '9:16',
|
|
118948
|
+
'portrait_4_3': '3:4',
|
|
118949
|
+
'square': '1:1',
|
|
118950
|
+
'square_hd': '1:1 HD'
|
|
118951
|
+
};
|
|
118952
|
+
const displayLabel = labelMap[sizeValue] || sizeValue;
|
|
118953
|
+
this.quickImageSizeButton.textContent = displayLabel;
|
|
118954
|
+
this.quickImageSizeButton.setAttribute('aria-label', `${this.out('Image size')}: ${displayLabel}`);
|
|
118955
|
+
}
|
|
118956
|
+
|
|
118957
|
+
/**
|
|
118958
|
+
* Populate the size popover with available options
|
|
118959
|
+
*/
|
|
118960
|
+
populateSizePopover(sizes, selectedSize) {
|
|
118961
|
+
const out = s => this.out(s);
|
|
118962
|
+
const sizeDefs = {
|
|
118963
|
+
'square_hd': out('Square HD'),
|
|
118964
|
+
'square': out('Square'),
|
|
118965
|
+
'landscape_4_3': out('Landscape 4x3'),
|
|
118966
|
+
'landscape_16_9': out('Landscape 16x9'),
|
|
118967
|
+
'portrait_4_3': out('Portrait 3x4'),
|
|
118968
|
+
'portrait_16_9': out('Portrait 9x16'),
|
|
118969
|
+
'1:1': out('Square'),
|
|
118970
|
+
'3:2': out('Landscape 3x2'),
|
|
118971
|
+
'4:3': out('Landscape 4x3'),
|
|
118972
|
+
'5:4': out('Landscape 5x4'),
|
|
118973
|
+
'16:9': out('Landscape 16x9'),
|
|
118974
|
+
'21:9': out('Landscape 21:9'),
|
|
118975
|
+
'2:3': out('Portrait 2x3'),
|
|
118976
|
+
'3:4': out('Portrait 3x4'),
|
|
118977
|
+
'4:5': out('Portrait 4x5'),
|
|
118978
|
+
'9:16': out('Portrait 9x16'),
|
|
118979
|
+
'9:21': out('Portrait 9:21')
|
|
118980
|
+
};
|
|
118981
|
+
this.sizeOptionsContainer.innerHTML = '';
|
|
118982
|
+
sizes.forEach(size => {
|
|
118983
|
+
const option = document.createElement('div');
|
|
118984
|
+
option.className = 'size-option' + (size === selectedSize ? ' selected' : '');
|
|
118985
|
+
option.setAttribute('role', 'menuitem');
|
|
118986
|
+
option.setAttribute('tabindex', '0');
|
|
118987
|
+
const radio = document.createElement('input');
|
|
118988
|
+
radio.type = 'radio';
|
|
118989
|
+
radio.name = 'quickImageSize';
|
|
118990
|
+
radio.value = size;
|
|
118991
|
+
radio.checked = size === selectedSize;
|
|
118992
|
+
radio.id = `quick-size-${size}`;
|
|
118993
|
+
const label = document.createElement('label');
|
|
118994
|
+
label.htmlFor = `quick-size-${size}`;
|
|
118995
|
+
label.textContent = sizeDefs[size] || size;
|
|
118996
|
+
// label.style.cursor = 'pointer';
|
|
118997
|
+
label.style.flex = '1';
|
|
118998
|
+
option.appendChild(radio);
|
|
118999
|
+
option.appendChild(label);
|
|
119000
|
+
|
|
119001
|
+
// Click handler
|
|
119002
|
+
option.addEventListener('click', () => {
|
|
119003
|
+
this.selectImageSize(size);
|
|
119004
|
+
});
|
|
119005
|
+
|
|
119006
|
+
// Keyboard handler
|
|
119007
|
+
option.addEventListener('keydown', e => {
|
|
119008
|
+
if (e.key === 'Enter' || e.key === ' ') {
|
|
119009
|
+
e.preventDefault();
|
|
119010
|
+
this.selectImageSize(size);
|
|
119011
|
+
}
|
|
119012
|
+
});
|
|
119013
|
+
this.sizeOptionsContainer.appendChild(option);
|
|
119014
|
+
});
|
|
119015
|
+
}
|
|
119016
|
+
|
|
119017
|
+
/**
|
|
119018
|
+
* Handle size selection
|
|
119019
|
+
*/
|
|
119020
|
+
selectImageSize(size) {
|
|
119021
|
+
// Update settings
|
|
119022
|
+
this.settings.imageSize = size;
|
|
119023
|
+
|
|
119024
|
+
// Sync with settings dialog
|
|
119025
|
+
this.imageSizeSelect.value = size;
|
|
119026
|
+
|
|
119027
|
+
// Update button label
|
|
119028
|
+
this.updateButtonLabel(size);
|
|
119029
|
+
|
|
119030
|
+
// Update popover selection
|
|
119031
|
+
this.sizeOptionsContainer.querySelectorAll('.size-option').forEach(opt => {
|
|
119032
|
+
opt.classList.remove('selected');
|
|
119033
|
+
opt.querySelector('input[type="radio"]').checked = false;
|
|
119034
|
+
});
|
|
119035
|
+
|
|
119036
|
+
// const selectedOption = this.sizeOptionsContainer.querySelector(`#quick-size-${size}`);
|
|
119037
|
+
const selectedOption = Array.from(this.sizeOptionsContainer.querySelectorAll('input[type="radio"]')).find(radio => radio.value === size);
|
|
119038
|
+
if (selectedOption) {
|
|
119039
|
+
selectedOption.closest('.size-option').classList.add('selected');
|
|
119040
|
+
selectedOption.checked = true;
|
|
119041
|
+
}
|
|
119042
|
+
|
|
119043
|
+
// Save to storage
|
|
119044
|
+
this.saveSettingsToStorage();
|
|
119045
|
+
|
|
119046
|
+
// Close popover
|
|
119047
|
+
this.closeImageSizePopover();
|
|
119048
|
+
|
|
119049
|
+
// Focus back to input
|
|
119050
|
+
this.promptInput.focus();
|
|
119051
|
+
}
|
|
119052
|
+
|
|
119053
|
+
/**
|
|
119054
|
+
* Toggle popover visibility
|
|
119055
|
+
*/
|
|
119056
|
+
toggleImageSizePopover() {
|
|
119057
|
+
const isVisible = this.imageSizePopover.style.display !== 'none';
|
|
119058
|
+
if (isVisible) {
|
|
119059
|
+
this.closeImageSizePopover();
|
|
119060
|
+
} else {
|
|
119061
|
+
this.openImageSizePopover();
|
|
119062
|
+
}
|
|
119063
|
+
}
|
|
119064
|
+
|
|
119065
|
+
/**
|
|
119066
|
+
* Open the size popover
|
|
119067
|
+
*/
|
|
119068
|
+
openImageSizePopover() {
|
|
119069
|
+
this.imageSizePopover.style.display = 'block';
|
|
119070
|
+
this.imageSizePopover.setAttribute('aria-hidden', 'false');
|
|
119071
|
+
this.quickImageSizeButton.setAttribute('aria-expanded', 'true');
|
|
119072
|
+
|
|
119073
|
+
// Focus first option
|
|
119074
|
+
const firstOption = this.sizeOptionsContainer.querySelector('.size-option');
|
|
119075
|
+
if (firstOption) {
|
|
119076
|
+
firstOption.focus();
|
|
119077
|
+
}
|
|
119078
|
+
}
|
|
119079
|
+
|
|
119080
|
+
/**
|
|
119081
|
+
* Close the size popover
|
|
119082
|
+
*/
|
|
119083
|
+
closeImageSizePopover() {
|
|
119084
|
+
this.imageSizePopover.style.display = 'none';
|
|
119085
|
+
this.imageSizePopover.setAttribute('aria-hidden', 'true');
|
|
119086
|
+
this.quickImageSizeButton.setAttribute('aria-expanded', 'false');
|
|
119087
|
+
}
|
|
118370
119088
|
out(s) {
|
|
118371
119089
|
let result = this.builder.lang[s];
|
|
118372
119090
|
if (result) return result;else return s;
|
|
@@ -118782,6 +119500,91 @@ Use grayscale for minimalist design.
|
|
|
118782
119500
|
|
|
118783
119501
|
> **Editorial Style:** Stick to black, white, and grays for a clean, minimalist aesthetic. Use color sparingly for accents.
|
|
118784
119502
|
|
|
119503
|
+
` + `
|
|
119504
|
+
|
|
119505
|
+
### Animation
|
|
119506
|
+
|
|
119507
|
+
**Transition**
|
|
119508
|
+
|
|
119509
|
+
Classes: transition-none, transition, transition-colors, transition-opacity, transition-shadow, transition-transform, transition-all
|
|
119510
|
+
|
|
119511
|
+
**Duration**
|
|
119512
|
+
|
|
119513
|
+
Classes: duration-75, duration-100, duration-150, duration-200, duration-300, duration-500, duration-700, duration-1000, duration-1500
|
|
119514
|
+
|
|
119515
|
+
**Timing**
|
|
119516
|
+
|
|
119517
|
+
Classes: ease-linear, ease-in, ease-out, ease-in-out
|
|
119518
|
+
|
|
119519
|
+
**Delay**
|
|
119520
|
+
|
|
119521
|
+
Classes: delay-75, delay-100, delay-150, delay-200, delay-300, delay-500
|
|
119522
|
+
|
|
119523
|
+
**Scale**
|
|
119524
|
+
|
|
119525
|
+
Classes: scale-0, scale-50, scale-75, scale-90, scale-95, scale-100, scale-105, scale-110, scale-125, scale-150
|
|
119526
|
+
|
|
119527
|
+
**Hover Effect**
|
|
119528
|
+
|
|
119529
|
+
Classes: hover:scale-105
|
|
119530
|
+
|
|
119531
|
+
**Rotate**
|
|
119532
|
+
|
|
119533
|
+
Classes: rotate-0, rotate-45, rotate-90, rotate-180
|
|
119534
|
+
|
|
119535
|
+
**Translate X**
|
|
119536
|
+
|
|
119537
|
+
Classes: translate-x-0, translate-x-1, translate-x-2, translate-x-4, translate-x-8
|
|
119538
|
+
|
|
119539
|
+
**Translate Y**
|
|
119540
|
+
|
|
119541
|
+
Classes: translate-y-0, translate-y-1, translate-y-2, translate-y-4, translate-y-8
|
|
119542
|
+
|
|
119543
|
+
**Skew**
|
|
119544
|
+
|
|
119545
|
+
Classes: skew-x-0, skew-x-3, skew-x-6, skew-y-0, skew-y-3, skew-y-6
|
|
119546
|
+
|
|
119547
|
+
**Overflow**
|
|
119548
|
+
|
|
119549
|
+
Classes: overflow-hidden, overflow-visible, overflow-scroll, overflow-auto
|
|
119550
|
+
|
|
119551
|
+
**Opacity**
|
|
119552
|
+
|
|
119553
|
+
Classes:
|
|
119554
|
+
|
|
119555
|
+
| Class | Color |
|
|
119556
|
+
| ------------ | ------------- |
|
|
119557
|
+
| '.opacity-0' | opacity: 0 |
|
|
119558
|
+
| '.opacity-2' | opacity: 0.02 |
|
|
119559
|
+
| '.opacity-4' | opacity: 0.04 |
|
|
119560
|
+
| '.opacity-5' | opacity: 0.05 |
|
|
119561
|
+
| '.opacity-6' | opacity: 0.06 |
|
|
119562
|
+
| '.opacity-8' | opacity: 0.07 |
|
|
119563
|
+
| '.opacity-10' | opacity: 0.1 |
|
|
119564
|
+
| '.opacity-12' | opacity: 0.12 |
|
|
119565
|
+
| '.opacity-15' | opacity: 0.15 |
|
|
119566
|
+
| '.opacity-20' | opacity: 0.2 |
|
|
119567
|
+
| '.opacity-25' | opacity: 0.25 |
|
|
119568
|
+
| '.opacity-30' | opacity: 0.3 |
|
|
119569
|
+
| '.opacity-35' | opacity: 0.35 |
|
|
119570
|
+
| '.opacity-40' | opacity: 0.4 |
|
|
119571
|
+
| '.opacity-45' | opacity: 0.45 |
|
|
119572
|
+
| '.opacity-50' | opacity: 0.5 |
|
|
119573
|
+
| '.opacity-55' | opacity: 0.55 |
|
|
119574
|
+
| '.opacity-60' | opacity: 0.6 |
|
|
119575
|
+
| '.opacity-65' | opacity: 0.65 |
|
|
119576
|
+
| '.opacity-70' | opacity: 0.7 |
|
|
119577
|
+
| '.opacity-75' | opacity: 0.75 |
|
|
119578
|
+
| '.opacity-80' | opacity: 0.8 |
|
|
119579
|
+
| '.opacity-85' | opacity: 0.85 |
|
|
119580
|
+
| '.opacity-90' | opacity: 0.9 |
|
|
119581
|
+
| '.opacity-95' | opacity: 0.95 |
|
|
119582
|
+
| '.opacity-100' | opacity: 1 |
|
|
119583
|
+
|
|
119584
|
+
**Animation keyframes**
|
|
119585
|
+
|
|
119586
|
+
Classes: spin, ping, pulse, bounce
|
|
119587
|
+
` + `
|
|
118785
119588
|
---
|
|
118786
119589
|
` + `
|
|
118787
119590
|
## Common Patterns
|
|
@@ -119058,6 +119861,31 @@ When creating icon-based features, benefits, or service sections: use Bootstrap
|
|
|
119058
119861
|
<h4 class="size-18 font-medium text-center pb-3">Lightning Fast</h4>
|
|
119059
119862
|
<p class="size-14 leading-16 text-gray-600 text-center">Description...</p>
|
|
119060
119863
|
|
|
119864
|
+
### 9. Image Layout with Hover Effect
|
|
119865
|
+
|
|
119866
|
+
Use this pattern for all images (galleries, featured images, portfolio items):
|
|
119867
|
+
|
|
119868
|
+
<div class="w-full overflow-hidden relative bg-gray-50" style="aspect-ratio:16/9">
|
|
119869
|
+
<img src="..." alt="..." class="w-full h-full object-cover transition-transform duration-1500 hover:scale-105">
|
|
119870
|
+
</div>
|
|
119871
|
+
|
|
119872
|
+
**Key elements:**
|
|
119873
|
+
- 'aspect-ratio:16/9' - maintains proportions (adjust as needed: 1/1, 4/3, 3/2, 16/9, etc.)
|
|
119874
|
+
- 'overflow-hidden' - keeps scaled image contained
|
|
119875
|
+
- 'bg-gray-50' - placeholder while image loads
|
|
119876
|
+
- 'transition-transform duration-1000' - smooth 1-second animation
|
|
119877
|
+
- 'hover:scale-105' - subtle 5% scale on hover
|
|
119878
|
+
- 'object-cover' - ensures image fills container
|
|
119879
|
+
|
|
119880
|
+
**Common aspect ratios:**
|
|
119881
|
+
- Square: 'aspect-ratio:1/1'
|
|
119882
|
+
- Portrait: 'aspect-ratio:3/4' or 'aspect-ratio:2/3'
|
|
119883
|
+
- Landscape: 'aspect-ratio:4/3' or 'aspect-ratio:3/2'
|
|
119884
|
+
- Wide: 'aspect-ratio:16/9' or 'aspect-ratio:21/9'
|
|
119885
|
+
- Tall portrait: 'aspect-ratio:9/16'
|
|
119886
|
+
|
|
119887
|
+
Always include this hover effect for a polished, interactive feel.
|
|
119888
|
+
|
|
119061
119889
|
`;
|
|
119062
119890
|
|
|
119063
119891
|
const contextCodeBlock$1 = `
|
|
@@ -119240,6 +120068,191 @@ Remember: The goal is to create code blocks that are **self-contained**, **confl
|
|
|
119240
120068
|
</div>
|
|
119241
120069
|
`;
|
|
119242
120070
|
|
|
120071
|
+
const contextDesignGuide$1 = `
|
|
120072
|
+
# Design Directive:
|
|
120073
|
+
|
|
120074
|
+
## Purpose
|
|
120075
|
+
|
|
120076
|
+
This guide complements the Content Framework documentation. It explains how to create **diverse, creative designs** that go beyond default aesthetics while strictly adhering to framework utility classes.
|
|
120077
|
+
|
|
120078
|
+
## Core Philosophy: Design Freedom Within Constraints
|
|
120079
|
+
|
|
120080
|
+
The frameworks provide utility classes for structure and typography. To create rich, varied designs:
|
|
120081
|
+
|
|
120082
|
+
1. **Use framework classes** for all structural elements
|
|
120083
|
+
2. **Add inline styles** for colors, backgrounds, gradients, shadows, transforms, and animations
|
|
120084
|
+
3. **Create embedded styles** in '<style>...</style>' blocks at the end when needed for animations, transitions, or reusable patterns
|
|
120085
|
+
|
|
120086
|
+
**Example <style>: When needed for animations, transitions, or reusable patterns**
|
|
120087
|
+
|
|
120088
|
+
<div class="row">
|
|
120089
|
+
<div class="column">
|
|
120090
|
+
|
|
120091
|
+
<!-- GUIDANCE: Use this layout to show images at any aspect ratio with a hover scale effect -->
|
|
120092
|
+
<div class="w-full overflow-hidden relative bg-gray-50" style="aspect-ratio:16/9">
|
|
120093
|
+
<img src="https://placehold.co/1200x1200/f5f5f5/999?text=Featured" alt="Featured Project" class="w-full h-full object-cover transition-transform duration-1500 hover:scale-105">
|
|
120094
|
+
</div>
|
|
120095
|
+
|
|
120096
|
+
</div>
|
|
120097
|
+
</div>
|
|
120098
|
+
|
|
120099
|
+
<div class="row">
|
|
120100
|
+
<div class="column">
|
|
120101
|
+
|
|
120102
|
+
<div class="featured-image">
|
|
120103
|
+
<img src="https://placehold.co/1600x700" alt="Featured Project">
|
|
120104
|
+
</div>
|
|
120105
|
+
|
|
120106
|
+
</div>
|
|
120107
|
+
</div>
|
|
120108
|
+
|
|
120109
|
+
<div class="row portfolio-row">
|
|
120110
|
+
<div class="column">
|
|
120111
|
+
|
|
120112
|
+
<div class="row-image">
|
|
120113
|
+
<img src="https://placehold.co/1200x900" alt="Digital Banking">
|
|
120114
|
+
</div>
|
|
120115
|
+
|
|
120116
|
+
</div>
|
|
120117
|
+
<div class="column">
|
|
120118
|
+
|
|
120119
|
+
<!-- Content -->
|
|
120120
|
+
|
|
120121
|
+
</div>
|
|
120122
|
+
</div>
|
|
120123
|
+
|
|
120124
|
+
<div class="row">
|
|
120125
|
+
|
|
120126
|
+
<div class="column">
|
|
120127
|
+
|
|
120128
|
+
<div class="p-12 bg-gray-50 hover-lift">
|
|
120129
|
+
<p class="size-18 leading-17 text-black pb-8">The level of professionalism and expertise demonstrated throughout the project was outstanding. Highly recommend to anyone looking for quality work.</p>
|
|
120130
|
+
<p class="size-14 font-semibold text-black pb-1">Michael Chen</p>
|
|
120131
|
+
<p class="size-13 text-gray-600 tracking-wide">Founder, Innovation Labs</p>
|
|
120132
|
+
</div>
|
|
120133
|
+
|
|
120134
|
+
</div>
|
|
120135
|
+
<div class="column">
|
|
120136
|
+
|
|
120137
|
+
<!-- Content -->
|
|
120138
|
+
|
|
120139
|
+
</div>
|
|
120140
|
+
</div>
|
|
120141
|
+
<style>
|
|
120142
|
+
/* Featured image */
|
|
120143
|
+
|
|
120144
|
+
.featured-image {
|
|
120145
|
+
width: 100%;
|
|
120146
|
+
aspect-ratio: 21/9;
|
|
120147
|
+
overflow: hidden;
|
|
120148
|
+
position: relative;
|
|
120149
|
+
background: #fafafa;
|
|
120150
|
+
}
|
|
120151
|
+
|
|
120152
|
+
.featured-image img {
|
|
120153
|
+
width: 100%;
|
|
120154
|
+
height: 100%;
|
|
120155
|
+
object-fit: cover;
|
|
120156
|
+
transition: transform 2s cubic-bezier(0.4, 0, 0.2, 1);
|
|
120157
|
+
}
|
|
120158
|
+
|
|
120159
|
+
.featured-image:hover img {
|
|
120160
|
+
transform: scale(1.03);
|
|
120161
|
+
}
|
|
120162
|
+
|
|
120163
|
+
/* Row image */
|
|
120164
|
+
|
|
120165
|
+
.row-image {
|
|
120166
|
+
width: 100%;
|
|
120167
|
+
aspect-ratio: 4/3;
|
|
120168
|
+
overflow: hidden;
|
|
120169
|
+
position: relative;
|
|
120170
|
+
background: #fafafa;
|
|
120171
|
+
}
|
|
120172
|
+
|
|
120173
|
+
.row-image img {
|
|
120174
|
+
width: 100%;
|
|
120175
|
+
height: 100%;
|
|
120176
|
+
object-fit: cover;
|
|
120177
|
+
transition: transform 1.4s cubic-bezier(0.4, 0, 0.2, 1);
|
|
120178
|
+
}
|
|
120179
|
+
|
|
120180
|
+
.portfolio-row:hover .row-image img {
|
|
120181
|
+
transform: scale(1.05);
|
|
120182
|
+
}
|
|
120183
|
+
|
|
120184
|
+
/* Smooth hover animations */
|
|
120185
|
+
.hover-lift {
|
|
120186
|
+
transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
|
120187
|
+
}
|
|
120188
|
+
|
|
120189
|
+
.hover-lift:hover {
|
|
120190
|
+
transform: translateY(-4px);
|
|
120191
|
+
}
|
|
120192
|
+
</style>
|
|
120193
|
+
|
|
120194
|
+
|
|
120195
|
+
## Key Aesthetic Philosophy:
|
|
120196
|
+
**Swiss/Minimalist meets Portfolio Presentation** - Clean, grid-based, information-focused design where content hierarchy is created through scale, weight, and spacing rather than color or decoration. Every element serves a functional purpose. Photography is professional and high-quality. Typography creates drama through size contrast. The overall feel is sophisticated, professional, and timeless.
|
|
120197
|
+
|
|
120198
|
+
## Design Characteristics:
|
|
120199
|
+
|
|
120200
|
+
### Typography Treatment
|
|
120201
|
+
- **Extreme scale contrast**: Massive headlines (80px-140px) paired with tiny metadata text
|
|
120202
|
+
- **Version/number typography**: Large numbers (like "1.1", "2.4", "2027") used as design elements
|
|
120203
|
+
- **Mix of weights**: Bold project names with light secondary information
|
|
120204
|
+
|
|
120205
|
+
### Layout Patterns
|
|
120206
|
+
- **Horizontal information bars**: Thin lines (1px-2px) separating sections or containing metadata
|
|
120207
|
+
- **Asymmetric content placement**: Image on left (40-45%), text/info on right (55-60%)
|
|
120208
|
+
- **Card-based presentation**: Content contained in white cards floating on gray backgrounds
|
|
120209
|
+
- **Top metadata strips**: Small text in corners (studio name, project type, year)
|
|
120210
|
+
- **Multi-column text blocks**: Body copy split into 2-3 narrow columns for readability
|
|
120211
|
+
|
|
120212
|
+
### Image Treatment
|
|
120213
|
+
- **Photography as hero**: Large, high-quality images dominating the layout (not decorative)
|
|
120214
|
+
- **Clean crops**: Images in rectangular containers, no fancy shapes
|
|
120215
|
+
- **Generous padding**: White space around images, never cramping them
|
|
120216
|
+
- **Grid systems for galleries**: Even-sized thumbnails in rows (4x2, 4x4 grids)
|
|
120217
|
+
- **Product-on-white aesthetic**: Clean product photography on pure white backgrounds
|
|
120218
|
+
|
|
120219
|
+
### Color & Background
|
|
120220
|
+
- **Pure white dominant**: Clean #ffffff backgrounds, not cream or off-white
|
|
120221
|
+
- **Minimal color usage**: Mostly black text on white, with occasional single accent color
|
|
120222
|
+
- **Light gray backgrounds**: #f5f5f5 or #e5e5e5 for page backgrounds behind white cards
|
|
120223
|
+
- **Strategic black sections**: Full black backgrounds for contrast moments
|
|
120224
|
+
- **Accent color blocks**: Small pops of color (red, orange) used sparingly as highlights
|
|
120225
|
+
|
|
120226
|
+
### Information Architecture
|
|
120227
|
+
- **Numbered lists**: "1. OVERVIEW", "2. SERVICES", etc. as section headers
|
|
120228
|
+
- **Metadata in lines**: "Client Name | Project Type | Year" separated by pipes or lines
|
|
120229
|
+
- **Small label categories**: Uppercase 11px labels like "SPECIALISED IN", "CONTACT", "ABOUT"
|
|
120230
|
+
- **Horizontal dividing lines**: Thin rules (1px) creating visual sections
|
|
120231
|
+
- **List-style information**: Stacked items with consistent spacing and alignment
|
|
120232
|
+
|
|
120233
|
+
### Spatial Organization
|
|
120234
|
+
- **Air and breathing room**: Generous margins and padding throughout
|
|
120235
|
+
- **Contained sections**: Content lives in defined rectangular areas
|
|
120236
|
+
- **Aligned grids**: Everything aligns to invisible grid lines
|
|
120237
|
+
- **Consistent gaps**: Equal spacing between elements (20px, 30px, 40px)
|
|
120238
|
+
- **Edge-to-edge in black sections**: Dark sections can be full-bleed
|
|
120239
|
+
|
|
120240
|
+
### Professional Polish
|
|
120241
|
+
- **Precise alignment**: Everything lines up perfectly (left edges, baselines, top edges)
|
|
120242
|
+
- **Consistent typography system**: Limited font sizes used repeatedly (12px, 14px, 16px, 32px, 80px, 120px)
|
|
120243
|
+
- **No decorative elements**: Everything serves a purpose, nothing ornamental
|
|
120244
|
+
- **Clean hover states**: Understated interactions, not flashy
|
|
120245
|
+
|
|
120246
|
+
### What to AVOID:
|
|
120247
|
+
- ❌ Gradients (use solid colors only)
|
|
120248
|
+
- ❌ Rounded corners on everything (keep rectangular, maybe subtle 4-8px radius on cards)
|
|
120249
|
+
- ❌ Drop shadows (use very subtle if any, like 0 2px 8px rgba(0,0,0,0.04))
|
|
120250
|
+
- ❌ Overly decorative fonts (stick to clean system-ui)
|
|
120251
|
+
- ❌ Busy patterns or textures
|
|
120252
|
+
- ❌ Too many accent colors (pick one, use sparingly)
|
|
120253
|
+
- ❌ Cramped spacing (always err on the side of more whitespace)
|
|
120254
|
+
`;
|
|
120255
|
+
|
|
119243
120256
|
class ContentBuilder {
|
|
119244
120257
|
constructor(opts = {}) {
|
|
119245
120258
|
let defaults = {
|
|
@@ -119257,6 +120270,33 @@ class ContentBuilder {
|
|
|
119257
120270
|
'snippets': []
|
|
119258
120271
|
},
|
|
119259
120272
|
screenMode: 'desktop',
|
|
120273
|
+
demoMode: false,
|
|
120274
|
+
/*
|
|
120275
|
+
demoConversations: [
|
|
120276
|
+
{
|
|
120277
|
+
role: 'user',
|
|
120278
|
+
content: 'Generate an image: "a house with beautiful mountain view. warm sunlight, golden-hour lighting, filmic teal-orange color grade".',
|
|
120279
|
+
// timestamp: Date.now() - 180000 // 3 minutes ago
|
|
120280
|
+
},
|
|
120281
|
+
{
|
|
120282
|
+
role: 'assistant',
|
|
120283
|
+
content: '✓ Image generated successfully',
|
|
120284
|
+
imagePreview: [
|
|
120285
|
+
{ url: 'uploads/ai-8vnqv.png', context: 'Generate image of a house with a beautiful mountain view' },
|
|
120286
|
+
]
|
|
120287
|
+
},
|
|
120288
|
+
{
|
|
120289
|
+
role: 'user',
|
|
120290
|
+
content: `Create a thoughtful article about finding home in extraordinary landscapes. Write vivid prose about mountain dwellings and how our environments shape the way we live.
|
|
120291
|
+
Use the generated image for this article, and present it as a premium design magazine feature.`,
|
|
120292
|
+
},
|
|
120293
|
+
{
|
|
120294
|
+
role: 'assistant',
|
|
120295
|
+
content: '✓ Create a thoughtful article about finding home in extraordinary landscapes with vivid prose about mountain dwellings and their impact on our lives, formatted as a premium design magazine feature.',
|
|
120296
|
+
}
|
|
120297
|
+
],
|
|
120298
|
+
*/
|
|
120299
|
+
|
|
119260
120300
|
// Live Preview
|
|
119261
120301
|
// previewURL: 'preview.html',
|
|
119262
120302
|
onPreviewOpen: () => {
|
|
@@ -120526,7 +121566,7 @@ class ContentBuilder {
|
|
|
120526
121566
|
this.ShortcutInfo = new ShortcutInfo(this);
|
|
120527
121567
|
if (!this.opts.isContentBox) {
|
|
120528
121568
|
this.codechat = new CodeChat$1({
|
|
120529
|
-
context: contextContentFramework$1 + contextCodeBlock$1
|
|
121569
|
+
context: contextContentFramework$1 + contextCodeBlock$1 + contextDesignGuide$1
|
|
120530
121570
|
}, this);
|
|
120531
121571
|
if (this.startAIAssistant) {
|
|
120532
121572
|
this.openAIAssistant();
|
|
@@ -143374,7 +144414,10 @@ class CodeChat {
|
|
|
143374
144414
|
};
|
|
143375
144415
|
this.builder = builder;
|
|
143376
144416
|
const builderStuff = this.builder.builderStuff;
|
|
143377
|
-
this.builderStuff = builderStuff;
|
|
144417
|
+
this.builderStuff = builderStuff; // Check if demo mode is enabled
|
|
144418
|
+
|
|
144419
|
+
this.isDemoMode = this.builder.demoMode || false;
|
|
144420
|
+
this.demoConversations = this.builder.demoConversations || [];
|
|
143378
144421
|
|
|
143379
144422
|
const out = s => this.out(s); // Load saved settings or use defaults
|
|
143380
144423
|
|
|
@@ -143387,6 +144430,9 @@ class CodeChat {
|
|
|
143387
144430
|
}
|
|
143388
144431
|
|
|
143389
144432
|
this.codeModels = [{
|
|
144433
|
+
id: 'anthropic/claude-opus-4.5',
|
|
144434
|
+
label: 'Claude Opus 4.5'
|
|
144435
|
+
}, {
|
|
143390
144436
|
id: 'google/gemini-3-pro-preview',
|
|
143391
144437
|
label: 'Google Gemini 3 Pro Preview'
|
|
143392
144438
|
}, {
|
|
@@ -143718,6 +144764,14 @@ class CodeChat {
|
|
|
143718
144764
|
this.imageModels = this.builder.imageGenerationModels;
|
|
143719
144765
|
}
|
|
143720
144766
|
|
|
144767
|
+
let inputPlaceholderText;
|
|
144768
|
+
|
|
144769
|
+
if (this.builder.editor) {
|
|
144770
|
+
inputPlaceholderText = out('e.g., Create a landing page for a creative studio');
|
|
144771
|
+
} else {
|
|
144772
|
+
inputPlaceholderText = out('e.g., Create an article about a productive home workspace');
|
|
144773
|
+
}
|
|
144774
|
+
|
|
143721
144775
|
let html = `
|
|
143722
144776
|
<style>
|
|
143723
144777
|
#chatPanel {
|
|
@@ -144049,10 +145103,12 @@ class CodeChat {
|
|
|
144049
145103
|
box-shadow: 6px 14px 20px 0px rgba(95, 95, 95, 0.11);
|
|
144050
145104
|
z-index: 10005;
|
|
144051
145105
|
display: none;
|
|
145106
|
+
pointer-events: auto; /* Reset cursor to default to prevent it from getting stuck */
|
|
144052
145107
|
}
|
|
144053
145108
|
|
|
144054
145109
|
#settingsDialog.open {
|
|
144055
145110
|
display: block;
|
|
145111
|
+
pointer-events: auto; /* Reset cursor to default to prevent it from getting stuck */
|
|
144056
145112
|
}
|
|
144057
145113
|
|
|
144058
145114
|
#settingsDialog .settings-header {
|
|
@@ -144313,9 +145369,118 @@ class CodeChat {
|
|
|
144313
145369
|
body.dark #chatPanel .copy-button:hover {
|
|
144314
145370
|
background: rgba(255, 255, 255, 0.2);
|
|
144315
145371
|
}
|
|
145372
|
+
|
|
145373
|
+
|
|
145374
|
+
/* Quick Image Size Button */
|
|
145375
|
+
#chatPanel .quick-image-size-button {
|
|
145376
|
+
width: 48px;
|
|
145377
|
+
height: 48px;
|
|
145378
|
+
border: none;
|
|
145379
|
+
border-radius: 8px;
|
|
145380
|
+
font-size: 13px;
|
|
145381
|
+
font-weight: 500;
|
|
145382
|
+
cursor: pointer;
|
|
145383
|
+
transition: background 0.2s;
|
|
145384
|
+
display: flex;
|
|
145385
|
+
align-items: center;
|
|
145386
|
+
justify-content: center;
|
|
145387
|
+
}
|
|
145388
|
+
|
|
145389
|
+
#chatPanel .quick-image-size-button:hover:not(:disabled) {
|
|
145390
|
+
background: rgba(0, 0, 0, 0.05);
|
|
145391
|
+
}
|
|
145392
|
+
|
|
145393
|
+
#chatPanel .quick-image-size-button:disabled {
|
|
145394
|
+
opacity: 0.6;
|
|
145395
|
+
cursor: not-allowed;
|
|
145396
|
+
}
|
|
145397
|
+
|
|
145398
|
+
body.dark #chatPanel .quick-image-size-button {
|
|
145399
|
+
background: #484848;
|
|
145400
|
+
}
|
|
145401
|
+
|
|
145402
|
+
body.dark #chatPanel .quick-image-size-button:hover:not(:disabled) {
|
|
145403
|
+
background: #4c4c4c;
|
|
145404
|
+
}
|
|
145405
|
+
|
|
145406
|
+
/* Image Size Popover */
|
|
145407
|
+
#chatPanel .image-size-popover {
|
|
145408
|
+
position: absolute;
|
|
145409
|
+
bottom: 72px;
|
|
145410
|
+
right: 68px;
|
|
145411
|
+
background: white;
|
|
145412
|
+
border: 1px solid #e5e5e5;
|
|
145413
|
+
border-radius: 8px;
|
|
145414
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
|
145415
|
+
z-index: 10006;
|
|
145416
|
+
min-width: 160px;
|
|
145417
|
+
max-height: 300px;
|
|
145418
|
+
overflow-y: auto;
|
|
145419
|
+
}
|
|
145420
|
+
|
|
145421
|
+
body.dark #chatPanel .image-size-popover {
|
|
145422
|
+
background: #3a3a3a;
|
|
145423
|
+
border-color: #555;
|
|
145424
|
+
}
|
|
145425
|
+
|
|
145426
|
+
#chatPanel .size-options {
|
|
145427
|
+
padding: 8px;
|
|
145428
|
+
}
|
|
145429
|
+
|
|
145430
|
+
#chatPanel .size-option {
|
|
145431
|
+
display: flex;
|
|
145432
|
+
align-items: center;
|
|
145433
|
+
padding: 10px 12px;
|
|
145434
|
+
cursor: pointer;
|
|
145435
|
+
border-radius: 6px;
|
|
145436
|
+
transition: background 0.2s;
|
|
145437
|
+
font-size: 14px;
|
|
145438
|
+
}
|
|
145439
|
+
#chatPanel .size-option label,
|
|
145440
|
+
#chatPanel .size-option input {
|
|
145441
|
+
cursor: pointer;
|
|
145442
|
+
}
|
|
145443
|
+
|
|
145444
|
+
#chatPanel .size-option:hover {
|
|
145445
|
+
background: rgba(0, 0, 0, 0.05);
|
|
145446
|
+
}
|
|
145447
|
+
|
|
145448
|
+
#chatPanel .size-option.selected {
|
|
145449
|
+
background: rgba(62, 147, 247, 0.1);
|
|
145450
|
+
font-weight: 500;
|
|
145451
|
+
}
|
|
145452
|
+
|
|
145453
|
+
#chatPanel .size-option input[type="radio"] {
|
|
145454
|
+
margin-right: 8px;
|
|
145455
|
+
}
|
|
145456
|
+
|
|
145457
|
+
body.dark #chatPanel .size-option:hover {
|
|
145458
|
+
background: rgba(255, 255, 255, 0.1);
|
|
145459
|
+
}
|
|
145460
|
+
|
|
145461
|
+
body.dark #chatPanel .size-option.selected {
|
|
145462
|
+
background: rgba(62, 147, 247, 0.2);
|
|
145463
|
+
}
|
|
145464
|
+
|
|
145465
|
+
#chatPanel .image-size-popover::-webkit-scrollbar {
|
|
145466
|
+
width: 6px;
|
|
145467
|
+
}
|
|
145468
|
+
|
|
145469
|
+
#chatPanel .image-size-popover::-webkit-scrollbar-track {
|
|
145470
|
+
background: transparent;
|
|
145471
|
+
}
|
|
145472
|
+
|
|
145473
|
+
#chatPanel .image-size-popover::-webkit-scrollbar-thumb {
|
|
145474
|
+
background: #e5e5e5;
|
|
145475
|
+
border-radius: 3px;
|
|
145476
|
+
}
|
|
145477
|
+
|
|
145478
|
+
body.dark #chatPanel .image-size-popover::-webkit-scrollbar-thumb {
|
|
145479
|
+
background: #555;
|
|
145480
|
+
}
|
|
144316
145481
|
</style>
|
|
144317
145482
|
<div
|
|
144318
|
-
class="hidden"
|
|
145483
|
+
class="hidden keep-selection"
|
|
144319
145484
|
id="chatPanel"
|
|
144320
145485
|
role="dialog"
|
|
144321
145486
|
aria-labelledby="chatPanelTitle"
|
|
@@ -144365,10 +145530,24 @@ class CodeChat {
|
|
|
144365
145530
|
<label for="promptInput" class="sr-only">${out('Message input')}</label>
|
|
144366
145531
|
<textarea
|
|
144367
145532
|
id="promptInput"
|
|
144368
|
-
placeholder="${
|
|
145533
|
+
placeholder="${inputPlaceholderText}"
|
|
144369
145534
|
rows="1"
|
|
144370
145535
|
aria-label="${out('Type your message')}"
|
|
144371
145536
|
></textarea>
|
|
145537
|
+
|
|
145538
|
+
<!-- NEW: Quick image size button -->
|
|
145539
|
+
<button
|
|
145540
|
+
id="quickImageSizeButton"
|
|
145541
|
+
type="button"
|
|
145542
|
+
class="quick-image-size-button"
|
|
145543
|
+
aria-label="${out('Select image size')}"
|
|
145544
|
+
aria-haspopup="true"
|
|
145545
|
+
aria-expanded="false"
|
|
145546
|
+
style="display: none;"
|
|
145547
|
+
>
|
|
145548
|
+
□
|
|
145549
|
+
</button>
|
|
145550
|
+
|
|
144372
145551
|
<button
|
|
144373
145552
|
id="sendButton"
|
|
144374
145553
|
type="button"
|
|
@@ -144382,15 +145561,30 @@ class CodeChat {
|
|
|
144382
145561
|
</svg>
|
|
144383
145562
|
</button>
|
|
144384
145563
|
</div>
|
|
145564
|
+
|
|
145565
|
+
<!-- NEW: Size selection popover -->
|
|
145566
|
+
<div
|
|
145567
|
+
id="imageSizePopover"
|
|
145568
|
+
class="image-size-popover"
|
|
145569
|
+
role="menu"
|
|
145570
|
+
aria-hidden="true"
|
|
145571
|
+
style="display: none;"
|
|
145572
|
+
>
|
|
145573
|
+
<div class="size-options" id="sizeOptionsContainer">
|
|
145574
|
+
<!-- Options populated dynamically -->
|
|
145575
|
+
</div>
|
|
145576
|
+
</div>
|
|
145577
|
+
|
|
144385
145578
|
</div>
|
|
144386
145579
|
</div>
|
|
144387
145580
|
|
|
144388
145581
|
<!-- Settings Dialog Overlay -->
|
|
144389
|
-
<div id="settingsOverlay" aria-hidden="true"></div>
|
|
145582
|
+
<div id="settingsOverlay" class="keep-selection" aria-hidden="true"></div>
|
|
144390
145583
|
|
|
144391
145584
|
<!-- Settings Dialog -->
|
|
144392
145585
|
<div
|
|
144393
145586
|
id="settingsDialog"
|
|
145587
|
+
class="keep-selection"
|
|
144394
145588
|
role="dialog"
|
|
144395
145589
|
aria-labelledby="settingsTitle"
|
|
144396
145590
|
aria-modal="true"
|
|
@@ -144520,11 +145714,17 @@ class CodeChat {
|
|
|
144520
145714
|
this.codeModelSelect.value = this.settings.codeModel;
|
|
144521
145715
|
this.chatModelSelect.value = this.settings.chatModel;
|
|
144522
145716
|
this.imageModelSelect.value = this.settings.imageModel;
|
|
144523
|
-
this.imageSizeSelect.value = this.settings.imageSize;
|
|
144524
|
-
|
|
145717
|
+
this.imageSizeSelect.value = this.settings.imageSize; // Check saved state - default to closed if never set
|
|
145718
|
+
|
|
145719
|
+
const savedState = localStorage.getItem('chatPanelVisible');
|
|
145720
|
+
let isChatVisible = savedState === 'true'; // Only open if explicitly set to 'true'
|
|
144525
145721
|
|
|
144526
145722
|
if (!isChatVisible) {
|
|
144527
145723
|
modal.classList.add('hidden');
|
|
145724
|
+
modal.setAttribute('aria-hidden', 'true');
|
|
145725
|
+
} else {
|
|
145726
|
+
modal.classList.remove('hidden');
|
|
145727
|
+
modal.removeAttribute('aria-hidden');
|
|
144528
145728
|
}
|
|
144529
145729
|
|
|
144530
145730
|
const btnClose = modal.querySelector('.close-button');
|
|
@@ -144608,8 +145808,43 @@ class CodeChat {
|
|
|
144608
145808
|
this.promptInput = promptInput;
|
|
144609
145809
|
this.closeChatButton = closeChatButton;
|
|
144610
145810
|
this.sendButton = sendButton;
|
|
144611
|
-
this.messagesContainer = messagesContainer;
|
|
145811
|
+
this.messagesContainer = messagesContainer; // NEW: Quick image size button elements
|
|
145812
|
+
|
|
145813
|
+
this.quickImageSizeButton = builderStuff.querySelector('#quickImageSizeButton');
|
|
145814
|
+
this.imageSizePopover = builderStuff.querySelector('#imageSizePopover');
|
|
145815
|
+
this.sizeOptionsContainer = builderStuff.querySelector('#sizeOptionsContainer'); // Quick Image Size Button Handlers
|
|
145816
|
+
|
|
145817
|
+
this.quickImageSizeButton.addEventListener('click', e => {
|
|
145818
|
+
e.stopPropagation();
|
|
145819
|
+
this.toggleImageSizePopover();
|
|
145820
|
+
}); // Close popover when clicking outside
|
|
145821
|
+
|
|
145822
|
+
document.addEventListener('click', e => {
|
|
145823
|
+
if (!this.imageSizePopover.contains(e.target) && !this.quickImageSizeButton.contains(e.target)) {
|
|
145824
|
+
this.closeImageSizePopover();
|
|
145825
|
+
}
|
|
145826
|
+
}); // Close popover on Escape
|
|
145827
|
+
|
|
145828
|
+
this.imageSizePopover.addEventListener('keydown', e => {
|
|
145829
|
+
if (e.key === 'Escape') {
|
|
145830
|
+
this.closeImageSizePopover();
|
|
145831
|
+
this.quickImageSizeButton.focus();
|
|
145832
|
+
}
|
|
145833
|
+
});
|
|
144612
145834
|
this.renderImageOptions();
|
|
145835
|
+
|
|
145836
|
+
if (this.demoConversations) {
|
|
145837
|
+
this.loadConversations();
|
|
145838
|
+
}
|
|
145839
|
+
|
|
145840
|
+
if (this.isDemoMode) {
|
|
145841
|
+
this.addDemoBanner(); // Disable input in demo mode
|
|
145842
|
+
|
|
145843
|
+
this.promptInput.disabled = true; // this.promptInput.placeholder = out('Demo mode - Chat is read-only');
|
|
145844
|
+
|
|
145845
|
+
this.sendButton.disabled = true;
|
|
145846
|
+
this.messagesContainer.scrollTop = this.messagesContainer.scrollHeight;
|
|
145847
|
+
}
|
|
144613
145848
|
}
|
|
144614
145849
|
|
|
144615
145850
|
renderImageOptions() {
|
|
@@ -144712,7 +145947,9 @@ class CodeChat {
|
|
|
144712
145947
|
}); // Trigger initial render with defaults
|
|
144713
145948
|
|
|
144714
145949
|
modelSelect.value = defaultModelId;
|
|
144715
|
-
renderSizes(defaultModelId, false);
|
|
145950
|
+
renderSizes(defaultModelId, false); // NEW: Initialize quick size button
|
|
145951
|
+
|
|
145952
|
+
this.updateQuickImageSizeButton();
|
|
144716
145953
|
}
|
|
144717
145954
|
/**
|
|
144718
145955
|
* ============================================================================
|
|
@@ -144784,7 +146021,9 @@ class CodeChat {
|
|
|
144784
146021
|
this.settingsOverlay.classList.remove('open');
|
|
144785
146022
|
this.settingsOverlay.setAttribute('aria-hidden', 'true');
|
|
144786
146023
|
this.settingsDialog.classList.remove('open');
|
|
144787
|
-
this.settingsDialog.setAttribute('aria-hidden', 'true');
|
|
146024
|
+
this.settingsDialog.setAttribute('aria-hidden', 'true'); // Reset cursor to default to prevent it from getting stuck
|
|
146025
|
+
|
|
146026
|
+
document.body.style.cursor = '';
|
|
144788
146027
|
|
|
144789
146028
|
if (this.settingsLastFocusedElement) {
|
|
144790
146029
|
this.settingsLastFocusedElement.focus();
|
|
@@ -144798,7 +146037,9 @@ class CodeChat {
|
|
|
144798
146037
|
this.settings.chatModel = this.chatModelSelect.value;
|
|
144799
146038
|
this.settings.imageModel = this.imageModelSelect.value;
|
|
144800
146039
|
this.settings.imageSize = this.imageSizeSelect.value;
|
|
144801
|
-
this.saveSettingsToStorage();
|
|
146040
|
+
this.saveSettingsToStorage(); // NEW: Update quick button when settings change
|
|
146041
|
+
|
|
146042
|
+
this.updateQuickImageSizeButton();
|
|
144802
146043
|
this.closeSettings();
|
|
144803
146044
|
}
|
|
144804
146045
|
/**
|
|
@@ -144833,6 +146074,106 @@ Your job:
|
|
|
144833
146074
|
3. Determine what each image should depict based on surrounding content and context
|
|
144834
146075
|
4. Create detailed image generation prompts for each image
|
|
144835
146076
|
|
|
146077
|
+
📸 EDITORIAL STYLE GUIDE - Apply to all image prompts:
|
|
146078
|
+
|
|
146079
|
+
- Default aesthetic: Minimalist magazine-style (Kinfolk, Cereal, Vogue Living)
|
|
146080
|
+
- Composition: Clean, lots of negative space, well-balanced
|
|
146081
|
+
|
|
146082
|
+
|
|
146083
|
+
CREATIVE PROMPT ENHANCEMENT:
|
|
146084
|
+
When constructing image prompts, intelligently enrich basic descriptions using these proven cinematic stylers:
|
|
146085
|
+
|
|
146086
|
+
1. **Golden Hour Cinematic**
|
|
146087
|
+
"Warm sunlight, golden-hour lighting. Low contrast with lifted shadows, ethereal glow throughout. Overall vibe: relaxed, coastal, sun-kissed, carefree, West Coast lifestyle, evoking warmth and endless summer."
|
|
146088
|
+
→ Best for: Landscapes, architecture, outdoor scenes, lifestyle content
|
|
146089
|
+
|
|
146090
|
+
2. **Morning Halo Effect**
|
|
146091
|
+
"The lighting is soft, morning sunlight coming, creating a 'halo' effect. Vibrant cinematic shot"
|
|
146092
|
+
→ Best for: Portraits, people in action, outdoor activities
|
|
146093
|
+
|
|
146094
|
+
3. **Natural Forest Serenity**
|
|
146095
|
+
"in a lush, green forest. The sunlight should be filtering through the trees, creating a serene and natural atmosphere"
|
|
146096
|
+
→ Best for: Nature scenes, outdoor activities, wellness content
|
|
146097
|
+
|
|
146098
|
+
4. **Coastal Summer Drama**
|
|
146099
|
+
"on a dramatic windswept coastline. The overall atmosphere is cheerful, breezy, and full of summer warmth"
|
|
146100
|
+
→ Best for: Beach/coastal scenes, adventure, travel content
|
|
146101
|
+
|
|
146102
|
+
5. **Modern Interior Elegance**
|
|
146103
|
+
"illuminated by warm, natural lighting. The background features a softly blurred modern interior with subtle lights and cool tones, adding depth without distraction"
|
|
146104
|
+
→ Best for: Indoor portraits, product shots, professional/business settings
|
|
146105
|
+
|
|
146106
|
+
ENHANCEMENT STRATEGY:
|
|
146107
|
+
- Analyze the subject matter and context from the HTML/request
|
|
146108
|
+
- Select the most appropriate styler that matches the scene type
|
|
146109
|
+
- Check if user has specified lighting/time → DO NOT apply contradicting styler elements
|
|
146110
|
+
* Example: User says "daylight" → DO NOT add "golden-hour" or "sunset"
|
|
146111
|
+
- Aim for creative elevation while maintaining the core subject integrity
|
|
146112
|
+
- Blend the styler naturally into the prompt (adapt grammar, pronouns, context)
|
|
146113
|
+
- IF user is vague (no specific lighting/mood) → Apply full styler enhancement
|
|
146114
|
+
- User's explicit details ALWAYS take precedence over styler recommendations
|
|
146115
|
+
` +
|
|
146116
|
+
/*
|
|
146117
|
+
ENHANCEMENT STRATEGY:
|
|
146118
|
+
- Analyze the subject matter and context from the HTML/request
|
|
146119
|
+
- Select the most appropriate styler that matches the scene type
|
|
146120
|
+
- Blend the styler naturally into the prompt (adapt grammar, pronouns, context)
|
|
146121
|
+
- If the subject already has specific lighting/atmosphere details, complement rather than override
|
|
146122
|
+
- Aim for creative elevation while maintaining the core subject integrity
|
|
146123
|
+
*/
|
|
146124
|
+
`
|
|
146125
|
+
Examples of enriched prompts:
|
|
146126
|
+
- Basic: "a house with mountain view"
|
|
146127
|
+
→ Enhanced: "a house with beautiful mountain view. Warm sunlight, golden-hour lighting. Low contrast with lifted shadows, ethereal glow throughout. Overall vibe: relaxed, coastal, sun-kissed, carefree, West Coast lifestyle, evoking warmth and endless summer."
|
|
146128
|
+
|
|
146129
|
+
- Basic: "person hiking"
|
|
146130
|
+
→ Enhanced: "a person hiking in nature. The lighting is soft, morning sunlight coming, creating a 'halo' effect. Vibrant cinematic shot"
|
|
146131
|
+
|
|
146132
|
+
- Basic: "woman reading"
|
|
146133
|
+
→ Enhanced: "a woman sitting comfortably and reading. Her face is illuminated by warm, natural lighting. The background features a softly blurred modern interior with subtle lights and cool tones, adding depth without distraction"
|
|
146134
|
+
|
|
146135
|
+
- Already detailed: "dramatic headshot with bokeh and rim lighting"
|
|
146136
|
+
→ No enhancement needed (preserve user's vision)
|
|
146137
|
+
|
|
146138
|
+
|
|
146139
|
+
CONTEXT-SPECIFIC GUIDELINES:
|
|
146140
|
+
|
|
146141
|
+
Interior/Indoor scenes:
|
|
146142
|
+
- Lighting: Soft natural window light
|
|
146143
|
+
- Backdrop: white walls or neutral tones
|
|
146144
|
+
- Mood: Calm, serene, inviting, uncluttered
|
|
146145
|
+
- Reference: "Kinfolk interior photography"
|
|
146146
|
+
|
|
146147
|
+
People/Portraits/Activities:
|
|
146148
|
+
- Lighting: Natural diffused light, flattering and soft
|
|
146149
|
+
- Styling: Effortlessly elegant, contemporary casual
|
|
146150
|
+
- Pose: Candid, authentic moments, relaxed
|
|
146151
|
+
- Reference: "modern lifestyle editorial photography"
|
|
146152
|
+
|
|
146153
|
+
Products/Objects:
|
|
146154
|
+
- Lighting: Clean studio or soft natural light
|
|
146155
|
+
- Backdrop: Minimalist neutral, lots of breathing room
|
|
146156
|
+
- Mood: Refined simplicity, premium feel
|
|
146157
|
+
- Reference: "high-end editorial product photography"
|
|
146158
|
+
|
|
146159
|
+
Food/Culinary:
|
|
146160
|
+
- Lighting: Soft daylight, gentle overhead or 45° angle
|
|
146161
|
+
- Styling: Minimal props, artisan ceramics, linen
|
|
146162
|
+
- Mood: Fresh, appetizing, rustic-modern
|
|
146163
|
+
- Reference: "Bon Appétit editorial food styling"
|
|
146164
|
+
|
|
146165
|
+
Outdoor/Landscape:
|
|
146166
|
+
- Composition: Serene, contemplative, minimal
|
|
146167
|
+
- Mood: Calm atmosphere, breathing space, lifted brightness
|
|
146168
|
+
- Colors: Vibrant cinematic shot.
|
|
146169
|
+
- Reference: "editorial travel photography"
|
|
146170
|
+
|
|
146171
|
+
CRITICAL RULES:
|
|
146172
|
+
1. If user specifies a style (cinematic, vintage, vibrant, etc.) → RESPECT IT, only add quality markers
|
|
146173
|
+
2. If user is vague → APPLY FULL EDITORIAL TREATMENT based on subject category
|
|
146174
|
+
3. Always maintain cohesive aesthetic across all images
|
|
146175
|
+
4. Every prompt should feel like it belongs in a high-end lifestyle magazine
|
|
146176
|
+
|
|
144836
146177
|
Respond with a JSON array with one entry per image to generate:
|
|
144837
146178
|
[
|
|
144838
146179
|
{
|
|
@@ -144937,7 +146278,12 @@ Response: [
|
|
|
144937
146278
|
|
|
144938
146279
|
|
|
144939
146280
|
async sendMessage() {
|
|
144940
|
-
const out = s => this.out(s);
|
|
146281
|
+
const out = s => this.out(s); // Prevent sending messages in demo mode
|
|
146282
|
+
|
|
146283
|
+
|
|
146284
|
+
if (this.isDemoMode) {
|
|
146285
|
+
return;
|
|
146286
|
+
}
|
|
144941
146287
|
|
|
144942
146288
|
const prompt = this.promptInput.value.trim();
|
|
144943
146289
|
if (!prompt) return;
|
|
@@ -145004,16 +146350,45 @@ Response: [
|
|
|
145004
146350
|
this.addMessage('assistant', `✓ ${result.description}`);
|
|
145005
146351
|
} else if (result.type === 'image') {
|
|
145006
146352
|
if (result.imageDetails && result.imageDetails.length > 1) {
|
|
145007
|
-
this.addMessage('assistant', `✓ Generated ${result.imageDetails.length} images successfully`);
|
|
146353
|
+
this.addMessage('assistant', `✓ Generated ${result.imageDetails.length} images successfully`); // this.addMessage('assistant', `✓ ${out('Generated {count} images successfully').replace('{count}', result.imageDetails.length)}`);
|
|
146354
|
+
|
|
145008
146355
|
this.addImagePreview(result.imageDetails);
|
|
145009
146356
|
} else {
|
|
145010
|
-
this.addMessage('assistant', '✓
|
|
146357
|
+
this.addMessage('assistant', '✓ Image generated successfully'); // this.addMessage('assistant', `✓ ${out('Image generated successfully')}`);
|
|
145011
146358
|
|
|
145012
146359
|
if (result.generatedUrls && result.generatedUrls[0]) {
|
|
145013
146360
|
this.addImagePreview([{
|
|
145014
146361
|
url: result.generatedUrls[0],
|
|
145015
146362
|
context: result.description
|
|
145016
|
-
}]);
|
|
146363
|
+
}]); // If there is a selected image, replace with the new image
|
|
146364
|
+
|
|
146365
|
+
const url = result.generatedUrls[0];
|
|
146366
|
+
|
|
146367
|
+
if (this.builder.editor) {
|
|
146368
|
+
// ContentBox
|
|
146369
|
+
const img = this.builder.editor.activeImage;
|
|
146370
|
+
|
|
146371
|
+
if (img) {
|
|
146372
|
+
this.builder.editor.saveForUndo();
|
|
146373
|
+
img.addEventListener('load', () => {
|
|
146374
|
+
this.builder.editor.element.image.repositionImageTool();
|
|
146375
|
+
this.builder.editor.elmTool.repositionElementTool();
|
|
146376
|
+
});
|
|
146377
|
+
this.builder.editor.activeImage.setAttribute('src', url);
|
|
146378
|
+
}
|
|
146379
|
+
} else {
|
|
146380
|
+
// ContentBuilder
|
|
146381
|
+
const img = this.builder.activeImage;
|
|
146382
|
+
|
|
146383
|
+
if (img) {
|
|
146384
|
+
this.builder.uo.saveForUndo();
|
|
146385
|
+
img.addEventListener('load', () => {
|
|
146386
|
+
this.builder.element.image.repositionImageTool();
|
|
146387
|
+
this.builder.elmTool.repositionElementTool();
|
|
146388
|
+
});
|
|
146389
|
+
this.builder.activeImage.setAttribute('src', url);
|
|
146390
|
+
}
|
|
146391
|
+
}
|
|
145017
146392
|
}
|
|
145018
146393
|
}
|
|
145019
146394
|
}
|
|
@@ -145071,14 +146446,14 @@ Response: [
|
|
|
145071
146446
|
`;
|
|
145072
146447
|
images.forEach(img => {
|
|
145073
146448
|
previewHTML += `
|
|
145074
|
-
<div style="border-radius:
|
|
145075
|
-
<img src="${img.url}" alt="${img.context || 'Generated image'}" style="width: 100%;
|
|
146449
|
+
<div style="border-radius: 6px; overflow: hidden; background: rgba(255,255,255,0.05);">
|
|
146450
|
+
<img src="${img.url}" alt="${img.context || 'Generated image'}" style="width: 100%;" />
|
|
145076
146451
|
<div style="padding: 8px; font-size: 11px; opacity: 0.8;">
|
|
145077
146452
|
${img.context || ''}
|
|
145078
146453
|
<a href="${img.url}" target="_blank" rel="noopener noreferrer" style="display: block; margin-top: 4px;">View</a>
|
|
145079
146454
|
</div>
|
|
145080
146455
|
</div>
|
|
145081
|
-
`;
|
|
146456
|
+
`; // height: 150px; object-fit: cover;
|
|
145082
146457
|
});
|
|
145083
146458
|
previewHTML += '</div>';
|
|
145084
146459
|
previewDiv.innerHTML = previewHTML;
|
|
@@ -145098,7 +146473,34 @@ Response: [
|
|
|
145098
146473
|
...this.builder.defaultHeaders
|
|
145099
146474
|
}; // Check if image generation is enabled
|
|
145100
146475
|
|
|
145101
|
-
const imageGenEnabled = this.builder.generateMediaUrl_Fal ? true : false;
|
|
146476
|
+
const imageGenEnabled = this.builder.generateMediaUrl_Fal ? true : false; // Build context about previously generated images
|
|
146477
|
+
|
|
146478
|
+
let imageHistoryContext = '';
|
|
146479
|
+
const previousImageResults = this.conversationResults.filter(r => r.type === 'image' && r.generatedUrls && r.generatedUrls.length > 0);
|
|
146480
|
+
|
|
146481
|
+
if (previousImageResults.length > 0) {
|
|
146482
|
+
imageHistoryContext = '\n\n=== PREVIOUSLY GENERATED IMAGES IN THIS CONVERSATION ===\n';
|
|
146483
|
+
imageHistoryContext += 'The following images were generated earlier in this conversation:\n\n';
|
|
146484
|
+
previousImageResults.forEach((result, idx) => {
|
|
146485
|
+
if (result.imageDetails && result.imageDetails.length > 0) {
|
|
146486
|
+
result.imageDetails.forEach((img, imgIdx) => {
|
|
146487
|
+
imageHistoryContext += `Generated Image ${idx + 1}.${imgIdx + 1}:\n`;
|
|
146488
|
+
imageHistoryContext += ` URL: ${img.url}\n`;
|
|
146489
|
+
imageHistoryContext += ` Context: ${img.context}\n`;
|
|
146490
|
+
imageHistoryContext += ` Description: ${result.description}\n\n`;
|
|
146491
|
+
});
|
|
146492
|
+
} else {
|
|
146493
|
+
result.generatedUrls.forEach((url, urlIdx) => {
|
|
146494
|
+
imageHistoryContext += `Generated Image ${idx + 1}.${urlIdx + 1}:\n`;
|
|
146495
|
+
imageHistoryContext += ` URL: ${url}\n`;
|
|
146496
|
+
imageHistoryContext += ` Description: ${result.description}\n\n`;
|
|
146497
|
+
});
|
|
146498
|
+
}
|
|
146499
|
+
});
|
|
146500
|
+
imageHistoryContext += '⚠️ IMPORTANT: If the user refers to "the generated image", "this image", "the image", or "previous image", they are referring to these images above.\n';
|
|
146501
|
+
imageHistoryContext += '⚠️ DO NOT create a new image task. Instead, create a CODE task that uses these existing URLs.\n\n';
|
|
146502
|
+
}
|
|
146503
|
+
|
|
145102
146504
|
const classificationPrompt = `Analyze this user message and break it down into tasks.
|
|
145103
146505
|
|
|
145104
146506
|
CURRENT HTML CONTEXT (use this to understand the page structure):
|
|
@@ -145106,11 +146508,19 @@ CURRENT HTML CONTEXT (use this to understand the page structure):
|
|
|
145106
146508
|
${this.builder.html()}
|
|
145107
146509
|
\`\`\`
|
|
145108
146510
|
|
|
146511
|
+
${imageHistoryContext}
|
|
146512
|
+
|
|
145109
146513
|
IMPORTANT: This is a WEB BUILDER tool with chat capabilities. Valid requests are:
|
|
145110
146514
|
- Creating/editing/removing HTML content (code tasks)
|
|
145111
146515
|
${imageGenEnabled ? '- Generating images for the webpage (image tasks)' : ''}
|
|
145112
146516
|
- Asking questions or having conversations (chat tasks) - THIS CAN BE ABOUT ANYTHING
|
|
145113
146517
|
|
|
146518
|
+
CRITICAL CONTEXT RULE:
|
|
146519
|
+
- In a web builder, "create an article/blog/story/content" means CREATE A WEBPAGE (CODE task)
|
|
146520
|
+
- Only use CHAT task for questions, explanations, or requests for advice
|
|
146521
|
+
- If user says "create", "write", "make", "build" followed by content → CODE task
|
|
146522
|
+
- If user says "explain", "how do I", "what is", "tell me about" → CHAT task
|
|
146523
|
+
|
|
145114
146524
|
${imageGenEnabled ? '' : `
|
|
145115
146525
|
⚠️ AI IMAGE GENERATION IS CURRENTLY DISABLED
|
|
145116
146526
|
- If user requests AI image generation/creation, explain that it's disabled
|
|
@@ -145180,6 +146590,18 @@ IMAGE TASK RULES:
|
|
|
145180
146590
|
- IMPORTANT: Look at the HTML context to understand if multiple images are involved
|
|
145181
146591
|
- If the target section has multiple images, indicate this in targetElement (e.g., "all 3 images in Culinary Delights section")
|
|
145182
146592
|
- Image tasks should come BEFORE code tasks that depend on them
|
|
146593
|
+
|
|
146594
|
+
- CRITICAL: DO NOT create image task for these phrases (they mean REUSE existing):
|
|
146595
|
+
* "use the generated image" / "use the image"
|
|
146596
|
+
* "use this image" / "use existing image"
|
|
146597
|
+
* "with the generated image" / "with this image"
|
|
146598
|
+
* "with the previous image" / "with the last image"
|
|
146599
|
+
* "using the image I just created/generated"
|
|
146600
|
+
* Any reference to a PREVIOUS image from conversation history
|
|
146601
|
+
- Decision logic:
|
|
146602
|
+
* "Generate a new image of X" → CREATE image task (new generation)
|
|
146603
|
+
* "Create article using the generated image" → NO image task (reuse existing)
|
|
146604
|
+
|
|
145183
146605
|
` : ''}
|
|
145184
146606
|
|
|
145185
146607
|
Examples:
|
|
@@ -145217,6 +146639,17 @@ Input: "Create a landing page about wood furniture workshop"
|
|
|
145217
146639
|
Output: {"is_valid": true, "tasks": [{"type": "code", "description": "Create a landing page for a wood furniture workshop", "order": 1}], "is_mixed": false}
|
|
145218
146640
|
Note: No image task created because user did not explicitly request AI image generation
|
|
145219
146641
|
|
|
146642
|
+
Input: "Create an inspiring article and use the generated image"
|
|
146643
|
+
Output: {"is_valid": true, "tasks": [{"type": "code", "description": "Create article using previously generated image from conversation history", "order": 1}], "is_mixed": false}
|
|
146644
|
+
Note: No image task because user wants to REUSE existing image
|
|
146645
|
+
|
|
146646
|
+
Input: "Write a blog post about productivity and use this image"
|
|
146647
|
+
Output: {"is_valid": true, "tasks": [{"type": "code", "description": "Create blog post using previously generated image", "order": 1}], "is_mixed": false}
|
|
146648
|
+
|
|
146649
|
+
Input: "Generate another mountain image and create a landing page"
|
|
146650
|
+
Output: {"tasks": [{"type": "image", "description": "Generate new mountain image", "imagePrompt": "...", "order": 1}, {"type": "code", "description": "Create landing page with new image", "order": 2}], "is_mixed": true}
|
|
146651
|
+
Note: "another" and "generate" indicate NEW image generation
|
|
146652
|
+
|
|
145220
146653
|
` : `
|
|
145221
146654
|
Input: "Generate an AI image of a mountain"
|
|
145222
146655
|
Output: {"is_valid": false, "reason": "AI image generation is currently disabled.", "tasks": [], "is_mixed": false}
|
|
@@ -145299,8 +146732,9 @@ Output: {"is_valid": false, "reason": "AI image generation is currently disabled
|
|
|
145299
146732
|
|
|
145300
146733
|
if (imageTasksFromThisRequest.length > 0) {
|
|
145301
146734
|
hasGeneratedImages = true;
|
|
145302
|
-
imageContext = '\n\n=== GENERATED IMAGE URLS (USE THESE FOR YOUR TASK) ===\n';
|
|
145303
|
-
|
|
146735
|
+
imageContext = '\n\n=== GENERATED IMAGE URLS (USE THESE FOR YOUR TASK) ===\n'; // ⭐ REVERSE to show most recent first
|
|
146736
|
+
|
|
146737
|
+
imageTasksFromThisRequest.reverse().forEach(imageTask => {
|
|
145304
146738
|
if (imageTask.imageDetails && imageTask.imageDetails.length > 0) {
|
|
145305
146739
|
// Multiple images with context
|
|
145306
146740
|
imageTask.imageDetails.forEach((img, idx) => {
|
|
@@ -145315,7 +146749,8 @@ Output: {"is_valid": false, "reason": "AI image generation is currently disabled
|
|
|
145315
146749
|
});
|
|
145316
146750
|
}
|
|
145317
146751
|
});
|
|
145318
|
-
imageContext += '\n⚠️ IMPORTANT: Use
|
|
146752
|
+
imageContext += '\n⚠️ IMPORTANT: Use the FIRST image URL listed above (most recent) unless the task specifically asks for a different image.\n';
|
|
146753
|
+
imageContext += '⚠️ The first image is the MOST RECENTLY GENERATED and should be used by default.\n';
|
|
145319
146754
|
imageContext += '⚠️ Your task description specifies WHICH images to update - follow it precisely.\n';
|
|
145320
146755
|
} // ⭐ ALSO CHECK FOR CHAT RESULTS FROM PREVIOUS TASKS
|
|
145321
146756
|
|
|
@@ -145414,6 +146849,10 @@ ${this.builder.html()}
|
|
|
145414
146849
|
TASK: ${task.description}
|
|
145415
146850
|
|
|
145416
146851
|
IMPORTANT: Follow the Best Practices in Content framework.
|
|
146852
|
+
${this.builder.editor ? `CRITICAL: This project uses the Content.css and Box framework, NOT Tailwind. ONLY use classes explicitly documented in this framework guide.
|
|
146853
|
+
DO NOT use Tailwind classes like gap-4, w-1/2, top-4, hover:scale-120, etc.` : `CRITICAL: This project uses the Content.css framework, NOT Tailwind. ONLY use classes explicitly documented in this framework guide.
|
|
146854
|
+
DO NOT use Tailwind classes like gap-4, w-1/2, top-4, hover:scale-120, etc.`}
|
|
146855
|
+
For flexibility, you can use inline styles or embedded <style> at the end of the generated HTML.
|
|
145417
146856
|
|
|
145418
146857
|
${imageContext}
|
|
145419
146858
|
${chatContext}
|
|
@@ -145894,6 +147333,320 @@ ${this.builder.html()}
|
|
|
145894
147333
|
document.body.removeChild(announcement);
|
|
145895
147334
|
}, 1000);
|
|
145896
147335
|
}
|
|
147336
|
+
/**
|
|
147337
|
+
* ============================================================================
|
|
147338
|
+
* DEMO MODE
|
|
147339
|
+
* ============================================================================
|
|
147340
|
+
*/
|
|
147341
|
+
|
|
147342
|
+
|
|
147343
|
+
loadConversations() {
|
|
147344
|
+
// Load demo conversations
|
|
147345
|
+
if (this.demoConversations && this.demoConversations.length > 0) {
|
|
147346
|
+
this.demoConversations.forEach(msg => {
|
|
147347
|
+
if (msg.role === 'user') {
|
|
147348
|
+
this.addMessage('user', msg.content);
|
|
147349
|
+
} else if (msg.role === 'assistant') {
|
|
147350
|
+
this.addMessage('assistant', msg.content, true); // Add image preview if available
|
|
147351
|
+
|
|
147352
|
+
if (msg.imagePreview && msg.imagePreview.length > 0) {
|
|
147353
|
+
this.addImagePreview(msg.imagePreview); // Include in conversationResults with correct structure
|
|
147354
|
+
|
|
147355
|
+
this.conversationResults.push({
|
|
147356
|
+
type: 'image',
|
|
147357
|
+
description: 'Previously generated image from demo',
|
|
147358
|
+
content: `Generated ${msg.imagePreview.length} images`,
|
|
147359
|
+
generatedUrls: msg.imagePreview.map(img => img.url),
|
|
147360
|
+
// Array of URLs
|
|
147361
|
+
imageDetails: msg.imagePreview.map(img => ({
|
|
147362
|
+
// Array of objects
|
|
147363
|
+
url: img.url,
|
|
147364
|
+
context: img.context,
|
|
147365
|
+
prompt: img.context || '' // Use context as prompt if no prompt available
|
|
147366
|
+
|
|
147367
|
+
})),
|
|
147368
|
+
targetElement: 'demo images'
|
|
147369
|
+
});
|
|
147370
|
+
}
|
|
147371
|
+
}
|
|
147372
|
+
});
|
|
147373
|
+
}
|
|
147374
|
+
}
|
|
147375
|
+
|
|
147376
|
+
addDemoBanner() {
|
|
147377
|
+
const out = s => this.out(s);
|
|
147378
|
+
|
|
147379
|
+
const banner = document.createElement('div');
|
|
147380
|
+
banner.className = 'demo-banner';
|
|
147381
|
+
banner.innerHTML = `
|
|
147382
|
+
<div style="
|
|
147383
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
147384
|
+
color: white;
|
|
147385
|
+
padding: 12px 16px;
|
|
147386
|
+
border-radius: 8px;
|
|
147387
|
+
font-size: 13px;
|
|
147388
|
+
display: flex;
|
|
147389
|
+
align-items: center;
|
|
147390
|
+
gap: 8px;
|
|
147391
|
+
box-shadow: 0 4px 12px rgba(102, 126, 234, 0.3);
|
|
147392
|
+
">
|
|
147393
|
+
<span style="font-size: 18px;">📖</span>
|
|
147394
|
+
<div>
|
|
147395
|
+
<strong>${out('Read-Only Demo')}</strong>
|
|
147396
|
+
<div style="font-size: 11px; opacity: 0.9; margin-top: 2px;">
|
|
147397
|
+
${out('Full AI chat available in the complete version.')}
|
|
147398
|
+
</div>
|
|
147399
|
+
</div>
|
|
147400
|
+
</div>
|
|
147401
|
+
`; // Insert banner at the top of messages container
|
|
147402
|
+
// this.messagesContainer.insertBefore(banner, this.messagesContainer.firstChild);
|
|
147403
|
+
|
|
147404
|
+
this.messagesContainer.appendChild(banner);
|
|
147405
|
+
}
|
|
147406
|
+
/**
|
|
147407
|
+
* Update the quick image size button based on current model and settings
|
|
147408
|
+
*/
|
|
147409
|
+
|
|
147410
|
+
|
|
147411
|
+
updateQuickImageSizeButton() {
|
|
147412
|
+
const imageGenEnabled = this.builder.generateMediaUrl_Fal ? true : false;
|
|
147413
|
+
|
|
147414
|
+
if (!imageGenEnabled) {
|
|
147415
|
+
this.quickImageSizeButton.style.display = 'none';
|
|
147416
|
+
return;
|
|
147417
|
+
}
|
|
147418
|
+
|
|
147419
|
+
const currentModelId = this.settings.imageModel;
|
|
147420
|
+
const availableSizes = this.getSizesForModel(currentModelId); // Hide button if model has no size options
|
|
147421
|
+
|
|
147422
|
+
if (!availableSizes || availableSizes.length === 0) {
|
|
147423
|
+
this.quickImageSizeButton.style.display = 'none';
|
|
147424
|
+
return;
|
|
147425
|
+
} // Show button
|
|
147426
|
+
|
|
147427
|
+
|
|
147428
|
+
this.quickImageSizeButton.style.display = 'flex'; // Smart selection: check if current size is available
|
|
147429
|
+
|
|
147430
|
+
let selectedSize = this.settings.imageSize;
|
|
147431
|
+
|
|
147432
|
+
if (!availableSizes.includes(selectedSize)) {
|
|
147433
|
+
// Current size not available, find best fallback
|
|
147434
|
+
selectedSize = this.findBestFallback(selectedSize, availableSizes);
|
|
147435
|
+
this.settings.imageSize = selectedSize; // Sync with settings dialog
|
|
147436
|
+
|
|
147437
|
+
this.imageSizeSelect.value = selectedSize; // Save to storage
|
|
147438
|
+
|
|
147439
|
+
this.saveSettingsToStorage();
|
|
147440
|
+
} // Update button label
|
|
147441
|
+
|
|
147442
|
+
|
|
147443
|
+
this.updateButtonLabel(selectedSize); // Populate popover options
|
|
147444
|
+
|
|
147445
|
+
this.populateSizePopover(availableSizes, selectedSize);
|
|
147446
|
+
}
|
|
147447
|
+
/**
|
|
147448
|
+
* Get available sizes for a model (reuse existing logic)
|
|
147449
|
+
*/
|
|
147450
|
+
|
|
147451
|
+
|
|
147452
|
+
getSizesForModel(modelId) {
|
|
147453
|
+
const model = this.imageModels.find(m => m.id === modelId);
|
|
147454
|
+
if (!model) return null; // if sizes explicitly empty array → means no size options
|
|
147455
|
+
|
|
147456
|
+
if (Array.isArray(model.sizes) && model.sizes.length === 0) {
|
|
147457
|
+
return null;
|
|
147458
|
+
}
|
|
147459
|
+
|
|
147460
|
+
const defaultSizes = ['square', 'square_hd', 'landscape_4_3', 'landscape_16_9', 'portrait_4_3', 'portrait_16_9'];
|
|
147461
|
+
return model.sizes || defaultSizes;
|
|
147462
|
+
}
|
|
147463
|
+
/**
|
|
147464
|
+
* Find best fallback size when current selection is not available
|
|
147465
|
+
*/
|
|
147466
|
+
|
|
147467
|
+
|
|
147468
|
+
findBestFallback(preferredSize, availableSizes) {
|
|
147469
|
+
// Strategy 1: Try to match orientation
|
|
147470
|
+
const orientation = this.getOrientation(preferredSize);
|
|
147471
|
+
const matchingOrientation = availableSizes.find(size => this.getOrientation(size) === orientation);
|
|
147472
|
+
if (matchingOrientation) return matchingOrientation; // Strategy 2: Common defaults
|
|
147473
|
+
|
|
147474
|
+
if (availableSizes.includes('16:9')) return '16:9';
|
|
147475
|
+
if (availableSizes.includes('landscape_16_9')) return 'landscape_16_9';
|
|
147476
|
+
if (availableSizes.includes('1:1')) return '1:1';
|
|
147477
|
+
if (availableSizes.includes('square')) return 'square'; // Strategy 3: First available
|
|
147478
|
+
|
|
147479
|
+
return availableSizes[0];
|
|
147480
|
+
}
|
|
147481
|
+
/**
|
|
147482
|
+
* Determine orientation from size value
|
|
147483
|
+
*/
|
|
147484
|
+
|
|
147485
|
+
|
|
147486
|
+
getOrientation(size) {
|
|
147487
|
+
const landscape = ['16:9', '21:9', '4:3', '3:2', '5:4', 'landscape_16_9', 'landscape_4_3'];
|
|
147488
|
+
const portrait = ['9:16', '9:21', '3:4', '2:3', '4:5', 'portrait_16_9', 'portrait_4_3'];
|
|
147489
|
+
if (landscape.includes(size)) return 'landscape';
|
|
147490
|
+
if (portrait.includes(size)) return 'portrait';
|
|
147491
|
+
return 'square';
|
|
147492
|
+
}
|
|
147493
|
+
/**
|
|
147494
|
+
* Update button label to show current size
|
|
147495
|
+
*/
|
|
147496
|
+
|
|
147497
|
+
|
|
147498
|
+
updateButtonLabel(sizeValue) {
|
|
147499
|
+
if (!sizeValue) {
|
|
147500
|
+
this.quickImageSizeButton.textContent = '□';
|
|
147501
|
+
this.quickImageSizeButton.setAttribute('aria-label', this.out('Select image size'));
|
|
147502
|
+
return;
|
|
147503
|
+
} // Convert verbose labels to short form
|
|
147504
|
+
|
|
147505
|
+
|
|
147506
|
+
const labelMap = {
|
|
147507
|
+
'landscape_16_9': '16:9',
|
|
147508
|
+
'landscape_4_3': '4:3',
|
|
147509
|
+
'portrait_16_9': '9:16',
|
|
147510
|
+
'portrait_4_3': '3:4',
|
|
147511
|
+
'square': '1:1',
|
|
147512
|
+
'square_hd': '1:1 HD'
|
|
147513
|
+
};
|
|
147514
|
+
const displayLabel = labelMap[sizeValue] || sizeValue;
|
|
147515
|
+
this.quickImageSizeButton.textContent = displayLabel;
|
|
147516
|
+
this.quickImageSizeButton.setAttribute('aria-label', `${this.out('Image size')}: ${displayLabel}`);
|
|
147517
|
+
}
|
|
147518
|
+
/**
|
|
147519
|
+
* Populate the size popover with available options
|
|
147520
|
+
*/
|
|
147521
|
+
|
|
147522
|
+
|
|
147523
|
+
populateSizePopover(sizes, selectedSize) {
|
|
147524
|
+
const out = s => this.out(s);
|
|
147525
|
+
|
|
147526
|
+
const sizeDefs = {
|
|
147527
|
+
'square_hd': out('Square HD'),
|
|
147528
|
+
'square': out('Square'),
|
|
147529
|
+
'landscape_4_3': out('Landscape 4x3'),
|
|
147530
|
+
'landscape_16_9': out('Landscape 16x9'),
|
|
147531
|
+
'portrait_4_3': out('Portrait 3x4'),
|
|
147532
|
+
'portrait_16_9': out('Portrait 9x16'),
|
|
147533
|
+
'1:1': out('Square'),
|
|
147534
|
+
'3:2': out('Landscape 3x2'),
|
|
147535
|
+
'4:3': out('Landscape 4x3'),
|
|
147536
|
+
'5:4': out('Landscape 5x4'),
|
|
147537
|
+
'16:9': out('Landscape 16x9'),
|
|
147538
|
+
'21:9': out('Landscape 21:9'),
|
|
147539
|
+
'2:3': out('Portrait 2x3'),
|
|
147540
|
+
'3:4': out('Portrait 3x4'),
|
|
147541
|
+
'4:5': out('Portrait 4x5'),
|
|
147542
|
+
'9:16': out('Portrait 9x16'),
|
|
147543
|
+
'9:21': out('Portrait 9:21')
|
|
147544
|
+
};
|
|
147545
|
+
this.sizeOptionsContainer.innerHTML = '';
|
|
147546
|
+
sizes.forEach(size => {
|
|
147547
|
+
const option = document.createElement('div');
|
|
147548
|
+
option.className = 'size-option' + (size === selectedSize ? ' selected' : '');
|
|
147549
|
+
option.setAttribute('role', 'menuitem');
|
|
147550
|
+
option.setAttribute('tabindex', '0');
|
|
147551
|
+
const radio = document.createElement('input');
|
|
147552
|
+
radio.type = 'radio';
|
|
147553
|
+
radio.name = 'quickImageSize';
|
|
147554
|
+
radio.value = size;
|
|
147555
|
+
radio.checked = size === selectedSize;
|
|
147556
|
+
radio.id = `quick-size-${size}`;
|
|
147557
|
+
const label = document.createElement('label');
|
|
147558
|
+
label.htmlFor = `quick-size-${size}`;
|
|
147559
|
+
label.textContent = sizeDefs[size] || size; // label.style.cursor = 'pointer';
|
|
147560
|
+
|
|
147561
|
+
label.style.flex = '1';
|
|
147562
|
+
option.appendChild(radio);
|
|
147563
|
+
option.appendChild(label); // Click handler
|
|
147564
|
+
|
|
147565
|
+
option.addEventListener('click', () => {
|
|
147566
|
+
this.selectImageSize(size);
|
|
147567
|
+
}); // Keyboard handler
|
|
147568
|
+
|
|
147569
|
+
option.addEventListener('keydown', e => {
|
|
147570
|
+
if (e.key === 'Enter' || e.key === ' ') {
|
|
147571
|
+
e.preventDefault();
|
|
147572
|
+
this.selectImageSize(size);
|
|
147573
|
+
}
|
|
147574
|
+
});
|
|
147575
|
+
this.sizeOptionsContainer.appendChild(option);
|
|
147576
|
+
});
|
|
147577
|
+
}
|
|
147578
|
+
/**
|
|
147579
|
+
* Handle size selection
|
|
147580
|
+
*/
|
|
147581
|
+
|
|
147582
|
+
|
|
147583
|
+
selectImageSize(size) {
|
|
147584
|
+
// Update settings
|
|
147585
|
+
this.settings.imageSize = size; // Sync with settings dialog
|
|
147586
|
+
|
|
147587
|
+
this.imageSizeSelect.value = size; // Update button label
|
|
147588
|
+
|
|
147589
|
+
this.updateButtonLabel(size); // Update popover selection
|
|
147590
|
+
|
|
147591
|
+
this.sizeOptionsContainer.querySelectorAll('.size-option').forEach(opt => {
|
|
147592
|
+
opt.classList.remove('selected');
|
|
147593
|
+
opt.querySelector('input[type="radio"]').checked = false;
|
|
147594
|
+
}); // const selectedOption = this.sizeOptionsContainer.querySelector(`#quick-size-${size}`);
|
|
147595
|
+
|
|
147596
|
+
const selectedOption = Array.from(this.sizeOptionsContainer.querySelectorAll('input[type="radio"]')).find(radio => radio.value === size);
|
|
147597
|
+
|
|
147598
|
+
if (selectedOption) {
|
|
147599
|
+
selectedOption.closest('.size-option').classList.add('selected');
|
|
147600
|
+
selectedOption.checked = true;
|
|
147601
|
+
} // Save to storage
|
|
147602
|
+
|
|
147603
|
+
|
|
147604
|
+
this.saveSettingsToStorage(); // Close popover
|
|
147605
|
+
|
|
147606
|
+
this.closeImageSizePopover(); // Focus back to input
|
|
147607
|
+
|
|
147608
|
+
this.promptInput.focus();
|
|
147609
|
+
}
|
|
147610
|
+
/**
|
|
147611
|
+
* Toggle popover visibility
|
|
147612
|
+
*/
|
|
147613
|
+
|
|
147614
|
+
|
|
147615
|
+
toggleImageSizePopover() {
|
|
147616
|
+
const isVisible = this.imageSizePopover.style.display !== 'none';
|
|
147617
|
+
|
|
147618
|
+
if (isVisible) {
|
|
147619
|
+
this.closeImageSizePopover();
|
|
147620
|
+
} else {
|
|
147621
|
+
this.openImageSizePopover();
|
|
147622
|
+
}
|
|
147623
|
+
}
|
|
147624
|
+
/**
|
|
147625
|
+
* Open the size popover
|
|
147626
|
+
*/
|
|
147627
|
+
|
|
147628
|
+
|
|
147629
|
+
openImageSizePopover() {
|
|
147630
|
+
this.imageSizePopover.style.display = 'block';
|
|
147631
|
+
this.imageSizePopover.setAttribute('aria-hidden', 'false');
|
|
147632
|
+
this.quickImageSizeButton.setAttribute('aria-expanded', 'true'); // Focus first option
|
|
147633
|
+
|
|
147634
|
+
const firstOption = this.sizeOptionsContainer.querySelector('.size-option');
|
|
147635
|
+
|
|
147636
|
+
if (firstOption) {
|
|
147637
|
+
firstOption.focus();
|
|
147638
|
+
}
|
|
147639
|
+
}
|
|
147640
|
+
/**
|
|
147641
|
+
* Close the size popover
|
|
147642
|
+
*/
|
|
147643
|
+
|
|
147644
|
+
|
|
147645
|
+
closeImageSizePopover() {
|
|
147646
|
+
this.imageSizePopover.style.display = 'none';
|
|
147647
|
+
this.imageSizePopover.setAttribute('aria-hidden', 'true');
|
|
147648
|
+
this.quickImageSizeButton.setAttribute('aria-expanded', 'false');
|
|
147649
|
+
}
|
|
145897
147650
|
|
|
145898
147651
|
out(s) {
|
|
145899
147652
|
let result = this.builder.lang[s];
|
|
@@ -146311,6 +148064,91 @@ Use grayscale for minimalist design.
|
|
|
146311
148064
|
|
|
146312
148065
|
> **Editorial Style:** Stick to black, white, and grays for a clean, minimalist aesthetic. Use color sparingly for accents.
|
|
146313
148066
|
|
|
148067
|
+
` + `
|
|
148068
|
+
|
|
148069
|
+
### Animation
|
|
148070
|
+
|
|
148071
|
+
**Transition**
|
|
148072
|
+
|
|
148073
|
+
Classes: transition-none, transition, transition-colors, transition-opacity, transition-shadow, transition-transform, transition-all
|
|
148074
|
+
|
|
148075
|
+
**Duration**
|
|
148076
|
+
|
|
148077
|
+
Classes: duration-75, duration-100, duration-150, duration-200, duration-300, duration-500, duration-700, duration-1000, duration-1500
|
|
148078
|
+
|
|
148079
|
+
**Timing**
|
|
148080
|
+
|
|
148081
|
+
Classes: ease-linear, ease-in, ease-out, ease-in-out
|
|
148082
|
+
|
|
148083
|
+
**Delay**
|
|
148084
|
+
|
|
148085
|
+
Classes: delay-75, delay-100, delay-150, delay-200, delay-300, delay-500
|
|
148086
|
+
|
|
148087
|
+
**Scale**
|
|
148088
|
+
|
|
148089
|
+
Classes: scale-0, scale-50, scale-75, scale-90, scale-95, scale-100, scale-105, scale-110, scale-125, scale-150
|
|
148090
|
+
|
|
148091
|
+
**Hover Effect**
|
|
148092
|
+
|
|
148093
|
+
Classes: hover:scale-105
|
|
148094
|
+
|
|
148095
|
+
**Rotate**
|
|
148096
|
+
|
|
148097
|
+
Classes: rotate-0, rotate-45, rotate-90, rotate-180
|
|
148098
|
+
|
|
148099
|
+
**Translate X**
|
|
148100
|
+
|
|
148101
|
+
Classes: translate-x-0, translate-x-1, translate-x-2, translate-x-4, translate-x-8
|
|
148102
|
+
|
|
148103
|
+
**Translate Y**
|
|
148104
|
+
|
|
148105
|
+
Classes: translate-y-0, translate-y-1, translate-y-2, translate-y-4, translate-y-8
|
|
148106
|
+
|
|
148107
|
+
**Skew**
|
|
148108
|
+
|
|
148109
|
+
Classes: skew-x-0, skew-x-3, skew-x-6, skew-y-0, skew-y-3, skew-y-6
|
|
148110
|
+
|
|
148111
|
+
**Overflow**
|
|
148112
|
+
|
|
148113
|
+
Classes: overflow-hidden, overflow-visible, overflow-scroll, overflow-auto
|
|
148114
|
+
|
|
148115
|
+
**Opacity**
|
|
148116
|
+
|
|
148117
|
+
Classes:
|
|
148118
|
+
|
|
148119
|
+
| Class | Color |
|
|
148120
|
+
| ------------ | ------------- |
|
|
148121
|
+
| '.opacity-0' | opacity: 0 |
|
|
148122
|
+
| '.opacity-2' | opacity: 0.02 |
|
|
148123
|
+
| '.opacity-4' | opacity: 0.04 |
|
|
148124
|
+
| '.opacity-5' | opacity: 0.05 |
|
|
148125
|
+
| '.opacity-6' | opacity: 0.06 |
|
|
148126
|
+
| '.opacity-8' | opacity: 0.07 |
|
|
148127
|
+
| '.opacity-10' | opacity: 0.1 |
|
|
148128
|
+
| '.opacity-12' | opacity: 0.12 |
|
|
148129
|
+
| '.opacity-15' | opacity: 0.15 |
|
|
148130
|
+
| '.opacity-20' | opacity: 0.2 |
|
|
148131
|
+
| '.opacity-25' | opacity: 0.25 |
|
|
148132
|
+
| '.opacity-30' | opacity: 0.3 |
|
|
148133
|
+
| '.opacity-35' | opacity: 0.35 |
|
|
148134
|
+
| '.opacity-40' | opacity: 0.4 |
|
|
148135
|
+
| '.opacity-45' | opacity: 0.45 |
|
|
148136
|
+
| '.opacity-50' | opacity: 0.5 |
|
|
148137
|
+
| '.opacity-55' | opacity: 0.55 |
|
|
148138
|
+
| '.opacity-60' | opacity: 0.6 |
|
|
148139
|
+
| '.opacity-65' | opacity: 0.65 |
|
|
148140
|
+
| '.opacity-70' | opacity: 0.7 |
|
|
148141
|
+
| '.opacity-75' | opacity: 0.75 |
|
|
148142
|
+
| '.opacity-80' | opacity: 0.8 |
|
|
148143
|
+
| '.opacity-85' | opacity: 0.85 |
|
|
148144
|
+
| '.opacity-90' | opacity: 0.9 |
|
|
148145
|
+
| '.opacity-95' | opacity: 0.95 |
|
|
148146
|
+
| '.opacity-100' | opacity: 1 |
|
|
148147
|
+
|
|
148148
|
+
**Animation keyframes**
|
|
148149
|
+
|
|
148150
|
+
Classes: spin, ping, pulse, bounce
|
|
148151
|
+
` + `
|
|
146314
148152
|
---
|
|
146315
148153
|
` + `
|
|
146316
148154
|
## Common Patterns
|
|
@@ -146587,6 +148425,31 @@ When creating icon-based features, benefits, or service sections: use Bootstrap
|
|
|
146587
148425
|
<h4 class="size-18 font-medium text-center pb-3">Lightning Fast</h4>
|
|
146588
148426
|
<p class="size-14 leading-16 text-gray-600 text-center">Description...</p>
|
|
146589
148427
|
|
|
148428
|
+
### 9. Image Layout with Hover Effect
|
|
148429
|
+
|
|
148430
|
+
Use this pattern for all images (galleries, featured images, portfolio items):
|
|
148431
|
+
|
|
148432
|
+
<div class="w-full overflow-hidden relative bg-gray-50" style="aspect-ratio:16/9">
|
|
148433
|
+
<img src="..." alt="..." class="w-full h-full object-cover transition-transform duration-1500 hover:scale-105">
|
|
148434
|
+
</div>
|
|
148435
|
+
|
|
148436
|
+
**Key elements:**
|
|
148437
|
+
- 'aspect-ratio:16/9' - maintains proportions (adjust as needed: 1/1, 4/3, 3/2, 16/9, etc.)
|
|
148438
|
+
- 'overflow-hidden' - keeps scaled image contained
|
|
148439
|
+
- 'bg-gray-50' - placeholder while image loads
|
|
148440
|
+
- 'transition-transform duration-1000' - smooth 1-second animation
|
|
148441
|
+
- 'hover:scale-105' - subtle 5% scale on hover
|
|
148442
|
+
- 'object-cover' - ensures image fills container
|
|
148443
|
+
|
|
148444
|
+
**Common aspect ratios:**
|
|
148445
|
+
- Square: 'aspect-ratio:1/1'
|
|
148446
|
+
- Portrait: 'aspect-ratio:3/4' or 'aspect-ratio:2/3'
|
|
148447
|
+
- Landscape: 'aspect-ratio:4/3' or 'aspect-ratio:3/2'
|
|
148448
|
+
- Wide: 'aspect-ratio:16/9' or 'aspect-ratio:21/9'
|
|
148449
|
+
- Tall portrait: 'aspect-ratio:9/16'
|
|
148450
|
+
|
|
148451
|
+
Always include this hover effect for a polished, interactive feel.
|
|
148452
|
+
|
|
146590
148453
|
`;
|
|
146591
148454
|
|
|
146592
148455
|
const contextBoxFramework = `
|
|
@@ -147355,45 +149218,120 @@ The frameworks provide utility classes for structure and typography. To create r
|
|
|
147355
149218
|
<!-- Content -->
|
|
147356
149219
|
</div>
|
|
147357
149220
|
|
|
147358
|
-
<!--
|
|
149221
|
+
<!-- Section 3 -->
|
|
149222
|
+
<div class="is-section is-box is-section-100 type-system-ui">
|
|
149223
|
+
|
|
149224
|
+
<div class="is-container leading-14 size-18 is-content-1100">
|
|
149225
|
+
|
|
149226
|
+
<div class="row">
|
|
149227
|
+
<div class="column">
|
|
149228
|
+
|
|
149229
|
+
<!-- GUIDANCE: Use this layout to show images at any aspect ratio with a hover scale effect -->
|
|
149230
|
+
<div class="w-full overflow-hidden relative bg-gray-50" style="aspect-ratio:16/9">
|
|
149231
|
+
<img src="https://placehold.co/1200x1200/f5f5f5/999?text=Featured" alt="Featured Project" class="w-full h-full object-cover transition-transform duration-1500 hover:scale-105">
|
|
149232
|
+
</div>
|
|
149233
|
+
|
|
149234
|
+
</div>
|
|
149235
|
+
</div>
|
|
149236
|
+
|
|
149237
|
+
<div class="row">
|
|
149238
|
+
<div class="column">
|
|
149239
|
+
|
|
149240
|
+
<div class="featured-image">
|
|
149241
|
+
<img src="https://placehold.co/1600x700" alt="Featured Project">
|
|
149242
|
+
</div>
|
|
149243
|
+
|
|
149244
|
+
</div>
|
|
149245
|
+
</div>
|
|
149246
|
+
|
|
149247
|
+
<div class="row portfolio-row">
|
|
149248
|
+
<div class="column">
|
|
149249
|
+
|
|
149250
|
+
<div class="row-image">
|
|
149251
|
+
<img src="https://placehold.co/1200x900" alt="Digital Banking">
|
|
149252
|
+
</div>
|
|
149253
|
+
|
|
149254
|
+
</div>
|
|
149255
|
+
<div class="column">
|
|
149256
|
+
|
|
149257
|
+
<!-- Content -->
|
|
149258
|
+
|
|
149259
|
+
</div>
|
|
149260
|
+
</div>
|
|
149261
|
+
|
|
149262
|
+
<div class="row">
|
|
149263
|
+
|
|
149264
|
+
<div class="column">
|
|
149265
|
+
|
|
149266
|
+
<div class="p-12 bg-gray-50 hover-lift">
|
|
149267
|
+
<p class="size-18 leading-17 text-black pb-8">The level of professionalism and expertise demonstrated throughout the project was outstanding. Highly recommend to anyone looking for quality work.</p>
|
|
149268
|
+
<p class="size-14 font-semibold text-black pb-1">Michael Chen</p>
|
|
149269
|
+
<p class="size-13 text-gray-600 tracking-wide">Founder, Innovation Labs</p>
|
|
149270
|
+
</div>
|
|
149271
|
+
|
|
149272
|
+
</div>
|
|
149273
|
+
<div class="column">
|
|
149274
|
+
|
|
149275
|
+
<!-- Content -->
|
|
147359
149276
|
|
|
147360
|
-
|
|
149277
|
+
</div>
|
|
149278
|
+
</div>
|
|
149279
|
+
</div>
|
|
149280
|
+
</div>
|
|
149281
|
+
|
|
149282
|
+
<!-- Embedded Styke -->
|
|
147361
149283
|
<style>
|
|
147362
|
-
|
|
147363
|
-
|
|
147364
|
-
|
|
147365
|
-
|
|
147366
|
-
|
|
147367
|
-
}
|
|
147368
|
-
50% {
|
|
147369
|
-
opacity: 0.8;
|
|
149284
|
+
/* Subtle hover zoom for background images */
|
|
149285
|
+
.is-overlay-bg {
|
|
149286
|
+
transition: transform 1s ease;
|
|
149287
|
+
}
|
|
149288
|
+
.is-box:hover .is-overlay-bg {
|
|
147370
149289
|
transform: scale(1.05);
|
|
147371
149290
|
}
|
|
147372
|
-
}
|
|
147373
149291
|
|
|
147374
|
-
|
|
147375
|
-
|
|
147376
|
-
|
|
147377
|
-
|
|
147378
|
-
|
|
149292
|
+
/* Featured image */
|
|
149293
|
+
.featured-image {
|
|
149294
|
+
width: 100%;
|
|
149295
|
+
aspect-ratio: 21/9;
|
|
149296
|
+
overflow: hidden;
|
|
149297
|
+
position: relative;
|
|
149298
|
+
background: #fafafa;
|
|
147379
149299
|
}
|
|
147380
|
-
|
|
147381
|
-
|
|
149300
|
+
.featured-image img {
|
|
149301
|
+
width: 100%;
|
|
149302
|
+
height: 100%;
|
|
149303
|
+
object-fit: cover;
|
|
149304
|
+
transition: transform 2s cubic-bezier(0.4, 0, 0.2, 1);
|
|
149305
|
+
}
|
|
149306
|
+
.featured-image:hover img {
|
|
149307
|
+
transform: scale(1.03);
|
|
147382
149308
|
}
|
|
147383
|
-
}
|
|
147384
149309
|
|
|
147385
|
-
|
|
147386
|
-
|
|
147387
|
-
|
|
149310
|
+
/* Row image */
|
|
149311
|
+
.row-image {
|
|
149312
|
+
width: 100%;
|
|
149313
|
+
aspect-ratio: 4/3;
|
|
149314
|
+
overflow: hidden;
|
|
149315
|
+
position: relative;
|
|
149316
|
+
background: #fafafa;
|
|
147388
149317
|
}
|
|
147389
|
-
|
|
147390
|
-
|
|
149318
|
+
.row-image img {
|
|
149319
|
+
width: 100%;
|
|
149320
|
+
height: 100%;
|
|
149321
|
+
object-fit: cover;
|
|
149322
|
+
transition: transform 1.4s cubic-bezier(0.4, 0, 0.2, 1);
|
|
149323
|
+
}
|
|
149324
|
+
.portfolio-row:hover .row-image img {
|
|
149325
|
+
transform: scale(1.05);
|
|
147391
149326
|
}
|
|
147392
|
-
}
|
|
147393
149327
|
|
|
147394
|
-
|
|
147395
|
-
|
|
147396
|
-
|
|
149328
|
+
/* Smooth hover animations */
|
|
149329
|
+
.hover-lift {
|
|
149330
|
+
transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
|
149331
|
+
}
|
|
149332
|
+
.hover-lift:hover {
|
|
149333
|
+
transform: translateY(-4px);
|
|
149334
|
+
}
|
|
147397
149335
|
</style>
|
|
147398
149336
|
|
|
147399
149337
|
|
|
@@ -147425,9 +149363,9 @@ The frameworks provide utility classes for structure and typography. To create r
|
|
|
147425
149363
|
- **Pure white dominant**: Clean #ffffff backgrounds, not cream or off-white
|
|
147426
149364
|
- **Minimal color usage**: Mostly black text on white, with occasional single accent color
|
|
147427
149365
|
- **Light gray backgrounds**: #f5f5f5 or #e5e5e5 for page backgrounds behind white cards
|
|
147428
|
-
- **Strategic black sections**: Full black backgrounds for contrast moments
|
|
147429
|
-
- **Accent color blocks**: Small pops of color (red, orange) used sparingly as highlights
|
|
147430
|
-
|
|
149366
|
+
` + // - **Strategic black sections**: Full black backgrounds for contrast moments
|
|
149367
|
+
// - **Accent color blocks**: Small pops of color (red, orange) used sparingly as highlights
|
|
149368
|
+
`
|
|
147431
149369
|
### Information Architecture
|
|
147432
149370
|
- **Numbered lists**: "1. OVERVIEW", "2. SERVICES", etc. as section headers
|
|
147433
149371
|
- **Metadata in lines**: "Client Name | Project Type | Year" separated by pipes or lines
|
|
@@ -154066,6 +156004,33 @@ Add an image for each feature.`, 'Create a new block showcasing a photo gallery
|
|
|
154066
156004
|
*/
|
|
154067
156005
|
|
|
154068
156006
|
},
|
|
156007
|
+
demoMode: false,
|
|
156008
|
+
|
|
156009
|
+
/*
|
|
156010
|
+
demoConversations: [
|
|
156011
|
+
{
|
|
156012
|
+
role: 'user',
|
|
156013
|
+
content: 'Generate an image: "a house with beautiful mountain view. warm sunlight, golden-hour lighting, filmic teal-orange color grade".',
|
|
156014
|
+
// timestamp: Date.now() - 180000 // 3 minutes ago
|
|
156015
|
+
},
|
|
156016
|
+
{
|
|
156017
|
+
role: 'assistant',
|
|
156018
|
+
content: '✓ Image generated successfully',
|
|
156019
|
+
imagePreview: [
|
|
156020
|
+
{ url: 'uploads/ai-8vnqv.png', context: 'Generate image of a house with a beautiful mountain view' },
|
|
156021
|
+
]
|
|
156022
|
+
},
|
|
156023
|
+
{
|
|
156024
|
+
role: 'user',
|
|
156025
|
+
content: `Create a thoughtful article about finding home in extraordinary landscapes. Write vivid prose about mountain dwellings and how our environments shape the way we live.
|
|
156026
|
+
Use the generated image for this article, and present it as a premium design magazine feature.`,
|
|
156027
|
+
},
|
|
156028
|
+
{
|
|
156029
|
+
role: 'assistant',
|
|
156030
|
+
content: '✓ Create a thoughtful article about finding home in extraordinary landscapes with vivid prose about mountain dwellings and their impact on our lives, formatted as a premium design magazine feature.',
|
|
156031
|
+
}
|
|
156032
|
+
],
|
|
156033
|
+
*/
|
|
154069
156034
|
|
|
154070
156035
|
/* Old Version (backward compatible) */
|
|
154071
156036
|
onAddSectionOpen: function () {},
|
|
@@ -157480,7 +159445,8 @@ Add an image for each feature.`, 'Create a new block showcasing a photo gallery
|
|
|
157480
159445
|
}
|
|
157481
159446
|
});
|
|
157482
159447
|
arrSections.forEach(section => {
|
|
157483
|
-
// Code Blocks Handling
|
|
159448
|
+
if (!section.classList.contains('is-section')) return; // Code Blocks Handling
|
|
159449
|
+
|
|
157484
159450
|
let codeBlocks = section.querySelectorAll('[data-html]');
|
|
157485
159451
|
codeBlocks.forEach(element => {
|
|
157486
159452
|
let html = decodeURIComponent(element.getAttribute('data-html')); // Original code is stored in data-html attribute
|
|
@@ -158317,6 +160283,8 @@ Add an image for each feature.`, 'Create a new block showcasing a photo gallery
|
|
|
158317
160283
|
// Add missing is-box class for full width (non splitted) section
|
|
158318
160284
|
if (!section.querySelector('.is-box')) {
|
|
158319
160285
|
section.classList.add('is-box');
|
|
160286
|
+
} else {
|
|
160287
|
+
section.classList.remove('is-box');
|
|
158320
160288
|
}
|
|
158321
160289
|
|
|
158322
160290
|
const containers = section.querySelectorAll('.is-container');
|